Skip to content

Commit c5b52bf

Browse files
committed
Add mcaf-dotnet-profiling skill
1 parent 40e08b9 commit c5b52bf

File tree

4 files changed

+310
-1
lines changed

4 files changed

+310
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ Platform-specific bundles can stay small and still be explicit.
115115
For example, a typical .NET repo baseline can install `mcaf-dotnet` as the entry skill, `mcaf-dotnet-features`, `mcaf-solution-governance`, `mcaf-testing`, exactly one of `mcaf-dotnet-xunit`, `mcaf-dotnet-tunit`, or `mcaf-dotnet-mstest`, plus `mcaf-dotnet-quality-ci`, `mcaf-dotnet-complexity`, `mcaf-solid-maintainability`, `mcaf-architecture-overview`, and `mcaf-ci-cd`.
116116
In that setup, `mcaf-dotnet` knows when to open the more specific .NET skills, the repo-root lowercase `.editorconfig` is the default source of truth for formatting and analyzer severity, and `AGENTS.md` records the exact `dotnet build`, `dotnet test`, `dotnet format`, `analyze`, and coverage commands. Nested `.editorconfig` files are allowed when they serve a clear subtree-specific purpose, such as stricter domain rules, generated-code handling, test-specific conventions, or legacy-code containment.
117117
For .NET code changes, the task is not done when tests are green if the repo also configured formatters, analyzers, coverage, architecture tests, or security gates. Agents should run the repo-defined post-change quality pass before completion.
118-
If the repo standardizes on concrete tools, install the matching tool skills as well. Typical open or free .NET additions include `mcaf-dotnet-format`, `mcaf-dotnet-code-analysis`, `mcaf-dotnet-analyzer-config`, `mcaf-dotnet-stylecop-analyzers`, `mcaf-dotnet-roslynator`, `mcaf-dotnet-meziantou-analyzer`, `mcaf-dotnet-cloc`, `mcaf-dotnet-coverlet`, `mcaf-dotnet-quickdup`, `mcaf-dotnet-reportgenerator`, `mcaf-dotnet-stryker`, `mcaf-dotnet-netarchtest`, `mcaf-dotnet-archunitnet`, `mcaf-dotnet-semgrep`, and `mcaf-dotnet-csharpier`. `mcaf-dotnet-codeql` stays available, but should be chosen only when its hosting and licensing model fits the repository.
118+
If the repo standardizes on concrete tools, install the matching tool skills as well. Typical open or free .NET additions include `mcaf-dotnet-format`, `mcaf-dotnet-code-analysis`, `mcaf-dotnet-analyzer-config`, `mcaf-dotnet-stylecop-analyzers`, `mcaf-dotnet-roslynator`, `mcaf-dotnet-meziantou-analyzer`, `mcaf-dotnet-cloc`, `mcaf-dotnet-coverlet`, `mcaf-dotnet-profiling`, `mcaf-dotnet-quickdup`, `mcaf-dotnet-reportgenerator`, `mcaf-dotnet-stryker`, `mcaf-dotnet-netarchtest`, `mcaf-dotnet-archunitnet`, `mcaf-dotnet-semgrep`, and `mcaf-dotnet-csharpier`. `mcaf-dotnet-codeql` stays available, but should be chosen only when its hosting and licensing model fits the repository.
119119

120120
### 2.5 Context Rules
121121

