Fix (and extend) AgentWriter benchmark#7882
Conversation
Execution-Time Benchmarks Report ⏱️Execution-time results for samples comparing This PR (7882) and master. ✅ No regressions detected - check the details below Full Metrics ComparisonFakeDbCommand
HttpMessageHandler
Comparison explanationExecution-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:
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 chartsFakeDbCommand (.NET Framework 4.8)gantt
title Execution time (ms) FakeDbCommand (.NET Framework 4.8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (7882) - mean (75ms) : 69, 82
master - mean (77ms) : 70, 84
section Bailout
This PR (7882) - mean (81ms) : 73, 89
master - mean (80ms) : 75, 84
section CallTarget+Inlining+NGEN
This PR (7882) - mean (1,074ms) : 1005, 1142
master - mean (1,068ms) : 1013, 1122
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 (7882) - mean (119ms) : 110, 127
master - mean (120ms) : 112, 127
section Bailout
This PR (7882) - mean (121ms) : 114, 128
master - mean (121ms) : 114, 127
section CallTarget+Inlining+NGEN
This PR (7882) - mean (769ms) : 723, 815
master - mean (773ms) : 733, 813
FakeDbCommand (.NET 6)gantt
title Execution time (ms) FakeDbCommand (.NET 6)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (7882) - mean (106ms) : 98, 114
master - mean (105ms) : 98, 112
section Bailout
This PR (7882) - mean (108ms) : 101, 115
master - mean (106ms) : 100, 111
section CallTarget+Inlining+NGEN
This PR (7882) - mean (713ms) : 677, 749
master - mean (711ms) : 682, 740
FakeDbCommand (.NET 8)gantt
title Execution time (ms) FakeDbCommand (.NET 8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (7882) - mean (104ms) : 98, 110
master - mean (105ms) : 97, 113
section Bailout
This PR (7882) - mean (106ms) : 97, 115
master - mean (105ms) : 100, 111
section CallTarget+Inlining+NGEN
This PR (7882) - mean (693ms) : 659, 726
master - mean (687ms) : 650, 725
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 (7882) - mean (194ms) : 189, 198
master - mean (193ms) : 188, 197
section Bailout
This PR (7882) - mean (198ms) : 194, 202
master - mean (195ms) : 193, 197
section CallTarget+Inlining+NGEN
This PR (7882) - mean (1,119ms) : 1060, 1179
master - mean (1,115ms) : 1043, 1187
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 (7882) - mean (278ms) : 272, 284
master - mean (275ms) : 270, 280
section Bailout
This PR (7882) - mean (279ms) : 274, 284
master - mean (276ms) : 272, 280
section CallTarget+Inlining+NGEN
This PR (7882) - mean (918ms) : 858, 979
master - mean (903ms) : 854, 951
HttpMessageHandler (.NET 6)gantt
title Execution time (ms) HttpMessageHandler (.NET 6)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (7882) - mean (275ms) : 264, 287
master - mean (268ms) : 265, 272
section Bailout
This PR (7882) - mean (273ms) : 267, 278
master - mean (269ms) : 264, 274
section CallTarget+Inlining+NGEN
This PR (7882) - mean (893ms) : 849, 938
master - mean (875ms) : 834, 917
HttpMessageHandler (.NET 8)gantt
title Execution time (ms) HttpMessageHandler (.NET 8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (7882) - mean (271ms) : 265, 277
master - mean (269ms) : 264, 274
section Bailout
This PR (7882) - mean (271ms) : 267, 275
master - mean (267ms) : 265, 270
section CallTarget+Inlining+NGEN
This PR (7882) - mean (837ms) : 807, 866
master - mean (822ms) : 802, 841
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
BenchmarksBenchmarks Report for benchmark platform 🐌Benchmarks for #7882 compared to master:
The following thresholds were used for comparing the benchmark speeds:
Allocation changes below 0.5% are ignored. Benchmark detailsBenchmarks.Trace.ActivityBenchmark - Same speed ✔️ Fewer allocations 🎉
|
| Benchmark | Base Allocated | Diff Allocated | Change | Change % |
|---|---|---|---|---|
| Benchmarks.Trace.ActivityBenchmark.StartStopWithChild‑net472 | 6.14 KB | 6.09 KB | -51 B | -0.83% |
Raw results
| Branch | Method | Toolchain | Mean | StdError | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|---|---|---|---|---|---|---|---|---|---|
| master | StartStopWithChild |
net6.0 | 10.6μs | 59.2ns | 360ns | 0 | 0 | 0 | 5.51 KB |
| master | StartStopWithChild |
netcoreapp3.1 | 14.3μs | 73ns | 350ns | 0 | 0 | 0 | 5.73 KB |
| master | StartStopWithChild |
net472 | 22.9μs | 118ns | 728ns | 0.896 | 0.336 | 0 | 6.14 KB |
| #7882 | StartStopWithChild |
net6.0 | 11.1μs | 58ns | 278ns | 0 | 0 | 0 | 5.51 KB |
| #7882 | StartStopWithChild |
netcoreapp3.1 | 13.8μs | 71.5ns | 358ns | 0 | 0 | 0 | 5.7 KB |
| #7882 | StartStopWithChild |
net472 | 22.1μs | 111ns | 566ns | 0.904 | 0.339 | 0 | 6.09 KB |
Benchmarks.Trace.AgentWriterBenchmark - Unknown 🤷 More allocations ⚠️
More allocations ⚠️ in #7882
Benchmark
Base Allocated
Diff Allocated
Change
Change %
Benchmarks.Trace.AgentWriterBenchmark.WriteAndFlushEnrichedTraces‑net6.0
0 b
2.71 KB
2.71 KB
∞
Benchmarks.Trace.AgentWriterBenchmark.WriteAndFlushEnrichedTraces‑netcoreapp3.1
0 b
2.7 KB
2.7 KB
∞
Benchmarks.Trace.AgentWriterBenchmark.WriteAndFlushEnrichedTraces‑net472
0 b
115.65 KB
115.65 KB
∞
| Benchmark | Base Allocated | Diff Allocated | Change | Change % |
|---|---|---|---|---|
| Benchmarks.Trace.AgentWriterBenchmark.WriteAndFlushEnrichedTraces‑net6.0 | 0 b | 2.71 KB | 2.71 KB | ∞ |
| Benchmarks.Trace.AgentWriterBenchmark.WriteAndFlushEnrichedTraces‑netcoreapp3.1 | 0 b | 2.7 KB | 2.7 KB | ∞ |
| Benchmarks.Trace.AgentWriterBenchmark.WriteAndFlushEnrichedTraces‑net472 | 0 b | 115.65 KB | 115.65 KB | ∞ |
Raw results
| Branch | Method | Toolchain | Mean | StdError | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|---|---|---|---|---|---|---|---|---|---|
| master | WriteAndFlushEnrichedTraces |
net6.0 | N/A | N/A | N/A | NaN | NaN | NaN | 0 b |
| master | WriteAndFlushEnrichedTraces |
netcoreapp3.1 | N/A | N/A | N/A | NaN | NaN | NaN | 0 b |
| master | WriteAndFlushEnrichedTraces |
net472 | N/A | N/A | N/A | NaN | NaN | NaN | 0 b |
| #7882 | WriteAndFlushEnrichedTraces |
net6.0 | 1.25ms | 84.7ns | 328ns | 0 | 0 | 0 | 2.71 KB |
| #7882 | WriteAndFlushEnrichedTraces |
netcoreapp3.1 | 1.38ms | 1.28μs | 4.96μs | 0 | 0 | 0 | 2.7 KB |
| #7882 | WriteAndFlushEnrichedTraces |
net472 | 1.77ms | 770ns | 2.98μs | 15.6 | 0 | 0 | 115.65 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.08μs | 5.79ns | 33.3ns | 0 | 0 | 0 | 1.22 KB |
| master | AllCycleSimpleBody |
netcoreapp3.1 | 1.39μs | 7.9ns | 55.9ns | 0 | 0 | 0 | 1.2 KB |
| master | AllCycleSimpleBody |
net472 | 1.11μs | 1.11ns | 4.3ns | 0.194 | 0 | 0 | 1.23 KB |
| master | AllCycleMoreComplexBody |
net6.0 | 7.22μs | 4.09ns | 15.8ns | 0 | 0 | 0 | 4.72 KB |
| master | AllCycleMoreComplexBody |
netcoreapp3.1 | 9.35μs | 43.6ns | 175ns | 0 | 0 | 0 | 4.62 KB |
| master | AllCycleMoreComplexBody |
net472 | 7.58μs | 3.67ns | 14.2ns | 0.718 | 0 | 0 | 4.74 KB |
| master | ObjectExtractorSimpleBody |
net6.0 | 321ns | 1.78ns | 11ns | 0 | 0 | 0 | 280 B |
| master | ObjectExtractorSimpleBody |
netcoreapp3.1 | 405ns | 1.99ns | 8.42ns | 0 | 0 | 0 | 272 B |
| master | ObjectExtractorSimpleBody |
net472 | 299ns | 0.178ns | 0.667ns | 0.0442 | 0 | 0 | 281 B |
| master | ObjectExtractorMoreComplexBody |
net6.0 | 6.27μs | 31.4ns | 137ns | 0 | 0 | 0 | 3.78 KB |
| master | ObjectExtractorMoreComplexBody |
netcoreapp3.1 | 7.87μs | 36.9ns | 148ns | 0 | 0 | 0 | 3.69 KB |
| master | ObjectExtractorMoreComplexBody |
net472 | 6.6μs | 1.21ns | 4.53ns | 0.598 | 0 | 0 | 3.8 KB |
| #7882 | AllCycleSimpleBody |
net6.0 | 1.05μs | 6.07ns | 49.3ns | 0 | 0 | 0 | 1.22 KB |
| #7882 | AllCycleSimpleBody |
netcoreapp3.1 | 1.39μs | 7.67ns | 49.1ns | 0 | 0 | 0 | 1.2 KB |
| #7882 | AllCycleSimpleBody |
net472 | 1.06μs | 3.9ns | 15.1ns | 0.193 | 0 | 0 | 1.23 KB |
| #7882 | AllCycleMoreComplexBody |
net6.0 | 7.14μs | 3ns | 11.6ns | 0 | 0 | 0 | 4.72 KB |
| #7882 | AllCycleMoreComplexBody |
netcoreapp3.1 | 8.88μs | 46ns | 221ns | 0 | 0 | 0 | 4.62 KB |
| #7882 | AllCycleMoreComplexBody |
net472 | 7.59μs | 9.19ns | 35.6ns | 0.718 | 0 | 0 | 4.74 KB |
| #7882 | ObjectExtractorSimpleBody |
net6.0 | 326ns | 1.74ns | 8.87ns | 0 | 0 | 0 | 280 B |
| #7882 | ObjectExtractorSimpleBody |
netcoreapp3.1 | 397ns | 2.19ns | 12.4ns | 0 | 0 | 0 | 272 B |
| #7882 | ObjectExtractorSimpleBody |
net472 | 301ns | 0.415ns | 1.61ns | 0.0444 | 0 | 0 | 281 B |
| #7882 | ObjectExtractorMoreComplexBody |
net6.0 | 6.28μs | 31.9ns | 153ns | 0 | 0 | 0 | 3.78 KB |
| #7882 | ObjectExtractorMoreComplexBody |
netcoreapp3.1 | 7.67μs | 39.5ns | 189ns | 0 | 0 | 0 | 3.69 KB |
| #7882 | ObjectExtractorMoreComplexBody |
net472 | 6.7μs | 4.41ns | 17.1ns | 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 | 76.3μs | 214ns | 828ns | 0 | 0 | 0 | 32.4 KB |
| master | EncodeArgs |
netcoreapp3.1 | 97.7μs | 24.1ns | 90.3ns | 0 | 0 | 0 | 32.4 KB |
| master | EncodeArgs |
net472 | 110μs | 27ns | 105ns | 4.94 | 0 | 0 | 32.51 KB |
| master | EncodeLegacyArgs |
net6.0 | 144μs | 26ns | 101ns | 0 | 0 | 0 | 2.15 KB |
| master | EncodeLegacyArgs |
netcoreapp3.1 | 201μs | 755ns | 2.93μs | 0 | 0 | 0 | 2.15 KB |
| master | EncodeLegacyArgs |
net472 | 265μs | 142ns | 551ns | 0 | 0 | 0 | 2.16 KB |
| #7882 | EncodeArgs |
net6.0 | 77.5μs | 223ns | 864ns | 0 | 0 | 0 | 32.4 KB |
| #7882 | EncodeArgs |
netcoreapp3.1 | 98.1μs | 275ns | 1.07μs | 0 | 0 | 0 | 32.4 KB |
| #7882 | EncodeArgs |
net472 | 109μs | 10.9ns | 42.1ns | 4.9 | 0 | 0 | 32.51 KB |
| #7882 | EncodeLegacyArgs |
net6.0 | 148μs | 55.5ns | 208ns | 0 | 0 | 0 | 2.15 KB |
| #7882 | EncodeLegacyArgs |
netcoreapp3.1 | 198μs | 70.3ns | 263ns | 0 | 0 | 0 | 2.15 KB |
| #7882 | EncodeLegacyArgs |
net472 | 266μs | 233ns | 901ns | 0 | 0 | 0 | 2.16 KB |
Benchmarks.Trace.Asm.AppSecWafBenchmark - Same speed ✔️ More allocations ⚠️
More allocations ⚠️ in #7882
Benchmark
Base Allocated
Diff Allocated
Change
Change %
Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmark‑net6.0
5.48 KB
5.82 KB
336 B
6.13%
Fewer allocations 🎉 in #7882
Benchmark
Base Allocated
Diff Allocated
Change
Change %
Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmarkWithAttack‑net6.0
2.83 KB
2.54 KB
-288 B
-10.17%
| Benchmark | Base Allocated | Diff Allocated | Change | Change % |
|---|---|---|---|---|
| Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmark‑net6.0 | 5.48 KB | 5.82 KB | 336 B | 6.13% |
| Benchmark | Base Allocated | Diff Allocated | Change | Change % |
|---|---|---|---|---|
| Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmarkWithAttack‑net6.0 | 2.83 KB | 2.54 KB | -288 B | -10.17% |
Raw results
| Branch | Method | Toolchain | Mean | StdError | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|---|---|---|---|---|---|---|---|---|---|
| master | RunWafRealisticBenchmark |
net6.0 | 446μs | 2.59μs | 23.2μs | 0 | 0 | 0 | 5.48 KB |
| master | RunWafRealisticBenchmark |
netcoreapp3.1 | 473μs | 2.77μs | 25.8μs | 0 | 0 | 0 | 4.58 KB |
| master | RunWafRealisticBenchmark |
net472 | 492μs | 356ns | 1.28μs | 0 | 0 | 0 | 0 b |
| master | RunWafRealisticBenchmarkWithAttack |
net6.0 | 321μs | 920ns | 3.19μs | 0 | 0 | 0 | 2.83 KB |
| master | RunWafRealisticBenchmarkWithAttack |
netcoreapp3.1 | 362μs | 3.19μs | 31.1μs | 0 | 0 | 0 | 2.32 KB |
| master | RunWafRealisticBenchmarkWithAttack |
net472 | 368μs | 449ns | 1.68μs | 0 | 0 | 0 | 0 b |
| #7882 | RunWafRealisticBenchmark |
net6.0 | 440μs | 2.32μs | 11.6μs | 0 | 0 | 0 | 5.82 KB |
| #7882 | RunWafRealisticBenchmark |
netcoreapp3.1 | 470μs | 2.6μs | 17.2μs | 0 | 0 | 0 | 4.58 KB |
| #7882 | RunWafRealisticBenchmark |
net472 | 505μs | 251ns | 870ns | 0 | 0 | 0 | 0 b |
| #7882 | RunWafRealisticBenchmarkWithAttack |
net6.0 | 318μs | 1.24μs | 4.62μs | 0 | 0 | 0 | 2.54 KB |
| #7882 | RunWafRealisticBenchmarkWithAttack |
netcoreapp3.1 | 350μs | 3.3μs | 32μs | 0 | 0 | 0 | 2.32 KB |
| #7882 | RunWafRealisticBenchmarkWithAttack |
net472 | 369μs | 405ns | 1.52μs | 0 | 0 | 0 | 0 b |
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 | 60.6μs | 36.8ns | 133ns | 0 | 0 | 0 | 14.52 KB |
| master | SendRequest |
netcoreapp3.1 | 72.2μs | 334ns | 1.34μs | 0 | 0 | 0 | 17.42 KB |
| master | SendRequest |
net472 | 0.161ns | 0.00536ns | 0.0208ns | 0 | 0 | 0 | 0 b |
| #7882 | SendRequest |
net6.0 | 61.5μs | 34.9ns | 126ns | 0 | 0 | 0 | 14.52 KB |
| #7882 | SendRequest |
netcoreapp3.1 | 72.7μs | 66ns | 247ns | 0 | 0 | 0 | 17.42 KB |
| #7882 | SendRequest |
net472 | 0.0132ns | 0.00364ns | 0.0141ns | 0 | 0 | 0 | 0 b |
Benchmarks.Trace.CharSliceBenchmark - Same speed ✔️ Fewer allocations 🎉
Fewer allocations 🎉 in #7882
Benchmark
Base Allocated
Diff Allocated
Change
Change %
Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSliceWithPool‑net6.0
640 B
304 B
-336 B
-52.50%
Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSlice‑net6.0
976 B
304 B
-672 B
-68.85%
| Benchmark | Base Allocated | Diff Allocated | Change | Change % |
|---|---|---|---|---|
| Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSliceWithPool‑net6.0 | 640 B | 304 B | -336 B | -52.50% |
| Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSlice‑net6.0 | 976 B | 304 B | -672 B | -68.85% |
Raw results
| Branch | Method | Toolchain | Mean | StdError | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|---|---|---|---|---|---|---|---|---|---|
| master | OriginalCharSlice |
net6.0 | 1.89ms | 1.31μs | 4.9μs | 0 | 0 | 0 | 640.3 KB |
| master | OriginalCharSlice |
netcoreapp3.1 | 3.99ms | 1.21μs | 4.19μs | 0 | 0 | 0 | 640.1 KB |
| master | OriginalCharSlice |
net472 | 2.66ms | 1.44μs | 5.59μs | 0 | 0 | 0 | 647.17 KB |
| master | OptimizedCharSlice |
net6.0 | 1.42ms | 502ns | 1.74μs | 0 | 0 | 0 | 976 B |
| master | OptimizedCharSlice |
netcoreapp3.1 | 2.77ms | 1.17μs | 4.53μs | 0 | 0 | 0 | 104 B |
| master | OptimizedCharSlice |
net472 | 1.92ms | 1.12μs | 4.18μs | 0 | 0 | 0 | 0 b |
| master | OptimizedCharSliceWithPool |
net6.0 | 1.01ms | 744ns | 2.88μs | 0 | 0 | 0 | 640 B |
| master | OptimizedCharSliceWithPool |
netcoreapp3.1 | 1.92ms | 1.72μs | 6.64μs | 0 | 0 | 0 | 104 B |
| master | OptimizedCharSliceWithPool |
net472 | 1.14ms | 273ns | 946ns | 0 | 0 | 0 | 0 b |
| #7882 | OriginalCharSlice |
net6.0 | 2.06ms | 2.02μs | 7.57μs | 0 | 0 | 0 | 640.98 KB |
| #7882 | OriginalCharSlice |
netcoreapp3.1 | 4.03ms | 1.82μs | 6.57μs | 0 | 0 | 0 | 640.1 KB |
| #7882 | OriginalCharSlice |
net472 | 2.67ms | 594ns | 2.3μs | 0 | 0 | 0 | 647.17 KB |
| #7882 | OptimizedCharSlice |
net6.0 | 1.48ms | 717ns | 2.78μs | 0 | 0 | 0 | 304 B |
| #7882 | OptimizedCharSlice |
netcoreapp3.1 | 3.01ms | 2.21μs | 8.58μs | 0 | 0 | 0 | 104 B |
| #7882 | OptimizedCharSlice |
net472 | 1.92ms | 1.48μs | 5.72μs | 0 | 0 | 0 | 0 b |
| #7882 | OptimizedCharSliceWithPool |
net6.0 | 1.07ms | 736ns | 2.85μs | 0 | 0 | 0 | 304 B |
| #7882 | OptimizedCharSliceWithPool |
netcoreapp3.1 | 1.88ms | 3.14μs | 12.1μs | 0 | 0 | 0 | 104 B |
| #7882 | OptimizedCharSliceWithPool |
net472 | 1.25ms | 615ns | 2.13μs | 0 | 0 | 0 | 0 b |
Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark - Same speed ✔️ Same allocations ✔️
Raw results
| Branch | Method | Toolchain | Mean | StdError | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|---|---|---|---|---|---|---|---|---|---|
| master | WriteAndFlushEnrichedTraces |
net6.0 | 714μs | 3.63μs | 16.6μs | 0 | 0 | 0 | 42.23 KB |
| master | WriteAndFlushEnrichedTraces |
netcoreapp3.1 | 746μs | 4.1μs | 24.9μs | 0 | 0 | 0 | 41.86 KB |
| master | WriteAndFlushEnrichedTraces |
net472 | 939μs | 4.3μs | 23.2μs | 4.46 | 0 | 0 | 55.79 KB |
| #7882 | WriteAndFlushEnrichedTraces |
net6.0 | 746μs | 3.15μs | 12.2μs | 0 | 0 | 0 | 42.05 KB |
| #7882 | WriteAndFlushEnrichedTraces |
netcoreapp3.1 | 818μs | 3.88μs | 15μs | 0 | 0 | 0 | 41.75 KB |
| #7882 | WriteAndFlushEnrichedTraces |
net472 | 1.01ms | 5.04μs | 26.2μs | 4.81 | 0 | 0 | 56.02 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 | 8.67ns | 33.6ns | 0 | 0 | 0 | 1.02 KB |
| master | ExecuteNonQuery |
netcoreapp3.1 | 2.53μs | 5.29ns | 20.5ns | 0 | 0 | 0 | 1.02 KB |
| master | ExecuteNonQuery |
net472 | 2.74μs | 3.2ns | 12.4ns | 0.151 | 0 | 0 | 987 B |
| #7882 | ExecuteNonQuery |
net6.0 | 1.84μs | 8.85ns | 37.5ns | 0 | 0 | 0 | 1.02 KB |
| #7882 | ExecuteNonQuery |
netcoreapp3.1 | 2.59μs | 12.1ns | 46.8ns | 0 | 0 | 0 | 1.02 KB |
| #7882 | ExecuteNonQuery |
net472 | 2.89μs | 4.22ns | 16.3ns | 0.148 | 0 | 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.75μs | 9.2ns | 44.1ns | 0 | 0 | 0 | 1.03 KB |
| master | CallElasticsearch |
netcoreapp3.1 | 2.26μs | 10.9ns | 45.1ns | 0 | 0 | 0 | 1.03 KB |
| master | CallElasticsearch |
net472 | 3.48μs | 1.22ns | 4.56ns | 0.157 | 0 | 0 | 1.04 KB |
| master | CallElasticsearchAsync |
net6.0 | 1.87μs | 7.73ns | 30ns | 0 | 0 | 0 | 1.01 KB |
| master | CallElasticsearchAsync |
netcoreapp3.1 | 2.41μs | 7.48ns | 25.9ns | 0 | 0 | 0 | 1.08 KB |
| master | CallElasticsearchAsync |
net472 | 3.69μs | 4.57ns | 17.7ns | 0.167 | 0 | 0 | 1.1 KB |
| #7882 | CallElasticsearch |
net6.0 | 1.72μs | 9.33ns | 49.4ns | 0 | 0 | 0 | 1.03 KB |
| #7882 | CallElasticsearch |
netcoreapp3.1 | 2.34μs | 8.12ns | 31.4ns | 0 | 0 | 0 | 1.03 KB |
| #7882 | CallElasticsearch |
net472 | 3.41μs | 2.93ns | 11.4ns | 0.154 | 0 | 0 | 1.04 KB |
| #7882 | CallElasticsearchAsync |
net6.0 | 1.8μs | 0.949ns | 3.55ns | 0 | 0 | 0 | 1.01 KB |
| #7882 | CallElasticsearchAsync |
netcoreapp3.1 | 2.56μs | 7.73ns | 29.9ns | 0 | 0 | 0 | 1.08 KB |
| #7882 | CallElasticsearchAsync |
net472 | 3.78μs | 3.72ns | 14.4ns | 0.172 | 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.92μs | 7.18ns | 27.8ns | 0 | 0 | 0 | 952 B |
| master | ExecuteAsync |
netcoreapp3.1 | 2.45μs | 8.55ns | 33.1ns | 0 | 0 | 0 | 952 B |
| master | ExecuteAsync |
net472 | 2.58μs | 2.98ns | 11.5ns | 0.141 | 0 | 0 | 915 B |
| #7882 | ExecuteAsync |
net6.0 | 1.85μs | 0.486ns | 1.75ns | 0 | 0 | 0 | 952 B |
| #7882 | ExecuteAsync |
netcoreapp3.1 | 2.42μs | 11.7ns | 45.2ns | 0 | 0 | 0 | 952 B |
| #7882 | ExecuteAsync |
net472 | 2.54μs | 1.44ns | 5.38ns | 0.14 | 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 | 7μs | 11.5ns | 44.4ns | 0 | 0 | 0 | 2.36 KB |
| master | SendAsync |
netcoreapp3.1 | 8.7μs | 19.8ns | 76.9ns | 0 | 0 | 0 | 2.9 KB |
| master | SendAsync |
net472 | 12.3μs | 7.96ns | 29.8ns | 0.489 | 0 | 0 | 3.18 KB |
| #7882 | SendAsync |
net6.0 | 7.19μs | 3.48ns | 12.1ns | 0 | 0 | 0 | 2.36 KB |
| #7882 | SendAsync |
netcoreapp3.1 | 8.82μs | 6.96ns | 27ns | 0 | 0 | 0 | 2.9 KB |
| #7882 | SendAsync |
net472 | 12.4μs | 13.5ns | 52.4ns | 0.492 | 0 | 0 | 3.18 KB |
Benchmarks.Trace.Iast.StringAspectsBenchmark - Same speed ✔️ More allocations ⚠️
More allocations ⚠️ in #7882
Benchmark
Base Allocated
Diff Allocated
Change
Change %
Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark‑net472
278.53 KB
286.72 KB
8.19 KB
2.94%
Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark‑netcoreapp3.1
273.14 KB
276.28 KB
3.14 KB
1.15%
Fewer allocations 🎉 in #7882
Benchmark
Base Allocated
Diff Allocated
Change
Change %
Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark‑net6.0
273.29 KB
257.51 KB
-15.78 KB
-5.77%
| Benchmark | Base Allocated | Diff Allocated | Change | Change % |
|---|---|---|---|---|
| Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark‑net472 | 278.53 KB | 286.72 KB | 8.19 KB | 2.94% |
| Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark‑netcoreapp3.1 | 273.14 KB | 276.28 KB | 3.14 KB | 1.15% |
| Benchmark | Base Allocated | Diff Allocated | Change | Change % |
|---|---|---|---|---|
| Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark‑net6.0 | 273.29 KB | 257.51 KB | -15.78 KB | -5.77% |
Raw results
| Branch | Method | Toolchain | Mean | StdError | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|---|---|---|---|---|---|---|---|---|---|
| master | StringConcatBenchmark |
net6.0 | 45μs | 304ns | 2.83μs | 0 | 0 | 0 | 43.78 KB |
| master | StringConcatBenchmark |
netcoreapp3.1 | 52.5μs | 503ns | 4.91μs | 0 | 0 | 0 | 43.09 KB |
| master | StringConcatBenchmark |
net472 | 57μs | 278ns | 1.15μs | 0 | 0 | 0 | 57.34 KB |
| master | StringConcatAspectBenchmark |
net6.0 | 460μs | 1.51μs | 8.01μs | 0 | 0 | 0 | 273.29 KB |
| master | StringConcatAspectBenchmark |
netcoreapp3.1 | 510μs | 2.39μs | 10.7μs | 0 | 0 | 0 | 273.14 KB |
| master | StringConcatAspectBenchmark |
net472 | 411μs | 1.98μs | 14.3μs | 0 | 0 | 0 | 278.53 KB |
| #7882 | StringConcatBenchmark |
net6.0 | 44.6μs | 236ns | 1.23μs | 0 | 0 | 0 | 43.64 KB |
| #7882 | StringConcatBenchmark |
netcoreapp3.1 | 49μs | 279ns | 1.93μs | 0 | 0 | 0 | 43.22 KB |
| #7882 | StringConcatBenchmark |
net472 | 56.2μs | 269ns | 1.04μs | 0 | 0 | 0 | 57.34 KB |
| #7882 | StringConcatAspectBenchmark |
net6.0 | 465μs | 2.21μs | 9.38μs | 0 | 0 | 0 | 257.51 KB |
| #7882 | StringConcatAspectBenchmark |
netcoreapp3.1 | 524μs | 1.3μs | 4.69μs | 0 | 0 | 0 | 276.28 KB |
| #7882 | StringConcatAspectBenchmark |
net472 | 400μs | 2.02μs | 9.25μs | 0 | 0 | 0 | 286.72 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.71μs | 13.2ns | 54.3ns | 0 | 0 | 0 | 1.7 KB |
| master | EnrichedLog |
netcoreapp3.1 | 3.62μs | 12.5ns | 48.5ns | 0 | 0 | 0 | 1.7 KB |
| master | EnrichedLog |
net472 | 3.95μs | 6.07ns | 23.5ns | 0.254 | 0 | 0 | 1.64 KB |
| #7882 | EnrichedLog |
net6.0 | 2.77μs | 7.87ns | 30.5ns | 0 | 0 | 0 | 1.7 KB |
| #7882 | EnrichedLog |
netcoreapp3.1 | 3.61μs | 12.1ns | 45.2ns | 0 | 0 | 0 | 1.7 KB |
| #7882 | EnrichedLog |
net472 | 3.9μs | 4.28ns | 16.6ns | 0.252 | 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 | 123μs | 78.6ns | 305ns | 0 | 0 | 0 | 4.31 KB |
| master | EnrichedLog |
netcoreapp3.1 | 126μs | 43ns | 161ns | 0 | 0 | 0 | 4.31 KB |
| master | EnrichedLog |
net472 | 165μs | 56.7ns | 204ns | 0 | 0 | 0 | 4.51 KB |
| #7882 | EnrichedLog |
net6.0 | 124μs | 73.6ns | 265ns | 0 | 0 | 0 | 4.31 KB |
| #7882 | EnrichedLog |
netcoreapp3.1 | 127μs | 185ns | 717ns | 0 | 0 | 0 | 4.31 KB |
| #7882 | EnrichedLog |
net472 | 167μs | 106ns | 410ns | 0 | 0 | 0 | 4.51 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.17μs | 21.3ns | 82.6ns | 0 | 0 | 0 | 2.26 KB |
| master | EnrichedLog |
netcoreapp3.1 | 7.06μs | 15.3ns | 57.1ns | 0 | 0 | 0 | 2.26 KB |
| master | EnrichedLog |
net472 | 7.73μs | 5.53ns | 21.4ns | 0.307 | 0 | 0 | 2.08 KB |
| #7882 | EnrichedLog |
net6.0 | 4.91μs | 4.08ns | 15.8ns | 0 | 0 | 0 | 2.26 KB |
| #7882 | EnrichedLog |
netcoreapp3.1 | 7.08μs | 19.8ns | 76.8ns | 0 | 0 | 0 | 2.26 KB |
| #7882 | EnrichedLog |
net472 | 7.64μs | 9.05ns | 35.1ns | 0.306 | 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 | 2.15μs | 1.92ns | 7.2ns | 0 | 0 | 0 | 1.2 KB |
| master | SendReceive |
netcoreapp3.1 | 2.65μs | 12.6ns | 52ns | 0 | 0 | 0 | 1.2 KB |
| master | SendReceive |
net472 | 3.11μs | 5.92ns | 22.9ns | 0.185 | 0 | 0 | 1.2 KB |
| #7882 | SendReceive |
net6.0 | 1.96μs | 10ns | 45.8ns | 0 | 0 | 0 | 1.2 KB |
| #7882 | SendReceive |
netcoreapp3.1 | 2.54μs | 12.6ns | 50.4ns | 0 | 0 | 0 | 1.2 KB |
| #7882 | SendReceive |
net472 | 3.25μs | 2.86ns | 11.1ns | 0.179 | 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.36μs | 11.4ns | 44.1ns | 0 | 0 | 0 | 1.58 KB |
| master | EnrichedLog |
netcoreapp3.1 | 5.82μs | 16.5ns | 64ns | 0 | 0 | 0 | 1.63 KB |
| master | EnrichedLog |
net472 | 6.56μs | 9.44ns | 36.5ns | 0.299 | 0 | 0 | 2.03 KB |
| #7882 | EnrichedLog |
net6.0 | 4.39μs | 16.2ns | 62.9ns | 0 | 0 | 0 | 1.58 KB |
| #7882 | EnrichedLog |
netcoreapp3.1 | 5.79μs | 7.22ns | 27ns | 0 | 0 | 0 | 1.63 KB |
| #7882 | EnrichedLog |
net472 | 6.62μs | 6.57ns | 25.4ns | 0.297 | 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 | 782ns | 3.87ns | 16.4ns | 0 | 0 | 0 | 576 B |
| master | StartFinishSpan |
netcoreapp3.1 | 984ns | 4.62ns | 17.9ns | 0 | 0 | 0 | 576 B |
| master | StartFinishSpan |
net472 | 917ns | 0.137ns | 0.514ns | 0.0879 | 0 | 0 | 578 B |
| master | StartFinishScope |
net6.0 | 932ns | 4.67ns | 20.9ns | 0 | 0 | 0 | 696 B |
| master | StartFinishScope |
netcoreapp3.1 | 1.17μs | 5.15ns | 19.3ns | 0 | 0 | 0 | 696 B |
| master | StartFinishScope |
net472 | 1.13μs | 0.23ns | 0.86ns | 0.102 | 0 | 0 | 658 B |
| master | StartFinishTwoScopes |
net6.0 | 1.73μs | 9.05ns | 43.4ns | 0 | 0 | 0 | 1.19 KB |
| master | StartFinishTwoScopes |
netcoreapp3.1 | 2.24μs | 11.4ns | 54.5ns | 0 | 0 | 0 | 1.19 KB |
| master | StartFinishTwoScopes |
net472 | 2.2μs | 1.84ns | 6.89ns | 0.166 | 0 | 0 | 1.08 KB |
| #7882 | StartFinishSpan |
net6.0 | 791ns | 3.02ns | 11.3ns | 0 | 0 | 0 | 576 B |
| #7882 | StartFinishSpan |
netcoreapp3.1 | 978ns | 4.83ns | 21.6ns | 0 | 0 | 0 | 576 B |
| #7882 | StartFinishSpan |
net472 | 908ns | 0.104ns | 0.389ns | 0.0908 | 0 | 0 | 578 B |
| #7882 | StartFinishScope |
net6.0 | 947ns | 0.651ns | 2.52ns | 0 | 0 | 0 | 696 B |
| #7882 | StartFinishScope |
netcoreapp3.1 | 1.17μs | 5.95ns | 27.9ns | 0 | 0 | 0 | 696 B |
| #7882 | StartFinishScope |
net472 | 1.11μs | 0.735ns | 2.85ns | 0.0996 | 0 | 0 | 658 B |
| #7882 | StartFinishTwoScopes |
net6.0 | 1.72μs | 9.39ns | 53.1ns | 0 | 0 | 0 | 1.19 KB |
| #7882 | StartFinishTwoScopes |
netcoreapp3.1 | 2.24μs | 11.2ns | 51.5ns | 0 | 0 | 0 | 1.19 KB |
| #7882 | StartFinishTwoScopes |
net472 | 2.17μs | 2.34ns | 9.05ns | 0.162 | 0 | 0 | 1.08 KB |
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.1μs | 1.17ns | 4.52ns | 0 | 0 | 0 | 696 B |
| master | RunOnMethodBegin |
netcoreapp3.1 | 1.42μs | 7.26ns | 33.3ns | 0 | 0 | 0 | 696 B |
| master | RunOnMethodBegin |
net472 | 1.43μs | 1.4ns | 5.43ns | 0.101 | 0 | 0 | 658 B |
| #7882 | RunOnMethodBegin |
net6.0 | 1.1μs | 5.36ns | 22.8ns | 0 | 0 | 0 | 696 B |
| #7882 | RunOnMethodBegin |
netcoreapp3.1 | 1.43μs | 6.73ns | 27.8ns | 0 | 0 | 0 | 696 B |
| #7882 | RunOnMethodBegin |
net472 | 1.44μs | 0.43ns | 1.67ns | 0.101 | 0 | 0 | 658 B |
tracer/test/benchmarks/Benchmarks.Trace/AgentWriterBenchmark.cs
Outdated
Show resolved
Hide resolved
…7884) ## Summary of changes - Fixes "incorrect" generated code from `TagsList` - Removes significant additional overhead during serialization - "Fix" vendored System.Buffers code to avoid the same issue ## Reason for change The current generated code for `TagsList` produces something like this: ```csharp private static ReadOnlySpan<byte> DbTypeBytes => new byte[] { 167, 100, 98, 46, 116, 121, 112, 101 }; ``` This _looks_ like it's allocating a new `byte[]` with every invocation, but the compiler actually optimizes this away to be completely zero-allocation, by embedding the array as part of the dll, and then simply returning a `ReadOnlySpan` wrapper pointing to this fixed data. You can see this if you look at the generated IL: ``` .method private hidebysig static specialname valuetype [System.Runtime]System.ReadOnlySpan`1<unsigned int8> get_DbTypeBytes() cil managed { .maxstack 8 // [20 58 - 20 109] IL_0000: ldsflda int64 '<PrivateImplementationDetails>'::A06A154BE3B860D0B56FA96C93523B732045BA0BCE2FFD4769109575CF1953BF IL_0005: ldc.i4.8 IL_0006: newobj instance void valuetype [System.Runtime]System.ReadOnlySpan`1<unsigned int8>::.ctor(void*, int32) IL_000b: ret } // end of method SqlTags::get_DbTypeBytes ``` However, in .NET Framework, even though we have vendored `ReadOnlySpan<T>` so we can get some of the benefits (mostly cleaner code), we _don't_ get these benefits. Which means that the above code _does_ generate a new array with every invocation: ``` .method private hidebysig static specialname valuetype Datadog.Trace.VendoredMicrosoftCode.System.ReadOnlySpan`1<unsigned int8> get_DbTypeBytes() cil managed { .maxstack 8 // [20 58 - 20 109] IL_0000: ldc.i4.8 IL_0001: newarr [netstandard]System.Byte IL_0006: dup IL_0007: ldtoken field int64 '<PrivateImplementationDetails>'::A06A154BE3B860D0B56FA96C93523B732045BA0BCE2FFD4769109575CF1953BF IL_000c: call void [netstandard]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [netstandard]System.Array, valuetype [netstandard]System.RuntimeFieldHandle) IL_0011: call valuetype Datadog.Trace.VendoredMicrosoftCode.System.ReadOnlySpan`1<!0/*unsigned int8*/> valuetype Datadog.Trace.VendoredMicrosoftCode.System.ReadOnlySpan`1<unsigned int8>::op_Implicit(!0/*unsigned int8*/[]) IL_0016: ret } // end of method SqlTags::get_DbTypeBytes ``` This is... Bad 😅 And it explains the _significant_ serialization overhead identified in #7882 for .NET Framework. I also confirmed this applies to all <.NET Core 3.1 too (because we compile for .NET Standard) | Method | Runtime | Mean | Allocated | Alloc Ratio | | -------------------------- | -------------------- | -------: | --------: | ----------: | | WriteEnrichedTraces_Before | .NET 6.0 | 488.9 us | 110 B | 0.001 | | WriteEnrichedTraces_Before | .NET Framework 4.7.2 | 703.3 us | 112537 B | 1.000 | | | | | | | | WriteEnrichedTraces_After | .NET 6.0 | 469.1 us | 105 B | 0.50 | | WriteEnrichedTraces_After | .NET Framework 4.7.2 | 703.4 us | 208 B | 1.00 | ## Implementation details The fix is to just do what we were doing before #5298 introduced this regression 😄 i.e. generate code like this: ```csharp #if NETCOREAPP private static ReadOnlySpan<byte> DbTypeBytes => new byte[] { 167, 100, 98, 46, 116, 121, 112, 101 }; #else private static readonly byte[] DbTypeBytes = new byte[] { 167, 100, 98, 46, 116, 121, 112, 101 #endif ``` ## Test coverage This is all covered by existing tests, and the new benchmark shows the improvment ## Other details I found a couple of other places in the vendored code that has the same issue, and fixed them directly in the code. However, this is not ideal, as if we re-vendor, we'll clobber these updates, so we'll need to update the vendoring code too
…7884) ## Summary of changes - Fixes "incorrect" generated code from `TagsList` - Removes significant additional overhead during serialization - "Fix" vendored System.Buffers code to avoid the same issue ## Reason for change The current generated code for `TagsList` produces something like this: ```csharp private static ReadOnlySpan<byte> DbTypeBytes => new byte[] { 167, 100, 98, 46, 116, 121, 112, 101 }; ``` This _looks_ like it's allocating a new `byte[]` with every invocation, but the compiler actually optimizes this away to be completely zero-allocation, by embedding the array as part of the dll, and then simply returning a `ReadOnlySpan` wrapper pointing to this fixed data. You can see this if you look at the generated IL: ``` .method private hidebysig static specialname valuetype [System.Runtime]System.ReadOnlySpan`1<unsigned int8> get_DbTypeBytes() cil managed { .maxstack 8 // [20 58 - 20 109] IL_0000: ldsflda int64 '<PrivateImplementationDetails>'::A06A154BE3B860D0B56FA96C93523B732045BA0BCE2FFD4769109575CF1953BF IL_0005: ldc.i4.8 IL_0006: newobj instance void valuetype [System.Runtime]System.ReadOnlySpan`1<unsigned int8>::.ctor(void*, int32) IL_000b: ret } // end of method SqlTags::get_DbTypeBytes ``` However, in .NET Framework, even though we have vendored `ReadOnlySpan<T>` so we can get some of the benefits (mostly cleaner code), we _don't_ get these benefits. Which means that the above code _does_ generate a new array with every invocation: ``` .method private hidebysig static specialname valuetype Datadog.Trace.VendoredMicrosoftCode.System.ReadOnlySpan`1<unsigned int8> get_DbTypeBytes() cil managed { .maxstack 8 // [20 58 - 20 109] IL_0000: ldc.i4.8 IL_0001: newarr [netstandard]System.Byte IL_0006: dup IL_0007: ldtoken field int64 '<PrivateImplementationDetails>'::A06A154BE3B860D0B56FA96C93523B732045BA0BCE2FFD4769109575CF1953BF IL_000c: call void [netstandard]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [netstandard]System.Array, valuetype [netstandard]System.RuntimeFieldHandle) IL_0011: call valuetype Datadog.Trace.VendoredMicrosoftCode.System.ReadOnlySpan`1<!0/*unsigned int8*/> valuetype Datadog.Trace.VendoredMicrosoftCode.System.ReadOnlySpan`1<unsigned int8>::op_Implicit(!0/*unsigned int8*/[]) IL_0016: ret } // end of method SqlTags::get_DbTypeBytes ``` This is... Bad 😅 And it explains the _significant_ serialization overhead identified in #7882 for .NET Framework. I also confirmed this applies to all <.NET Core 3.1 too (because we compile for .NET Standard) | Method | Runtime | Mean | Allocated | Alloc Ratio | | -------------------------- | -------------------- | -------: | --------: | ----------: | | WriteEnrichedTraces_Before | .NET 6.0 | 488.9 us | 110 B | 0.001 | | WriteEnrichedTraces_Before | .NET Framework 4.7.2 | 703.3 us | 112537 B | 1.000 | | | | | | | | WriteEnrichedTraces_After | .NET 6.0 | 469.1 us | 105 B | 0.50 | | WriteEnrichedTraces_After | .NET Framework 4.7.2 | 703.4 us | 208 B | 1.00 | ## Implementation details The fix is to just do what we were doing before #5298 introduced this regression 😄 i.e. generate code like this: ```csharp #if NETCOREAPP private static ReadOnlySpan<byte> DbTypeBytes => new byte[] { 167, 100, 98, 46, 116, 121, 112, 101 }; #else private static readonly byte[] DbTypeBytes = new byte[] { 167, 100, 98, 46, 116, 121, 112, 101 #endif ``` ## Test coverage This is all covered by existing tests, and the new benchmark shows the improvment ## Other details I found a couple of other places in the vendored code that has the same issue, and fixed them directly in the code. However, this is not ideal, as if we re-vendor, we'll clobber these updates, so we'll need to update the vendoring code too
Summary of changes
nullreference exception inAgentWriterbenchmark (introduced in Handle changes toMutableSettingsandExporterSettingswithout rebuilding #7724)Reason for change
The
AgentWriterbenchmark has been broken since #7724 was merged, as it's passing a null ref to a non-null field. This fixes that issue.Also, this adds a benchmark (which doesn't run in CI currently) which tests the serialization of spans without flushing, so we can distinguish the source of allocation more easily.
Finally, I made some changes to the spans used in the existing
AgentWriterbenchmark. This is due to discrepancies I noticed in the results from the benchmark vs other testing.Implementation details
StatsdManagerinto theAgentWriterinstead ofnullApiwhich doesn't do anything, and use that in a differentAgentWriterinstance, this effectively isolates the overhead in the benchmark to being the serialization only, instead of including "flush" related overhead (which is included in the existing benchmark). To avoid bloating our benchmarking runs, don't bother to run this one in CI (it's just useful for inestigation).SqlTagsobject into the spans, with a couple of fields set.envon the spans.envis a "special" trace-level tag, so it doesn't really do what you think it does here and IMO is less revealing.Test coverage
Tested locally - running the benchmarks without the sql tags change:
I then made the
SqlTagschange, and ran again:Yikes, we have some rogue allocation there on .NET FX!
Other details