6.3 KiB
6.3 KiB
dotTrace Command-Line Profiler
Installation
Installed as a .NET global tool:
dotnet tool install --global JetBrains.dotTrace.GlobalTools
Update to latest:
dotnet tool update --global JetBrains.dotTrace.GlobalTools
Current version: 2025.3.3
Quick Start
Profile the NATS server (sampling, 30 seconds)
dottrace start --framework=NetCore --profiling-type=Sampling \
--timeout=30s --save-to=./snapshots/nats-sampling.dtp \
-- dotnet run --project src/NATS.Server.Host -- -p 14222
Profile the NATS server (timeline, with async/TPL info)
dottrace start --framework=NetCore --profiling-type=Timeline \
--timeout=30s --save-to=./snapshots/nats-timeline.dtt \
-- dotnet run --project src/NATS.Server.Host -- -p 14222
Attach to a running server by PID
dottrace attach <PID> --profiling-type=Sampling \
--timeout=30s --save-to=./snapshots/nats-attach.dtp
Attach by process name
dottrace attach NATS.Server.Host --profiling-type=Sampling \
--timeout=30s --save-to=./snapshots/nats-attach.dtp
Profiling Types
| Type | Flag | Snapshot Extension | Use Case |
|---|---|---|---|
| Sampling | --profiling-type=Sampling |
.dtp |
Low overhead, CPU hotspots (default) |
| Timeline | --profiling-type=Timeline |
.dtt |
Thread activity, async/await, TPL tasks |
| Tracing | --profiling-type=Tracing |
.dtp |
Exact call counts, higher overhead |
| Line-by-Line | --profiling-type=LineByLine |
.dtp |
Per-line timing (not available for attach) |
Sampling options
# Use thread time instead of CPU instructions
--time-measurement=ThreadTime
# Default (CPU instruction count)
--time-measurement=CpuInstruction
Timeline options
# Disable TPL data collection for better performance
--disable-tpl
Common Options
| Option | Description |
|---|---|
--framework=NetCore |
Required for .NET Core / .NET 5+ apps |
--save-to=<path> |
Snapshot output path (file or directory) |
--overwrite |
Overwrite existing snapshot files |
--timeout=<duration> |
Auto-stop after duration (e.g., 30s, 5m, 1h) |
--propagate-exit-code |
Return the profiled app's exit code instead of dotTrace's |
--profile-child |
Also profile child processes |
--profile-child=<mask> |
Profile matching child processes (e.g., dotnet) |
--work-dir=<path> |
Set working directory for the profiled app |
--collect-data-from-start=off |
Don't collect until explicitly started via service messages |
Interactive Profiling with Service Messages
For fine-grained control over when data is collected, use --service-input=stdin:
dottrace start --framework=NetCore --service-input=stdin \
--save-to=./snapshots/nats-interactive.dtp \
-- dotnet run --project src/NATS.Server.Host -- -p 14222
Then type these commands into stdin (each must start on a new line and end with a carriage return):
| Command | Effect |
|---|---|
##dotTrace["start"] |
Start collecting performance data |
##dotTrace["get-snapshot"] |
Save snapshot and stop collecting |
##dotTrace["drop"] |
Discard collected data and stop |
##dotTrace["disconnect"] |
Detach/stop profiler |
Stdout will emit status messages like:
##dotTrace["ready"]
##dotTrace["connected", {pid: 1234, path:"dotnet"}]
##dotTrace["started", {pid: 1234, path:"dotnet"}]
##dotTrace["snapshot-saved", {pid: 1234, filename:"./snapshots/nats-interactive.dtp"}]
Example Workflows
Profile a benchmark run
dottrace start --framework=NetCore --profiling-type=Sampling \
--save-to=./snapshots/bench.dtp \
-- dotnet run --project tests/NATS.Server.Benchmarks -c Release
Profile tests
dottrace start --framework=NetCore --profiling-type=Sampling \
--timeout=2m --save-to=./snapshots/tests.dtp \
-- dotnet test tests/NATS.Server.Core.Tests --filter "FullyQualifiedName~PubSub"
Profile with child processes (e.g., server spawns workers)
dottrace start --framework=NetCore --profile-child \
--timeout=30s --save-to=./snapshots/nats-children.dtp \
-- dotnet run --project src/NATS.Server.Host
Exporting Reports
dotTrace's XML report tool (Reporter.exe) is Windows-only. On macOS, use dotnet-trace for profiling with exportable formats:
# Install dotnet-trace
dotnet tool install --global dotnet-trace
# Collect a trace from a running process (nettrace format)
dotnet-trace collect --process-id <PID> --duration 00:00:30
# Collect directly in speedscope format
dotnet-trace collect --process-id <PID> --format speedscope --duration 00:00:30
# Convert an existing .nettrace file to speedscope
dotnet-trace convert --format speedscope trace.nettrace
Speedscope files can be visualized at speedscope.app — a web-based flame graph viewer that works on any platform.
dotnet-trace output formats
| Format | Extension | Viewer |
|---|---|---|
nettrace (default) |
.nettrace |
PerfView, Visual Studio, Rider |
speedscope |
.speedscope.json |
speedscope.app |
chromium |
.chromium.json |
Chrome DevTools (chrome://tracing) |
Example: profile NATS server and export flame graph
# Start the server
dotnet run --project src/NATS.Server.Host -- -p 14222 &
SERVER_PID=$!
# Collect a 30-second trace in speedscope format
dotnet-trace collect --process-id $SERVER_PID --format speedscope \
--duration 00:00:30 --output ./snapshots/nats-trace
# Open the flame graph
open ./snapshots/nats-trace.speedscope.json # opens in default browser at speedscope.app
Viewing Snapshots
Open .dtp / .dtt snapshot files in:
- dotTrace GUI (
/Users/dohertj2/Applications/dotTrace.app) - JetBrains Rider (built-in profiler viewer)
open /Users/dohertj2/Applications/dotTrace.app --args ./snapshots/nats-sampling.dtp
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 65 | Profiling failure |
Notes
- Snapshots consist of multiple files:
*.dtp,*.dtp.0000,*.dtp.0001, etc. Keep them together. - Attach on macOS requires .NET 5 or later.
- Use
--before the executable path if arguments start with-. - The
snapshots/directory is not tracked in git. Create it before profiling:mkdir -p snapshots