Skip to content

[Profiler] Generate heap snapshot#7681

Merged
chrisnas merged 27 commits intomasterfrom
chrisnas/add_class_histogram
Nov 26, 2025
Merged

[Profiler] Generate heap snapshot#7681
chrisnas merged 27 commits intomasterfrom
chrisnas/add_class_histogram

Conversation

@chrisnas
Copy link
Contributor

Summary of changes

Allow the generation of heap snapshots that are sent to the backend

Reason for change

For memory leak workflow, we would like to compare the surviving objects count to identify the leaky ones. These heap snapshots will be transformed into class histograms to look like what is generated by Java.

Implementation details

The .NET runtime allows the creation of "gcdump" thanks to dotnet-gcdump tool. Behind the scene, an induced GC is triggered when an event pipe session is created with the right keyword/verbosity. Undocumented events are then emitted by the runtime at the end of the GC - read https://chnasarre.medium.com/net-gcdump-internals-fcce5d327be7?source=friends_link&sk=3225ff119458adafc0e6935951fcc323 for more details.

Test coverage

Test added as needed

Other details

@chrisnas chrisnas requested a review from a team as a code owner October 21, 2025 08:22
@github-actions github-actions bot added the area:profiler Issues related to the continous-profiler label Oct 21, 2025
Copy link
Member

@andrewlock andrewlock left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just configuration, right? There's no implementation of taking the snapshot here?

@dd-trace-dotnet-ci-bot
Copy link

dd-trace-dotnet-ci-bot bot commented Oct 21, 2025

Execution-Time Benchmarks Report ⏱️