TUTORIAL.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ Add tool-specific .NET skills only when the repo standardizes on them:
148148
- `mcaf-dotnet-format`
149149
- `mcaf-dotnet-meziantou-analyzer`
150150
- `mcaf-dotnet-netarchtest`
151+
- `mcaf-dotnet-profiling`
151152
- `mcaf-dotnet-quickdup`
152153
- `mcaf-dotnet-reportgenerator`
153154
- `mcaf-dotnet-roslynator`
@@ -182,6 +183,7 @@ The website build generates this list from the actual folders under `skills/`.
182183
- `mcaf-dotnet-meziantou-analyzer`[Folder](https://github.com/managedcode/MCAF/blob/main/skills/mcaf-dotnet-meziantou-analyzer), [Raw SKILL](https://raw.githubusercontent.com/managedcode/MCAF/main/skills/mcaf-dotnet-meziantou-analyzer/SKILL.md)
183184
- `mcaf-dotnet-mstest`[Folder](https://github.com/managedcode/MCAF/blob/main/skills/mcaf-dotnet-mstest), [Raw SKILL](https://raw.githubusercontent.com/managedcode/MCAF/main/skills/mcaf-dotnet-mstest/SKILL.md)
184185
- `mcaf-dotnet-netarchtest`[Folder](https://github.com/managedcode/MCAF/blob/main/skills/mcaf-dotnet-netarchtest), [Raw SKILL](https://raw.githubusercontent.com/managedcode/MCAF/main/skills/mcaf-dotnet-netarchtest/SKILL.md)
186+
- `mcaf-dotnet-profiling`[Folder](https://github.com/managedcode/MCAF/blob/main/skills/mcaf-dotnet-profiling), [Raw SKILL](https://raw.githubusercontent.com/managedcode/MCAF/main/skills/mcaf-dotnet-profiling/SKILL.md)
185187
- `mcaf-dotnet-quality-ci`[Folder](https://github.com/managedcode/MCAF/blob/main/skills/mcaf-dotnet-quality-ci), [Raw SKILL](https://raw.githubusercontent.com/managedcode/MCAF/main/skills/mcaf-dotnet-quality-ci/SKILL.md)
186188
- `mcaf-dotnet-quickdup`[Folder](https://github.com/managedcode/MCAF/blob/main/skills/mcaf-dotnet-quickdup), [Raw SKILL](https://raw.githubusercontent.com/managedcode/MCAF/main/skills/mcaf-dotnet-quickdup/SKILL.md)
187189
- `mcaf-dotnet-reportgenerator`[Folder](https://github.com/managedcode/MCAF/blob/main/skills/mcaf-dotnet-reportgenerator), [Raw SKILL](https://raw.githubusercontent.com/managedcode/MCAF/main/skills/mcaf-dotnet-reportgenerator/SKILL.md)
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
---
2+
name: mcaf-dotnet-profiling
3+
description: "Use the free official .NET diagnostics CLI tools for profiling and runtime investigation in .NET repositories. Use when a repo needs CPU tracing, live counters, GC and allocation investigation, exception or contention tracing, heap snapshots, or startup diagnostics without GUI-only tooling."
4+
compatibility: "Requires a .NET app or process to inspect; respects the repo's `AGENTS.md` commands first."
5+
---
6+
7+
# MCAF: .NET Profiling
8+
9+
## Trigger On
10+
11+
- the repo needs performance or runtime profiling for a .NET application
12+
- the user asks about slow code, high CPU, GC pressure, allocation growth, exception storms, lock contention, or startup diagnostics
13+
- the team wants official CLI-based diagnostics without depending on `dnx`
14+
15+
## Value
16+
17+
- produce a concrete project delta: code, docs, config, tests, CI, or review artifact
18+
- reduce ambiguity through explicit planning, verification, and final validation skills
19+
- leave reusable project context so future tasks are faster and safer
20+
21+
## Do Not Use For
22+
23+
- replacing realistic performance tests or load tests with ad-hoc tracing alone
24+
- production heap collection when the pause risk has not been accepted
25+
- GUI-only workflows that the repo cannot automate or document
26+
27+
## Inputs
28+
29+
- the nearest `AGENTS.md`
30+
- target application, process, or startup path
31+
- the symptom being investigated: CPU, memory, GC, contention, exceptions, or startup
32+
33+
## Quick Start
34+
35+
1. Read the nearest `AGENTS.md` and confirm scope and constraints.
36+
2. Run this skill's `Workflow` through the `Ralph Loop` until outcomes are acceptable.
37+
3. Return the `Required Result Format` with concrete artifacts and verification evidence.
38+
39+
## Workflow
40+
41+
1. Build and run a realistic target first:
42+
- prefer `Release`
43+
- prefer realistic config, inputs, and data volume
44+
2. Start with the lightest useful tool:
45+
- `dotnet-counters` for live health signals
46+
- `dotnet-trace` for CPU, exception, contention, GC, and startup traces
47+
- `dotnet-gcdump` for managed heap inspection when memory shape matters
48+
3. Prefer installed CLI tools over `dnx` one-shot execution so the repo commands stay stable and reproducible.
49+
4. Capture one focused profile at a time instead of mixing every signal into one run.
50+
5. For CPU and general runtime hotspots, start with `dotnet-trace collect`.
51+
6. For live triage, start with `dotnet-counters monitor` on `System.Runtime`.
52+
7. For heap analysis, use `dotnet-gcdump` carefully and document the pause risk.
53+
8. After each change, rerun the same measurement path and compare before versus after.
54+
55+
## Bootstrap When Missing
56+
57+
If official .NET profiling tools are not available yet:
58+
59+
1. Detect current state:
60+
- `dotnet --info`
61+
- `dotnet tool list --global`
62+
- `command -v dotnet-counters`
63+
- `command -v dotnet-trace`
64+
- `command -v dotnet-gcdump`
65+
2. Choose the install path deliberately:
66+
- preferred machine-level install:
67+
- `dotnet tool install --global dotnet-counters`
68+
- `dotnet tool install --global dotnet-trace`
69+
- `dotnet tool install --global dotnet-gcdump`
70+
- direct-download fallback when global tools are not suitable:
71+
- use the official Microsoft Learn download links for `dotnet-counters`, `dotnet-trace`, and `dotnet-gcdump`
72+
3. Verify the installed tools resolve correctly:
73+
- `dotnet-counters --version`
74+
- `dotnet-trace --version`
75+
- `dotnet-gcdump --version`
76+
4. Record exact profiling commands in `AGENTS.md`, for example:
77+
- `dotnet-counters monitor --process-id <pid> --counters System.Runtime`
78+
- `dotnet-trace collect --process-id <pid> --profile dotnet-common,dotnet-sampled-thread-time -o trace.nettrace`
79+
- `dotnet-gcdump collect --process-id <pid> --output heap.gcdump`
80+
5. Run one bounded command and return `status: configured` or `status: improved`.
81+
6. If the repo intentionally standardizes on another profiling stack and does not want these tools, return `status: not_applicable`.
82+
83+
## Deliver
84+
85+
- explicit official .NET profiling commands
86+
- a clear profiling path for CPU, counters, and heap inspection
87+
- reproducible diagnostics commands that humans and agents can rerun
88+
89+
## Validate
90+
91+
- the chosen tool matches the actual symptom
92+
- commands target a realistic process and configuration
93+
- before/after comparisons use the same scenario
94+
- heap collection warnings are explicit when `dotnet-gcdump` is used
95+
96+
## Ralph Loop
97+
98+
Use the Ralph Loop for every task, including docs, architecture, testing, and tooling work.
99+
100+
1. Plan first (mandatory):
101+
- analyze current state
102+
- define target outcome, constraints, and risks
103+
- write a detailed execution plan
104+
- list final validation skills to run at the end, with order and reason
105+
2. Execute one planned step and produce a concrete delta.
106+
3. Review the result and capture findings with actionable next fixes.
107+
4. Apply fixes in small batches and rerun the relevant checks or review steps.
108+
5. Update the plan after each iteration.
109+
6. Repeat until outcomes are acceptable or only explicit exceptions remain.
110+
7. If a dependency is missing, bootstrap it or return `status: not_applicable` with explicit reason and fallback path.
111+
112+
### Required Result Format
113+
114+
- `status`: `complete` | `clean` | `improved` | `configured` | `not_applicable` | `blocked`
115+
- `plan`: concise plan and current iteration step
116+
- `actions_taken`: concrete changes made
117+
- `validation_skills`: final skills run, or skipped with reasons
118+
- `verification`: commands, checks, or review evidence summary
119+
- `remaining`: top unresolved items or `none`
120+
121+
For setup-only requests with no execution, return `status: configured` and exact next commands.
122+
123+
## Load References
124+
125+
- read `references/profiling.md` first
126+
127+
## Example Requests
128+
129+
- "Profile this .NET app for CPU hotspots."
130+
- "Investigate GC pressure in this service."
131+
- "Capture counters and a trace from startup."
132+
- "Set up official .NET profiling tools for local investigations."
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
# Official .NET Profiling Tools
2+
3+
## What This Skill Uses
4+
5+
This skill standardizes on official CLI-based .NET diagnostics tools:
6+
7+
- `dotnet-counters` for live metrics and exported counters
8+
- `dotnet-trace` for trace capture and hotspot investigation
9+
- `dotnet-gcdump` for managed heap snapshots
10+
11+
It intentionally avoids `dnx`-only flows so the commands remain explicit and durable in repo docs.
12+
13+
## Installation Paths
14+
15+
Preferred install path for frequent local diagnostics:
16+
17+
```bash
18+
dotnet tool install --global dotnet-counters
19+
dotnet tool install --global dotnet-trace
20+
dotnet tool install --global dotnet-gcdump
21+
```
22+
23+
Verify the tools:
24+
25+
```bash
26+
dotnet-counters --version
27+
dotnet-trace --version
28+
dotnet-gcdump --version
29+
```
30+
31+
If global tools are not suitable, use the official Microsoft Learn direct-download links for each tool:
32+
33+
- `dotnet-counters`
34+
- `dotnet-trace`
35+
- `dotnet-gcdump`
36+
37+
## Release-First Rule
38+
39+
Profile realistic builds and realistic scenarios:
40+
41+
```bash
42+
dotnet build -c Release
43+
dotnet run -c Release --project ./src/MyApp/MyApp.csproj
44+
```
45+
46+
Avoid profiling Debug builds unless the debugging overhead itself is the question.
47+
48+
## First-Line Live Triage with dotnet-counters
49+
50+
Use `dotnet-counters` first when you need fast feedback about:
51+
52+
- CPU usage
53+
- GC activity
54+
- allocation growth
55+
- exception rate
56+
- working set
57+
- thread pool pressure
58+
59+
List candidate processes:
60+
61+
```bash
62+
dotnet-counters ps
63+
```
64+
65+
Monitor runtime counters:
66+
67+
```bash
68+
dotnet-counters monitor --process-id <pid> --counters System.Runtime
69+
```
70+
71+
Export counters for later comparison:
72+
73+
```bash
74+
dotnet-counters collect --process-id <pid> --counters System.Runtime --format json -o counters.json
75+
```
76+
77+
For startup diagnostics:
78+
79+
```bash
80+
dotnet-counters monitor --counters System.Runtime -- dotnet exec ./bin/Release/net10.0/MyApp.dll
81+
```
82+
83+
## CPU and Runtime Tracing with dotnet-trace
84+
85+
Use `dotnet-trace` when counters show that deeper investigation is needed.
86+
87+
List candidate processes:
88+
89+
```bash
90+
dotnet-trace ps
91+
```
92+
93+
Capture a focused general-purpose trace:
94+
95+
```bash
96+
dotnet-trace collect --process-id <pid> --profile dotnet-common,dotnet-sampled-thread-time -o trace.nettrace
97+
```
98+
99+
Capture GC-heavy detail:
100+
101+
```bash
102+
dotnet-trace collect --process-id <pid> --profile gc-verbose -o gc.nettrace
103+
```
104+
105+
Trace startup directly:
106+
107+
```bash
108+
dotnet-trace collect -- dotnet exec ./bin/Release/net10.0/MyApp.dll
109+
```
110+
111+
Get a top-method summary from a captured trace:
112+
113+
```bash
114+
dotnet-trace report trace.nettrace topN --number 20
115+
```
116+
117+
Convert for external viewers when needed:
118+
119+
```bash
120+
dotnet-trace convert trace.nettrace --format Speedscope
121+
```
122+
123+
## Exceptions, Contention, and JIT Clues
124+
125+
`dotnet-trace` is the main CLI path when you need:
126+
127+
- exception-heavy traces
128+
- contention signals
129+
- JIT and runtime event visibility
130+
131+
Keep the run focused and compare the same scenario before and after each fix.
132+
133+
## Heap Investigation with dotnet-gcdump
134+
135+
Use `dotnet-gcdump` when you need managed heap composition rather than CPU stacks.
136+
137+
List candidate processes:
138+
139+
```bash
140+
dotnet-gcdump ps
141+
```
142+
143+
Capture a heap snapshot:
144+
145+
```bash
146+
dotnet-gcdump collect --process-id <pid> --output heap.gcdump
147+
```
148+
149+
Get a heap summary report:
150+
151+
```bash
152+
dotnet-gcdump report heap.gcdump
153+
```
154+
155+
Important warning:
156+
157+
- `dotnet-gcdump collect` triggers a full Gen 2 GC
158+
- this can pause the target process for a long time on large heaps
159+
- do not use it casually on latency-sensitive production paths
160+
161+
## Practical Investigation Order
162+
163+
1. Reproduce the issue in a realistic `Release` scenario.
164+
2. Start with `dotnet-counters monitor`.
165+
3. If the symptom is CPU or startup related, capture `dotnet-trace`.
166+
4. If the symptom is memory-shape related, capture `dotnet-gcdump`.
167+
5. Apply one fix at a time.
168+
6. Rerun the same command set and compare.
169+
170+
## Useful Guardrails
171+
172+
- use the same user as the target process, or root where required
173+
- on Linux and macOS, the tool and target process may need the same `TMPDIR`
174+
- prefer `dotnet exec` or direct app launch over `dotnet run` for startup tracing, because `dotnet run` may spawn extra child processes
175+
- keep artifacts named and stored predictably so comparisons are easy

0 commit comments

Comments
 (0)