Skip to content

Commit 136dc83

Browse files
[docs] update notes about dotnet-trace and dotnet-gcdump (#8713)
Context: dotnet/diagnostics#4337 Update `Documentation/guides/tracing.md` to be up-to-date for .NET 8.
1 parent e41a31b commit 136dc83

File tree

1 file changed

+119
-67
lines changed

1 file changed

+119
-67
lines changed

Documentation/guides/tracing.md

Lines changed: 119 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,138 @@
1-
# Using a device connected via USB
1+
# Tracing .NET Android Applications
22

3-
## Startup profiling
4-
### Set up reverse port forwarding:
3+
Attaching `dotnet-trace` to a .NET Android application, allows you to
4+
get profiling information in formats like `.nettrace` and
5+
`.speedscope`. These give you CPU sampling information about the time
6+
spent in each method in your application. This is quite useful for
7+
finding *where* time is spent in the startup or general performance of
8+
your .NET applications.
59

6-
Note that you can skip this step if the Android application is running on an
7-
Android emulator; it is only required for physical Android devices.
10+
To use `dotnet-trace` on Android, the following tools/components work
11+
together to make this happen:
812

9-
```sh
10-
$ adb reverse tcp:9000 tcp:9001
11-
```
12-
This will forward port 9000 on device to port 9001.
13+
* [`dotnet-trace`][dotnet-trace] itself is a .NET global tool.
1314

14-
_Alternatively:_
15-
```sh
16-
$ adb reverse tcp:0 tcp:9001
17-
43399
18-
```
19-
This will allocate a random port on remote and forward it to port 9001 on the host. The forwarded port is printed by adb
15+
* [`dotnet-dsrouter`][dotnet-dsrouter] is a .NET global tool that
16+
forwards a connection from a remote Android or iOS device or
17+
emulator to a local port on your development machine.
2018

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

23-
```sh
24-
$ adb shell setprop debug.mono.profile '127.0.0.1:9000,suspend'
25-
```
22+
* The Mono Diagnostic component, `libmono-component-diagnostics_tracing.so`,
23+
is included in the application and is used to collect the trace data.
24+
25+
See the [`dotnet-trace` documentation][dotnet-trace] for further details about its usage.
2626

27-
### Install `dotnet-dsrouter`
27+
[dotnet-trace]: https://learn.microsoft.com/dotnet/core/diagnostics/dotnet-trace
28+
[dotnet-dsrouter]: https://learn.microsoft.com/dotnet/core/diagnostics/dotnet-dsrouter
29+
[dotnet-gcdump]: https://learn.microsoft.com/dotnet/core/diagnostics/dotnet-gcdump
2830

29-
Generally, you can use a stable `dotnet-dsrouter` from NuGet:
31+
## Install .NET Global Tools
32+
33+
Generally, you can install the required tooling such as:
3034

3135
```sh
36+
$ dotnet tool install -g dotnet-trace
37+
You can invoke the tool using the following command: dotnet-trace
38+
Tool 'dotnet-trace' was successfully installed.
3239
$ dotnet tool install -g dotnet-dsrouter
3340
You can invoke the tool using the following command: dotnet-dsrouter
3441
Tool 'dotnet-dsrouter' was successfully installed.
42+
$ dotnet tool install -g dotnet-gcdump
43+
You can invoke the tool using the following command: dotnet-gcdump
44+
Tool 'dotnet-gcdump' was successfully installed.
3545
```
3646

37-
Or use a build from the nightly feed `https://aka.ms/dotnet-tools/index.json`:
47+
You can also install prerelease builds from the nightly feed
48+
`https://aka.ms/dotnet-tools/index.json`:
3849

3950
```sh
4051
$ dotnet tool install -g dotnet-dsrouter --add-source=https://aka.ms/dotnet-tools/index.json --prerelease
52+
You can invoke the tool using the following command: dotnet-dsrouter
53+
Tool 'dotnet-dsrouter' was successfully installed.
4154
```
4255

43-
### Start the tracing router/proxy on host
56+
## Configuration & Setup
4457

45-
For profiling an Android application running on an Android emulator:
46-
```sh
47-
$ dotnet-dsrouter android-emu --verbose debug
48-
WARNING: dotnet-dsrouter is a development tool not intended for production environments.
58+
### Running `dotnet-dsrouter` on the Host
59+
60+
For profiling an Android application running on an Android *emulator*:
4961

50-
Start an application on android emulator with one of the following environment variables set:
62+
```sh
63+
$ dotnet-dsrouter android-emu
64+
How to connect current dotnet-dsrouter pid=1234 with android emulator and diagnostics tooling.
65+
Start an application on android emulator with ONE of the following environment variables set:
66+
[Default Tracing]
5167
DOTNET_DiagnosticPorts=10.0.2.2:9000,nosuspend,connect
68+
[Startup Tracing]
5269
DOTNET_DiagnosticPorts=10.0.2.2:9000,suspend,connect
70+
Run diagnotic tool connecting application on android emulator through dotnet-dsrouter pid=1234:
71+
dotnet-trace collect -p 1234
72+
See https://learn.microsoft.com/dotnet/core/diagnostics/dotnet-dsrouter for additional details and examples.
73+
74+
info: dotnet-dsrouter-1234[0]
75+
Starting dotnet-dsrouter using pid=1234
76+
info: dotnet-dsrouter-1234[0]
77+
Starting IPC server (dotnet-diagnostic-dsrouter-1234) <--> TCP server (127.0.0.1:9000) router.
78+
```
5379

54-
info: dotnet-dsrouter[0]
55-
Starting dotnet-dsrouter using pid=21352
56-
dbug: dotnet-dsrouter[0]
57-
Using default IPC server path, dotnet-diagnostic-dsrouter-21352.
58-
dbug: dotnet-dsrouter[0]
59-
Attach to default dotnet-dsrouter IPC server using --process-id 21352 diagnostic tooling argument.
60-
info: dotnet-dsrouter[0]
61-
Starting IPC server (dotnet-diagnostic-dsrouter-21352) <--> TCP server (127.0.0.1:9000) router.
62-
dbug: dotnet-dsrouter[0]
63-
Trying to create new router instance.
64-
dbug: dotnet-dsrouter[0]
65-
Waiting for a new TCP connection at endpoint "127.0.0.1:9000".
66-
dbug: dotnet-dsrouter[0]
67-
Waiting for new ipc connection at endpoint "dotnet-diagnostic-dsrouter-21352".
80+
For profiling an Android application running on an Android *device*:
81+
82+
```sh
83+
# `adb reverse` is required when using hardware devices
84+
$ adb reverse tcp:9000 tcp:9001
85+
$ dotnet-dsrouter android
86+
How to connect current dotnet-dsrouter pid=1234 with android device and diagnostics tooling.
87+
Start an application on android device with ONE of the following environment variables set:
88+
[Default Tracing]
89+
DOTNET_DiagnosticPorts=127.0.0.1:9000,nosuspend,connect
90+
[Startup Tracing]
91+
DOTNET_DiagnosticPorts=127.0.0.1:9000,suspend,connect
92+
Run diagnotic tool connecting application on android device through dotnet-dsrouter pid=1234:
93+
dotnet-trace collect -p 1234
94+
...
6895
```
6996

70-
### For Android devices
97+
### Android System Properties
7198

72-
For profiling an Android application running on an Android device:
99+
Note the log message that `dotnet-dsrouter` prints that mentions
100+
`$DOTNET_DiagnosticPorts`. `$DOTNET_DiagnosticPorts` is an environment
101+
variable that could be defined in an `@(AndroidEnvironment)` file, but
102+
it is simpler to use the `debug.mono.profile` Android system property.
103+
Android system properties can be used without rebuilding the app.
73104

105+
For emulators, `$DOTNET_DiagnosticPorts` should specify an IP address
106+
of 10.0.2.2:
107+
108+
```sh
109+
$ adb shell setprop debug.mono.profile '10.0.2.2:9000,suspend,connect'
74110
```
75-
$ dotnet-dsrouter server-server -tcps 127.0.0.1:9001 --verbose debug
111+
112+
For devices, `$DOTNET_DiagnosticPorts` should specify an IP address of
113+
127.0.0.1, and the port number should be the [port used used with adb
114+
reverse](#start-the-tracing-routerproxy-on-host), e.g:
115+
116+
```sh
117+
# `adb reverse` is required when using hardware devices
118+
$ adb reverse tcp:9000 tcp:9001
119+
$ adb shell setprop debug.mono.profile '127.0.0.1:9000,suspend,connect'
76120
```
77121

78-
Eventually, we will be able to simply do `dotnet-dsrouter android` when
79-
[dotnet/diagnostics#4337][4337] is resolved. `adb reverse tcp:9000 tcp:9001` is
80-
also currently required as mentioned above.
122+
`suspend` is useful as it blocks application startup, so you can
123+
actually `dotnet-trace` startup times of the application.
124+
125+
If you are wanting to collect a `gcdump` or just get things working,
126+
try `nosuspend` instead. See the [`dotnet-dsrouter`
127+
documentation][nosuspend] for further information.
81128

82-
[4337]: https://github.com/dotnet/diagnostics/issues/4337
129+
[nosuspend]: https://learn.microsoft.com/dotnet/core/diagnostics/dotnet-dsrouter#collect-a-trace-using-dotnet-trace-from-a-net-application-running-on-android
83130

84-
### Start the tracing client
131+
### Running `dotnet-trace` on the Host
85132

86133
First, run `dotnet-trace ps` to find a list of processes:
87134

88-
```
135+
```sh
89136
> dotnet-trace ps
90137
38604 dotnet-dsrouter C:\Users\myuser\.dotnet\tools\dotnet-dsrouter.exe "C:\Users\myuser\.dotnet\tools\dotnet-dsrouter.exe" android-emu --verbose debug
91138
```
@@ -95,7 +142,7 @@ connect *through it* appropriately.
95142

96143
Using the process ID from the previous step, run `dotnet-trace collect`:
97144

98-
```
145+
```sh
99146
$ dotnet-trace collect -p 38604 --format speedscope
100147
No profile or providers specified, defaulting to trace profile 'cpu-sampling'
101148

@@ -107,15 +154,23 @@ Waiting for connection on /tmp/maui-app
107154
Start an application with the following environment variable: DOTNET_DiagnosticPorts=/tmp/maui-app
108155
```
109156

110-
The `--format` argument is optional and it defaults to `nettrace`. However, `nettrace` files can be viewed only with
111-
Perfview on Windows, while the speedscope JSON files can be viewed "on" Unix by uploading them to https://speedscope.app
157+
The `--format` argument is optional and it defaults to `nettrace`.
158+
However, `nettrace` files can be viewed only with Perfview or Visual
159+
Studio on Windows, while the speedscope JSON files can be viewed "on"
160+
Unix by uploading them to [https://speedscope.app/][speedscope].
112161

113-
### Compile and run the application
162+
[speedscope]: https://speedscope.app/
114163

115-
```
164+
### Running the .NET Android Application
165+
166+
`$(AndroidEnableProfiler)` must be set to `true` as it includes the
167+
Mono diagnostic component in the application. This component is the
168+
`libmono-component-diagnostics_tracing.so` native library.
169+
170+
```sh
116171
$ dotnet build -f net8.0-android -t:Run -c Release -p:AndroidEnableProfiler=true
117172
```
118-
_NOTE: `-f net8.0-android` is only needed for projects with multiple `$(TargetFrameworks)`._
173+
*NOTE: `-f net8.0-android` is only needed for projects with multiple `$(TargetFrameworks)`.*
119174

120175
Once the application is installed and started, `dotnet-trace` should show something similar to:
121176

@@ -141,14 +196,8 @@ directory.
141196

142197
## How to get GC memory dumps?
143198

144-
If running on desktop, you can use the `dotnet-gcdump` global tool.
145-
This can be installed via:
146-
147-
```dotnetcli
148-
$ dotnet tool install --global dotnet-gcdump
149-
```
150-
151-
To use it, for example:
199+
If running on desktop, you can use the `dotnet-gcdump` global tool for
200+
local processes. For example:
152201

153202
```sh
154203
# `hw-readline` is a standard Hello World, with a `Console.ReadLine()` at the end
@@ -167,6 +216,7 @@ $ dotnet-gcdump collect -p 33972
167216
Writing gcdump to '.../hw-readline/20230314_113922_33972.gcdump'...
168217
Finished writing 5624131 bytes.
169218
```
219+
170220
See the [`dotnet-gcdump` documentation][dotnet-gcdump]
171221
for further details about its usage.
172222

@@ -188,6 +238,9 @@ $ dotnet-gcdump collect -p 38604
188238

189239
This will create a `*.gcdump` file in the current directory.
190240

241+
Note that using `nosuspend` in the `debug.mono.profile` property is
242+
useful, as it won't block application startup.
243+
191244
## Memory Dumps for Android in .NET 7
192245

193246
In .NET 7, we have to use th older, more complicated method for collecting
@@ -228,12 +281,11 @@ This saves a `foo.gcdump` that you can open in Visual Studio.
228281
See the [dotnet/runtime documentation][gc-dumps-on-mono] for
229282
additional details.
230283

231-
[dotnet-gcdump]: https://learn.microsoft.com/dotnet/core/diagnostics/dotnet-gcdump
232284
[mono-events]: https://github.com/dotnet/runtime/blob/c887c92d8af4ce65b19962b777f96ae8eb997a42/src/coreclr/vm/ClrEtwAll.man#L7433-L7468
233285
[dotnet-trace-help]: https://github.com/dotnet/diagnostics/blob/6d755e8b5435b1380c118e9d81e075654b0330c9/documentation/dotnet-trace-instructions.md#dotnet-trace-help
234286
[gc-dumps-on-mono]: https://github.com/dotnet/runtime/blob/728fd85bc7ad04f5a0ea2ad0d4d8afe371ff9b64/docs/design/mono/diagnostics-tracing.md#collect-gc-dumps-on-monovm
235287

236-
## How to `dotnet trace` our build?
288+
## How to `dotnet trace` a Build?
237289

238290
Setting this up is easy, the main issue is there end up being
239291
potentially *a lot* of threads (30-40) depending on the build.

0 commit comments

Comments
 (0)