Execution-time results for samples comparing This PR (7681) 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
duration74.99 ± (74.96 - 75.69) ms74.63 ± (74.70 - 75.30) ms-0.5%
.NET Framework 4.8 - Bailout
duration79.50 ± (79.08 - 79.63) ms78.60 ± (78.55 - 79.06) ms-1.1%
.NET Framework 4.8 - CallTarget+Inlining+NGEN
duration1054.21 ± (1054.88 - 1064.33) ms1053.09 ± (1059.17 - 1071.29) ms-0.1%
.NET Core 3.1 - Baseline
process.internal_duration_ms22.98 ± (22.90 - 23.06) ms22.65 ± (22.59 - 22.72) ms-1.4%
process.time_to_main_ms86.72 ± (86.39 - 87.04) ms86.03 ± (85.66 - 86.40) ms-0.8%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.92 ± (10.92 - 10.93) MB10.92 ± (10.92 - 10.93) MB-0.0%
runtime.dotnet.threads.count12 ± (12 - 12)12 ± (12 - 12)+0.0%
.NET Core 3.1 - Bailout
process.internal_duration_ms22.88 ± (22.82 - 22.94) ms22.58 ± (22.51 - 22.65) ms-1.3%
process.time_to_main_ms89.60 ± (89.25 - 89.94) ms86.88 ± (86.50 - 87.25) ms-3.0%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.96 ± (10.96 - 10.97) MB10.97 ± (10.96 - 10.97) MB+0.0%✅⬆️
runtime.dotnet.threads.count13 ± (13 - 13)13 ± (13 - 13)+0.0%
.NET Core 3.1 - CallTarget+Inlining+NGEN
process.internal_duration_ms219.28 ± (218.00 - 220.56) ms221.29 ± (219.78 - 222.80) ms+0.9%✅⬆️
process.time_to_main_ms497.57 ± (496.51 - 498.63) ms498.09 ± (497.07 - 499.10) ms+0.1%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed47.73 ± (47.70 - 47.75) MB47.80 ± (47.77 - 47.82) MB+0.1%✅⬆️
runtime.dotnet.threads.count28 ± (28 - 28)28 ± (28 - 28)-0.0%
.NET 6 - Baseline
process.internal_duration_ms21.93 ± (21.85 - 22.00) ms21.86 ± (21.79 - 21.93) ms-0.3%
process.time_to_main_ms77.47 ± (77.12 - 77.82) ms76.27 ± (75.94 - 76.60) ms-1.5%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.60 ± (10.59 - 10.60) MB10.65 ± (10.64 - 10.65) MB+0.5%✅⬆️
runtime.dotnet.threads.count10 ± (10 - 10)10 ± (10 - 10)+0.0%
.NET 6 - Bailout
process.internal_duration_ms21.67 ± (21.61 - 21.73) ms21.83 ± (21.77 - 21.89) ms+0.7%✅⬆️
process.time_to_main_ms76.84 ± (76.51 - 77.18) ms77.54 ± (77.18 - 77.90) ms+0.9%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.64 ± (10.64 - 10.65) MB10.68 ± (10.67 - 10.68) MB+0.3%✅⬆️
runtime.dotnet.threads.count11 ± (11 - 11)11 ± (11 - 11)+0.0%
.NET 6 - CallTarget+Inlining+NGEN
process.internal_duration_ms210.56 ± (209.19 - 211.93) ms209.59 ± (208.28 - 210.89) ms-0.5%
process.time_to_main_ms465.15 ± (464.20 - 466.09) ms465.06 ± (464.04 - 466.09) ms-0.0%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed48.04 ± (48.02 - 48.07) MB48.17 ± (48.14 - 48.20) MB+0.3%✅⬆️
runtime.dotnet.threads.count28 ± (28 - 28)28 ± (28 - 28)-0.0%
.NET 8 - Baseline
process.internal_duration_ms20.00 ± (19.92 - 20.07) ms19.94 ± (19.87 - 20.01) ms-0.3%
process.time_to_main_ms75.42 ± (75.06 - 75.78) ms75.23 ± (74.90 - 75.56) ms-0.3%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed7.65 ± (7.65 - 7.66) MB7.67 ± (7.67 - 7.68) MB+0.3%✅⬆️
runtime.dotnet.threads.count10 ± (10 - 10)10 ± (10 - 10)+0.0%
.NET 8 - Bailout
process.internal_duration_ms19.90 ± (19.84 - 19.95) ms19.98 ± (19.91 - 20.05) ms+0.4%✅⬆️
process.time_to_main_ms76.06 ± (75.78 - 76.33) ms77.02 ± (76.71 - 77.34) ms+1.3%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed7.70 ± (7.70 - 7.71) MB7.70 ± (7.70 - 7.71) MB+0.0%✅⬆️
runtime.dotnet.threads.count11 ± (11 - 11)11 ± (11 - 11)+0.0%
.NET 8 - CallTarget+Inlining+NGEN
process.internal_duration_ms191.06 ± (190.13 - 191.98) ms192.86 ± (191.88 - 193.85) ms+0.9%✅⬆️
process.time_to_main_ms453.35 ± (452.57 - 454.14) ms456.01 ± (455.04 - 456.98) ms+0.6%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed36.36 ± (36.31 - 36.40) MB36.39 ± (36.35 - 36.42) 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
duration191.33 ± (191.17 - 191.92) ms191.49 ± (191.49 - 192.30) ms+0.1%✅⬆️
.NET Framework 4.8 - Bailout
duration195.81 ± (195.54 - 196.39) ms195.36 ± (195.17 - 195.57) ms-0.2%
.NET Framework 4.8 - CallTarget+Inlining+NGEN
duration1102.50 ± (1107.10 - 1116.52) ms1103.46 ± (1104.30 - 1113.34) ms+0.1%✅⬆️
.NET Core 3.1 - Baseline
process.internal_duration_ms186.75 ± (186.46 - 187.04) ms185.99 ± (185.73 - 186.24) ms-0.4%
process.time_to_main_ms80.21 ± (80.01 - 80.41) ms79.98 ± (79.79 - 80.16) ms-0.3%
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed16.11 ± (16.08 - 16.13) MB16.16 ± (16.13 - 16.19) MB+0.3%✅⬆️
runtime.dotnet.threads.count20 ± (19 - 20)20 ± (20 - 20)+0.5%✅⬆️
.NET Core 3.1 - Bailout
process.internal_duration_ms186.61 ± (186.31 - 186.90) ms186.64 ± (186.27 - 187.01) ms+0.0%✅⬆️
process.time_to_main_ms81.47 ± (81.34 - 81.60) ms81.47 ± (81.31 - 81.64) ms+0.0%✅⬆️
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed16.17 ± (16.14 - 16.20) MB16.19 ± (16.16 - 16.22) MB+0.1%✅⬆️
runtime.dotnet.threads.count20 ± (20 - 21)21 ± (21 - 21)+1.1%✅⬆️
.NET Core 3.1 - CallTarget+Inlining+NGEN
process.internal_duration_ms399.27 ± (396.73 - 401.82) ms407.07 ± (403.78 - 410.36) ms+2.0%✅⬆️
process.time_to_main_ms468.60 ± (467.86 - 469.34) ms469.47 ± (468.67 - 470.27) ms+0.2%✅⬆️
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed58.59 ± (58.47 - 58.71) MB58.45 ± (58.32 - 58.59) MB-0.2%
runtime.dotnet.threads.count30 ± (29 - 30)29 ± (29 - 30)-0.1%
.NET 6 - Baseline
process.internal_duration_ms191.50 ± (191.19 - 191.80) ms191.12 ± (190.76 - 191.47) ms-0.2%
process.time_to_main_ms69.85 ± (69.68 - 70.02) ms69.59 ± (69.41 - 69.77) ms-0.4%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed15.89 ± (15.72 - 16.06) MB16.02 ± (15.87 - 16.18) MB+0.9%✅⬆️
runtime.dotnet.threads.count18 ± (18 - 18)18 ± (18 - 18)+1.0%✅⬆️
.NET 6 - Bailout
process.internal_duration_ms190.10 ± (189.89 - 190.32) ms190.09 ± (189.76 - 190.42) ms-0.0%
process.time_to_main_ms70.42 ± (70.35 - 70.49) ms70.29 ± (70.19 - 70.39) ms-0.2%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed16.24 ± (16.10 - 16.38) MB16.02 ± (15.86 - 16.18) MB-1.4%
runtime.dotnet.threads.count19 ± (19 - 19)19 ± (19 - 19)-0.9%
.NET 6 - CallTarget+Inlining+NGEN
process.internal_duration_ms415.11 ± (411.93 - 418.28) ms410.70 ± (407.70 - 413.71) ms-1.1%
process.time_to_main_ms439.76 ± (439.25 - 440.27) ms439.34 ± (438.75 - 439.93) ms-0.1%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed58.68 ± (58.53 - 58.83) MB58.38 ± (58.23 - 58.54) MB-0.5%
runtime.dotnet.threads.count30 ± (30 - 30)30 ± (29 - 30)-0.1%
.NET 8 - Baseline
process.internal_duration_ms189.85 ± (189.48 - 190.22) ms188.74 ± (188.49 - 189.00) ms-0.6%
process.time_to_main_ms69.41 ± (69.22 - 69.60) ms68.90 ± (68.71 - 69.08) ms-0.7%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed11.79 ± (11.77 - 11.81) MB11.74 ± (11.71 - 11.77) MB-0.4%
runtime.dotnet.threads.count18 ± (18 - 18)18 ± (18 - 18)-0.1%
.NET 8 - Bailout
process.internal_duration_ms188.25 ± (188.02 - 188.49) ms188.11 ± (187.88 - 188.33) ms-0.1%
process.time_to_main_ms70.20 ± (70.09 - 70.31) ms69.80 ± (69.73 - 69.88) ms-0.6%
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed11.85 ± (11.78 - 11.91) MB11.69 ± (11.59 - 11.78) MB-1.4%
runtime.dotnet.threads.count19 ± (18 - 19)19 ± (18 - 19)-0.9%
.NET 8 - CallTarget+Inlining+NGEN
process.internal_duration_ms363.66 ± (362.36 - 364.96) ms361.13 ± (359.63 - 362.64) ms-0.7%
process.time_to_main_ms427.55 ± (427.04 - 428.07) ms427.74 ± (427.14 - 428.34) ms+0.0%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed47.87 ± (47.83 - 47.90) MB47.85 ± (47.81 - 47.88) MB-0.0%
runtime.dotnet.threads.count29 ± (29 - 29)29 ± (29 - 29)-0.0%
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 (7681) - mean (75ms)  : 71, 79
    master - mean (75ms)  : 70, 81

    section Bailout
    This PR (7681) - mean (79ms)  : 75, 82
    master - mean (79ms)  : 75, 83

    section CallTarget+Inlining+NGEN
    This PR (7681) - mean (1,065ms)  : 973, 1158
    master - mean (1,060ms)  : 992, 1127

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 (7681) - mean (116ms)  : 109, 124
    master - mean (117ms)  : 111, 123

    section Bailout
    This PR (7681) - mean (117ms)  : 109, 125
    master - mean (120ms)  : 114, 125

    section CallTarget+Inlining+NGEN
    This PR (7681) - mean (762ms)  : 720, 803
    master - mean (753ms)  : 720, 786

