Skip to content

[Coding Agent] Add find-allocation-opportunities skill#8386

Draft
lucaspimentel wants to merge 4 commits intomasterfrom
lpimentel/allocations-claude-skill
Draft

[Coding Agent] Add find-allocation-opportunities skill#8386
lucaspimentel wants to merge 4 commits intomasterfrom
lpimentel/allocations-claude-skill

Conversation

@lucaspimentel
Copy link
Copy Markdown
Member

@lucaspimentel lucaspimentel commented Mar 27, 2026

Summary of changes

Add a Claude Code skill that scans code for heap allocation opportunities in hot paths, codifying 22+ proven allocation-avoidance patterns used by the team.

Reason for change

The dd-trace-dotnet tracer runs in-process with customer applications, so heap allocations in hot paths directly impact customer GC pressure. The team has accumulated significant tribal knowledge about allocation-avoidance patterns. This skill makes that knowledge consistently available to AI-assisted code reviews and allocation audits.

Implementation details

  • SKILL.md: Skill definition with triggering keywords, assessment criteria (severity levels, confidence thresholds), and structured output format for allocation findings
  • references/patterns.md: 22+ proven allocation-avoidance patterns with before/after examples (e.g., ArraySegment<T> over Array.Copy, struct enumerators, TryFormat over ToString(), tag list pre-sizing)
  • references/anti-patterns.md: Common allocation anti-patterns organized by category (string operations, collections, LINQ, boxing, closures, async, logging) with severity ratings and fixes

Test coverage

N/A — skill definition files only (no compiled code).

Other details

The skill covers both scanning existing code and reviewing PR diffs for missed optimization opportunities. It prioritizes findings by hot-path proximity and uses confidence-based filtering to minimize false positives.

🤖 Co-Authored-By: Claude Code <noreply@anthropic.com>
🤖 Co-Authored-By: Claude Code <noreply@anthropic.com>
🤖 Co-Authored-By: Claude Code <noreply@anthropic.com>
@lucaspimentel lucaspimentel added AI Generated Largely based on code generated by an AI or LLM. This label is the same across all dd-trace-* repos for-ai-agents 🤖 files used by AI agents, not humans and removed area:docs labels Mar 27, 2026
@lucaspimentel lucaspimentel changed the title [Claude Code] Add find-allocation-opportunities skill [Coding Agent] Add find-allocation-opportunities skill Mar 27, 2026
Backlog of 7 analyzers (DDALLOC001-007) to detect heap-allocation
anti-patterns at compile time, covering: ToString() in log calls,
missing JsonArrayPool, new StringBuilder, Enum.HasFlag/ToString boxing,
capturing lambdas in Task.Run, and throw-in-AggressiveInlining methods.

🤖 Co-Authored-By: Claude Code <noreply@anthropic.com>
@dd-trace-dotnet-ci-bot
Copy link
Copy Markdown

Execution-Time Benchmarks Report ⏱️

Execution-time results for samples comparing This PR (8386) and master.

✅ No regressions detected - check the details below

Full Metrics Comparison

FakeDbCommand

