From fae96abea6746f0389e8535b53525502647f5823 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Fri, 9 Feb 2024 10:33:28 -0600 Subject: [PATCH 1/5] [docs] update notes about `dotnet-trace` and `dotnet-gcdump` * Mention `dotnet-dsrouter android` https://github.com/dotnet/diagnostics/issues/4337 Was fixed by .NET 8 GA, so we can remove the section mentioning it. * Mention the relationship between the `debug.mono.profile` Android system property and `$DOTNET_DiagnosticPorts`. * Mention `suspend` vs `nosuspend`. * Mention `libmono-component-diagnostics_tracing.so` and the Mono diagnostic component. These all came up from conversations with customers, so I think it will be useful for anyone. --- Documentation/guides/tracing.md | 43 ++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/Documentation/guides/tracing.md b/Documentation/guides/tracing.md index c785f048cf6..5ce573779d0 100644 --- a/Documentation/guides/tracing.md +++ b/Documentation/guides/tracing.md @@ -18,12 +18,6 @@ $ adb reverse tcp:0 tcp:9001 ``` This will allocate a random port on remote and forward it to port 9001 on the host. The forwarded port is printed by adb -### Configure the device so that the profiled app suspends until tracing utility connects - -```sh -$ adb shell setprop debug.mono.profile '127.0.0.1:9000,suspend' -``` - ### Install `dotnet-dsrouter` Generally, you can use a stable `dotnet-dsrouter` from NuGet: @@ -67,19 +61,33 @@ dbug: dotnet-dsrouter[0] Waiting for new ipc connection at endpoint "dotnet-diagnostic-dsrouter-21352". ``` -### For Android devices +Use `dotnet-dsrouter android` instead, if you are testing on an +Android device. The `adb reverse` command mentioned above is required +for physical devices. + +### Configure the device so that the profiled app suspends until tracing utility connects -For profiling an Android application running on an Android device: +Note the log message that `dotnet-dsrouter` prints that mentions +`$DOTNET_DiagnosticPorts`. `$DOTNET_DiagnosticPorts` is an environment +variable that could be defined in an `@(AndroidEnvironment)`, but it +is simpler to use the `debug.mono.profile` Android system property. +Android system properties can be used without rebuilding the app. -``` -$ dotnet-dsrouter server-server -tcps 127.0.0.1:9001 --verbose debug +Based on the value `dotnet-dsrouter` logs for +`DOTNET_DiagnosticPorts`, choose one of: + +```sh +# Emulators will be 10.x.x.x +$ adb shell setprop debug.mono.profile '10.0.2.2:9000,suspend,connect' +# Devices will be 127.0.0.1, but require `adb reverse` as mentioned above +$ adb shell setprop debug.mono.profile '127.0.0.1:9000,suspend,connect' ``` -Eventually, we will be able to simply do `dotnet-dsrouter android` when -[dotnet/diagnostics#4337][4337] is resolved. `adb reverse tcp:9000 tcp:9001` is -also currently required as mentioned above. +`suspend` is useful as it blocks application startup, so you can +actually `dotnet-trace` startup times of the application. -[4337]: https://github.com/dotnet/diagnostics/issues/4337 +If you are wanting to collect a `gcdump` or just get things working, +try `nosuspend` instead. ### Start the tracing client @@ -112,6 +120,10 @@ Perfview on Windows, while the speedscope JSON files can be viewed "on" Unix by ### Compile and run the application +`$(AndroidEnableProfiler)` must be set to `true` as it includes the +Mono diagnostic component in the application. This component is the +`libmono-component-diagnostics_tracing.so` native library. + ``` $ dotnet build -f net8.0-android -t:Run -c Release -p:AndroidEnableProfiler=true ``` @@ -188,6 +200,9 @@ $ dotnet-gcdump collect -p 38604 This will create a `*.gcdump` file in the current directory. +Note that using `nosuspend` in the `debug.mono.profile` property is +useful, as it won't block application startup. + ## Memory Dumps for Android in .NET 7 In .NET 7, we have to use th older, more complicated method for collecting From 222801232c1cb4214c2adce31045d4b542925a76 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Mon, 12 Feb 2024 08:50:07 -0600 Subject: [PATCH 2/5] Improved `dsrouter` instructions/output --- Documentation/guides/tracing.md | 53 +++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/Documentation/guides/tracing.md b/Documentation/guides/tracing.md index 5ce573779d0..62703fd746c 100644 --- a/Documentation/guides/tracing.md +++ b/Documentation/guides/tracing.md @@ -36,34 +36,41 @@ $ dotnet tool install -g dotnet-dsrouter --add-source=https://aka.ms/dotnet-tool ### Start the tracing router/proxy on host -For profiling an Android application running on an Android emulator: +For profiling an Android application running on an Android _emulator_: ```sh -$ dotnet-dsrouter android-emu --verbose debug -WARNING: dotnet-dsrouter is a development tool not intended for production environments. - -Start an application on android emulator with one of the following environment variables set: +$ dotnet-dsrouter android-emu +How to connect current dotnet-dsrouter pid=1234 with android emulator and diagnostics tooling. +Start an application on android emulator with ONE of the following environment variables set: +[Default Tracing] DOTNET_DiagnosticPorts=10.0.2.2:9000,nosuspend,connect +[Startup Tracing] DOTNET_DiagnosticPorts=10.0.2.2:9000,suspend,connect - -info: dotnet-dsrouter[0] - Starting dotnet-dsrouter using pid=21352 -dbug: dotnet-dsrouter[0] - Using default IPC server path, dotnet-diagnostic-dsrouter-21352. -dbug: dotnet-dsrouter[0] - Attach to default dotnet-dsrouter IPC server using --process-id 21352 diagnostic tooling argument. -info: dotnet-dsrouter[0] - Starting IPC server (dotnet-diagnostic-dsrouter-21352) <--> TCP server (127.0.0.1:9000) router. -dbug: dotnet-dsrouter[0] - Trying to create new router instance. -dbug: dotnet-dsrouter[0] - Waiting for a new TCP connection at endpoint "127.0.0.1:9000". -dbug: dotnet-dsrouter[0] - Waiting for new ipc connection at endpoint "dotnet-diagnostic-dsrouter-21352". +Run diagnotic tool connecting application on android emulator through dotnet-dsrouter pid=1234: +dotnet-trace collect -p 1234 +See https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-dsrouter for additional details and examples. + +info: dotnet-dsrouter-1234[0] + Starting dotnet-dsrouter using pid=1234 +info: dotnet-dsrouter-1234[0] + Starting IPC server (dotnet-diagnostic-dsrouter-1234) <--> TCP server (127.0.0.1:9000) router. ``` -Use `dotnet-dsrouter android` instead, if you are testing on an -Android device. The `adb reverse` command mentioned above is required -for physical devices. +For profiling an Android application running on an Android _device_: + +```sh +# `adb reverse` is required when using hardware devices +$ adb reverse tcp:9000 tcp:9001 +$ dotnet-dsrouter android +How to connect current dotnet-dsrouter pid=1234 with android device and diagnostics tooling. +Start an application on android device with ONE of the following environment variables set: +[Default Tracing] +DOTNET_DiagnosticPorts=127.0.0.1:9000,nosuspend,connect +[Startup Tracing] +DOTNET_DiagnosticPorts=127.0.0.1:9000,suspend,connect +Run diagnotic tool connecting application on android device through dotnet-dsrouter pid=1234: +dotnet-trace collect -p 1234 +... +``` ### Configure the device so that the profiled app suspends until tracing utility connects From 6dc6fb3ef0a03a21af02d1dc2c0805c715805bc9 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Mon, 12 Feb 2024 08:53:19 -0600 Subject: [PATCH 3/5] `$DOTNET_DiagnosticPorts` example cleanup --- Documentation/guides/tracing.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Documentation/guides/tracing.md b/Documentation/guides/tracing.md index 62703fd746c..7b431b0a8e6 100644 --- a/Documentation/guides/tracing.md +++ b/Documentation/guides/tracing.md @@ -80,13 +80,18 @@ variable that could be defined in an `@(AndroidEnvironment)`, but it is simpler to use the `debug.mono.profile` Android system property. Android system properties can be used without rebuilding the app. -Based on the value `dotnet-dsrouter` logs for -`DOTNET_DiagnosticPorts`, choose one of: +For emulators, `$DOTNET_DiagnosticPorts` should specify an IP address +of 10.0.2.2: ```sh -# Emulators will be 10.x.x.x $ adb shell setprop debug.mono.profile '10.0.2.2:9000,suspend,connect' -# Devices will be 127.0.0.1, but require `adb reverse` as mentioned above +``` + +For devices, `$DOTNET_DiagnosticPorts` should specify an IP address of +127.0.0.1, and the port number should be the [port used used with adb +reverse](#start-the-tracing-routerproxy-on-host), e.g: + +```sh $ adb shell setprop debug.mono.profile '127.0.0.1:9000,suspend,connect' ``` From a04b79ba51ada797e7bf04f49b796bf2f6476148 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Mon, 12 Feb 2024 08:55:04 -0600 Subject: [PATCH 4/5] Link to dotnet-dsrouter docs --- Documentation/guides/tracing.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Documentation/guides/tracing.md b/Documentation/guides/tracing.md index 7b431b0a8e6..22690cae689 100644 --- a/Documentation/guides/tracing.md +++ b/Documentation/guides/tracing.md @@ -47,7 +47,7 @@ DOTNET_DiagnosticPorts=10.0.2.2:9000,nosuspend,connect DOTNET_DiagnosticPorts=10.0.2.2:9000,suspend,connect Run diagnotic tool connecting application on android emulator through dotnet-dsrouter pid=1234: dotnet-trace collect -p 1234 -See https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-dsrouter for additional details and examples. +See https://learn.microsoft.com/dotnet/core/diagnostics/dotnet-dsrouter for additional details and examples. info: dotnet-dsrouter-1234[0] Starting dotnet-dsrouter using pid=1234 @@ -99,7 +99,10 @@ $ adb shell setprop debug.mono.profile '127.0.0.1:9000,suspend,connect' actually `dotnet-trace` startup times of the application. If you are wanting to collect a `gcdump` or just get things working, -try `nosuspend` instead. +try `nosuspend` instead. See the [`dotnet-dsrouter` +documentation][nosuspend] for further information. + +[nosuspend]: https://learn.microsoft.com/dotnet/core/diagnostics/dotnet-dsrouter#collect-a-trace-using-dotnet-trace-from-a-net-application-running-on-android ### Start the tracing client From 385f567262bc8e33859b89a9411ca5678bb729ac Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Tue, 20 Feb 2024 16:29:21 -0600 Subject: [PATCH 5/5] Restructured document --- Documentation/guides/tracing.md | 106 +++++++++++++++++++------------- 1 file changed, 64 insertions(+), 42 deletions(-) diff --git a/Documentation/guides/tracing.md b/Documentation/guides/tracing.md index 22690cae689..285df67f49f 100644 --- a/Documentation/guides/tracing.md +++ b/Documentation/guides/tracing.md @@ -1,42 +1,64 @@ -# Using a device connected via USB +# Tracing .NET Android Applications -## Startup profiling -### Set up reverse port forwarding: +Attaching `dotnet-trace` to a .NET Android application, allows you to +get profiling information in formats like `.nettrace` and +`.speedscope`. These give you CPU sampling information about the time +spent in each method in your application. This is quite useful for +finding *where* time is spent in the startup or general performance of +your .NET applications. -Note that you can skip this step if the Android application is running on an -Android emulator; it is only required for physical Android devices. +To use `dotnet-trace` on Android, the following tools/components work +together to make this happen: -```sh -$ adb reverse tcp:9000 tcp:9001 -``` -This will forward port 9000 on device to port 9001. +* [`dotnet-trace`][dotnet-trace] itself is a .NET global tool. -_Alternatively:_ -```sh -$ adb reverse tcp:0 tcp:9001 -43399 -``` -This will allocate a random port on remote and forward it to port 9001 on the host. The forwarded port is printed by adb +* [`dotnet-dsrouter`][dotnet-dsrouter] is a .NET global tool that + forwards a connection from a remote Android or iOS device or + emulator to a local port on your development machine. + +* [`dotnet-gcdump`][dotnet-gcdump] is a .NET global tool that can be + used to collect memory dumps of .NET applications. -### Install `dotnet-dsrouter` +* The Mono Diagnostic component, `libmono-component-diagnostics_tracing.so`, + is included in the application and is used to collect the trace data. -Generally, you can use a stable `dotnet-dsrouter` from NuGet: +See the [`dotnet-trace` documentation][dotnet-trace] for further details about its usage. + +[dotnet-trace]: https://learn.microsoft.com/dotnet/core/diagnostics/dotnet-trace +[dotnet-dsrouter]: https://learn.microsoft.com/dotnet/core/diagnostics/dotnet-dsrouter +[dotnet-gcdump]: https://learn.microsoft.com/dotnet/core/diagnostics/dotnet-gcdump + +## Install .NET Global Tools + +Generally, you can install the required tooling such as: ```sh +$ dotnet tool install -g dotnet-trace +You can invoke the tool using the following command: dotnet-trace +Tool 'dotnet-trace' was successfully installed. $ dotnet tool install -g dotnet-dsrouter You can invoke the tool using the following command: dotnet-dsrouter Tool 'dotnet-dsrouter' was successfully installed. +$ dotnet tool install -g dotnet-gcdump +You can invoke the tool using the following command: dotnet-gcdump +Tool 'dotnet-gcdump' was successfully installed. ``` -Or use a build from the nightly feed `https://aka.ms/dotnet-tools/index.json`: +You can also install prerelease builds from the nightly feed +`https://aka.ms/dotnet-tools/index.json`: ```sh $ dotnet tool install -g dotnet-dsrouter --add-source=https://aka.ms/dotnet-tools/index.json --prerelease +You can invoke the tool using the following command: dotnet-dsrouter +Tool 'dotnet-dsrouter' was successfully installed. ``` -### Start the tracing router/proxy on host +## Configuration & Setup + +### Running `dotnet-dsrouter` on the Host + +For profiling an Android application running on an Android *emulator*: -For profiling an Android application running on an Android _emulator_: ```sh $ dotnet-dsrouter android-emu How to connect current dotnet-dsrouter pid=1234 with android emulator and diagnostics tooling. @@ -55,7 +77,7 @@ info: dotnet-dsrouter-1234[0] Starting IPC server (dotnet-diagnostic-dsrouter-1234) <--> TCP server (127.0.0.1:9000) router. ``` -For profiling an Android application running on an Android _device_: +For profiling an Android application running on an Android *device*: ```sh # `adb reverse` is required when using hardware devices @@ -72,12 +94,12 @@ dotnet-trace collect -p 1234 ... ``` -### Configure the device so that the profiled app suspends until tracing utility connects +### Android System Properties Note the log message that `dotnet-dsrouter` prints that mentions `$DOTNET_DiagnosticPorts`. `$DOTNET_DiagnosticPorts` is an environment -variable that could be defined in an `@(AndroidEnvironment)`, but it -is simpler to use the `debug.mono.profile` Android system property. +variable that could be defined in an `@(AndroidEnvironment)` file, but +it is simpler to use the `debug.mono.profile` Android system property. Android system properties can be used without rebuilding the app. For emulators, `$DOTNET_DiagnosticPorts` should specify an IP address @@ -92,6 +114,8 @@ For devices, `$DOTNET_DiagnosticPorts` should specify an IP address of reverse](#start-the-tracing-routerproxy-on-host), e.g: ```sh +# `adb reverse` is required when using hardware devices +$ adb reverse tcp:9000 tcp:9001 $ adb shell setprop debug.mono.profile '127.0.0.1:9000,suspend,connect' ``` @@ -104,11 +128,11 @@ documentation][nosuspend] for further information. [nosuspend]: https://learn.microsoft.com/dotnet/core/diagnostics/dotnet-dsrouter#collect-a-trace-using-dotnet-trace-from-a-net-application-running-on-android -### Start the tracing client +### Running `dotnet-trace` on the Host First, run `dotnet-trace ps` to find a list of processes: -``` +```sh > dotnet-trace ps 38604 dotnet-dsrouter C:\Users\myuser\.dotnet\tools\dotnet-dsrouter.exe "C:\Users\myuser\.dotnet\tools\dotnet-dsrouter.exe" android-emu --verbose debug ``` @@ -118,7 +142,7 @@ connect *through it* appropriately. Using the process ID from the previous step, run `dotnet-trace collect`: -``` +```sh $ dotnet-trace collect -p 38604 --format speedscope No profile or providers specified, defaulting to trace profile 'cpu-sampling' @@ -130,19 +154,23 @@ Waiting for connection on /tmp/maui-app Start an application with the following environment variable: DOTNET_DiagnosticPorts=/tmp/maui-app ``` -The `--format` argument is optional and it defaults to `nettrace`. However, `nettrace` files can be viewed only with -Perfview on Windows, while the speedscope JSON files can be viewed "on" Unix by uploading them to https://speedscope.app +The `--format` argument is optional and it defaults to `nettrace`. +However, `nettrace` files can be viewed only with Perfview or Visual +Studio on Windows, while the speedscope JSON files can be viewed "on" +Unix by uploading them to [https://speedscope.app/][speedscope]. + +[speedscope]: https://speedscope.app/ -### Compile and run the application +### Running the .NET Android Application `$(AndroidEnableProfiler)` must be set to `true` as it includes the Mono diagnostic component in the application. This component is the `libmono-component-diagnostics_tracing.so` native library. -``` +```sh $ dotnet build -f net8.0-android -t:Run -c Release -p:AndroidEnableProfiler=true ``` -_NOTE: `-f net8.0-android` is only needed for projects with multiple `$(TargetFrameworks)`._ +*NOTE: `-f net8.0-android` is only needed for projects with multiple `$(TargetFrameworks)`.* Once the application is installed and started, `dotnet-trace` should show something similar to: @@ -168,14 +196,8 @@ directory. ## How to get GC memory dumps? -If running on desktop, you can use the `dotnet-gcdump` global tool. -This can be installed via: - -```dotnetcli -$ dotnet tool install --global dotnet-gcdump -``` - -To use it, for example: +If running on desktop, you can use the `dotnet-gcdump` global tool for +local processes. For example: ```sh # `hw-readline` is a standard Hello World, with a `Console.ReadLine()` at the end @@ -194,6 +216,7 @@ $ dotnet-gcdump collect -p 33972 Writing gcdump to '.../hw-readline/20230314_113922_33972.gcdump'... Finished writing 5624131 bytes. ``` + See the [`dotnet-gcdump` documentation][dotnet-gcdump] for further details about its usage. @@ -258,12 +281,11 @@ This saves a `foo.gcdump` that you can open in Visual Studio. See the [dotnet/runtime documentation][gc-dumps-on-mono] for additional details. -[dotnet-gcdump]: https://learn.microsoft.com/dotnet/core/diagnostics/dotnet-gcdump [mono-events]: https://github.com/dotnet/runtime/blob/c887c92d8af4ce65b19962b777f96ae8eb997a42/src/coreclr/vm/ClrEtwAll.man#L7433-L7468 [dotnet-trace-help]: https://github.com/dotnet/diagnostics/blob/6d755e8b5435b1380c118e9d81e075654b0330c9/documentation/dotnet-trace-instructions.md#dotnet-trace-help [gc-dumps-on-mono]: https://github.com/dotnet/runtime/blob/728fd85bc7ad04f5a0ea2ad0d4d8afe371ff9b64/docs/design/mono/diagnostics-tracing.md#collect-gc-dumps-on-monovm -## How to `dotnet trace` our build? +## How to `dotnet trace` a Build? Setting this up is easy, the main issue is there end up being potentially *a lot* of threads (30-40) depending on the build.