Loading
FakeDbCommand (.NET 6)
gantt
    title Execution time (ms) FakeDbCommand (.NET 6)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (7681) - mean (105ms)  : 99, 112
    master - mean (106ms)  : 100, 113

    section Bailout
    This PR (7681) - mean (106ms)  : 99, 114
    master - mean (106ms)  : 100, 111

    section CallTarget+Inlining+NGEN
    This PR (7681) - mean (706ms)  : 670, 742
    master - mean (704ms)  : 670, 738

Loading
FakeDbCommand (.NET 8)
gantt
    title Execution time (ms) FakeDbCommand (.NET 8)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (7681) - mean (104ms)  : 97, 110
    master - mean (104ms)  : 97, 111

    section Bailout
    This PR (7681) - mean (106ms)  : 100, 112
    master - mean (105ms)  : 99, 110

    section CallTarget+Inlining+NGEN
    This PR (7681) - mean (689ms)  : 660, 719
    master - mean (681ms)  : 649, 714

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 (7681) - mean (192ms)  : 188, 196
    master - mean (192ms)  : 188, 195

    section Bailout
    This PR (7681) - mean (195ms)  : 194, 197
    master - mean (196ms)  : 192, 200

    section CallTarget+Inlining+NGEN
    This PR (7681) - mean (1,109ms)  : 1042, 1175
    master - mean (1,112ms)  : 1040, 1184

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 (7681) - mean (274ms)  : 270, 278
    master - mean (275ms)  : 270, 280

    section Bailout
    This PR (7681) - mean (276ms)  : 270, 282
    master - mean (276ms)  : 272, 280

    section CallTarget+Inlining+NGEN
    This PR (7681) - mean (905ms)  : 841, 970
    master - mean (901ms)  : 854, 947

Loading
HttpMessageHandler (.NET 6)
gantt
    title Execution time (ms) HttpMessageHandler (.NET 6)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (7681) - mean (269ms)  : 265, 274
    master - mean (270ms)  : 265, 274

    section Bailout
    This PR (7681) - mean (268ms)  : 264, 273
    master - mean (268ms)  : 266, 270

    section CallTarget+Inlining+NGEN
    This PR (7681) - mean (883ms)  : 823, 943
    master - mean (888ms)  : 830, 946

Loading
HttpMessageHandler (.NET 8)
gantt
    title Execution time (ms) HttpMessageHandler (.NET 8)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (7681) - mean (267ms)  : 263, 271
    master - mean (269ms)  : 264, 274

    section Bailout
    This PR (7681) - mean (267ms)  : 264, 270
    master - mean (268ms)  : 265, 271

    section CallTarget+Inlining+NGEN
    This PR (7681) - mean (820ms)  : 800, 840
    master - mean (821ms)  : 798, 844

Loading

@pr-commenter
Copy link

pr-commenter bot commented Oct 24, 2025

Benchmarks

Benchmarks Report for benchmark platform 🐌

Benchmarks for #7681 compared to master:

  • 1 benchmarks are faster, with geometric mean 2.098
  • 1 benchmarks are slower, with geometric mean 1.173
  • 5 benchmarks have fewer allocations
  • 6 benchmarks have more allocations

The following thresholds were used for comparing the benchmark speeds:

  • Mann–Whitney U test with statistical test for significance of 5%
  • Only results indicating a difference greater than 10% and 0.3 ns are considered.

Allocation changes below 0.5% are ignored.

Benchmark details