Metric Master (Mean ± 95% CI) Current (Mean ± 95% CI) Change Status
.NET Framework 4.8 - Baseline
duration72.41 ± (72.36 - 72.68) ms72.18 ± (72.24 - 72.60) ms-0.3%
.NET Framework 4.8 - Bailout
duration76.00 ± (76.01 - 76.39) ms76.27 ± (76.16 - 76.55) ms+0.4%✅⬆️
.NET Framework 4.8 - CallTarget+Inlining+NGEN
duration1072.13 ± (1072.53 - 1077.96) ms1077.45 ± (1077.59 - 1084.38) ms+0.5%✅⬆️
.NET Core 3.1 - Baseline
process.internal_duration_ms22.36 ± (22.32 - 22.40) ms22.24 ± (22.21 - 22.27) ms-0.5%
process.time_to_main_ms83.60 ± (83.40 - 83.80) ms83.08 ± (82.88 - 83.27) ms-0.6%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.91 ± (10.91 - 10.92) MB10.93 ± (10.92 - 10.93) MB+0.2%✅⬆️
runtime.dotnet.threads.count12 ± (12 - 12)12 ± (12 - 12)+0.0%
.NET Core 3.1 - Bailout
process.internal_duration_ms22.32 ± (22.28 - 22.36) ms22.20 ± (22.17 - 22.24) ms-0.5%
process.time_to_main_ms84.43 ± (84.23 - 84.63) ms84.44 ± (84.25 - 84.63) ms+0.0%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.94 ± (10.94 - 10.95) MB10.96 ± (10.96 - 10.97) MB+0.2%✅⬆️
runtime.dotnet.threads.count13 ± (13 - 13)13 ± (13 - 13)+0.0%
.NET Core 3.1 - CallTarget+Inlining+NGEN
process.internal_duration_ms224.27 ± (223.08 - 225.46) ms221.89 ± (220.72 - 223.05) ms-1.1%
process.time_to_main_ms537.55 ± (536.40 - 538.70) ms534.34 ± (533.01 - 535.68) ms-0.6%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed48.22 ± (48.19 - 48.26) MB48.27 ± (48.24 - 48.31) MB+0.1%✅⬆️
runtime.dotnet.threads.count28 ± (28 - 28)28 ± (28 - 28)+0.3%✅⬆️
.NET 6 - Baseline
process.internal_duration_ms21.02 ± (20.98 - 21.05) ms21.00 ± (20.96 - 21.03) ms-0.1%
process.time_to_main_ms71.89 ± (71.73 - 72.05) ms72.20 ± (72.05 - 72.35) ms+0.4%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.62 ± (10.62 - 10.62) MB10.65 ± (10.65 - 10.65) MB+0.3%✅⬆️
runtime.dotnet.threads.count10 ± (10 - 10)10 ± (10 - 10)+0.0%
.NET 6 - Bailout
process.internal_duration_ms20.82 ± (20.79 - 20.85) ms20.95 ± (20.92 - 20.99) ms+0.6%✅⬆️
process.time_to_main_ms72.87 ± (72.71 - 73.04) ms73.17 ± (73.02 - 73.31) ms+0.4%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.72 ± (10.72 - 10.72) MB10.76 ± (10.76 - 10.76) MB+0.4%✅⬆️
runtime.dotnet.threads.count11 ± (11 - 11)11 ± (11 - 11)+0.0%
.NET 6 - CallTarget+Inlining+NGEN
process.internal_duration_ms387.08 ± (384.68 - 389.47) ms386.38 ± (383.23 - 389.53) ms-0.2%
process.time_to_main_ms528.76 ± (527.85 - 529.67) ms529.76 ± (528.55 - 530.98) ms+0.2%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed50.32 ± (50.29 - 50.34) MB50.28 ± (50.25 - 50.32) MB-0.1%
runtime.dotnet.threads.count28 ± (28 - 28)28 ± (28 - 28)-0.0%
.NET 8 - Baseline
process.internal_duration_ms19.10 ± (19.07 - 19.13) ms19.36 ± (19.33 - 19.40) ms+1.4%✅⬆️
process.time_to_main_ms71.49 ± (71.32 - 71.65) ms72.27 ± (72.10 - 72.45) ms+1.1%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed7.69 ± (7.68 - 7.70) MB7.72 ± (7.71 - 7.73) MB+0.4%✅⬆️
runtime.dotnet.threads.count10 ± (10 - 10)10 ± (10 - 10)+0.0%
.NET 8 - Bailout
process.internal_duration_ms19.25 ± (19.20 - 19.29) ms19.39 ± (19.36 - 19.43) ms+0.8%✅⬆️
process.time_to_main_ms72.93 ± (72.77 - 73.08) ms73.13 ± (73.00 - 73.26) ms+0.3%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed7.77 ± (7.75 - 7.78) MB7.74 ± (7.74 - 7.75) MB-0.3%
runtime.dotnet.threads.count11 ± (11 - 11)11 ± (11 - 11)+0.0%
.NET 8 - CallTarget+Inlining+NGEN
process.internal_duration_ms307.01 ± (304.48 - 309.53) ms309.15 ± (306.90 - 311.41) ms+0.7%✅⬆️
process.time_to_main_ms491.34 ± (490.49 - 492.19) ms490.17 ± (489.41 - 490.93) ms-0.2%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed37.21 ± (37.19 - 37.23) MB37.25 ± (37.23 - 37.27) MB+0.1%✅⬆️
runtime.dotnet.threads.count27 ± (27 - 27)27 ± (27 - 27)+0.1%✅⬆️

HttpMessageHandler

