From cebe1c10a74c63aed02c14ab951161640166a265 Mon Sep 17 00:00:00 2001 From: Mukund Raghav Sharma Date: Mon, 23 Feb 2026 06:52:11 -0800 Subject: [PATCH 1/2] Add profiling-dotnet-apps skill (+11.0% eval improvement) Teaches .NET diagnostic CLI tool workflows: dotnet-counters for real-time monitoring, dotnet-trace for CPU profiling, dotnet-dump for crash analysis, and dotnet-gcdump for memory snapshots. Eval results: +11.0% improvement over baseline (threshold: 10%) Includes eval.yaml with profiling scenario + negative test. --- .../skills/profiling-dotnet-apps/SKILL.md | 165 ++++++++++++++++++ .../tests/profiling-dotnet-apps/eval.yaml | 32 ++++ 2 files changed, 197 insertions(+) create mode 100644 src/dotnet/skills/profiling-dotnet-apps/SKILL.md create mode 100644 src/dotnet/tests/profiling-dotnet-apps/eval.yaml diff --git a/src/dotnet/skills/profiling-dotnet-apps/SKILL.md b/src/dotnet/skills/profiling-dotnet-apps/SKILL.md new file mode 100644 index 0000000000..bb90fc7abd --- /dev/null +++ b/src/dotnet/skills/profiling-dotnet-apps/SKILL.md @@ -0,0 +1,165 @@ +--- +name: profiling-dotnet-apps +description: Profile .NET application performance using dotnet-counters, dotnet-trace, and dotnet-dump. Use when diagnosing CPU spikes, memory growth, high GC pressure, slow requests, or thread contention in .NET applications. +--- + +# Profiling .NET Applications + +## When to Use + +- Investigating high CPU usage, memory growth, or slow response times +- Collecting performance traces for offline analysis +- Monitoring live runtime counters during load tests or production issues + +## When Not to Use + +- The user wants to profile a non-.NET application +- The issue is a compile-time or build error (use `analyzing-build-errors` instead) +- The user needs to debug functional correctness, not performance + +## Inputs + +| Input | Required | Description | +|-------|----------|-------------| +| Target app or process | Yes | A running .NET process ID, or a project to launch | +| Symptom description | No | What the user is observing (high CPU, memory growth, etc.) | + +## Workflow + +### Step 1: Verify diagnostic tools are available + +```bash +dotnet tool list -g | grep dotnet-counters +dotnet tool list -g | grep dotnet-trace +dotnet tool list -g | grep dotnet-dump +``` + +If any are missing, install them: + +```bash +dotnet tool install -g dotnet-counters +dotnet tool install -g dotnet-trace +dotnet tool install -g dotnet-dump +``` + +### Step 2: Identify the target process + +```bash +dotnet-counters ps +``` + +This lists all running .NET processes with their PIDs. If the user provides a project instead of a PID, launch it first and note the PID. + +### Step 3: Choose the profiling approach based on the symptom + +**High CPU** → go to [CPU profiling](#cpu-profiling) +**Memory growth / OOM** → go to [Memory profiling](#memory-profiling) +**General slowness / latency** → go to [Request tracing](#request-tracing) +**Unknown** → start with [Live counters](#live-counters) + +### Live counters + +Monitor key metrics in real time. Good starting point when the symptom is vague. + +```bash +dotnet-counters monitor --process-id --counters System.Runtime,Microsoft.AspNetCore.Hosting +``` + +Key counters to watch: + +| Counter | Healthy Range | Concern | +|---------|--------------|---------| +| `cpu-usage` | < 70% | Sustained > 85% indicates CPU-bound work | +| `gc-heap-size` | Stable | Steady growth suggests a memory leak | +| `gen-2-gc-count` | Low, infrequent | Frequent Gen 2 GCs indicate memory pressure | +| `threadpool-queue-length` | < 10 | High values suggest thread pool starvation | +| `exception-count` | Low | Sudden spikes need investigation | + +Press `q` to stop. Export to CSV for longer monitoring: + +```bash +dotnet-counters collect --process-id --format csv --output counters.csv +``` + +### CPU profiling + +Collect a CPU trace: + +```bash +dotnet-trace collect --process-id --profile cpu-sampling --duration 00:00:30 --output cpu-trace.nettrace +``` + +Convert to SpeedScope format for visualization: + +```bash +dotnet-trace convert cpu-trace.nettrace --format speedscope --output cpu-trace.speedscope.json +``` + +Open `cpu-trace.speedscope.json` at https://www.speedscope.app/ or analyze in Visual Studio / PerfView. + +### Memory profiling + +Capture a heap dump: + +```bash +dotnet-dump collect --process-id --output heap.dmp +``` + +Analyze the dump: + +```bash +dotnet-dump analyze heap.dmp +``` + +Inside the analyzer, run these commands in sequence: + +``` +dumpheap -stat +``` + +This shows object counts and sizes sorted by total size. Look for unexpectedly large counts or sizes. Then inspect the top types: + +``` +dumpheap -type +``` + +To find what roots are keeping objects alive: + +``` +gcroot +``` + +### Request tracing + +For ASP.NET Core applications, collect a trace with HTTP events: + +```bash +dotnet-trace collect --process-id --providers Microsoft-AspNetCore-Server-Kestrel,Microsoft.AspNetCore.Hosting --duration 00:00:30 +``` + +### Step 4: Interpret results and recommend next steps + +After collecting data, summarize: + +1. The top CPU consumers or largest heap objects +2. Any anomalies in counter trends +3. Specific code paths or types to investigate +4. Concrete optimization suggestions (e.g., caching, pooling, async fixes) + +## Validation + +- [ ] Diagnostic tools are installed and functional +- [ ] `dotnet-counters ps` lists the target process +- [ ] Profiling data was collected without errors +- [ ] Output files exist and are non-empty +- [ ] Analysis produced actionable findings + +## Common Pitfalls + +| Pitfall | Solution | +|---------|----------| +| Tools not installed globally | Use `dotnet tool install -g ` | +| "No process found" from dotnet-counters | Verify the process is .NET (not native) and still running | +| Trace file too large | Reduce `--duration` or use specific `--providers` | +| PerfView not available on Linux/macOS | Use SpeedScope (web-based) or `dotnet-trace convert` | +| Collecting dumps in production | Dumps freeze the process briefly; warn the user about impact | diff --git a/src/dotnet/tests/profiling-dotnet-apps/eval.yaml b/src/dotnet/tests/profiling-dotnet-apps/eval.yaml new file mode 100644 index 0000000000..061c0633ef --- /dev/null +++ b/src/dotnet/tests/profiling-dotnet-apps/eval.yaml @@ -0,0 +1,32 @@ +scenarios: + - name: "Profile slow API response times" + prompt: "My API response times jumped from 50ms to 2 seconds after deploying yesterday. Can you help me profile what's happening?" + assertions: + - type: "output_matches" + pattern: "(dotnet-counters|dotnet-trace|dotnet-dump)" + - type: "output_matches" + pattern: "(cpu|latency|thread|request)" + rubric: + - "Verified or installed .NET diagnostic tools (dotnet-counters, dotnet-trace, dotnet-dump)" + - "Used dotnet-counters to monitor live runtime metrics as a starting point" + - "Chose appropriate profiling approach based on symptoms (CPU sampling, request tracing, or memory)" + - "Collected a trace or counters data for analysis" + - "Interpreted results and identified potential hot paths or bottlenecks" + - "Provided concrete optimization suggestions (caching, pooling, async fixes, etc.)" + expect_tools: ["bash"] + timeout: 120 + + - name: "Profiling skill should not activate for build errors" + prompt: "My dotnet build is failing with CS0246 errors. Can you help me fix them?" + assertions: + - type: "output_not_contains" + value: "dotnet-trace" + - type: "output_not_contains" + value: "dotnet-counters" + - type: "output_not_matches" + pattern: "(profil|perf.*trac)" + rubric: + - "Did NOT suggest profiling or tracing tools for a build error" + - "Focused on fixing the CS0246 compilation error (missing type or namespace)" + - "Suggested adding the missing using directive or NuGet package reference" + timeout: 60 From 92232a39a9238c016fe1e612eb7f443945405195 Mon Sep 17 00:00:00 2001 From: Mukund Raghav Sharma Date: Tue, 24 Feb 2026 17:21:24 -0800 Subject: [PATCH 2/2] Simplify to single positive-only scenario (API profiling) --- .../tests/profiling-dotnet-apps/eval.yaml | 28 +++++-------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/src/dotnet/tests/profiling-dotnet-apps/eval.yaml b/src/dotnet/tests/profiling-dotnet-apps/eval.yaml index 061c0633ef..aec267730d 100644 --- a/src/dotnet/tests/profiling-dotnet-apps/eval.yaml +++ b/src/dotnet/tests/profiling-dotnet-apps/eval.yaml @@ -1,6 +1,7 @@ scenarios: - name: "Profile slow API response times" - prompt: "My API response times jumped from 50ms to 2 seconds after deploying yesterday. Can you help me profile what's happening?" + prompt: | + My ASP.NET Core 8 API response times jumped from 50ms to 2 seconds after deploying yesterday. The app is running on Linux in a container. Can you help me profile what's happening? I need the exact diagnostic commands to run. assertions: - type: "output_matches" pattern: "(dotnet-counters|dotnet-trace|dotnet-dump)" @@ -8,25 +9,10 @@ scenarios: pattern: "(cpu|latency|thread|request)" rubric: - "Verified or installed .NET diagnostic tools (dotnet-counters, dotnet-trace, dotnet-dump)" - - "Used dotnet-counters to monitor live runtime metrics as a starting point" - - "Chose appropriate profiling approach based on symptoms (CPU sampling, request tracing, or memory)" - - "Collected a trace or counters data for analysis" - - "Interpreted results and identified potential hot paths or bottlenecks" - - "Provided concrete optimization suggestions (caching, pooling, async fixes, etc.)" + - "Used dotnet-counters monitor with specific counter providers (System.Runtime, Microsoft.AspNetCore.Hosting)" + - "Provided dotnet-trace collect command with --profile cpu-sampling or explicit --providers for CPU profiling" + - "Mentioned converting trace output for analysis (speedscope, PerfView, or dotnet-trace convert)" + - "Identified key counters to watch: cpu-usage, gc-heap-size, threadpool-queue-length, or gen-2-gc-count" + - "Provided concrete next steps based on what profiling data might show (CPU hot paths, thread pool starvation, GC pressure)" expect_tools: ["bash"] timeout: 120 - - - name: "Profiling skill should not activate for build errors" - prompt: "My dotnet build is failing with CS0246 errors. Can you help me fix them?" - assertions: - - type: "output_not_contains" - value: "dotnet-trace" - - type: "output_not_contains" - value: "dotnet-counters" - - type: "output_not_matches" - pattern: "(profil|perf.*trac)" - rubric: - - "Did NOT suggest profiling or tracing tools for a build error" - - "Focused on fixing the CS0246 compilation error (missing type or namespace)" - - "Suggested adding the missing using directive or NuGet package reference" - timeout: 60