Benchmarks.Trace.ActivityBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master StartStopWithChild net6.0 10.6μs 57ns 302ns 0 0 0 5.51 KB
master StartStopWithChild netcoreapp3.1 13.7μs 71.7ns 336ns 0 0 0 5.7 KB
master StartStopWithChild net472 22.4μs 126ns 829ns 0.994 0.331 0.11 6.06 KB
#7681 StartStopWithChild net6.0 10.6μs 59.1ns 369ns 0 0 0 5.52 KB
#7681 StartStopWithChild netcoreapp3.1 13.9μs 29.5ns 114ns 0 0 0 5.7 KB
#7681 StartStopWithChild net472 21.6μs 115ns 608ns 1.03 0.344 0.115 6.07 KB
Benchmarks.Trace.AgentWriterBenchmark - Same speed ✔️ Fewer allocations 🎉

Fewer allocations 🎉 in #7681

Benchmark Base Allocated Diff Allocated Change Change %
Benchmarks.Trace.AgentWriterBenchmark.WriteAndFlushEnrichedTraces‑net472 3.35 KB 3.31 KB -46 B -1.37%

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master WriteAndFlushEnrichedTraces net6.0 944μs 322ns 1.25μs 0 0 0 2.7 KB
master WriteAndFlushEnrichedTraces netcoreapp3.1 1.04ms 270ns 1.04μs 0 0 0 2.7 KB
master WriteAndFlushEnrichedTraces net472 1.21ms 61ns 236ns 0 0 0 3.35 KB
#7681 WriteAndFlushEnrichedTraces net6.0 935μs 42.7ns 154ns 0 0 0 2.7 KB
#7681 WriteAndFlushEnrichedTraces netcoreapp3.1 1.05ms 149ns 579ns 0 0 0 2.7 KB
#7681 WriteAndFlushEnrichedTraces net472 1.19ms 50.4ns 189ns 0 0 0 3.31 KB
Benchmarks.Trace.Asm.AppSecBodyBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master AllCycleSimpleBody net6.0 1.05μs 5.98ns 43.1ns 0 0 0 1.22 KB
master AllCycleSimpleBody netcoreapp3.1 1.39μs 7.22ns 36.8ns 0 0 0 1.2 KB
master AllCycleSimpleBody net472 1.02μs 0.294ns 1.1ns 0.192 0 0 1.23 KB
master AllCycleMoreComplexBody net6.0 7.06μs 37.2ns 200ns 0 0 0 4.72 KB
master AllCycleMoreComplexBody netcoreapp3.1 9.07μs 49ns 273ns 0 0 0 4.62 KB
master AllCycleMoreComplexBody net472 7.71μs 4ns 15.5ns 0.735 0 0 4.74 KB
master ObjectExtractorSimpleBody net6.0 322ns 1.72ns 8.94ns 0 0 0 280 B
master ObjectExtractorSimpleBody netcoreapp3.1 397ns 2.03ns 8.13ns 0 0 0 272 B
master ObjectExtractorSimpleBody net472 299ns 0.0547ns 0.212ns 0.0442 0 0 281 B
master ObjectExtractorMoreComplexBody net6.0 6.22μs 31ns 142ns 0 0 0 3.78 KB
master ObjectExtractorMoreComplexBody netcoreapp3.1 7.98μs 40.1ns 175ns 0 0 0 3.69 KB
master ObjectExtractorMoreComplexBody net472 6.7μs 2.24ns 8.39ns 0.57 0 0 3.8 KB
#7681 AllCycleSimpleBody net6.0 1.06μs 0.402ns 1.56ns 0 0 0 1.22 KB
#7681 AllCycleSimpleBody netcoreapp3.1 1.42μs 7.67ns 43.4ns 0 0 0 1.2 KB
#7681 AllCycleSimpleBody net472 1.02μs 0.474ns 1.83ns 0.191 0 0 1.23 KB
#7681 AllCycleMoreComplexBody net6.0 7.03μs 37.5ns 202ns 0 0 0 4.72 KB
#7681 AllCycleMoreComplexBody netcoreapp3.1 8.9μs 44.7ns 205ns 0 0 0 4.62 KB
#7681 AllCycleMoreComplexBody net472 7.6μs 4.3ns 16.7ns 0.723 0 0 4.74 KB
#7681 ObjectExtractorSimpleBody net6.0 317ns 1.72ns 10ns 0 0 0 280 B
#7681 ObjectExtractorSimpleBody netcoreapp3.1 402ns 2.11ns 11.2ns 0 0 0 272 B
#7681 ObjectExtractorSimpleBody net472 301ns 0.202ns 0.783ns 0.0442 0 0 281 B
#7681 ObjectExtractorMoreComplexBody net6.0 6.24μs 29.3ns 110ns 0 0 0 3.78 KB
#7681 ObjectExtractorMoreComplexBody netcoreapp3.1 7.8μs 38.8ns 160ns 0 0 0 3.69 KB
#7681 ObjectExtractorMoreComplexBody net472 6.66μs 1.66ns 6.44ns 0.6 0 0 3.8 KB
Benchmarks.Trace.Asm.AppSecEncoderBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master EncodeArgs net6.0 77.9μs 242ns 939ns 0 0 0 32.4 KB
master EncodeArgs netcoreapp3.1 97.9μs 284ns 1.1μs 0 0 0 32.4 KB
master EncodeArgs net472 109μs 19.8ns 76.8ns 4.93 0 0 32.5 KB
master EncodeLegacyArgs net6.0 145μs 201ns 778ns 0 0 0 2.15 KB
master EncodeLegacyArgs netcoreapp3.1 200μs 178ns 665ns 0 0 0 2.15 KB
master EncodeLegacyArgs net472 261μs 87.9ns 340ns 0 0 0 2.16 KB
#7681 EncodeArgs net6.0 76.8μs 32ns 124ns 0 0 0 32.4 KB
#7681 EncodeArgs netcoreapp3.1 97.7μs 219ns 847ns 0 0 0 32.4 KB
#7681 EncodeArgs net472 109μs 13.5ns 52.3ns 4.91 0 0 32.51 KB
#7681 EncodeLegacyArgs net6.0 146μs 39ns 151ns 0 0 0 2.14 KB
#7681 EncodeLegacyArgs netcoreapp3.1 198μs 152ns 587ns 0 0 0 2.15 KB
#7681 EncodeLegacyArgs net472 266μs 47.6ns 184ns 0 0 0 2.16 KB
Benchmarks.Trace.Asm.AppSecWafBenchmark - Faster 🎉 Same allocations ✔️