Metric Master (Mean ± 95% CI) Current (Mean ± 95% CI) Change Status
.NET Framework 4.8 - Baseline
duration216.19 ± (215.90 - 216.92) ms215.16 ± (214.76 - 215.95) ms-0.5%
.NET Framework 4.8 - Bailout
duration221.29 ± (221.03 - 222.12) ms219.32 ± (218.67 - 219.66) ms-0.9%
.NET Framework 4.8 - CallTarget+Inlining+NGEN
duration1264.28 ± (1264.37 - 1272.79) ms1257.32 ± (1254.43 - 1262.01) ms-0.6%
.NET Core 3.1 - Baseline
process.internal_duration_ms212.56 ± (212.02 - 213.10) ms208.19 ± (207.66 - 208.71) ms-2.1%
process.time_to_main_ms92.50 ± (92.13 - 92.88) ms90.58 ± (90.26 - 90.91) ms-2.1%
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed15.87 ± (15.84 - 15.89) MB15.94 ± (15.92 - 15.96) MB+0.5%✅⬆️
runtime.dotnet.threads.count20 ± (20 - 20)20 ± (20 - 20)-0.2%
.NET Core 3.1 - Bailout
process.internal_duration_ms213.46 ± (212.91 - 214.01) ms209.66 ± (209.13 - 210.19) ms-1.8%
process.time_to_main_ms94.27 ± (93.93 - 94.61) ms92.23 ± (91.95 - 92.51) ms-2.2%
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed15.85 ± (15.82 - 15.87) MB16.06 ± (16.04 - 16.08) MB+1.4%✅⬆️
runtime.dotnet.threads.count21 ± (21 - 21)21 ± (21 - 21)-0.7%
.NET Core 3.1 - CallTarget+Inlining+NGEN
process.internal_duration_ms424.35 ± (422.90 - 425.81) ms422.84 ± (421.51 - 424.17) ms-0.4%
process.time_to_main_ms574.45 ± (572.90 - 576.01) ms572.95 ± (571.57 - 574.32) ms-0.3%
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed59.16 ± (59.12 - 59.20) MB59.26 ± (59.21 - 59.31) MB+0.2%✅⬆️
runtime.dotnet.threads.count30 ± (30 - 30)30 ± (30 - 30)-0.2%
.NET 6 - Baseline
process.internal_duration_ms218.62 ± (218.04 - 219.19) ms215.70 ± (215.14 - 216.26) ms-1.3%
process.time_to_main_ms81.01 ± (80.72 - 81.31) ms79.37 ± (79.09 - 79.64) ms-2.0%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed16.17 ± (16.15 - 16.19) MB16.22 ± (16.19 - 16.24) MB+0.3%✅⬆️
runtime.dotnet.threads.count20 ± (19 - 20)20 ± (19 - 20)+0.0%✅⬆️
.NET 6 - Bailout
process.internal_duration_ms216.76 ± (216.24 - 217.29) ms213.74 ± (213.22 - 214.26) ms-1.4%
process.time_to_main_ms81.17 ± (80.88 - 81.45) ms80.72 ± (80.45 - 80.99) ms-0.6%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed16.18 ± (16.15 - 16.20) MB16.24 ± (16.21 - 16.26) MB+0.4%✅⬆️
runtime.dotnet.threads.count20 ± (20 - 21)20 ± (20 - 21)+0.0%✅⬆️
.NET 6 - CallTarget+Inlining+NGEN
process.internal_duration_ms596.20 ± (593.96 - 598.43) ms596.52 ± (594.02 - 599.03) ms+0.1%✅⬆️
process.time_to_main_ms579.57 ± (578.24 - 580.89) ms574.51 ± (573.20 - 575.81) ms-0.9%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed61.61 ± (61.51 - 61.71) MB61.66 ± (61.56 - 61.76) MB+0.1%✅⬆️
runtime.dotnet.threads.count31 ± (31 - 31)31 ± (31 - 31)+0.0%✅⬆️
.NET 8 - Baseline
process.internal_duration_ms216.80 ± (216.24 - 217.36) ms212.64 ± (212.09 - 213.19) ms-1.9%
process.time_to_main_ms80.34 ± (80.07 - 80.62) ms78.54 ± (78.32 - 78.77) ms-2.2%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed11.53 ± (11.51 - 11.56) MB11.59 ± (11.57 - 11.61) MB+0.5%✅⬆️
runtime.dotnet.threads.count19 ± (19 - 19)19 ± (19 - 19)-0.5%
.NET 8 - Bailout
process.internal_duration_ms217.02 ± (216.46 - 217.58) ms212.67 ± (212.18 - 213.16) ms-2.0%
process.time_to_main_ms81.25 ± (81.00 - 81.49) ms80.34 ± (80.10 - 80.59) ms-1.1%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed11.55 ± (11.53 - 11.57) MB11.66 ± (11.64 - 11.68) MB+1.0%✅⬆️
runtime.dotnet.threads.count20 ± (20 - 20)20 ± (20 - 20)-0.1%
.NET 8 - CallTarget+Inlining+NGEN
process.internal_duration_ms596.06 ± (588.53 - 603.60) ms584.30 ± (576.97 - 591.63) ms-2.0%
process.time_to_main_ms539.44 ± (537.87 - 541.01) ms534.35 ± (533.23 - 535.47) ms-0.9%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed51.76 ± (51.67 - 51.85) MB51.62 ± (51.52 - 51.72) MB-0.3%
runtime.dotnet.threads.count30 ± (30 - 30)30 ± (30 - 30)-0.1%
Comparison explanation

