doc/articles/guides/profiling-applications.md
.NET provides the ability to do CPU profiling through dotnet-trace for iOS and Android applications.
Run the following commands
dotnet tool update -g dotnet-dsrouterdotnet tool update -g dotnet-tracedotnet tool update -g dotnet-gcdump[!NOTE] This documentation is based on .NET iOS profiling and .NET Android profiling documentation.
Profiling iOS apps needs to be done on a mac machine.
First, create an alias to mlaunch:
cd [your-folder-with-the-csproj]
alias mlaunch=$(dotnet build -getProperty:MlaunchPath *.csproj -f net10.0-ios)
Build the app with the following parameters:
cd [your-folder-with-the-csproj]
dotnet build -f net10.0-ios -p:DiagnosticAddress=127.0.0.1 -p:DiagnosticPort=9000 -p:DiagnosticSuspend=true -p:DiagnosticListenMode=listen
Find the simulator you want to run on:
$ xcrun simctl list devices
Find a device that is shutdown or booted, and take note of its UDID.
Launch the app (it will be paused on startup waiting for the .NET tooling to connect):
mlaunch --device :v2:udid=xxxxxxxx-yyyy-zzzz-aaaa-bbbbbbbbbbbb --wait-for-exit --stdout=$(tty) --stderr=$(tty) --launchsim=[your-app-path]/bin/Debug/net*-ios/*/*.app
Replace the UDID with the one you found above.
Once the app is waiting, go ahead and start profiling:
dotnet-trace collect --dsrouter ios-sim --format speedscope
Optionally take a GC dump:
dotnet-gcdump collect --dsrouter ios-sim
Build the app with the following parameters:
cd [your-folder-with-the-csproj]
dotnet build -f net10.0-ios -p:DiagnosticAddress=127.0.0.1 -p:DiagnosticPort=9000 -p:DiagnosticSuspend=true -p:DiagnosticListenMode=listen
Install & launch the app:
mlaunch --installdev bin/Debug/net*/*/*.app --devname ...
mlaunch --launchdev bin/Debug/net*/*/*.app --devname ... --wait-for-exit
Start CPU profiling:
dotnet-trace collect --dsrouter ios --format speedscope
Optionally take a GC dump:
dotnet-gcdump collect --dsrouter ios
In Platforms/Android/environment.conf, add one of the following lines:
For devices:
DOTNET_DiagnosticPorts=127.0.0.1:9000,suspend,connect
For emulators:
DOTNET_DiagnosticPorts=10.0.2.2:9000,suspend,connect
The suspend directive means that the application will wait for dotnet-trace connections before starting, nosuspend may also be used.
Start the diagnostics router:
For devices, run adb reverse tcp:9000 tcp:9001 then dotnet-dsrouter android -v debug
For emulators, run dotnet-dsrouter android-emu -v debug
Run dotnet-trace, in the folder where you want your traces to be stored, using the PID provided by the dotnet-dsrouter output:
dotnet-trace collect -p PID --format speedscope
Start the x64 emulator or the arm64 device
Running on a 32 bits device is not supported and will generate unusable traces in SpeedScope
Build the application with profiling enabled
dotnet build -c Release -f net10.0-android -r android-arm64 -t:Run -p:AndroidEnableProfiler=true
Use -r android-x64 for emulators instead.
The app will start and dotnet-trace will display a MB number counting up
Use the app, once done, stop dotnet-trace by pressing Enter or Ctrl+C
Open a browser at https://speedscope.app and drop the *.speedscope.json file in it
This section provides insights into what to look for when analyzing flame charts.
System.Private.CoreLib!System.Runtime.CompilerServices.RuntimeHelpers.CompileMethod(object), indicating that that the JIT is doing a lot of work. This can make performance improvements harder to find.RuntimeHelpers.CompileMethod invocations. In such cases, you may need to find what is causing the AOT compiler to skip IL portions. If the JIT still impacts cold paths of your application, you may still need to adjust your code to avoid the JIT. For instance, some generics constructs force the AOT compiler to still use JITing. In other cases, it could be accessing static-type members. The JIT conditions are runtime version dependent, and looking at the runtime code can help to find out which ones.Android.Runtime.JNIEnv or Java.Interop.TypeManager), operations that cannot be adjusted by the application. One change to consider is to reduce the native code invocations to a strict minimum, where impactful.You can analyze the GC memory .gcdump files using the Visual Studio 2022/2026 memory profiler by using the File / Open menu and navigating the results.
Profiling Skia-based Uno Platform targets can be done on Windows in Visual Studio 2019 and 2022 using time and memory profilers.
As of Dotnet 10.0, runtime diagnostics like performance traces and GC dumps can be collected by calling some Javascript methods exposed by the Dotnet runtime. For more details, see the dotnet 10.0 release notes
Profiling WebAssembly applications can be done through the use of AOT compilation, and browsers' performance tab.
Enable emcc profiling:
<PropertyGroup>
<WasmShellEnableEmccProfiling>true</WasmShellEnableEmccProfiling>
</PropertyGroup>
Enable AOT compilation:
<PropertyGroup>
<WasmShellMonoRuntimeExecutionMode>InterpreterAndAOT</WasmShellMonoRuntimeExecutionMode>
</PropertyGroup>
Build and deploy the application
Open the Performance tab in your browser
Use your application or restart your application while recording the trace