Faster 🎉 in #7681

Benchmark base/diff Base Median (ns) Diff Median (ns) Modality
Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmark‑netcoreapp3.1 2.098 858,209.90 409,119.05

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master RunWafRealisticBenchmark net6.0 390μs 45.3ns 175ns 0 0 0 4.55 KB
master RunWafRealisticBenchmark netcoreapp3.1 852μs 5.43μs 54.1μs 0 0 0 4.48 KB
master RunWafRealisticBenchmark net472 431μs 56.4ns 218ns 0 0 0 4.66 KB
master RunWafRealisticBenchmarkWithAttack net6.0 284μs 34ns 127ns 0 0 0 2.24 KB
master RunWafRealisticBenchmarkWithAttack netcoreapp3.1 298μs 200ns 775ns 0 0 0 2.22 KB
master RunWafRealisticBenchmarkWithAttack net472 308μs 39.8ns 154ns 0 0 0 2.29 KB
#7681 RunWafRealisticBenchmark net6.0 400μs 90.9ns 352ns 0 0 0 4.55 KB
#7681 RunWafRealisticBenchmark netcoreapp3.1 409μs 327ns 1.22μs 0 0 0 4.48 KB
#7681 RunWafRealisticBenchmark net472 428μs 50.9ns 190ns 0 0 0 4.66 KB
#7681 RunWafRealisticBenchmarkWithAttack net6.0 287μs 62.5ns 225ns 0 0 0 2.24 KB
#7681 RunWafRealisticBenchmarkWithAttack netcoreapp3.1 296μs 47.6ns 184ns 0 0 0 2.22 KB
#7681 RunWafRealisticBenchmarkWithAttack net472 310μs 63ns 236ns 0 0 0 2.29 KB
Benchmarks.Trace.AspNetCoreBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master SendRequest net6.0 62.2μs 305ns 1.22μs 0 0 0 14.52 KB
master SendRequest netcoreapp3.1 71.4μs 94.4ns 353ns 0 0 0 17.42 KB
master SendRequest net472 0.0093ns 0.00283ns 0.011ns 0 0 0 0 b
#7681 SendRequest net6.0 60.5μs 21.2ns 73.6ns 0 0 0 14.52 KB
#7681 SendRequest netcoreapp3.1 71.2μs 126ns 454ns 0 0 0 17.42 KB
#7681 SendRequest net472 0.0026ns 0.00103ns 0.00398ns 0 0 0 0 b
Benchmarks.Trace.CharSliceBenchmark - Same speed ✔️ More allocations ⚠️

More allocations ⚠️ in #7681

Benchmark Base Allocated Diff Allocated Change Change %
Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSliceWithPool‑net472 47 B 48 B 1 B 2.13%

Fewer allocations 🎉 in #7681

Benchmark Base Allocated Diff Allocated Change Change %
Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSlice‑net6.0 4 B 2 B -2 B -50.00%
Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSliceWithPool‑netcoreapp3.1 1 B 0 b -1 B -100.00%

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master OriginalCharSlice net6.0 1.89ms 3.22μs 12.5μs 0 0 0 640.01 KB
master OriginalCharSlice netcoreapp3.1 2.1ms 1.4μs 5.41μs 0 0 0 640 KB
master OriginalCharSlice net472 2.6ms 107ns 415ns 100 0 0 641.95 KB
master OptimizedCharSlice net6.0 1.43ms 286ns 1.11μs 0 0 0 4 B
master OptimizedCharSlice netcoreapp3.1 1.73ms 492ns 1.91μs 0 0 0 1 B
master OptimizedCharSlice net472 1.97ms 298ns 1.07μs 0 0 0 73 B
master OptimizedCharSliceWithPool net6.0 820μs 46.5ns 180ns 0 0 0 4 B
master OptimizedCharSliceWithPool netcoreapp3.1 814μs 171ns 660ns 0 0 0 1 B
master OptimizedCharSliceWithPool net472 1.18ms 136ns 526ns 0 0 0 47 B
#7681 OriginalCharSlice net6.0 1.94ms 299ns 1.16μs 0 0 0 640.01 KB
#7681 OriginalCharSlice netcoreapp3.1 2.12ms 2.65μs 9.93μs 0 0 0 640 KB
#7681 OriginalCharSlice net472 2.64ms 118ns 424ns 100 0 0 641.95 KB
#7681 OptimizedCharSlice net6.0 1.44ms 83.1ns 288ns 0 0 0 2 B
#7681 OptimizedCharSlice netcoreapp3.1 1.65ms 559ns 2.17μs 0 0 0 1 B
#7681 OptimizedCharSlice net472 1.92ms 1.3μs 5.04μs 0 0 0 73 B
#7681 OptimizedCharSliceWithPool net6.0 831μs 36.6ns 142ns 0 0 0 4 B
#7681 OptimizedCharSliceWithPool netcoreapp3.1 834μs 67.6ns 262ns 0 0 0 0 b
#7681 OptimizedCharSliceWithPool net472 1.16ms 171ns 662ns 0 0 0 48 B
Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark - Slower ⚠️ More allocations ⚠️

