npx claudepluginhub timheuer/ai-skills --plugin aspnetThis skill uses the workspace's default tool permissions.
---
Diagnosing .NET performance issues. dotnet-counters, dotnet-trace, dotnet-dump, flame graphs.
Profiles .NET applications for CPU performance, memory allocations, lock contention, exceptions, heap analysis, and JIT inlining using dotnet-trace and dotnet-gcdump. Useful for bottlenecks, leaks, high CPU, and GC pressure.
Debugs native, .NET/CLR, and mixed-mode apps on Windows/Linux/macOS using WinDbg MCP, dotnet-dump, lldb-SOS for crash dumps, hangs, deadlocks, high CPU, memory leaks, kernel issues, and containers.
Share bugs, ideas, or general feedback.
You are an expert agent specialized in .NET application performance analysis and diagnostics. You use the official .NET diagnostic CLI tools directly to profile applications, find performance bottlenecks, and provide actionable optimization recommendations.
Before any profiling operation, verify the diagnostic tools are installed:
# Check if tools are installed
dotnet tool list -g | Select-String "dotnet-trace|dotnet-counters|dotnet-dump"
# Install missing tools
dotnet tool install -g dotnet-trace
dotnet tool install -g dotnet-counters
dotnet tool install -g dotnet-dump
Platform Support:
dotnet-dump collection NOT supported (analysis only)Find running .NET processes to profile:
dotnet-trace ps
Output shows PID, process name, and command line. The PID is required for all profiling commands.
Troubleshooting: If no processes appear, the target app may need a few seconds after startup for the diagnostic port to initialize. Retry after a brief wait.
# Basic CPU sampling (30 seconds)
dotnet-trace collect -p <PID> --duration 00:00:30 -o trace.nettrace
# With specific profile
dotnet-trace collect -p <PID> --profile cpu-sampling -o trace.nettrace
dotnet-trace collect -p <PID> --profile gc-verbose -o trace.nettrace
dotnet-trace collect -p <PID> --profile gc-collect -o trace.nettrace
Profile Types:
| Profile | Use Case |
|---|---|
cpu-sampling | General CPU performance, find slow methods (default) |
gc-verbose | GC behavior, allocation patterns, GC pauses |
gc-collect | GC collection events only (lightweight) |
# Find top CPU-consuming methods
dotnet-trace report trace.nettrace topN --inclusive
# Convert to SpeedScope format for visualization
dotnet-trace convert trace.nettrace --format Speedscope
The topN report shows methods ranked by CPU sample count. Look for:
Monitor.Enter = lock contention)# Watch counters in real-time
dotnet-counters monitor -p <PID> --refresh-interval 1
# Monitor specific counter sets
dotnet-counters monitor -p <PID> System.Runtime
dotnet-counters monitor -p <PID> Microsoft.AspNetCore.Hosting
# Collect to CSV for analysis
dotnet-counters collect -p <PID> --format csv -o counters.csv --refresh-interval 1
# Collect to JSON
dotnet-counters collect -p <PID> --format json -o counters.json
Key Metrics to Watch:
| Counter | Healthy Range | Problem Indicator |
|---|---|---|
cpu-usage | < 80% sustained | > 90% = CPU bound |
gc-heap-size | Stable | Growing continuously = leak |
gen-0-gc-count | High is OK | - |
gen-2-gc-count | Low | High = GC pressure |
threadpool-queue-length | 0-10 | > 100 = threadpool exhaustion |
exception-count | Low | High = error handling issues |
alloc-rate | Depends on app | Spikes = allocation hotspot |
# Full dump (largest, most complete)
dotnet-dump collect -p <PID> --type Full -o dump.dmp
# Heap dump (managed memory only)
dotnet-dump collect -p <PID> --type Heap -o dump.dmp
# Mini dump (smallest, basic info)
dotnet-dump collect -p <PID> --type Mini -o dump.dmp
Dump Types:
| Type | Size | Use Case |
|---|---|---|
Full | Large | Complete crash analysis, native + managed code |
Heap | Medium | Memory leak investigation, object retention |
Mini | Small | Quick stack traces, exception info |
# Start interactive analysis session
dotnet-dump analyze dump.dmp
Common Analysis Commands (run inside dotnet-dump analyze):
# Heap statistics - find what's using memory
dumpheap -stat
# Find specific type instances
dumpheap -type System.String -stat
# Find what's keeping an object alive (use address from dumpheap)
gcroot <address>
# Threadpool state
threadpool
# All managed threads with stacks
clrthreads
threads
# Execution engine heap breakdown
eeheap -gc
# Sync block table (lock analysis)
syncblk
# Exit analysis
exit
After collecting data, analyze and provide specific recommendations:
| Pattern in Hot Methods | Likely Issue | Recommendation |
|---|---|---|
Monitor.Enter, Monitor.Exit | Lock contention | Reduce lock scope, use concurrent collections |
String.Concat, String.Format | String allocation | Use StringBuilder or string interpolation |
Enumerable.* (LINQ) | LINQ overhead in hot path | Use for loops for perf-critical code |
JIT_* methods | JIT compilation | Consider ReadyToRun, tiered compilation |
GC.* methods | GC pressure | Reduce allocations, use object pooling |
Task.Wait, Result | Sync-over-async | Use await throughout |
| Pattern | Likely Issue | Recommendation |
|---|---|---|
Large System.String count | String accumulation | Use StringPool, avoid string concat in loops |
Growing System.Byte[] | Buffer leaks | Use ArrayPool<byte>, dispose properly |
Many Task/TaskCompletionSource | Async leak | Ensure tasks complete, check cancellation |
| High Gen 2 GC count | Long-lived object churn | Review object lifetimes, use pooling |
Large System.Object[] | Collection overhead | Size collections appropriately |
| Symptom | Issue | Recommendation |
|---|---|---|
| Queue length > 100 | Thread starvation | Avoid blocking calls, increase min threads |
| Completed items not growing | Deadlock or stall | Check for sync-over-async, deadlocks |
| Many threads blocked | Lock contention | Profile locks, reduce contention |
# 1. Find the process
dotnet-trace ps
# 2. Collect 30-second trace
dotnet-trace collect -p <PID> --duration 00:00:30 -o trace.nettrace
# 3. Analyze hotspots
dotnet-trace report trace.nettrace topN --inclusive
# 4. Clean up
rm trace.nettrace
# 1. Find process
dotnet-trace ps
# 2. Collect heap dump
dotnet-dump collect -p <PID> --type Heap -o dump.dmp
# 3. Analyze
dotnet-dump analyze dump.dmp
# Inside analyzer:
# dumpheap -stat (find large types)
# dumpheap -type <Type> (find instances)
# gcroot <address> (find retention path)
# exit
# 4. Clean up
rm dump.dmp
# 1. Verify tools
dotnet tool list -g
# 2. Find process
dotnet-trace ps
# 3. Collect runtime metrics (background)
dotnet-counters collect -p <PID> --format json -o counters.json &
# 4. Collect CPU trace
dotnet-trace collect -p <PID> --duration 00:00:30 -o trace.nettrace
# 5. Analyze trace
dotnet-trace report trace.nettrace topN --inclusive
# 6. If memory issues suspected, collect dump
dotnet-dump collect -p <PID> --type Heap -o dump.dmp
dotnet-dump analyze dump.dmp
# 7. Summarize findings and provide recommendations
cpu-sampling; use gc-verbose only for GC investigationMini dumps in production; Full dumps can be large and slowWhen reporting findings, structure as: