Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[docs] update notes about dotnet-trace and dotnet-gcdump #8713

Merged
merged 5 commits into from Mar 6, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
186 changes: 119 additions & 67 deletions Documentation/guides/tracing.md
@@ -1,91 +1,138 @@
# 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.

### Configure the device so that the profiled app suspends until tracing utility connects
* [`dotnet-gcdump`][dotnet-gcdump] is a .NET global tool that can be
used to collect memory dumps of .NET applications.

```sh
$ adb shell setprop debug.mono.profile '127.0.0.1:9000,suspend'
```
* The Mono Diagnostic component, `libmono-component-diagnostics_tracing.so`,
is included in the application and is used to collect the trace data.

See the [`dotnet-trace` documentation][dotnet-trace] for further details about its usage.

### Install `dotnet-dsrouter`
[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

Generally, you can use a stable `dotnet-dsrouter` from NuGet:
## 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

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.
### Running `dotnet-dsrouter` on the Host

For profiling an Android application running on an Android *emulator*:

Start an application on android emulator with one of the following environment variables set:
```sh
$ 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
Run diagnotic tool connecting application on android emulator through dotnet-dsrouter pid=1234:
dotnet-trace collect -p 1234
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
info: dotnet-dsrouter-1234[0]
Starting IPC server (dotnet-diagnostic-dsrouter-1234) <--> TCP server (127.0.0.1:9000) router.
```

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".
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
...
```

### For Android devices
### Android System Properties

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)` 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
of 10.0.2.2:

```sh
$ adb shell setprop debug.mono.profile '10.0.2.2:9000,suspend,connect'
```
$ dotnet-dsrouter server-server -tcps 127.0.0.1:9001 --verbose debug

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 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'
```

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.
jonathanpeppers marked this conversation as resolved.
Show resolved Hide resolved

If you are wanting to collect a `gcdump` or just get things working,
try `nosuspend` instead. See the [`dotnet-dsrouter`
documentation][nosuspend] for further information.

[4337]: https://github.com/dotnet/diagnostics/issues/4337
[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
```
Expand All @@ -95,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'

Expand All @@ -107,15 +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].

### Compile and run the application
[speedscope]: https://speedscope.app/

```
### 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:

Expand All @@ -141,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
Expand All @@ -167,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.

Expand All @@ -188,6 +238,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
Expand Down Expand Up @@ -228,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.
Expand Down