Slower ⚠️ in #7681

Benchmark diff/base Base Median (ns) Diff Median (ns) Modality
Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark.WriteAndFlushEnrichedTraces‑net6.0 1.173 636,464.76 746,789.45

More allocations ⚠️ in #7681

Benchmark Base Allocated Diff Allocated Change Change %
Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark.WriteAndFlushEnrichedTraces‑net472 56.42 KB 61.95 KB 5.53 KB 9.80%

Fewer allocations 🎉 in #7681

Benchmark Base Allocated Diff Allocated Change Change %
Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark.WriteAndFlushEnrichedTraces‑netcoreapp3.1 42.76 KB 42.24 KB -515 B -1.20%

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master WriteAndFlushEnrichedTraces net6.0 648μs 3.63μs 23.2μs 0 0 0 41.7 KB
master WriteAndFlushEnrichedTraces netcoreapp3.1 740μs 4.1μs 26.6μs 0 0 0 42.76 KB
master WriteAndFlushEnrichedTraces net472 861μs 1.45μs 5.03μs 8.33 0 0 56.42 KB
#7681 WriteAndFlushEnrichedTraces net6.0 747μs 992ns 3.84μs 0 0 0 41.51 KB
#7681 WriteAndFlushEnrichedTraces netcoreapp3.1 737μs 3.9μs 21.4μs 0 0 0 42.24 KB
#7681 WriteAndFlushEnrichedTraces net472 889μs 4.97μs 31.8μs 0 0 0 61.95 KB
Benchmarks.Trace.DbCommandBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master ExecuteNonQuery net6.0 1.91μs 0.398ns 1.49ns 0 0 0 1.02 KB
master ExecuteNonQuery netcoreapp3.1 2.54μs 9.26ns 34.7ns 0 0 0 1.02 KB
master ExecuteNonQuery net472 2.86μs 4.12ns 15.9ns 0.144 0.0144 0 987 B
#7681 ExecuteNonQuery net6.0 1.93μs 0.788ns 2.73ns 0 0 0 1.02 KB
#7681 ExecuteNonQuery netcoreapp3.1 2.55μs 1.83ns 7.09ns 0 0 0 1.02 KB
#7681 ExecuteNonQuery net472 2.88μs 1.25ns 4.85ns 0.145 0.0145 0 987 B
Benchmarks.Trace.ElasticsearchBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master CallElasticsearch net6.0 1.74μs 9.05ns 47ns 0 0 0 1.03 KB
master CallElasticsearch netcoreapp3.1 2.21μs 8.09ns 30.3ns 0 0 0 1.03 KB
master CallElasticsearch net472 3.62μs 3.06ns 11.8ns 0.162 0 0 1.04 KB
master CallElasticsearchAsync net6.0 1.85μs 9.22ns 39.1ns 0 0 0 1.01 KB
master CallElasticsearchAsync netcoreapp3.1 2.32μs 11.5ns 51.2ns 0 0 0 1.08 KB
master CallElasticsearchAsync net472 3.78μs 5.84ns 22.6ns 0.17 0 0 1.1 KB
#7681 CallElasticsearch net6.0 1.71μs 8.91ns 44.5ns 0 0 0 1.03 KB
#7681 CallElasticsearch netcoreapp3.1 2.26μs 6.96ns 27ns 0 0 0 1.03 KB
#7681 CallElasticsearch net472 3.63μs 5.71ns 22.1ns 0.161 0 0 1.04 KB
#7681 CallElasticsearchAsync net6.0 1.83μs 9.17ns 43ns 0 0 0 1.01 KB
#7681 CallElasticsearchAsync netcoreapp3.1 2.4μs 11.5ns 44.6ns 0 0 0 1.08 KB
#7681 CallElasticsearchAsync net472 3.74μs 3.28ns 12.7ns 0.165 0 0 1.1 KB
Benchmarks.Trace.GraphQLBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master ExecuteAsync net6.0 1.88μs 8.7ns 33.7ns 0 0 0 952 B
master ExecuteAsync netcoreapp3.1 2.49μs 8.26ns 32ns 0 0 0 952 B
master ExecuteAsync net472 2.55μs 0.614ns 2.38ns 0.14 0 0 915 B
#7681 ExecuteAsync net6.0 1.85μs 8.71ns 34.8ns 0 0 0 952 B
#7681 ExecuteAsync netcoreapp3.1 2.43μs 8.5ns 31.8ns 0 0 0 952 B
#7681 ExecuteAsync net472 2.67μs 2.9ns 10.4ns 0.134 0 0 915 B
Benchmarks.Trace.HttpClientBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master SendAsync net6.0 6.86μs 5.86ns 21.1ns 0 0 0 2.36 KB
master SendAsync netcoreapp3.1 8.71μs 22.3ns 86.2ns 0 0 0 2.9 KB
master SendAsync net472 12.1μs 6.59ns 25.5ns 0.484 0 0 3.18 KB
#7681 SendAsync net6.0 6.76μs 5.63ns 21.8ns 0 0 0 2.36 KB
#7681 SendAsync netcoreapp3.1 8.69μs 22ns 85.4ns 0 0 0 2.9 KB
#7681 SendAsync net472 12.2μs 6.36ns 24.6ns 0.486 0 0 3.18 KB
Benchmarks.Trace.Iast.StringAspectsBenchmark - Same speed ✔️ More allocations ⚠️

More allocations ⚠️ in #7681

