-
Notifications
You must be signed in to change notification settings - Fork 151
Create System.Diagnostics.Metrics-based runtime metrics listener
#8027
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
System.Diagnostics.Metrics-based runtime metrics listener
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
tracer/test/benchmarks/Benchmarks.Trace/TelemetryHttpClientBenchmark.cs
Outdated
Show resolved
Hide resolved
… RuntimeEventListener
94ffd7d to
fc47fb8
Compare
This comment has been minimized.
This comment has been minimized.
Execution-Time Benchmarks Report ⏱️Execution-time results for samples comparing This PR (8027) and master.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Metric | Master (Mean ± 95% CI) | Current (Mean ± 95% CI) | Change | Status |
|---|---|---|---|---|
| .NET Framework 4.8 - Baseline | ||||
| duration | 68.36 ± (68.32 - 68.55) ms | 75.56 ± (75.52 - 75.93) ms | +10.5% | ❌⬆️ |
| .NET Framework 4.8 - Bailout | ||||
| duration | 72.25 ± (72.18 - 72.41) ms | 79.36 ± (79.27 - 79.72) ms | +9.8% | ❌⬆️ |
| .NET Framework 4.8 - CallTarget+Inlining+NGEN | ||||
| duration | 1002.07 ± (1005.27 - 1011.80) ms | 1067.30 ± (1068.98 - 1078.53) ms | +6.5% | ❌⬆️ |
Full Metrics Comparison
FakeDbCommand
| Metric | Master (Mean ± 95% CI) | Current (Mean ± 95% CI) | Change | Status |
|---|---|---|---|---|
| .NET Framework 4.8 - Baseline | ||||
| duration | 68.36 ± (68.32 - 68.55) ms | 75.56 ± (75.52 - 75.93) ms | +10.5% | ❌⬆️ |
| .NET Framework 4.8 - Bailout | ||||
| duration | 72.25 ± (72.18 - 72.41) ms | 79.36 ± (79.27 - 79.72) ms | +9.8% | ❌⬆️ |
| .NET Framework 4.8 - CallTarget+Inlining+NGEN | ||||
| duration | 1002.07 ± (1005.27 - 1011.80) ms | 1067.30 ± (1068.98 - 1078.53) ms | +6.5% | ❌⬆️ |
| .NET Core 3.1 - Baseline | ||||
| process.internal_duration_ms | 21.98 ± (21.94 - 22.01) ms | 23.01 ± (22.97 - 23.05) ms | +4.7% | ✅⬆️ |
| process.time_to_main_ms | 78.54 ± (78.42 - 78.67) ms | 87.11 ± (86.89 - 87.34) ms | +10.9% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 0 ± (0 - 0) | 0 ± (0 - 0) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 10.90 ± (10.90 - 10.91) MB | 10.90 ± (10.89 - 10.90) MB | -0.1% | ✅ |
| runtime.dotnet.threads.count | 12 ± (12 - 12) | 12 ± (12 - 12) | +0.0% | ✅ |
| .NET Core 3.1 - Bailout | ||||
| process.internal_duration_ms | 21.80 ± (21.78 - 21.81) ms | 23.18 ± (23.11 - 23.25) ms | +6.3% | ✅⬆️ |
| process.time_to_main_ms | 79.60 ± (79.52 - 79.68) ms | 88.80 ± (88.59 - 89.01) ms | +11.6% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 0 ± (0 - 0) | 0 ± (0 - 0) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 10.96 ± (10.95 - 10.96) MB | 10.94 ± (10.93 - 10.94) MB | -0.2% | ✅ |
| runtime.dotnet.threads.count | 13 ± (13 - 13) | 13 ± (13 - 13) | +0.0% | ✅ |
| .NET Core 3.1 - CallTarget+Inlining+NGEN | ||||
| process.internal_duration_ms | 254.89 ± (251.24 - 258.55) ms | 264.39 ± (260.23 - 268.54) ms | +3.7% | ✅⬆️ |
| process.time_to_main_ms | 470.66 ± (470.13 - 471.19) ms | 503.28 ± (502.37 - 504.19) ms | +6.9% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 0 ± (0 - 0) | 0 ± (0 - 0) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 48.23 ± (48.21 - 48.25) MB | 48.26 ± (48.24 - 48.28) MB | +0.1% | ✅⬆️ |
| runtime.dotnet.threads.count | 28 ± (28 - 28) | 28 ± (28 - 28) | -0.0% | ✅ |
| .NET 6 - Baseline | ||||
| process.internal_duration_ms | 20.64 ± (20.61 - 20.66) ms | 21.67 ± (21.63 - 21.72) ms | +5.0% | ✅⬆️ |
| process.time_to_main_ms | 68.21 ± (68.08 - 68.34) ms | 75.05 ± (74.88 - 75.21) ms | +10.0% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 0 ± (0 - 0) | 0 ± (0 - 0) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 10.61 ± (10.60 - 10.61) MB | 10.64 ± (10.64 - 10.65) MB | +0.4% | ✅⬆️ |
| runtime.dotnet.threads.count | 10 ± (10 - 10) | 10 ± (10 - 10) | +0.0% | ✅ |
| .NET 6 - Bailout | ||||
| process.internal_duration_ms | 20.58 ± (20.56 - 20.60) ms | 21.56 ± (21.51 - 21.61) ms | +4.8% | ✅⬆️ |
| process.time_to_main_ms | 68.92 ± (68.87 - 68.98) ms | 76.19 ± (76.02 - 76.36) ms | +10.5% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 0 ± (0 - 0) | 0 ± (0 - 0) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 10.66 ± (10.65 - 10.66) MB | 10.74 ± (10.73 - 10.74) MB | +0.7% | ✅⬆️ |
| runtime.dotnet.threads.count | 11 ± (11 - 11) | 11 ± (11 - 11) | +0.0% | ✅ |
| .NET 6 - CallTarget+Inlining+NGEN | ||||
| process.internal_duration_ms | 245.69 ± (244.37 - 247.01) ms | 255.50 ± (252.50 - 258.50) ms | +4.0% | ✅⬆️ |
| process.time_to_main_ms | 439.84 ± (439.33 - 440.36) ms | 468.24 ± (467.51 - 468.97) ms | +6.5% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 0 ± (0 - 0) | 0 ± (0 - 0) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 48.63 ± (48.60 - 48.67) MB | 48.63 ± (48.61 - 48.65) MB | -0.0% | ✅ |
| runtime.dotnet.threads.count | 28 ± (28 - 28) | 28 ± (28 - 28) | +0.0% | ✅⬆️ |
| .NET 8 - Baseline | ||||
| process.internal_duration_ms | 18.90 ± (18.86 - 18.94) ms | 19.84 ± (19.80 - 19.87) ms | +5.0% | ✅⬆️ |
| process.time_to_main_ms | 67.30 ± (67.19 - 67.41) ms | 75.14 ± (74.94 - 75.34) ms | +11.7% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 0 ± (0 - 0) | 0 ± (0 - 0) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 7.67 ± (7.67 - 7.68) MB | 7.66 ± (7.66 - 7.67) MB | -0.2% | ✅ |
| runtime.dotnet.threads.count | 10 ± (10 - 10) | 10 ± (10 - 10) | +0.0% | ✅ |
| .NET 8 - Bailout | ||||
| process.internal_duration_ms | 18.88 ± (18.85 - 18.91) ms | 19.72 ± (19.67 - 19.77) ms | +4.5% | ✅⬆️ |
| process.time_to_main_ms | 68.06 ± (68.01 - 68.11) ms | 75.06 ± (74.91 - 75.21) ms | +10.3% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 0 ± (0 - 0) | 0 ± (0 - 0) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 7.73 ± (7.73 - 7.74) MB | 7.72 ± (7.71 - 7.73) MB | -0.2% | ✅ |
| runtime.dotnet.threads.count | 11 ± (11 - 11) | 11 ± (11 - 11) | +0.0% | ✅ |
| .NET 8 - CallTarget+Inlining+NGEN | ||||
| process.internal_duration_ms | 178.09 ± (177.13 - 179.05) ms | 189.37 ± (188.58 - 190.17) ms | +6.3% | ✅⬆️ |
| process.time_to_main_ms | 424.97 ± (424.37 - 425.57) ms | 451.45 ± (450.71 - 452.20) ms | +6.2% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 0 ± (0 - 0) | 0 ± (0 - 0) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 36.32 ± (36.28 - 36.35) MB | 36.49 ± (36.45 - 36.52) MB | +0.5% | ✅⬆️ |
| runtime.dotnet.threads.count | 27 ± (27 - 27) | 27 ± (27 - 27) | +0.1% | ✅⬆️ |
HttpMessageHandler
| Metric | Master (Mean ± 95% CI) | Current (Mean ± 95% CI) | Change | Status |
|---|---|---|---|---|
| .NET Framework 4.8 - Baseline | ||||
| duration | 192.13 ± (192.26 - 193.23) ms | 193.69 ± (193.87 - 194.75) ms | +0.8% | ✅⬆️ |
| .NET Framework 4.8 - Bailout | ||||
| duration | 195.68 ± (195.56 - 196.08) ms | 197.46 ± (197.21 - 197.74) ms | +0.9% | ✅⬆️ |
| .NET Framework 4.8 - CallTarget+Inlining+NGEN | ||||
| duration | 1102.19 ± (1107.71 - 1116.85) ms | 1107.55 ± (1111.44 - 1119.40) ms | +0.5% | ✅⬆️ |
| .NET Core 3.1 - Baseline | ||||
| process.internal_duration_ms | 187.25 ± (186.83 - 187.68) ms | 188.16 ± (187.74 - 188.59) ms | +0.5% | ✅⬆️ |
| process.time_to_main_ms | 80.24 ± (80.03 - 80.45) ms | 81.29 ± (81.02 - 81.55) ms | +1.3% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 3 ± (3 - 3) | 3 ± (3 - 3) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 16.09 ± (16.06 - 16.11) MB | 16.16 ± (16.13 - 16.19) MB | +0.5% | ✅⬆️ |
| runtime.dotnet.threads.count | 20 ± (19 - 20) | 20 ± (20 - 20) | +0.8% | ✅⬆️ |
| .NET Core 3.1 - Bailout | ||||
| process.internal_duration_ms | 185.91 ± (185.64 - 186.18) ms | 187.65 ± (187.38 - 187.92) ms | +0.9% | ✅⬆️ |
| process.time_to_main_ms | 81.30 ± (81.17 - 81.43) ms | 82.18 ± (82.05 - 82.32) ms | +1.1% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 3 ± (3 - 3) | 3 ± (3 - 3) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 16.22 ± (16.19 - 16.25) MB | 16.17 ± (16.13 - 16.21) MB | -0.3% | ✅ |
| runtime.dotnet.threads.count | 20 ± (20 - 21) | 21 ± (21 - 21) | +1.8% | ✅⬆️ |
| .NET Core 3.1 - CallTarget+Inlining+NGEN | ||||
| process.internal_duration_ms | 425.50 ± (422.53 - 428.47) ms | 423.65 ± (420.01 - 427.29) ms | -0.4% | ✅ |
| process.time_to_main_ms | 471.46 ± (470.91 - 472.01) ms | 474.04 ± (473.49 - 474.59) ms | +0.5% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 3 ± (3 - 3) | 3 ± (3 - 3) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 58.62 ± (58.50 - 58.74) MB | 58.60 ± (58.47 - 58.73) MB | -0.0% | ✅ |
| runtime.dotnet.threads.count | 29 ± (29 - 30) | 29 ± (29 - 30) | +0.1% | ✅⬆️ |
| .NET 6 - Baseline | ||||
| process.internal_duration_ms | 190.33 ± (190.04 - 190.62) ms | 192.33 ± (191.90 - 192.75) ms | +1.0% | ✅⬆️ |
| process.time_to_main_ms | 69.50 ± (69.35 - 69.65) ms | 69.87 ± (69.71 - 70.02) ms | +0.5% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 4 ± (4 - 4) | 4 ± (4 - 4) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 16.05 ± (15.90 - 16.21) MB | 16.44 ± (16.40 - 16.47) MB | +2.4% | ✅⬆️ |
| runtime.dotnet.threads.count | 18 ± (18 - 18) | 19 ± (19 - 19) | +4.2% | ✅⬆️ |
| .NET 6 - Bailout | ||||
| process.internal_duration_ms | 190.42 ± (190.10 - 190.74) ms | 191.33 ± (191.02 - 191.63) ms | +0.5% | ✅⬆️ |
| process.time_to_main_ms | 70.52 ± (70.41 - 70.62) ms | 70.77 ± (70.69 - 70.84) ms | +0.4% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 4 ± (4 - 4) | 4 ± (4 - 4) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 15.80 ± (15.63 - 15.96) MB | 15.98 ± (15.82 - 16.14) MB | +1.2% | ✅⬆️ |
| runtime.dotnet.threads.count | 19 ± (19 - 19) | 19 ± (19 - 19) | +0.7% | ✅⬆️ |
| .NET 6 - CallTarget+Inlining+NGEN | ||||
| process.internal_duration_ms | 453.30 ± (451.34 - 455.26) ms | 457.52 ± (455.48 - 459.57) ms | +0.9% | ✅⬆️ |
| process.time_to_main_ms | 442.29 ± (441.85 - 442.73) ms | 447.84 ± (447.10 - 448.57) ms | +1.3% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 4 ± (4 - 4) | 4 ± (4 - 4) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 58.33 ± (58.22 - 58.44) MB | 58.27 ± (58.14 - 58.40) MB | -0.1% | ✅ |
| runtime.dotnet.threads.count | 29 ± (29 - 30) | 30 ± (30 - 30) | +0.2% | ✅⬆️ |
| .NET 8 - Baseline | ||||
| process.internal_duration_ms | 188.83 ± (188.54 - 189.12) ms | 190.39 ± (190.07 - 190.71) ms | +0.8% | ✅⬆️ |
| process.time_to_main_ms | 68.70 ± (68.56 - 68.84) ms | 69.78 ± (69.61 - 69.96) ms | +1.6% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 4 ± (4 - 4) | 4 ± (4 - 4) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 11.75 ± (11.72 - 11.78) MB | 11.77 ± (11.73 - 11.80) MB | +0.2% | ✅⬆️ |
| runtime.dotnet.threads.count | 18 ± (18 - 18) | 18 ± (18 - 18) | +0.4% | ✅⬆️ |
| .NET 8 - Bailout | ||||
| process.internal_duration_ms | 188.42 ± (188.14 - 188.70) ms | 189.59 ± (189.27 - 189.91) ms | +0.6% | ✅⬆️ |
| process.time_to_main_ms | 70.05 ± (69.94 - 70.17) ms | 70.73 ± (70.61 - 70.84) ms | +1.0% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 4 ± (4 - 4) | 4 ± (4 - 4) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 11.77 ± (11.70 - 11.85) MB | 11.82 ± (11.79 - 11.85) MB | +0.4% | ✅⬆️ |
| runtime.dotnet.threads.count | 19 ± (18 - 19) | 19 ± (19 - 19) | +2.5% | ✅⬆️ |
| .NET 8 - CallTarget+Inlining+NGEN | ||||
| process.internal_duration_ms | 361.30 ± (359.81 - 362.79) ms | 364.79 ± (363.20 - 366.39) ms | +1.0% | ✅⬆️ |
| process.time_to_main_ms | 424.87 ± (424.35 - 425.40) ms | 430.02 ± (429.46 - 430.57) ms | +1.2% | ✅⬆️ |
| runtime.dotnet.exceptions.count | 4 ± (4 - 4) | 4 ± (4 - 4) | +0.0% | ✅ |
| runtime.dotnet.mem.committed | 47.94 ± (47.91 - 47.97) MB | 48.03 ± (48.00 - 48.06) MB | +0.2% | ✅⬆️ |
| runtime.dotnet.threads.count | 29 ± (29 - 29) | 29 ± (29 - 29) | +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 (8027) - mean (76ms) : 73, 79
master - mean (68ms) : 67, 70
section Bailout
This PR (8027) - mean (79ms) : crit, 77, 82
master - mean (72ms) : 71, 73
section CallTarget+Inlining+NGEN
This PR (8027) - mean (1,074ms) : crit, 1004, 1143
master - mean (1,009ms) : 961, 1057
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 (8027) - mean (117ms) : 114, 121
master - mean (106ms) : 103, 108
section Bailout
This PR (8027) - mean (119ms) : crit, 116, 122
master - mean (106ms) : 105, 108
section CallTarget+Inlining+NGEN
This PR (8027) - mean (800ms) : crit, 734, 867
master - mean (750ms) : 694, 805
FakeDbCommand (.NET 6)
gantt
title Execution time (ms) FakeDbCommand (.NET 6)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8027) - mean (103ms) : 100, 106
master - mean (94ms) : 91, 96
section Bailout
This PR (8027) - mean (104ms) : crit, 102, 107
master - mean (94ms) : 93, 95
section CallTarget+Inlining+NGEN
This PR (8027) - mean (755ms) : crit, 705, 805
master - mean (709ms) : 685, 734
FakeDbCommand (.NET 8)
gantt
title Execution time (ms) FakeDbCommand (.NET 8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8027) - mean (103ms) : 99, 107
master - mean (92ms) : 90, 94
section Bailout
This PR (8027) - mean (103ms) : crit, 101, 104
master - mean (93ms) : 92, 94
section CallTarget+Inlining+NGEN
This PR (8027) - mean (670ms) : crit, 647, 692
master - mean (631ms) : 616, 646
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 (8027) - mean (194ms) : 190, 199
master - mean (193ms) : 188, 198
section Bailout
This PR (8027) - mean (197ms) : 195, 200
master - mean (196ms) : 193, 198
section CallTarget+Inlining+NGEN
This PR (8027) - mean (1,115ms) : 1058, 1173
master - mean (1,112ms) : 1046, 1179
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 (8027) - mean (278ms) : 273, 283
master - mean (276ms) : 271, 281
section Bailout
This PR (8027) - mean (278ms) : 274, 282
master - mean (275ms) : 272, 279
section CallTarget+Inlining+NGEN
This PR (8027) - mean (928ms) : 878, 978
master - mean (926ms) : 881, 970
HttpMessageHandler (.NET 6)
gantt
title Execution time (ms) HttpMessageHandler (.NET 6)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8027) - mean (271ms) : 265, 276
master - mean (268ms) : 263, 273
section Bailout
This PR (8027) - mean (270ms) : 266, 274
master - mean (269ms) : 264, 274
section CallTarget+Inlining+NGEN
This PR (8027) - mean (932ms) : 892, 972
master - mean (925ms) : 893, 957
HttpMessageHandler (.NET 8)
gantt
title Execution time (ms) HttpMessageHandler (.NET 8)
dateFormat x
axisFormat %Q
todayMarker off
section Baseline
This PR (8027) - mean (270ms) : 266, 274
master - mean (267ms) : 263, 272
section Bailout
This PR (8027) - mean (270ms) : 266, 273
master - mean (268ms) : 263, 273
section CallTarget+Inlining+NGEN
This PR (8027) - mean (825ms) : 801, 850
master - mean (816ms) : 798, 834
BenchmarksBenchmark execution time: 2026-01-09 14:47:44 Comparing candidate commit bc8f4cf in PR branch Found 9 performance improvements and 9 performance regressions! Performance is the same for 153 metrics, 15 unstable metrics. scenario:Benchmarks.Trace.ActivityBenchmark.StartStopWithChild net472
scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleMoreComplexBody net472
scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleSimpleBody net6.0
scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleSimpleBody netcoreapp3.1
scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorSimpleBody net6.0
scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorSimpleBody netcoreapp3.1
scenario:Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark.WriteAndFlushEnrichedTraces net472
scenario:Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark.WriteAndFlushEnrichedTraces net6.0
scenario:Benchmarks.Trace.CharSliceBenchmark.OriginalCharSlice net6.0
scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark net6.0
scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark netcoreapp3.1
scenario:Benchmarks.Trace.Log4netBenchmark.EnrichedLog netcoreapp3.1
scenario:Benchmarks.Trace.SerilogBenchmark.EnrichedLog netcoreapp3.1
scenario:Benchmarks.Trace.SpanBenchmark.StartFinishSpan netcoreapp3.1
scenario:Benchmarks.Trace.SpanBenchmark.StartFinishTwoScopes net6.0
scenario:Benchmarks.Trace.SpanBenchmark.StartFinishTwoScopes netcoreapp3.1
scenario:Benchmarks.Trace.TraceAnnotationsBenchmark.RunOnMethodBegin net6.0
|
tracer/test/Datadog.Trace.Tests/RuntimeMetrics/DiagnosticMetricsRuntimeMetricsListenerTests.cs
Outdated
Show resolved
Hide resolved
tracer/src/Datadog.Trace/RuntimeMetrics/DiagnosticsMetricsRuntimeMetricsListener.cs
Outdated
Show resolved
Hide resolved
tracer/src/Datadog.Trace/RuntimeMetrics/DiagnosticsMetricsRuntimeMetricsListener.cs
Outdated
Show resolved
Hide resolved
tracer/src/Datadog.Trace/RuntimeMetrics/DiagnosticsMetricsRuntimeMetricsListener.cs
Outdated
Show resolved
Hide resolved
tracer/src/Datadog.Trace/RuntimeMetrics/DiagnosticsMetricsRuntimeMetricsListener.cs
Show resolved
Hide resolved
tracer/src/Datadog.Trace/RuntimeMetrics/DiagnosticsMetricsRuntimeMetricsListener.cs
Show resolved
Hide resolved
tracer/src/Datadog.Trace/RuntimeMetrics/DiagnosticsMetricsRuntimeMetricsListener.cs
Show resolved
Hide resolved
tracer/src/Datadog.Trace/RuntimeMetrics/DiagnosticsMetricsRuntimeMetricsListener.cs
Show resolved
Hide resolved
tracer/src/Datadog.Trace/RuntimeMetrics/DiagnosticsMetricsRuntimeMetricsListener.cs
Outdated
Show resolved
Hide resolved
tracer/src/Datadog.Trace/RuntimeMetrics/DiagnosticsMetricsRuntimeMetricsListener.cs
Outdated
Show resolved
Hide resolved
Co-authored-by: Steven Bouwkamp <steven.bouwkamp@datadoghq.com>
Summary of changes
Creates a .NET 6+ only implementation of
IRuntimeMetricsListenerthat uses theSystem.Diagnostics.Metrics(and other) APIsReason for change
.NET Core (probably all versions, but at least .NET 6+) has a memory leak with the event pipes, which means if we enable runtime metrics, we likely have a slow memory leak 😬 This was raised ~1 year ago with .NET team, specifically citing dd-trace-dotnet. but doesn't have a fix yet. Also a PR has been open on the .NET repo with a tentative fix for ~2 months, so at best this might be fixed in .NET 11.
Separately, the
System.Diagnostics.MetricsAPIs were introduced in .NET 6, with support for aspnetcore-based metrics added in .NET 8, and support for "runtime" metrics in .NET 9.This PR introduces a new (experimental for now)
IRuntimeMetricsListenerimplementation that doesn't useEventListener, and instead uses theSystem.Diagnostics.MetricsAPIs, aiming to provide essentially the same runtime metrics we currently do, just using a different source.Implementation details
IRuntimeMetricsListenerimplementation,DiagnosticsMetricsRuntimeMetricsListenerDD_RUNTIME_METRICS_DIAGNOSTICS_METRICS_API_ENABLEDTo give as wide compatibility as possible, and to avoid any additional overhead, whenever the built-in runtime metrics use existing APIs (e.g. via
GCcalls), we use those instead of the metrics.In summary:
Thread metrics:
runtime.dotnet.threads.workers_count: viaThreadPool.ThreadCount(same asRuntimeEventListener)runtime.dotnet.threads.contention_count: viaMonitor.LockContentionCount`GC metrics:
runtime.dotnet.gc.size.gen#from info inGC.GetGCMemoryInfo(), which mirrors the built-in approach.runtime.dotnet.gc.memory_loadwas a tricky one as the built-in uses a new API, but I think the info we get inGC.GetGCMemoryInfo()is broadly good enoughruntime.dotnet.gc.count.gen#usesGC.CollectionCount(), same as built-in approachruntime.dotnet.gc.pause_timethis was also a tricky one, more on it below...runtime.dotnet.gc.pause_timeis a runtime metric that's available in .NET 9, so when we're running in .NET 9 we just use that value. There's actually also a public API introduce in .NET 6,GetTotalPauseDuration(), but it's only available from 6.0.21, so we can't directly reference it. Resorted to using a simpleCreateDelegatecall to invoke it in these cases. We could use duck typing, but didn't seem worth it. If we're running < 6.0.21, there's no feasible way to get the value, so we just don't emit it.ASP.NET Core metrics:
runtime.dotnet.aspnetcore.requests.currentruntime.dotnet.aspnetcore.requests.failedruntime.dotnet.aspnetcore.requests.totalruntime.dotnet.aspnetcore.requests.queue_lengthruntime.dotnet.aspnetcore.connections.currentruntime.dotnet.aspnetcore.connections.queue_lengthruntime.dotnet.aspnetcore.connections.totalNote that the
.totaland.failedrequests are recorded as gauges (which monotonically increase), which doesn't feel right to me (they should be counters, surely), but that's whatRuntimeEventListeneris using, so we have to stick to the same thing (metric types are global by metric, so we can't change it). It means there's a risk of overflow there, but that's already the case forRuntimeEventListenerso I guess we just ignore it 🤷♂️I couldn't find a way to get the following metrics at all without using
EventListener:runtime.dotnet.threads.contention_timeTest coverage
Added unit and integration tests for the listener behavior.
I also manually ran an aspnetcore app in a loop with both the
RuntimeEventListenerand the new listener producing metrics (hacked in, we wont ever do this in "normal" execution), and did a manual comparison of the metrics. Overall, the values were in broad agreement (slightly off, due to skew in sampling time) and helped identify some cases where I'd made incorrect assumptions (e.g. aspnetcore.totalmetrics are never "reset" to 0.Other details
Relates to: