@cratis/pi 7.102.0 → 7.103.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package/corpus/harnesses/copilot/instructions/profiles.instructions.md +10 -1
- package/package/corpus/harnesses/copilot/instructions/pull-requests.instructions.md +2 -0
- package/package/corpus/harnesses/copilot/instructions/secrets.instructions.md +4 -0
- package/package/corpus/hooks/README.md +11 -1
- package/package/corpus/hooks/scripts/cratis-check-pr.mjs +12 -1
- package/package/corpus/hooks/scripts/cratis-guard-secrets.sh +79 -23
- package/package/corpus/hooks/scripts/cratis-guard-writes.sh +145 -40
- package/package/corpus/rules/profiles.md +10 -1
- package/package/corpus/rules/pull-requests.md +2 -0
- package/package/corpus/rules/secrets.md +4 -0
- package/package/corpus/skills/analyzing-dotnet-performance/LICENSE +23 -0
- package/package/corpus/skills/analyzing-dotnet-performance/NOTICE +36 -0
- package/package/corpus/skills/analyzing-dotnet-performance/SKILL.md +214 -0
- package/package/corpus/skills/analyzing-dotnet-performance/references/async-patterns.md +122 -0
- package/package/corpus/skills/analyzing-dotnet-performance/references/collections-and-linq.md +220 -0
- package/package/corpus/skills/analyzing-dotnet-performance/references/critical-patterns.md +291 -0
- package/package/corpus/skills/analyzing-dotnet-performance/references/io-and-serialization.md +135 -0
- package/package/corpus/skills/analyzing-dotnet-performance/references/memory-and-strings.md +219 -0
- package/package/corpus/skills/analyzing-dotnet-performance/references/regex-patterns.md +95 -0
- package/package/corpus/skills/analyzing-dotnet-performance/references/structural-patterns.md +38 -0
- package/package/corpus/skills/binlog-generation/LICENSE +23 -0
- package/package/corpus/skills/binlog-generation/NOTICE +22 -0
- package/package/corpus/skills/binlog-generation/SKILL.md +129 -0
- package/package/corpus/skills/check-bin-obj-clash/LICENSE +23 -0
- package/package/corpus/skills/check-bin-obj-clash/NOTICE +27 -0
- package/package/corpus/skills/check-bin-obj-clash/SKILL.md +127 -0
- package/package/corpus/skills/check-bin-obj-clash/references/common-causes-and-fixes.md +206 -0
- package/package/corpus/skills/coverage-analysis/LICENSE +23 -0
- package/package/corpus/skills/coverage-analysis/NOTICE +32 -0
- package/package/corpus/skills/coverage-analysis/SKILL.md +198 -0
- package/package/corpus/skills/coverage-analysis/references/guidelines.md +68 -0
- package/package/corpus/skills/coverage-analysis/references/output-format.md +91 -0
- package/package/corpus/skills/coverage-analysis/references/report-generation.md +58 -0
- package/package/corpus/skills/coverage-analysis/references/setup-discovery.md +307 -0
- package/package/corpus/skills/coverage-analysis/scripts/Compute-CrapScores.ps1 +80 -0
- package/package/corpus/skills/coverage-analysis/scripts/CoverageData.ps1 +272 -0
- package/package/corpus/skills/coverage-analysis/scripts/Extract-MethodCoverage.ps1 +65 -0
- package/package/corpus/skills/csharp-refactoring/LICENSE +23 -0
- package/package/corpus/skills/csharp-refactoring/NOTICE +22 -0
- package/package/corpus/skills/csharp-refactoring/SKILL.md +175 -0
- package/package/corpus/skills/csharp-refactoring/references/operation-catalog.md +37 -0
- package/package/corpus/skills/directory-build-organization/LICENSE +23 -0
- package/package/corpus/skills/directory-build-organization/NOTICE +21 -0
- package/package/corpus/skills/directory-build-organization/SKILL.md +205 -0
- package/package/corpus/skills/directory-build-organization/references/common-patterns.md +56 -0
- package/package/corpus/skills/directory-build-organization/references/multi-level-examples.md +167 -0
- package/package/corpus/skills/directory-build-organization/references/targetframework-props-pitfall.md +54 -0
- package/package/corpus/skills/dotnet-aot-compat/LICENSE +23 -0
- package/package/corpus/skills/dotnet-aot-compat/NOTICE +18 -0
- package/package/corpus/skills/dotnet-aot-compat/SKILL.md +265 -0
- package/package/corpus/skills/dotnet-aot-compat/references/polyfills.md +43 -0
- package/package/corpus/skills/dotnet-trace-collect/LICENSE +23 -0
- package/package/corpus/skills/dotnet-trace-collect/NOTICE +65 -0
- package/package/corpus/skills/dotnet-trace-collect/SKILL.md +116 -0
- package/package/corpus/skills/dotnet-trace-collect/references/dotnet-monitor.md +97 -0
- package/package/corpus/skills/dotnet-trace-collect/references/dotnet-trace-collect-linux.md +84 -0
- package/package/corpus/skills/dotnet-trace-collect/references/dotnet-trace-collect.md +91 -0
- package/package/corpus/skills/dotnet-trace-collect/references/perfcollect.md +200 -0
- package/package/corpus/skills/dotnet-trace-collect/references/perfview.md +141 -0
- package/package/corpus/skills/dotnet-trace-collect/references/tool-selection.md +160 -0
- package/package/corpus/skills/dump-collect/LICENSE +23 -0
- package/package/corpus/skills/dump-collect/NOTICE +40 -0
- package/package/corpus/skills/dump-collect/SKILL.md +97 -0
- package/package/corpus/skills/dump-collect/references/container-dumps.md +412 -0
- package/package/corpus/skills/dump-collect/references/coreclr-dumps.md +108 -0
- package/package/corpus/skills/dump-collect/references/nativeaot-dumps.md +280 -0
- package/package/corpus/skills/eliminate-redundant-restores/LICENSE +23 -0
- package/package/corpus/skills/eliminate-redundant-restores/NOTICE +19 -0
- package/package/corpus/skills/eliminate-redundant-restores/SKILL.md +112 -0
- package/package/corpus/skills/extension-points/LICENSE +23 -0
- package/package/corpus/skills/extension-points/NOTICE +18 -0
- package/package/corpus/skills/extension-points/SKILL.md +248 -0
- package/package/corpus/skills/filter-syntax/LICENSE +23 -0
- package/package/corpus/skills/filter-syntax/NOTICE +17 -0
- package/package/corpus/skills/filter-syntax/SKILL.md +179 -0
- package/package/corpus/skills/including-generated-files/LICENSE +23 -0
- package/package/corpus/skills/including-generated-files/NOTICE +17 -0
- package/package/corpus/skills/including-generated-files/SKILL.md +139 -0
- package/package/corpus/skills/microbenchmarking/LICENSE +23 -0
- package/package/corpus/skills/microbenchmarking/NOTICE +36 -0
- package/package/corpus/skills/microbenchmarking/SKILL.md +131 -0
- package/package/corpus/skills/microbenchmarking/references/bdn-internals-and-tuning.md +143 -0
- package/package/corpus/skills/microbenchmarking/references/comparison-strategies.md +200 -0
- package/package/corpus/skills/microbenchmarking/references/diagnosers-and-exporters.md +150 -0
- package/package/corpus/skills/microbenchmarking/references/project-setup-and-running.md +189 -0
- package/package/corpus/skills/microbenchmarking/references/writing-benchmarks.md +310 -0
- package/package/corpus/skills/msbuild/LICENSE +23 -0
- package/package/corpus/skills/msbuild/NOTICE +55 -0
- package/package/corpus/skills/msbuild/SKILL.md +117 -0
- package/package/corpus/skills/msbuild/references/antipatterns/additional-antipatterns.md +291 -0
- package/package/corpus/skills/msbuild/references/antipatterns/incremental-build-inputs-outputs.md +57 -0
- package/package/corpus/skills/msbuild/references/antipatterns/private-assets.md +29 -0
- package/package/corpus/skills/msbuild/references/binlog-failure-analysis.md +85 -0
- package/package/corpus/skills/msbuild/references/binlog-generation.md +69 -0
- package/package/corpus/skills/msbuild/references/build-perf-baseline.md +493 -0
- package/package/corpus/skills/msbuild/references/build-perf-diagnostics.md +268 -0
- package/package/corpus/skills/msbuild/references/copy-to-output-directory.md +183 -0
- package/package/corpus/skills/msbuild/references/eval-performance.md +190 -0
- package/package/corpus/skills/msbuild/references/extension-points.md +281 -0
- package/package/corpus/skills/msbuild/references/incremental-build.md +365 -0
- package/package/corpus/skills/msbuild/references/msbuild-antipatterns.md +401 -0
- package/package/corpus/skills/orleans/LICENSE +21 -0
- package/package/corpus/skills/orleans/NOTICE +64 -0
- package/package/corpus/skills/orleans/SKILL.md +140 -0
- package/package/corpus/skills/orleans/references/anti-patterns.md +660 -0
- package/package/corpus/skills/orleans/references/configuration-api.md +933 -0
- package/package/corpus/skills/orleans/references/examples.md +66 -0
- package/package/corpus/skills/orleans/references/grain-api.md +784 -0
- package/package/corpus/skills/orleans/references/grains.md +75 -0
- package/package/corpus/skills/orleans/references/hosting.md +71 -0
- package/package/corpus/skills/orleans/references/implementation.md +591 -0
- package/package/corpus/skills/orleans/references/official-docs-index.md +250 -0
- package/package/corpus/skills/orleans/references/patterns.md +811 -0
- package/package/corpus/skills/orleans/references/persistence-api.md +495 -0
- package/package/corpus/skills/orleans/references/primitive-selection.md +35 -0
- package/package/corpus/skills/orleans/references/scheduling-and-services.md +295 -0
- package/package/corpus/skills/orleans/references/serialization-api.md +299 -0
- package/package/corpus/skills/orleans/references/streaming-api.md +396 -0
- package/package/corpus/skills/orleans/references/testing-patterns.md +210 -0
- package/package/corpus/skills/platform-detection/LICENSE +23 -0
- package/package/corpus/skills/platform-detection/NOTICE +17 -0
- package/package/corpus/skills/platform-detection/SKILL.md +230 -0
- package/package/corpus/skills/platform-detection/references/command-mode.md +27 -0
- package/package/corpus/skills/profiling/LICENSE +21 -0
- package/package/corpus/skills/profiling/NOTICE +50 -0
- package/package/corpus/skills/profiling/SKILL.md +144 -0
- package/package/corpus/skills/profiling/references/commands.md +439 -0
- package/package/corpus/skills/profiling/references/patterns.md +586 -0
- package/package/corpus/skills/profiling/references/profiling.md +190 -0
- package/package/corpus/skills/run-tests/LICENSE +23 -0
- package/package/corpus/skills/run-tests/NOTICE +19 -0
- package/package/corpus/skills/run-tests/SKILL.md +305 -0
- package/package/corpus/skills/target-authoring/LICENSE +23 -0
- package/package/corpus/skills/target-authoring/NOTICE +17 -0
- package/package/corpus/skills/target-authoring/SKILL.md +165 -0
- package/package/corpus/skills/vectorization/LICENSE +23 -0
- package/package/corpus/skills/vectorization/NOTICE +17 -0
- package/package/corpus/skills/vectorization/SKILL.md +189 -0
- package/package/profile-catalog.json +85 -1
- package/package.json +1 -1
|
@@ -0,0 +1,586 @@
|
|
|
1
|
+
# .NET Profiling Patterns Reference
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- CPU Profiling Patterns
|
|
6
|
+
- Memory Profiling Patterns
|
|
7
|
+
- GC Analysis Patterns
|
|
8
|
+
- Contention Profiling Patterns
|
|
9
|
+
- Exception Profiling Patterns
|
|
10
|
+
- Startup Profiling Patterns
|
|
11
|
+
- Production Profiling Patterns
|
|
12
|
+
- Comparison and Benchmarking Patterns
|
|
13
|
+
- Tool Selection Guide
|
|
14
|
+
|
|
15
|
+
This reference covers common profiling patterns for CPU, memory, GC, and performance analysis in .NET applications.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## CPU Profiling Patterns
|
|
20
|
+
|
|
21
|
+
### Pattern: CPU Hotspot Analysis
|
|
22
|
+
|
|
23
|
+
**When to use**: Application is slow or using excessive CPU.
|
|
24
|
+
|
|
25
|
+
**Approach**:
|
|
26
|
+
1. Ensure the application is running under realistic load
|
|
27
|
+
2. Collect a CPU sampling trace
|
|
28
|
+
3. Analyze the flame graph for time-consuming methods
|
|
29
|
+
4. Focus on your code, not framework internals
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Collect CPU sampling trace
|
|
33
|
+
dotnet-trace collect --process-id <PID> --profile cpu-sampling --duration 00:00:30
|
|
34
|
+
|
|
35
|
+
# Convert for visualization
|
|
36
|
+
dotnet-trace convert trace.nettrace --format Speedscope
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Analysis checklist**:
|
|
40
|
+
- [ ] Identify top 5 methods by inclusive time
|
|
41
|
+
- [ ] Look for unexpected methods in hot paths
|
|
42
|
+
- [ ] Check for string operations in loops
|
|
43
|
+
- [ ] Check for repeated allocations causing GC
|
|
44
|
+
- [ ] Check for synchronous I/O blocking threads
|
|
45
|
+
|
|
46
|
+
### Pattern: Method-Level Timing
|
|
47
|
+
|
|
48
|
+
**When to use**: Need precise timing for specific operations.
|
|
49
|
+
|
|
50
|
+
**Approach**:
|
|
51
|
+
1. Add `System.Diagnostics.Activity` or `Stopwatch` instrumentation
|
|
52
|
+
2. Use EventCounters for custom metrics
|
|
53
|
+
3. Collect with dotnet-counters
|
|
54
|
+
|
|
55
|
+
```csharp
|
|
56
|
+
// Custom EventCounter for method timing
|
|
57
|
+
public class OperationMetrics : EventSource
|
|
58
|
+
{
|
|
59
|
+
public static readonly OperationMetrics Instance = new();
|
|
60
|
+
|
|
61
|
+
private readonly IncrementingEventCounter _operationCount;
|
|
62
|
+
private readonly EventCounter _operationDuration;
|
|
63
|
+
|
|
64
|
+
public OperationMetrics()
|
|
65
|
+
{
|
|
66
|
+
_operationCount = new IncrementingEventCounter("operation-count", this);
|
|
67
|
+
_operationDuration = new EventCounter("operation-duration-ms", this);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public void RecordOperation(double durationMs)
|
|
71
|
+
{
|
|
72
|
+
_operationCount.Increment();
|
|
73
|
+
_operationDuration.WriteMetric(durationMs);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# Monitor custom counters
|
|
80
|
+
dotnet-counters monitor --process-id <PID> \
|
|
81
|
+
--counters "MyApp.OperationMetrics[operation-count,operation-duration-ms]"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Pattern: Thread Pool Starvation Detection
|
|
85
|
+
|
|
86
|
+
**When to use**: Application becomes unresponsive under load.
|
|
87
|
+
|
|
88
|
+
**Symptoms**:
|
|
89
|
+
- High thread pool queue length
|
|
90
|
+
- Increasing response times
|
|
91
|
+
- Thread count growing continuously
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# Monitor thread pool health
|
|
95
|
+
dotnet-counters monitor --process-id <PID> \
|
|
96
|
+
--counters "System.Runtime[threadpool-thread-count,threadpool-queue-length,threadpool-completed-items-count]"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Thresholds to watch**:
|
|
100
|
+
- `threadpool-queue-length` > 0 sustained indicates starvation
|
|
101
|
+
- `threadpool-thread-count` growing continuously indicates blocking calls
|
|
102
|
+
- High `threadpool-completed-items-count` with high queue length indicates throughput issues
|
|
103
|
+
|
|
104
|
+
**Common causes**:
|
|
105
|
+
- Sync-over-async (calling `.Result` or `.Wait()`)
|
|
106
|
+
- Blocking I/O on thread pool threads
|
|
107
|
+
- Long-running synchronous work on thread pool
|
|
108
|
+
- Too many concurrent operations
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Memory Profiling Patterns
|
|
113
|
+
|
|
114
|
+
### Pattern: Memory Leak Detection
|
|
115
|
+
|
|
116
|
+
**When to use**: Memory grows continuously over time.
|
|
117
|
+
|
|
118
|
+
**Approach**:
|
|
119
|
+
1. Establish baseline memory usage
|
|
120
|
+
2. Run under load for extended period
|
|
121
|
+
3. Take periodic GC dumps
|
|
122
|
+
4. Compare heap snapshots
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Baseline snapshot
|
|
126
|
+
dotnet-gcdump collect --process-id <PID> --output baseline.gcdump
|
|
127
|
+
|
|
128
|
+
# After load test
|
|
129
|
+
dotnet-gcdump collect --process-id <PID> --output afterload.gcdump
|
|
130
|
+
|
|
131
|
+
# Generate reports
|
|
132
|
+
dotnet-gcdump report baseline.gcdump > baseline-report.txt
|
|
133
|
+
dotnet-gcdump report afterload.gcdump > afterload-report.txt
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Analysis steps**:
|
|
137
|
+
1. Compare type counts between snapshots
|
|
138
|
+
2. Look for types with growing instance counts
|
|
139
|
+
3. Identify retained object graphs
|
|
140
|
+
4. Check for event handler subscriptions
|
|
141
|
+
5. Check for static collections
|
|
142
|
+
|
|
143
|
+
### Pattern: Large Object Heap (LOH) Analysis
|
|
144
|
+
|
|
145
|
+
**When to use**: GC pauses are long or memory fragmentation suspected.
|
|
146
|
+
|
|
147
|
+
**Symptoms**:
|
|
148
|
+
- Gen 2 GC frequency increasing
|
|
149
|
+
- Long GC pause times
|
|
150
|
+
- High memory usage despite low live object count
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
# Collect GC verbose trace
|
|
154
|
+
dotnet-trace collect --process-id <PID> --profile gc-verbose --duration 00:01:00
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Common LOH issues**:
|
|
158
|
+
- Arrays > 85,000 bytes allocated frequently
|
|
159
|
+
- String concatenation creating large strings
|
|
160
|
+
- Large buffers not pooled
|
|
161
|
+
- Byte arrays from serialization
|
|
162
|
+
|
|
163
|
+
**Mitigations**:
|
|
164
|
+
```csharp
|
|
165
|
+
// Use ArrayPool for large buffers
|
|
166
|
+
var buffer = ArrayPool<byte>.Shared.Rent(100000);
|
|
167
|
+
try
|
|
168
|
+
{
|
|
169
|
+
// Use buffer
|
|
170
|
+
}
|
|
171
|
+
finally
|
|
172
|
+
{
|
|
173
|
+
ArrayPool<byte>.Shared.Return(buffer);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Use string pooling
|
|
177
|
+
var pooledString = string.Intern(frequentlyUsedString);
|
|
178
|
+
|
|
179
|
+
// Use Span<T> to avoid allocations
|
|
180
|
+
ReadOnlySpan<byte> span = stackalloc byte[256];
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Pattern: Allocation Rate Analysis
|
|
184
|
+
|
|
185
|
+
**When to use**: GC running too frequently.
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
# Monitor allocation rate
|
|
189
|
+
dotnet-counters monitor --process-id <PID> \
|
|
190
|
+
--counters "System.Runtime[alloc-rate,gc-heap-size,gen-0-gc-count,gen-1-gc-count,gen-2-gc-count]"
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Thresholds to watch**:
|
|
194
|
+
- `alloc-rate` > 100 MB/s may cause GC pressure
|
|
195
|
+
- Frequent Gen 0 collections (> 10/sec) indicate high allocation
|
|
196
|
+
- Gen 2 collections > 1/min may indicate LOH issues or leaks
|
|
197
|
+
|
|
198
|
+
**Allocation hotspot trace**:
|
|
199
|
+
```bash
|
|
200
|
+
# Collect allocation events
|
|
201
|
+
dotnet-trace collect --process-id <PID> \
|
|
202
|
+
--providers "Microsoft-Windows-DotNETRuntime:0x80000:4"
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## GC Analysis Patterns
|
|
208
|
+
|
|
209
|
+
### Pattern: GC Pause Analysis
|
|
210
|
+
|
|
211
|
+
**When to use**: Application has latency spikes correlated with GC.
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
# Collect detailed GC events
|
|
215
|
+
dotnet-trace collect --process-id <PID> \
|
|
216
|
+
--profile gc-verbose \
|
|
217
|
+
--duration 00:02:00
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**Key metrics to extract**:
|
|
221
|
+
- GC pause duration per generation
|
|
222
|
+
- GC frequency per generation
|
|
223
|
+
- Promoted bytes per collection
|
|
224
|
+
- Fragmentation percentage
|
|
225
|
+
|
|
226
|
+
### Pattern: GC Mode Selection
|
|
227
|
+
|
|
228
|
+
**Server GC vs Workstation GC**:
|
|
229
|
+
|
|
230
|
+
| Characteristic | Server GC | Workstation GC |
|
|
231
|
+
|---------------|-----------|----------------|
|
|
232
|
+
| Threads | One per CPU core | Single thread |
|
|
233
|
+
| Heap | Segmented per core | Single heap |
|
|
234
|
+
| Latency | Higher pause times | Lower pause times |
|
|
235
|
+
| Throughput | Higher throughput | Lower throughput |
|
|
236
|
+
| Memory | Higher memory usage | Lower memory usage |
|
|
237
|
+
| Best for | Server workloads | Desktop apps |
|
|
238
|
+
|
|
239
|
+
```xml
|
|
240
|
+
<!-- Enable server GC in .csproj -->
|
|
241
|
+
<PropertyGroup>
|
|
242
|
+
<ServerGarbageCollection>true</ServerGarbageCollection>
|
|
243
|
+
</PropertyGroup>
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
```json
|
|
247
|
+
// Or in runtimeconfig.json
|
|
248
|
+
{
|
|
249
|
+
"runtimeOptions": {
|
|
250
|
+
"configProperties": {
|
|
251
|
+
"System.GC.Server": true
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Pattern: Concurrent vs Background GC Analysis
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
# Monitor GC behavior
|
|
261
|
+
dotnet-counters monitor --process-id <PID> \
|
|
262
|
+
--counters "System.Runtime[gc-heap-size,gen-0-gc-count,gen-1-gc-count,gen-2-gc-count,time-in-gc]"
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**time-in-gc interpretation**:
|
|
266
|
+
- < 5%: Healthy
|
|
267
|
+
- 5-10%: Monitor closely
|
|
268
|
+
- > 10%: GC tuning needed
|
|
269
|
+
|
|
270
|
+
### Pattern: Pinned Object Analysis
|
|
271
|
+
|
|
272
|
+
**When to use**: Suspected fragmentation from pinned objects.
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
# Analyze pinned objects in dump
|
|
276
|
+
dotnet-dump analyze mydump.dmp
|
|
277
|
+
> gcheapstat
|
|
278
|
+
> dumpheap -stat
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
**Common pinning issues**:
|
|
282
|
+
- Interop callbacks holding managed references
|
|
283
|
+
- Async I/O buffers
|
|
284
|
+
- Native code integration
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Contention Profiling Patterns
|
|
289
|
+
|
|
290
|
+
### Pattern: Lock Contention Analysis
|
|
291
|
+
|
|
292
|
+
**When to use**: Application throughput limited by synchronization.
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
# Collect contention events
|
|
296
|
+
dotnet-trace collect --process-id <PID> \
|
|
297
|
+
--providers "Microsoft-Windows-DotNETRuntime:0x4000:4"
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
**Analysis steps**:
|
|
301
|
+
1. Identify frequently contended locks
|
|
302
|
+
2. Analyze lock hold times
|
|
303
|
+
3. Look for lock ordering issues
|
|
304
|
+
4. Check for unnecessary locking
|
|
305
|
+
|
|
306
|
+
### Pattern: Thread Synchronization Overhead
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
# Monitor thread-related counters
|
|
310
|
+
dotnet-counters monitor --process-id <PID> \
|
|
311
|
+
--counters "System.Runtime[monitor-lock-contention-count,threadpool-thread-count]"
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
**High contention indicators**:
|
|
315
|
+
- `monitor-lock-contention-count` growing rapidly
|
|
316
|
+
- Thread count higher than expected
|
|
317
|
+
- CPU usage lower than expected under load
|
|
318
|
+
|
|
319
|
+
**Mitigations**:
|
|
320
|
+
```csharp
|
|
321
|
+
// Use lock-free collections
|
|
322
|
+
var dict = new ConcurrentDictionary<string, int>();
|
|
323
|
+
|
|
324
|
+
// Use reader-writer locks for read-heavy workloads
|
|
325
|
+
var rwLock = new ReaderWriterLockSlim();
|
|
326
|
+
|
|
327
|
+
// Use Interlocked for simple operations
|
|
328
|
+
Interlocked.Increment(ref counter);
|
|
329
|
+
|
|
330
|
+
// Use async semaphores
|
|
331
|
+
var semaphore = new SemaphoreSlim(maxConcurrency);
|
|
332
|
+
await semaphore.WaitAsync();
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
## Exception Profiling Patterns
|
|
338
|
+
|
|
339
|
+
### Pattern: Exception Rate Analysis
|
|
340
|
+
|
|
341
|
+
**When to use**: Performance impacted by exception handling.
|
|
342
|
+
|
|
343
|
+
```bash
|
|
344
|
+
# Monitor exception count
|
|
345
|
+
dotnet-counters monitor --process-id <PID> \
|
|
346
|
+
--counters "System.Runtime[exception-count]"
|
|
347
|
+
|
|
348
|
+
# Collect exception events with stack traces
|
|
349
|
+
dotnet-trace collect --process-id <PID> \
|
|
350
|
+
--providers "Microsoft-Windows-DotNETRuntime:0x8000:4"
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
**Thresholds**:
|
|
354
|
+
- < 10 exceptions/sec: Normal
|
|
355
|
+
- 10-100 exceptions/sec: Review exception usage
|
|
356
|
+
- > 100 exceptions/sec: Performance impact likely
|
|
357
|
+
|
|
358
|
+
**Common exception anti-patterns**:
|
|
359
|
+
```csharp
|
|
360
|
+
// Anti-pattern: Using exceptions for flow control
|
|
361
|
+
try
|
|
362
|
+
{
|
|
363
|
+
value = dict[key];
|
|
364
|
+
}
|
|
365
|
+
catch (KeyNotFoundException)
|
|
366
|
+
{
|
|
367
|
+
value = default;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Better: Use TryGetValue
|
|
371
|
+
if (!dict.TryGetValue(key, out value))
|
|
372
|
+
{
|
|
373
|
+
value = default;
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### Pattern: First-Chance Exception Analysis
|
|
378
|
+
|
|
379
|
+
```bash
|
|
380
|
+
# Collect first-chance exceptions
|
|
381
|
+
dotnet-trace collect --process-id <PID> \
|
|
382
|
+
--providers "Microsoft-Windows-DotNETRuntime:0x8000:5"
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Analyze the trace to find:
|
|
386
|
+
- Exception types thrown frequently
|
|
387
|
+
- Exception origins (your code vs framework)
|
|
388
|
+
- Exception handling patterns
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
## Startup Profiling Patterns
|
|
393
|
+
|
|
394
|
+
### Pattern: Cold Start Analysis
|
|
395
|
+
|
|
396
|
+
**When to use**: Application startup is slow.
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
# Trace from application launch
|
|
400
|
+
dotnet-trace collect \
|
|
401
|
+
--output startup-trace.nettrace \
|
|
402
|
+
-- dotnet run --project MyApp.csproj
|
|
403
|
+
|
|
404
|
+
# Or with specific configuration
|
|
405
|
+
dotnet-trace collect \
|
|
406
|
+
--output startup-trace.nettrace \
|
|
407
|
+
-- dotnet run -c Release --project MyApp.csproj
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
**Startup phases to analyze**:
|
|
411
|
+
1. CLR initialization
|
|
412
|
+
2. Assembly loading
|
|
413
|
+
3. JIT compilation
|
|
414
|
+
4. Type initialization (static constructors)
|
|
415
|
+
5. Dependency injection setup
|
|
416
|
+
6. Application initialization
|
|
417
|
+
|
|
418
|
+
### Pattern: Assembly Loading Analysis
|
|
419
|
+
|
|
420
|
+
```bash
|
|
421
|
+
# Collect loader events
|
|
422
|
+
dotnet-trace collect --process-id <PID> \
|
|
423
|
+
--providers "Microsoft-Windows-DotNETRuntime:0x8:4"
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
**Optimization strategies**:
|
|
427
|
+
- Use ReadyToRun (R2R) compilation
|
|
428
|
+
- Lazy-load optional assemblies
|
|
429
|
+
- Use trimming for single-file apps
|
|
430
|
+
- Profile and defer non-critical initialization
|
|
431
|
+
|
|
432
|
+
```xml
|
|
433
|
+
<!-- Enable ReadyToRun -->
|
|
434
|
+
<PropertyGroup>
|
|
435
|
+
<PublishReadyToRun>true</PublishReadyToRun>
|
|
436
|
+
</PropertyGroup>
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
### Pattern: JIT Compilation Analysis
|
|
440
|
+
|
|
441
|
+
```bash
|
|
442
|
+
# Collect JIT events
|
|
443
|
+
dotnet-trace collect --process-id <PID> \
|
|
444
|
+
--providers "Microsoft-Windows-DotNETRuntime:0x10:4"
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
**JIT optimization strategies**:
|
|
448
|
+
- Use tiered compilation (default in .NET Core 3.0+)
|
|
449
|
+
- Pre-JIT critical paths with warmup
|
|
450
|
+
- Use AOT/R2R for startup-sensitive scenarios
|
|
451
|
+
|
|
452
|
+
---
|
|
453
|
+
|
|
454
|
+
## Production Profiling Patterns
|
|
455
|
+
|
|
456
|
+
### Pattern: Low-Overhead Production Monitoring
|
|
457
|
+
|
|
458
|
+
**Approach**: Use dotnet-counters for continuous, low-impact monitoring.
|
|
459
|
+
|
|
460
|
+
```bash
|
|
461
|
+
# Lightweight monitoring script
|
|
462
|
+
#!/bin/bash
|
|
463
|
+
while true; do
|
|
464
|
+
dotnet-counters collect \
|
|
465
|
+
--process-id $APP_PID \
|
|
466
|
+
--counters "System.Runtime[cpu-usage,working-set,gc-heap-size,exception-count]" \
|
|
467
|
+
--output metrics-$(date +%Y%m%d-%H%M%S).csv \
|
|
468
|
+
--format csv \
|
|
469
|
+
--duration 60
|
|
470
|
+
done
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
### Pattern: Triggered Diagnostics Collection
|
|
474
|
+
|
|
475
|
+
**Approach**: Collect detailed diagnostics only when anomalies detected.
|
|
476
|
+
|
|
477
|
+
```bash
|
|
478
|
+
# Collect trace when CPU exceeds threshold
|
|
479
|
+
CPU_THRESHOLD=80
|
|
480
|
+
|
|
481
|
+
while true; do
|
|
482
|
+
CPU=$(dotnet-counters monitor --process-id $APP_PID \
|
|
483
|
+
--counters "System.Runtime[cpu-usage]" \
|
|
484
|
+
--duration 5 2>/dev/null | grep cpu-usage | awk '{print $2}')
|
|
485
|
+
|
|
486
|
+
if (( $(echo "$CPU > $CPU_THRESHOLD" | bc -l) )); then
|
|
487
|
+
dotnet-trace collect --process-id $APP_PID \
|
|
488
|
+
--profile cpu-sampling \
|
|
489
|
+
--duration 00:00:30 \
|
|
490
|
+
--output high-cpu-$(date +%Y%m%d-%H%M%S).nettrace
|
|
491
|
+
fi
|
|
492
|
+
|
|
493
|
+
sleep 60
|
|
494
|
+
done
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
### Pattern: Memory Dump on OOM
|
|
498
|
+
|
|
499
|
+
```bash
|
|
500
|
+
# Configure automatic dump on OOM
|
|
501
|
+
export DOTNET_DbgEnableMiniDump=1
|
|
502
|
+
export DOTNET_DbgMiniDumpType=4
|
|
503
|
+
export DOTNET_DbgMiniDumpName=/var/dumps/oom-%p-%t.dmp
|
|
504
|
+
|
|
505
|
+
# Run application
|
|
506
|
+
dotnet MyApp.dll
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
---
|
|
510
|
+
|
|
511
|
+
## Comparison and Benchmarking Patterns
|
|
512
|
+
|
|
513
|
+
### Pattern: Before/After Comparison
|
|
514
|
+
|
|
515
|
+
**Approach**: Collect identical metrics before and after changes.
|
|
516
|
+
|
|
517
|
+
```bash
|
|
518
|
+
# Baseline collection
|
|
519
|
+
dotnet-counters collect --process-id $BASELINE_PID \
|
|
520
|
+
--counters System.Runtime \
|
|
521
|
+
--output baseline-counters.csv \
|
|
522
|
+
--format csv \
|
|
523
|
+
--duration 300
|
|
524
|
+
|
|
525
|
+
# After optimization
|
|
526
|
+
dotnet-counters collect --process-id $OPTIMIZED_PID \
|
|
527
|
+
--counters System.Runtime \
|
|
528
|
+
--output optimized-counters.csv \
|
|
529
|
+
--format csv \
|
|
530
|
+
--duration 300
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
**Comparison checklist**:
|
|
534
|
+
- [ ] Same workload profile
|
|
535
|
+
- [ ] Same duration
|
|
536
|
+
- [ ] Same warmup period
|
|
537
|
+
- [ ] Same hardware/environment
|
|
538
|
+
- [ ] Multiple runs for statistical significance
|
|
539
|
+
|
|
540
|
+
### Pattern: Regression Detection
|
|
541
|
+
|
|
542
|
+
**Approach**: Establish performance baselines in CI.
|
|
543
|
+
|
|
544
|
+
```bash
|
|
545
|
+
# CI performance check script
|
|
546
|
+
#!/bin/bash
|
|
547
|
+
set -e
|
|
548
|
+
|
|
549
|
+
# Run app with load
|
|
550
|
+
./start-load-test.sh &
|
|
551
|
+
LOAD_PID=$!
|
|
552
|
+
|
|
553
|
+
# Collect metrics
|
|
554
|
+
dotnet-counters collect --process-id $APP_PID \
|
|
555
|
+
--counters System.Runtime \
|
|
556
|
+
--output ci-metrics.csv \
|
|
557
|
+
--format csv \
|
|
558
|
+
--duration 60
|
|
559
|
+
|
|
560
|
+
# Stop load test
|
|
561
|
+
kill $LOAD_PID
|
|
562
|
+
|
|
563
|
+
# Compare against baseline (example threshold check)
|
|
564
|
+
ALLOC_RATE=$(grep alloc-rate ci-metrics.csv | awk -F',' '{sum+=$2; count++} END {print sum/count}')
|
|
565
|
+
BASELINE_ALLOC_RATE=50000000 # 50 MB/s
|
|
566
|
+
|
|
567
|
+
if (( $(echo "$ALLOC_RATE > $BASELINE_ALLOC_RATE * 1.2" | bc -l) )); then
|
|
568
|
+
echo "REGRESSION: Allocation rate increased by >20%"
|
|
569
|
+
exit 1
|
|
570
|
+
fi
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
---
|
|
574
|
+
|
|
575
|
+
## Tool Selection Guide
|
|
576
|
+
|
|
577
|
+
| Symptom | Primary Tool | Secondary Tool |
|
|
578
|
+
|---------|-------------|----------------|
|
|
579
|
+
| High CPU | dotnet-trace (cpu-sampling) | dotnet-counters |
|
|
580
|
+
| Memory growth | dotnet-gcdump | dotnet-dump |
|
|
581
|
+
| GC pauses | dotnet-trace (gc-verbose) | dotnet-counters |
|
|
582
|
+
| Slow startup | dotnet-trace (from launch) | - |
|
|
583
|
+
| Lock contention | dotnet-trace (contention) | dotnet-counters |
|
|
584
|
+
| Exception storms | dotnet-counters | dotnet-trace |
|
|
585
|
+
| Crash analysis | dotnet-dump | - |
|
|
586
|
+
| Live health | dotnet-counters | - |
|