Benchmark Base Allocated Diff Allocated Change Change %
Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatBenchmark‑net6.0 44.14 KB 52.48 KB 8.34 KB 18.88%
Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatBenchmark‑net472 57.34 KB 65.54 KB 8.19 KB 14.29%
Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark‑net6.0 260.02 KB 276.27 KB 16.25 KB 6.25%
Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatBenchmark‑netcoreapp3.1 42.64 KB 44.04 KB 1.4 KB 3.28%

Fewer allocations 🎉 in #7681

Benchmark Base Allocated Diff Allocated Change Change %
Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark‑net472 286.72 KB 276.42 KB -10.3 KB -3.59%

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master StringConcatBenchmark net6.0 46.9μs 283ns 2.71μs 0 0 0 44.14 KB
master StringConcatBenchmark netcoreapp3.1 50.5μs 266ns 1.46μs 0 0 0 42.64 KB
master StringConcatBenchmark net472 55.8μs 260ns 972ns 0 0 0 57.34 KB
master StringConcatAspectBenchmark net6.0 483μs 2.01μs 6.95μs 0 0 0 260.02 KB
master StringConcatAspectBenchmark netcoreapp3.1 503μs 2.48μs 10.2μs 0 0 0 257.86 KB
master StringConcatAspectBenchmark net472 406μs 2.02μs 8.55μs 0 0 0 286.72 KB
#7681 StringConcatBenchmark net6.0 45.2μs 191ns 974ns 0 0 0 52.48 KB
#7681 StringConcatBenchmark netcoreapp3.1 48.5μs 176ns 633ns 0 0 0 44.04 KB
#7681 StringConcatBenchmark net472 58.4μs 278ns 1.08μs 0 0 0 65.54 KB
#7681 StringConcatAspectBenchmark net6.0 474μs 1.99μs 6.91μs 0 0 0 276.27 KB
#7681 StringConcatAspectBenchmark netcoreapp3.1 506μs 1.86μs 6.44μs 0 0 0 258 KB
#7681 StringConcatAspectBenchmark net472 414μs 2.29μs 13.3μs 0 0 0 276.42 KB
Benchmarks.Trace.ILoggerBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master EnrichedLog net6.0 2.65μs 2.59ns 10ns 0 0 0 1.7 KB
master EnrichedLog netcoreapp3.1 3.61μs 17.4ns 73.8ns 0 0 0 1.71 KB
master EnrichedLog net472 3.91μs 3.8ns 14.2ns 0.253 0 0 1.64 KB
#7681 EnrichedLog net6.0 2.61μs 13.6ns 65.4ns 0 0 0 1.7 KB
#7681 EnrichedLog netcoreapp3.1 3.64μs 18.5ns 80.8ns 0 0 0 1.7 KB
#7681 EnrichedLog net472 3.95μs 2.7ns 10.4ns 0.257 0 0 1.64 KB
Benchmarks.Trace.Log4netBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master EnrichedLog net6.0 125μs 267ns 1.03μs 0 0 0 4.31 KB
master EnrichedLog netcoreapp3.1 127μs 128ns 480ns 0 0 0 4.31 KB
master EnrichedLog net472 167μs 72.9ns 283ns 0 0 0 4.52 KB
#7681 EnrichedLog net6.0 124μs 483ns 1.87μs 0 0 0 4.31 KB
#7681 EnrichedLog netcoreapp3.1 127μs 109ns 409ns 0 0 0 4.31 KB
#7681 EnrichedLog net472 167μs 114ns 426ns 0 0 0 4.52 KB
Benchmarks.Trace.NLogBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master EnrichedLog net6.0 5.06μs 18.4ns 71.4ns 0 0 0 2.26 KB
master EnrichedLog netcoreapp3.1 6.84μs 21.1ns 81.8ns 0 0 0 2.26 KB
master EnrichedLog net472 7.57μs 9.61ns 37.2ns 0.305 0 0 2.08 KB
#7681 EnrichedLog net6.0 5.12μs 4.3ns 16.7ns 0 0 0 2.26 KB
#7681 EnrichedLog netcoreapp3.1 6.91μs 20.2ns 78.4ns 0 0 0 2.26 KB
#7681 EnrichedLog net472 7.63μs 8.1ns 30.3ns 0.304 0 0 2.08 KB
Benchmarks.Trace.RedisBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master SendReceive net6.0 1.93μs 8.24ns 31.9ns 0 0 0 1.2 KB
master SendReceive netcoreapp3.1 2.65μs 6.74ns 26.1ns 0 0 0 1.2 KB
master SendReceive net472 3.18μs 1.74ns 6.26ns 0.177 0 0 1.2 KB
#7681 SendReceive net6.0 1.92μs 8.67ns 33.6ns 0 0 0 1.2 KB
#7681 SendReceive netcoreapp3.1 2.55μs 12.4ns 52.8ns 0 0 0 1.2 KB
#7681 SendReceive net472 3.17μs 5.84ns 22.6ns 0.191 0 0 1.2 KB
Benchmarks.Trace.SerilogBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master EnrichedLog net6.0 4.35μs 10.8ns 41.8ns 0 0 0 1.58 KB
master EnrichedLog netcoreapp3.1 5.73μs 12.1ns 46.8ns 0 0 0 1.63 KB
master EnrichedLog net472 6.74μs 14ns 54.2ns 0.303 0 0 2.03 KB
#7681 EnrichedLog net6.0 4.32μs 17.3ns 67ns 0 0 0 1.58 KB
#7681 EnrichedLog netcoreapp3.1 5.58μs 19ns 73.8ns 0 0 0 1.63 KB
#7681 EnrichedLog net472 6.66μs 14.4ns 55.8ns 0.302 0 0 2.03 KB
Benchmarks.Trace.SpanBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master StartFinishSpan net6.0 770ns 3.51ns 13.6ns 0 0 0 576 B
master StartFinishSpan netcoreapp3.1 954ns 5.02ns 26.6ns 0 0 0 576 B
master StartFinishSpan net472 948ns 0.081ns 0.303ns 0.0907 0 0 578 B
master StartFinishScope net6.0 918ns 4.76ns 22.3ns 0 0 0 696 B
master StartFinishScope netcoreapp3.1 1.18μs 6.14ns 30.1ns 0 0 0 696 B
master StartFinishScope net472 1.18μs 0.511ns 1.91ns 0.1 0 0 658 B
#7681 StartFinishSpan net6.0 786ns 1.75ns 6.32ns 0 0 0 576 B
#7681 StartFinishSpan netcoreapp3.1 985ns 4.71ns 18.2ns 0 0 0 576 B
#7681 StartFinishSpan net472 950ns 0.393ns 1.52ns 0.0905 0 0 578 B
#7681 StartFinishScope net6.0 940ns 2.49ns 9.31ns 0 0 0 696 B
#7681 StartFinishScope netcoreapp3.1 1.16μs 5.79ns 25.2ns 0 0 0 696 B
#7681 StartFinishScope net472 1.16μs 1.04ns 4.03ns 0.104 0 0 658 B
Benchmarks.Trace.TraceAnnotationsBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master RunOnMethodBegin net6.0 1.11μs 5.16ns 20ns 0 0 0 696 B
master RunOnMethodBegin netcoreapp3.1 1.42μs 7.57ns 38.6ns 0 0 0 696 B
master RunOnMethodBegin net472 1.47μs 3.72ns 14.4ns 0.103 0 0 658 B
#7681 RunOnMethodBegin net6.0 1.05μs 5.67ns 31ns 0 0 0 696 B
#7681 RunOnMethodBegin netcoreapp3.1 1.49μs 3.01ns 11.7ns 0 0 0 696 B
#7681 RunOnMethodBegin net472 1.43μs 1.19ns 4.61ns 0.1 0 0 658 B