Execution-time benchmarks measure the whole time it takes to execute a program, and are intended to measure the one-off costs. Cases where the execution time results for the PR are worse than latest master results are highlighted in **red**. The following thresholds were used for comparing the execution times:

  • Welch test with statistical test for significance of 5%
  • Only results indicating a difference greater than 5% and 5 ms are considered.

Note that these results are based on a single point-in-time result for each branch. For full results, see the dashboard.

Graphs show the p99 interval based on the mean and StdDev of the test run, as well as the mean value of the run (shown as a diamond below the graph).

Duration charts
FakeDbCommand (.NET Framework 4.8)
gantt
    title Execution time (ms) FakeDbCommand (.NET Framework 4.8)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (8386) - mean (72ms)  : 70, 75
    master - mean (73ms)  : 70, 75

    section Bailout
    This PR (8386) - mean (76ms)  : 74, 78
    master - mean (76ms)  : 74, 78

    section CallTarget+Inlining+NGEN
    This PR (8386) - mean (1,081ms)  : 1030, 1132
    master - mean (1,075ms)  : 1036, 1115

Loading
FakeDbCommand (.NET Core 3.1)
gantt
    title Execution time (ms) FakeDbCommand (.NET Core 3.1)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (8386) - mean (112ms)  : 109, 115
    master - mean (113ms)  : 109, 116

    section Bailout
    This PR (8386) - mean (113ms)  : 110, 116
    master - mean (113ms)  : 111, 116

    section CallTarget+Inlining+NGEN
    This PR (8386) - mean (797ms)  : 779, 814
    master - mean (798ms)  : 781, 816

Loading
FakeDbCommand (.NET 6)
gantt
    title Execution time (ms) FakeDbCommand (.NET 6)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (8386) - mean (99ms)  : 96, 102
    master - mean (99ms)  : 96, 102

    section Bailout
    This PR (8386) - mean (100ms)  : 98, 102
    master - mean (100ms)  : 97, 103

    section CallTarget+Inlining+NGEN
    This PR (8386) - mean (947ms)  : 907, 986
    master - mean (946ms)  : 911, 980

Loading
FakeDbCommand (.NET 8)
gantt
    title Execution time (ms) FakeDbCommand (.NET 8)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (8386) - mean (99ms)  : 96, 103
    master - mean (98ms)  : 95, 101

    section Bailout
    This PR (8386) - mean (100ms)  : 98, 102
    master - mean (100ms)  : 97, 102

    section CallTarget+Inlining+NGEN
    This PR (8386) - mean (829ms)  : 790, 868
    master - mean (833ms)  : 786, 880

Loading
HttpMessageHandler (.NET Framework 4.8)
gantt
    title Execution time (ms) HttpMessageHandler (.NET Framework 4.8)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (8386) - mean (215ms)  : 208, 223
    master - mean (216ms)  : 211, 222

    section Bailout
    This PR (8386) - mean (219ms)  : 214, 224
    master - mean (222ms)  : 215, 228

    section CallTarget+Inlining+NGEN
    This PR (8386) - mean (1,258ms)  : 1202, 1315
    master - mean (1,269ms)  : 1205, 1332

Loading
HttpMessageHandler (.NET Core 3.1)
gantt
    title Execution time (ms) HttpMessageHandler (.NET Core 3.1)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (8386) - mean (309ms)  : 301, 316
    master - mean (315ms)  : 308, 322

    section Bailout
    This PR (8386) - mean (311ms)  : 301, 322
    master - mean (317ms)  : 310, 325

    section CallTarget+Inlining+NGEN
    This PR (8386) - mean (1,033ms)  : 1003, 1064
    master - mean (1,039ms)  : 1004, 1073

Loading
HttpMessageHandler (.NET 6)
gantt
    title Execution time (ms) HttpMessageHandler (.NET 6)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (8386) - mean (305ms)  : 296, 313
    master - mean (309ms)  : 301, 316

    section Bailout
    This PR (8386) - mean (304ms)  : 294, 314
    master - mean (307ms)  : 299, 315

    section CallTarget+Inlining+NGEN
    This PR (8386) - mean (1,202ms)  : 1162, 1242
    master - mean (1,208ms)  : 1170, 1246

Loading
HttpMessageHandler (.NET 8)
gantt
    title Execution time (ms) HttpMessageHandler (.NET 8)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (8386) - mean (302ms)  : 294, 310
    master - mean (308ms)  : 301, 315

    section Bailout
    This PR (8386) - mean (304ms)  : 297, 311
    master - mean (309ms)  : 298, 320

    section CallTarget+Inlining+NGEN
    This PR (8386) - mean (1,146ms)  : 1023, 1269
    master - mean (1,160ms)  : 1036, 1285

Loading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI Generated Largely based on code generated by an AI or LLM. This label is the same across all dd-trace-* repos area:docs for-ai-agents 🤖 files used by AI agents, not humans

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant