Skip to main content

dotnet-performance-profiling-and-optimization

Use when a .NET process is slow, hung, memory-heavy, or deadlocked, or when analyzing C#/ASP.NET Core code for performance anti-patterns across memory, async, LINQ, database, JSON, caching, DI, concurrency, HttpClient, exceptions, response, strings, startup, and metrics.

설치로 이동

소스 정보

저장소
MCCTeam/UMPK
최근 소스 활동
2026년 9월 12일 15:34
감지된 SKILL.md 언어
영어
스타
2
포크
0

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
14 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
dotnet-performance-profiling-and-optimization
description
Use when a .NET process is slow, hung, memory-heavy, or deadlocked, or when analyzing C#/ASP.NET Core code for performance anti-patterns across memory, async, LINQ, database, JSON, caching, DI, concurrency, HttpClient, exceptions, response, strings, startup, and metrics.
metadata
{"category":"technique","version":"1.1.0","platform":".NET 8 and .NET 10 (no .NET 9 projects in scope)","triggers":["dotnet-counters","dotnet-trace","dotnet-dump","dotnet-gcdump","dotnet-stack","benchmarkdotnet","allocations","gc pressure","memory leak","hot path","linq","stackalloc","span","boxing","heap","latency","throughput","slow","hang","deadlock","optimize","performance","async","caching","di lifetime","ef core","cosmosdb","json serialization","httpclient","middleware"]}
# .NET Performance: Diagnostic & Code Review Unified C#/.NET performance skill targeting **.NET 8 and .NET 10**. Two modes: live process diagnostics (Mode A) and static code optimization review with fixes (Mode B). ## Step 0 — Detect the target framework Before recommending APIs, inspect `Directory.Build.props` and the target project. This repository targets .NET 10. When reviewing external multi-targeted code, use the oldest target's supported API. Stephen Toub's posts are the primary benchmark source: [Performance Improvements in .NET 8](https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-8/) · [Performance Improvements in .NET 10](https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-10/). ## References Load on demand: - [references/memory-model-gc.md](references/memory-model-gc.md) — stack vs heap, generations, LOH, boxing, GC tuning - [references/code-patterns.md](references/code-patterns.md) — LINQ, Span/Memory, stackalloc, structs, boxing, pooling, strings (conceptual framing) - [references/categories.md](references/categories.md) — 14 optimization category definitions with checks and grep patterns (Mode B spine) - [references/grep-patterns.md](references/grep-patterns.md) — consolidated anti-pattern grep library for Phase 1 scanning - [references/measurement-guide.md](references/measurement-guide.md) — BenchmarkDotNet, k6, dotnet-counters, KPI targets, CI/CD Pattern catalogs (with measured impact numbers, ❌/✅ pairs, and per-topic Detection recipes): - [references/critical-patterns.md](references/critical-patterns.md) — 17 🔴 patterns: deadlocks, order-of-magnitude regressions, excessive allocations - [references/async-patterns.md](references/async-patterns.md) — sync-over-async, ValueTask hot paths, Channels, false sharing - [references/memory-and-strings.md](references/memory-and-strings.md) — `u8` literals, `Span.Split`/`TryWrite`, compound `+=`, chained `.Replace()` - [references/collections-and-linq.md](references/collections-and-linq.md) — `FrozenDictionary`, `GetAlternateLookup`, `CollectionsMarshal.GetValueRefOrAddDefault`, hoisting static data - [references/regex-patterns.md](references/regex-patterns.md) — `[GeneratedRegex]`, `IsMatch`, `EnumerateMatches`, `NonBacktracking` - [references/io-and-serialization.md](references/io-and-serialization.md) — `HttpCompletionOption.ResponseHeadersRead`, `useAsync` `FileStream`, `Memory<byte>` overloads - [references/structural-patterns.md](references/structural-patterns.md) — sealed-class devirtualization (absence pattern, scale-based severity) Reference loading guide for Mode B by signal: | Signal in Code | Load | |---|---| | `async`, `await`, `Task`, `ValueTask` | `async-patterns.md` | | `Span<`, `Memory<`, `stackalloc`, `string.Substring`, `+=` in loops, `params` | `memory-and-strings.md` | | `Regex`, `[GeneratedRegex]`, `Regex.Match`, `RegexOptions.Compiled` | `regex-patterns.md` | | `Dictionary<`, `List<`, `.ToList()`, LINQ chains, `static readonly Dictionary<` | `collections-and-linq.md` | | `JsonSerializer`, `HttpClient`, `Stream`, `FileStream` | `io-and-serialization.md` | | Any code review on a hot path | always check `critical-patterns.md` first | | Codebase-wide scans (sealed classes, static `Dictionary` → `FrozenDictionary`) | `structural-patterns.md` | ## Iron Rule **Always measure first, change second, and re-measure third.** Never claim an optimization without before/after evidence from the same scenario. | Rationalization | Reality | |---|---| | "This is obviously slow" | The runtime, JIT, and libraries often invalidate intuition. | | "struct means stack" | Value types are stored inline — not always on the stack. | | "All LINQ is slow" | .NET 9+ improved many LINQ paths. Measure before rewriting. | | "GC.Collect will fix it" | Forced collection treats symptoms, not cause. | | "Too small to matter" | MEDIUM+ impact is cumulative across the request pipeline. | | "I'll change the DI lifetime while I'm here" | DI lifetime changes require explicit user approval. | | "Need to refactor to optimize" | Optimization fixes must be surgical. Refactoring is a separate task. | | "Tests pass so fix is correct" | Tests passing = behavior preserved. Still verify the metric improved. | ## Mode Selection | Situation | Mode | |---|---| | Live process: slow, high CPU/memory, hung, deadlocked, GC pauses | **A – Diagnostic** | | Asking how GC, heap, boxing, or LINQ overhead works in .NET | **A – Diagnostic** (conceptual) | | Code to analyze for anti-patterns, then fix | **B – Code Review** | | Both a running process AND code to fix | Start with **A**, then **B** on hot paths identified | **Not for:** Visual Studio, Rider, PerfView, speedscope, or GUI-first workflows. --- ## Mode A: Diagnostic (Live Process) ### Investigation Order 1. **`dotnet-counters`** — always start here for live triage. 2. **`dotnet-stack`** — immediately if process is stuck, hung, or deadlocked. 3. **`dotnet-trace`** — if CPU or allocation hot paths matter. 4. **`dotnet-gcdump`** — if heap growth matters more than call paths. 5. **`dotnet-dump`** — if SOS heap inspection or postmortem analysis is needed. 6. After live evidence identifies a candidate routine, apply patterns from [references/code-patterns.md](references/code-patterns.md) and [references/memory-model-gc.md](references/memory-model-gc.md). 7. Use BenchmarkDotNet if the change is isolated and needs microbenchmark comparison. 8. Re-run the original live capture to prove the real workload improved. ### CLI Tool Selection | Question | Tool | What it answers | |---|---|---| | Is the process allocating, GCing, or saturating CPU? | `dotnet-counters` | Live counters and trend direction | | Is the process hung or deadlocked right now? | `dotnet-stack` | Current managed stack snapshot | | Which call paths consume CPU or allocate heavily? | `dotnet-trace` | Sampled execution and runtime events | | Which object types dominate managed heap? | `dotnet-gcdump` | Heap composition and type totals | | Need SOS heap inspection or thread state? | `dotnet-dump` | Full dump plus CLI analysis | | Did a code change improve an isolated routine? | BenchmarkDotNet | Reproducible microbenchmark comparison | ### Minimal CLI Commands ```bash dotnet-counters monitor -p <PID> --counters System.Runtime dotnet-counters monitor -n <ProcessName> --counters System.Runtime,Microsoft.AspNetCore.Hosting dotnet-stack report -p <PID> dotnet-trace collect -p <PID> --duration 00:00:30 dotnet-trace report <trace.nettrace> topN dotnet-gcdump collect -p <PID> dotnet-gcdump report <file.gcdump> dotnet-dump collect -p <PID> --type Heap dotnet-dump analyze <dump> -c "dumpheap -stat" -c "exit" ``` Minimal BenchmarkDotNet pattern: ```csharp [MemoryDiagnoser] [SimpleJob(RuntimeMoniker.Net10_0)] public class CandidateBench { [Benchmark(Baseline = true)] public int Original() => OriginalImpl(); [Benchmark] public int Candidate() => CandidateImpl(); } ``` ```bash dotnet run -c Release ``` ### Reference Loading Guide | User question | Load first | |---|---| | "How do stack and heap really work in .NET?" | `references/memory-model-gc.md` | | "Why is GC pausing or why is LOH churn hurting us?" | `references/memory-model-gc.md` | | "How should I optimize this LINQ?" | `references/code-patterns.md` | | "Can I move this to the stack with stackalloc or Span?" | `references/code-patterns.md` | | "Should this be a struct, ref struct, readonly struct, or class?" | Both | | "Why is this boxing?" | `references/code-patterns.md` | ### Diagnostic Output Report: measured symptom + evidence (counter values, trace hotspots, heap stats) · chosen tool and why · relevant tradeoff (allocation vs copy, deferred vs eager, stack vs pool) · before/after result, or explicitly state if still unverified. --- ## Mode B: Code Review (Static Analysis) ### Target `$ARGUMENTS` is the optimization target: - **File path**: Analyze that file and its close dependencies. - **Directory**: Analyze all C# files in that directory. - **"all"**: Scan the solution with Grep, deep-dive the worst offenders. - **`--fix`** anywhere: Skip confirmation and apply fixes after analysis. - **Empty**: Check `git diff --name-only HEAD~5 -- '*.cs'` for recently changed files. If none, ask the user. ### Phase 1: Discovery 1. **Glob** to find `.cs` files matching the target. 2. **Read** file contents. For files under 500 lines, read the whole file first — visual inspection catches patterns faster than grep, then grep confirms counts. 3. **Detect signals** in the code (async, Span, Regex, Dictionary, JsonSerializer, etc.) and **load matching pattern catalogs** from the per-topic references listed at the top of this file. 4. **Grep** for anti-patterns. Run the recipes in [references/grep-patterns.md](references/grep-patterns.md) plus the per-topic Detection sections in the catalogs you loaded. 5. **Emit a scan execution checklist** before classifying — list each recipe and the hit count. **0 hits is valid and valuable** (confirms good practice). ### Phase 2: Analysis (Read-Only) Check each file against all 14 categories. Record per finding: **file path, line number, current pattern, recommended pattern, impact level, category**. Read [references/categories.md](references/categories.md) for detailed check definitions. #### Compound Allocation Check Single-line grep recipes miss multi-allocation patterns. After running scan recipes, look for: 1. **Branched `.Replace()` chains** — methods that call `.Replace()` across multiple `if/else` branches. Report total allocation count across all branches, not just per-line. 2. **Cross-method chaining** — public method A calls B (which does 3 regex replaces) then calls C (which allocates). Report the total chain cost as one finding, not per-method. 3. **Compound `+=` with embedded allocating calls** — `result += $"...{Foo().ToLower()}"` is 2+ allocations (interpolation + `ToLower` + concatenation). Flag the compound cost, not just `.ToLower()`. 4. **`string.Format` specificity** — distinguish resource-loaded format strings (not fixable) from compile-time literal format strings (fixable with interpolation). Enumerate only the actionable sites. #### Cross-File Consistency Check If an optimized pattern is found in one file, check whether sibling files (same directory, same interface, same base class) use the un-optimized equivalent. Flag as MEDIUM with the optimized file as evidence. #### Verify-the-Inverse Rule For absence patterns (e.g., unsealed classes, static `Dictionary` not converted to `FrozenDictionary`, `RegexOptions.Compiled` not migrated to `[GeneratedRegex]`), always count both sides and report the **N-of-M ratio**, not just the count of bad cases. The ratio determines severity: - 0/185 sealed → systematic codebase-wide issue - 12/15 sealed → consistency fix on the remaining 3 - 50/100 sealed → mid-migration; flag the laggards | # | Category | Code | Focus | |---|---|---|---| | 1 | Memory Allocation | MEM | Span, ArrayPool, pooling, stackalloc, string optimization, collections | | 2 | Async Anti-Patterns | ASYNC | Blocking, ValueTask, CancellationToken, IAsyncEnumerable, Channel | | 3 | LINQ Inefficiencies | LINQ | Count vs Any, multiple enumeration, filter/project order | | 4 | Database | DB | EF Core, CosmosDB patterns, N+1, partition keys, RU cost | | 5 | JSON Serialization | JSON | Options reuse, source generators, serializer boundaries | | 6 | Caching | CACHE | HybridCache, stampede protection, output cache, size limits | | 7 | DI Lifetimes | DI | Captive dependencies, lifetime mismatches, IOptions patterns | | 8 | Concurrency | CONC | Lock contention, throttling, thread safety, Channel patterns | | 9 | HttpClient | HTTP | IHttpClientFactory, resilience, response disposal | | 10 | Exception Control Flow | EXC | Try/catch for expected paths, broad catches | | 11 | Response Optimization | RESP | Compression, pagination, ETags | | 12 | String Optimization | STR | Concatenation loops, ToLower/ToUpper, String.Format | | 13 | Startup & Pipeline | STARTUP | Middleware ordering, compression, health checks, PGO | | 14 | Metrics & Observability | METRICS | IMeterFactory, histograms, tag cardinality, OpenTelemetry | ### Phase 3: Report ``` ## Performance Analysis Report ### Summary - Files analyzed: N - Total findings: N - Critical (HIGH): N | Moderate (MEDIUM): N | Minor (LOW): N ### Findings by Category #### [CATEGORY_NAME] (N findings) | # | Impact | File:Line | Issue | Recommendation | |---|--------|-----------|-------|----------------| | 1 | HIGH | `path/File.cs:42` | Current anti-pattern | Recommended fix | ### Prioritized Action List 1. [HIGH] Fix blocking async calls in X — thread pool starvation risk 2. [MEDIUM] Switch to ArrayPool in Z — reduces GC pressure on upload path ``` **Impact levels:** - **HIGH**: Measurable gain, prevents starvation, fixes correctness, reduces P95 latency. Examples: blocking async, missing CancellationToken, N+1 queries, captive dependencies. - **MEDIUM**: Reduces allocations, GC pressure, or unnecessary work. Examples: ArrayPool, StringBuilder, FrozenDictionary. - **LOW**: Minor improvements, cold-path optimizations. Examples: initial collection capacity, Count() vs Any(). **Scale-based severity escalation.** When the same anti-pattern appears across many instances, escalate: - 1–10 instances → report at the pattern's base severity - 11–50 instances → escalate LOW patterns to MEDIUM - 50+ instances → MEDIUM with elevated priority; flag as a codebase-wide systematic issue Always report **exact counts from scan recipes**, not estimates. Group findings by severity (HIGH → MEDIUM → LOW), not by file. Merge related findings that share the same fix (e.g., all `.ToLower()` calls in one finding, not split per file). ### Phase 4: Optimization (Apply Fixes) After presenting the report: - If `--fix` in `$ARGUMENTS`, proceed directly. - Otherwise ask: "Would you like me to apply these optimizations? I'll work one category at a time, starting with HIGH impact. You can specify categories or findings (e.g., 'fix ASYNC and MEM' or 'fix #1, #3')." **Before any fix:** 1. **Read actual code context** around the grep match — false positives exist (`.Result` in `Task.FromResult` is NOT blocking). 2. Confirm the finding is real. If uncertain, flag as "needs manual review." **Applying fixes:** 1. One category at a time, highest impact first. Use Edit tool with brief before/after summary. 2. After each category: `dotnet build --no-restore`
GitHub에서 보기
이 SKILL.md는 매우 커서 SkillsMP가 여기에는 첫 섹션만 미리 보여줍니다. GitHub에서 보기