@chrisnas
Copy link
Contributor Author

chrisnas commented Nov 7, 2025

This is just configuration, right? There's no implementation of taking the snapshot here?

Work in progress yes :^)
My last commit seems to generate a "class histogram" as expected by our backend when conditions are fullfiled

@datadog-datadog-prod-us1

This comment has been minimized.


std::unique_ptr<std::thread> _pLoopThread;
DWORD _loopThreadOsId;
volatile bool _shutdownRequested = false;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use std::atomic instead.
volatile does not guarantee atomicity, or memory ordering (not like in C#)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting... I've used the exact same definition as what is done in StackSamplerLoop
Maybe we should change in both places


HeapSnapshotManager::~HeapSnapshotManager()
{
StopImpl();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't we call Stop instead of StopImpl.
Stop will modify the state of the service but not StopImpl.
In this case it's not big, because it lives as long as the process lives, but just to be clean

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure because the destructor is the last chance of cleanup and the service lifetime stop should have been called before. I've followed what the StackSamplerLoop is doing because they both have created threads that need to be stopped.

Comment on lines +85 to +87
_pLoopThread = std::make_unique<std::thread>([this] {
OpSysTools::SetNativeThreadName(ThreadName);
MainLoop();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not in this PR, but I wonder if we should not check if the thread is correctly started before returning true.
If the thread failed to start, we should return false.
This should be done in all other classes that have the same pattern.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting question... Not sure to find a reason why a thread would not be able to be started by the OS.
Let's discuss that pattern and decide what to do in another PR


std::string HeapSnapshotManager::GetAndClearHeapSnapshotText()
{
// TODO: this should be protected by a lock because both the dedicated thread and the exporter thread
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ done

std::string className;
if (_pFrameStore->GetTypeName(static_cast<ClassID>(pNodes[i].TypeID), className))
{
ClassHistogramEntry histogramEntry(className);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could move className

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ done

class INativeThreadList
{
public:
virtual bool RegisterThread(uint32_t tid) = 0;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a virtual dtor with = default

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ done

bool NativeThreadList::Contains(uint32_t tid) const
{
std::lock_guard<std::mutex> lock(_mutex);
return _nativeThreadIds.find(tid) != _nativeThreadIds.end();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you may be able to use the contains function instead

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ done

const char* GetName() override;

// Inherited via INativeThreadList
bool RegisterThread(uint32_t tid);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add override for RegisterThread

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ done

Comment on lines +734 to +743
std::stringstream builder;

// TODO: just for tests, the heap snapshot manager returns a string instead of a reference to an unorderedmap
auto heapSnapshot = _heapSnapshotManager->GetAndClearHeapSnapshotText();
if (!heapSnapshot.empty())
{
builder << heapSnapshot;
}

return builder.str();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: you rewrite this so the builder is created only if heapSnapshot is not empty()

Copy link
Contributor Author

@chrisnas chrisnas Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ done
I'm not 100% sure of this part where the manager has to know how to serialize the class histogram instead of letting the exporter be responsible for the format. Looks good for a preview

@@ -0,0 +1,28 @@
using System.Linq;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add the header pls

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ good catch

@andrewlock andrewlock self-requested a review November 21, 2025 19:17
Copy link
Collaborator

@gleocadie gleocadie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@chrisnas chrisnas merged commit 0d21d39 into master Nov 26, 2025
157 checks passed
@chrisnas chrisnas deleted the chrisnas/add_class_histogram branch November 26, 2025 08:56
@github-actions github-actions bot added this to the vNext-v3 milestone Nov 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:profiler Issues related to the continous-profiler

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants