Skip to content

fix(profiler): five native profiler bug fixes#8533

Merged
r1viollet merged 7 commits into
masterfrom
r1viollet/profiler-bug-fixes-followup
Apr 29, 2026
Merged

fix(profiler): five native profiler bug fixes#8533
r1viollet merged 7 commits into
masterfrom
r1viollet/profiler-bug-fixes-followup

Conversation

@r1viollet

@r1viollet r1viollet commented Apr 28, 2026

Copy link
Copy Markdown
Collaborator

Five correctness bugs found by static analysis of the native profiler.

AdaptiveSampler: volatilestd::atomic
_probability and _samplesBudget were volatile but written by the timer thread and read concurrently by Sample(). No memory-model guarantees; TSAN-visible data race, torn reads on ARM64.

ProfilerSignalManager: atomic _handler + DCL fix
_handler was a plain pointer read from the signal handler thread (in CallCustomHandler) without any lock — a data race. Made std::atomic<HandlerFn_t> with acquire/release ordering.
Also fixed the double-checked locking: the inner guard after acquiring the mutex was checking a stale pre-lock local instead of re-reading _handler, allowing two racing threads to both call SetupSignalHandler() and corrupt _previousAction.

ContentionProvider: atomic failureCount + always drop empty-stack samples
failureCount was a non-atomic static local incremented from concurrent CLR callback threads. Also: the empty-stack early-return was gated on failureCount % 1000 == 0, so 999 out of every 1000 empty-stack failures fell through and emitted a corrupt zero-frame sample. The return is now unconditional; only the log is rate-limited.

ManagedCodeCache: skip zero-size code ranges
GetCodeInfo2 entries with size == 0 produced endAddress = startAddress - 1 (underflow). For startAddress == 0 this gives endAddress = UINTPTR_MAX and the page-insertion loop runs forever, hanging the background worker. Guard added; JIT callbacks also now check SUCCEEDED(hrStatus) before calling AddFunction.

@r1viollet
r1viollet requested a review from a team as a code owner April 28, 2026 12:21
@pr-commenter

pr-commenter Bot commented Apr 28, 2026

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-04-29 16:33:57

Comparing candidate commit 3149a14 in PR branch r1viollet/profiler-bug-fixes-followup with baseline commit bc123ee in branch master.

Found 0 performance improvements and 0 performance regressions! Performance is the same for 27 metrics, 0 unstable metrics, 59 known flaky benchmarks, 28 flaky benchmarks without significant changes.

Explanation

This is an A/B test comparing a candidate commit's performance against that of a baseline commit. Performance changes are noted in the tables below as:

  • 🟩 = significantly better candidate vs. baseline
  • 🟥 = significantly worse candidate vs. baseline

We compute a confidence interval (CI) over the relative difference of means between metrics from the candidate and baseline commits, considering the baseline as the reference.

If the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD), the change is considered significant.

Feel free to reach out to #apm-benchmarking-platform on Slack if you have any questions.

More details about the CI and significant changes

You can imagine this CI as a range of values that is likely to contain the true difference of means between the candidate and baseline commits.

CIs of the difference of means are often centered around 0%, because often changes are not that big:

---------------------------------(------|---^--------)-------------------------------->
                              -0.6%    0%  0.3%     +1.2%
                                 |          |        |
         lower bound of the CI --'          |        |
sample mean (center of the CI) -------------'        |
         upper bound of the CI ----------------------'

As described above, a change is considered significant if the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD).

For instance, for an execution time metric, this confidence interval indicates a significantly worse performance:

----------------------------------------|---------|---(---------^---------)---------->
                                       0%        1%  1.3%      2.2%      3.1%
                                                  |   |         |         |
       significant impact threshold --------------'   |         |         |
                      lower bound of CI --------------'         |         |
       sample mean (center of the CI) --------------------------'         |
                      upper bound of CI ----------------------------------'

Known flaky benchmarks

These benchmarks are marked as flaky and will not trigger a failure. Modify FLAKY_BENCHMARKS_REGEX to control which benchmarks are marked as flaky.

scenario:Benchmarks.Trace.ActivityBenchmark.StartStopWithChild net6.0

  • 🟩 throughput [+8325.852op/s; +10858.802op/s] or [+6.998%; +9.127%]

scenario:Benchmarks.Trace.AgentWriterBenchmark.WriteAndFlushEnrichedTraces net472

  • 🟥 execution_time [+303.151ms; +308.714ms] or [+150.434%; +153.195%]
  • 🟥 throughput [-43.681op/s; -40.056op/s] or [-7.859%; -7.207%]

scenario:Benchmarks.Trace.AgentWriterBenchmark.WriteAndFlushEnrichedTraces net6.0

  • 🟥 execution_time [+376.589ms; +378.121ms] or [+297.528%; +298.739%]
  • 🟩 throughput [+100.207op/s; +103.800op/s] or [+13.212%; +13.686%]

scenario:Benchmarks.Trace.AgentWriterBenchmark.WriteAndFlushEnrichedTraces netcoreapp3.1

  • 🟥 execution_time [+392.374ms; +395.744ms] or [+347.236%; +350.218%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleMoreComplexBody net472

  • 🟥 allocated_mem [+1.308KB; +1.308KB] or [+27.529%; +27.541%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleMoreComplexBody net6.0

  • 🟥 allocated_mem [+471 bytes; +472 bytes] or [+9.977%; +9.987%]
  • 🟩 execution_time [-15.598ms; -11.428ms] or [-7.285%; -5.337%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleMoreComplexBody netcoreapp3.1

  • 🟥 allocated_mem [+1.272KB; +1.272KB] or [+27.502%; +27.510%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleSimpleBody net472

  • 🟥 allocated_mem [+1.307KB; +1.307KB] or [+105.746%; +105.759%]
  • 🟥 throughput [-272556.146op/s; -267924.460op/s] or [-27.829%; -27.356%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleSimpleBody net6.0

  • 🟥 allocated_mem [+471 bytes; +472 bytes] or [+38.558%; +38.566%]
  • 🟩 execution_time [-25.779ms; -20.914ms] or [-11.496%; -9.327%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleSimpleBody netcoreapp3.1

  • 🟥 allocated_mem [+1.272KB; +1.272KB] or [+105.292%; +105.304%]
  • 🟥 throughput [-136850.163op/s; -120483.536op/s] or [-19.663%; -17.311%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorMoreComplexBody net6.0

  • 🟩 throughput [+8718.446op/s; +11681.325op/s] or [+5.547%; +7.433%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorMoreComplexBody netcoreapp3.1

  • 🟩 throughput [+6861.944op/s; +9501.305op/s] or [+5.466%; +7.569%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorSimpleBody net6.0

  • 🟩 throughput [+368005.869op/s; +387209.392op/s] or [+12.271%; +12.911%]

scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorSimpleBody netcoreapp3.1

  • 🟩 execution_time [-18.790ms; -14.439ms] or [-8.661%; -6.656%]
  • 🟩 throughput [+204062.783op/s; +257954.498op/s] or [+8.100%; +10.239%]

scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeArgs net472

  • 🟥 execution_time [+299.683ms; +300.302ms] or [+149.742%; +150.051%]

scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeArgs net6.0

  • 🟥 execution_time [+299.501ms; +302.955ms] or [+151.039%; +152.781%]

scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeArgs netcoreapp3.1

  • 🟥 execution_time [+300.116ms; +302.740ms] or [+151.175%; +152.497%]

scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeLegacyArgs net472

  • 🟥 execution_time [+296.017ms; +296.880ms] or [+145.392%; +145.816%]

scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeLegacyArgs net6.0

  • 🟥 execution_time [+292.597ms; +295.614ms] or [+143.040%; +144.515%]

scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeLegacyArgs netcoreapp3.1

  • 🟥 execution_time [+301.986ms; +303.124ms] or [+150.932%; +151.501%]

scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmarkWithAttack net6.0

  • 🟥 execution_time [+22.828µs; +46.449µs] or [+7.288%; +14.829%]
  • 🟥 throughput [-431.922op/s; -233.169op/s] or [-13.464%; -7.269%]

scenario:Benchmarks.Trace.AspNetCoreBenchmark.SendRequest net472

  • 🟥 execution_time [+299.681ms; +300.408ms] or [+149.572%; +149.935%]

scenario:Benchmarks.Trace.AspNetCoreBenchmark.SendRequest net6.0

  • 🟥 execution_time [+410.810ms; +415.492ms] or [+446.362%; +451.449%]
  • 🟩 throughput [+1101.845op/s; +1235.173op/s] or [+9.054%; +10.150%]

scenario:Benchmarks.Trace.AspNetCoreBenchmark.SendRequest netcoreapp3.1

  • unstable execution_time [+291.209ms; +330.684ms] or [+221.112%; +251.085%]
  • 🟩 throughput [+607.863op/s; +811.916op/s] or [+5.885%; +7.860%]

scenario:Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark.WriteAndFlushEnrichedTraces net472

  • unstable execution_time [+294.647ms; +328.891ms] or [+135.476%; +151.221%]
  • 🟥 throughput [-523.887op/s; -489.412op/s] or [-47.469%; -44.346%]

scenario:Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark.WriteAndFlushEnrichedTraces net6.0

  • unstable execution_time [+202.200ms; +335.429ms] or [+86.169%; +142.946%]
  • 🟥 throughput [-670.205op/s; -586.698op/s] or [-44.703%; -39.133%]

scenario:Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark.WriteAndFlushEnrichedTraces netcoreapp3.1

  • 🟥 execution_time [+329.859ms; +339.390ms] or [+197.294%; +202.995%]
  • 🟥 throughput [-407.059op/s; -370.866op/s] or [-28.343%; -25.823%]

scenario:Benchmarks.Trace.CharSliceBenchmark.OriginalCharSlice net6.0

  • 🟩 execution_time [-153.513µs; -119.250µs] or [-7.776%; -6.041%]
  • 🟩 throughput [+34.077op/s; +43.306op/s] or [+6.727%; +8.549%]

scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearch net472

  • 🟥 execution_time [+301.432ms; +302.839ms] or [+151.795%; +152.504%]

scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearch net6.0

  • 🟥 execution_time [+301.627ms; +303.159ms] or [+151.146%; +151.913%]

scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearch netcoreapp3.1

  • 🟥 execution_time [+302.121ms; +305.228ms] or [+151.773%; +153.334%]

scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearchAsync net472

  • 🟥 execution_time [+302.898ms; +304.409ms] or [+152.105%; +152.864%]

scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearchAsync net6.0

  • 🟥 execution_time [+296.889ms; +298.933ms] or [+146.799%; +147.809%]

scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearchAsync netcoreapp3.1

  • 🟥 execution_time [+302.939ms; +309.232ms] or [+153.543%; +156.732%]

scenario:Benchmarks.Trace.GraphQLBenchmark.ExecuteAsync net472

  • 🟥 execution_time [+300.843ms; +302.412ms] or [+150.996%; +151.783%]

scenario:Benchmarks.Trace.GraphQLBenchmark.ExecuteAsync net6.0

  • 🟥 execution_time [+301.091ms; +304.561ms] or [+150.066%; +151.796%]
  • 🟩 throughput [+48822.147op/s; +54140.427op/s] or [+9.694%; +10.751%]

scenario:Benchmarks.Trace.GraphQLBenchmark.ExecuteAsync netcoreapp3.1

  • 🟥 execution_time [+299.021ms; +301.413ms] or [+148.760%; +149.950%]

scenario:Benchmarks.Trace.ILoggerBenchmark.EnrichedLog net6.0

  • 🟩 execution_time [-16.351ms; -12.685ms] or [-7.603%; -5.898%]

scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark net6.0

  • 🟩 allocated_mem [-19.736KB; -19.716KB] or [-7.199%; -7.192%]
  • unstable execution_time [-44.003µs; +7.734µs] or [-8.697%; +1.529%]

scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark netcoreapp3.1

  • unstable execution_time [-50.430µs; +7.641µs] or [-8.739%; +1.324%]

scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatBenchmark net6.0

  • 🟥 execution_time [+6.229µs; +10.161µs] or [+14.724%; +24.018%]
  • 🟥 throughput [-4664.914op/s; -2914.716op/s] or [-19.638%; -12.270%]

scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatBenchmark netcoreapp3.1

  • unstable execution_time [-12.707µs; -5.067µs] or [-19.715%; -7.861%]
  • 🟩 throughput [+1348.974op/s; +2946.003op/s] or [+8.276%; +18.075%]

scenario:Benchmarks.Trace.Log4netBenchmark.EnrichedLog net472

  • 🟥 execution_time [+302.630ms; +304.241ms] or [+152.966%; +153.780%]

scenario:Benchmarks.Trace.Log4netBenchmark.EnrichedLog net6.0

  • 🟥 execution_time [+303.241ms; +305.470ms] or [+154.349%; +155.483%]

scenario:Benchmarks.Trace.Log4netBenchmark.EnrichedLog netcoreapp3.1

  • 🟥 execution_time [+300.074ms; +302.212ms] or [+150.224%; +151.294%]

scenario:Benchmarks.Trace.RedisBenchmark.SendReceive net6.0

  • 🟩 throughput [+37034.709op/s; +39782.501op/s] or [+7.010%; +7.530%]

scenario:Benchmarks.Trace.SerilogBenchmark.EnrichedLog net472

  • 🟥 execution_time [+300.285ms; +302.081ms] or [+149.665%; +150.560%]

scenario:Benchmarks.Trace.SerilogBenchmark.EnrichedLog net6.0

  • 🟥 execution_time [+302.261ms; +303.251ms] or [+151.781%; +152.278%]

scenario:Benchmarks.Trace.SerilogBenchmark.EnrichedLog netcoreapp3.1

  • 🟥 execution_time [+303.349ms; +306.222ms] or [+153.839%; +155.296%]

scenario:Benchmarks.Trace.SingleSpanAspNetCoreBenchmark.SingleSpanAspNetCore net472

  • 🟥 execution_time [+299.830ms; +300.541ms] or [+149.557%; +149.911%]
  • 🟩 throughput [+66054030.366op/s; +66320799.449op/s] or [+48.105%; +48.299%]

scenario:Benchmarks.Trace.SingleSpanAspNetCoreBenchmark.SingleSpanAspNetCore net6.0

  • 🟥 execution_time [+427.418ms; +431.585ms] or [+531.570%; +536.753%]
  • 🟩 throughput [+1030.427op/s; +1206.724op/s] or [+7.966%; +9.329%]

scenario:Benchmarks.Trace.SingleSpanAspNetCoreBenchmark.SingleSpanAspNetCore netcoreapp3.1

  • 🟥 execution_time [+299.020ms; +299.935ms] or [+149.144%; +149.601%]
  • 🟩 throughput [+18421762.327op/s; +19369030.744op/s] or [+8.160%; +8.579%]

scenario:Benchmarks.Trace.SpanBenchmark.StartFinishScope net6.0

  • 🟩 throughput [+89759.125op/s; +101851.674op/s] or [+8.381%; +9.510%]

scenario:Benchmarks.Trace.SpanBenchmark.StartFinishScope netcoreapp3.1

  • 🟩 throughput [+60930.068op/s; +80665.149op/s] or [+7.053%; +9.337%]

scenario:Benchmarks.Trace.SpanBenchmark.StartFinishSpan net6.0

  • 🟩 throughput [+77072.427op/s; +108003.122op/s] or [+5.966%; +8.360%]

scenario:Benchmarks.Trace.SpanBenchmark.StartFinishSpan netcoreapp3.1

  • 🟩 throughput [+94801.256op/s; +103107.989op/s] or [+9.415%; +10.240%]

scenario:Benchmarks.Trace.SpanBenchmark.StartFinishTwoScopes net6.0

  • 🟩 throughput [+46731.648op/s; +52661.293op/s] or [+8.486%; +9.562%]

scenario:Benchmarks.Trace.SpanBenchmark.StartFinishTwoScopes netcoreapp3.1

  • 🟩 throughput [+31680.077op/s; +41378.980op/s] or [+7.091%; +9.262%]

scenario:Benchmarks.Trace.TraceAnnotationsBenchmark.RunOnMethodBegin net6.0

  • 🟩 throughput [+71808.727op/s; +91194.584op/s] or [+8.023%; +10.189%]

Known flaky benchmarks without significant changes:

  • scenario:Benchmarks.Trace.ActivityBenchmark.StartStopWithChild net472
  • scenario:Benchmarks.Trace.ActivityBenchmark.StartStopWithChild netcoreapp3.1
  • scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorMoreComplexBody net472
  • scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorSimpleBody net472
  • scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmark net472
  • scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmark net6.0
  • scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmark netcoreapp3.1
  • scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmarkWithAttack net472
  • scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmarkWithAttack netcoreapp3.1
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSlice net472
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSlice net6.0
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSlice netcoreapp3.1
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSliceWithPool net472
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSliceWithPool net6.0
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSliceWithPool netcoreapp3.1
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OriginalCharSlice net472
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OriginalCharSlice netcoreapp3.1
  • scenario:Benchmarks.Trace.ILoggerBenchmark.EnrichedLog net472
  • scenario:Benchmarks.Trace.ILoggerBenchmark.EnrichedLog netcoreapp3.1
  • scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark net472
  • scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatBenchmark net472
  • scenario:Benchmarks.Trace.RedisBenchmark.SendReceive net472
  • scenario:Benchmarks.Trace.RedisBenchmark.SendReceive netcoreapp3.1
  • scenario:Benchmarks.Trace.SpanBenchmark.StartFinishScope net472
  • scenario:Benchmarks.Trace.SpanBenchmark.StartFinishSpan net472
  • scenario:Benchmarks.Trace.SpanBenchmark.StartFinishTwoScopes net472
  • scenario:Benchmarks.Trace.TraceAnnotationsBenchmark.RunOnMethodBegin net472
  • scenario:Benchmarks.Trace.TraceAnnotationsBenchmark.RunOnMethodBegin netcoreapp3.1

@dd-trace-dotnet-ci-bot

dd-trace-dotnet-ci-bot Bot commented Apr 28, 2026

Copy link
Copy Markdown

Execution-Time Benchmarks Report ⏱️

Execution-time results for samples comparing This PR (8533) 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
duration75.75 ± (75.56 - 76.07) ms75.65 ± (75.57 - 76.19) ms-0.1%
.NET Framework 4.8 - Bailout
duration78.63 ± (78.59 - 79.09) ms79.03 ± (78.82 - 79.33) ms+0.5%✅⬆️
.NET Framework 4.8 - CallTarget+Inlining+NGEN
duration1080.55 ± (1077.44 - 1085.09) ms1084.97 ± (1084.25 - 1093.92) ms+0.4%✅⬆️
.NET Core 3.1 - Baseline
process.internal_duration_ms22.96 ± (22.89 - 23.03) ms22.86 ± (22.80 - 22.93) ms-0.4%
process.time_to_main_ms88.18 ± (87.83 - 88.53) ms85.46 ± (85.13 - 85.79) ms-3.1%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.91 ± (10.91 - 10.91) MB10.92 ± (10.91 - 10.92) MB+0.1%✅⬆️
runtime.dotnet.threads.count12 ± (12 - 12)12 ± (12 - 12)+0.0%
.NET Core 3.1 - Bailout
process.internal_duration_ms22.42 ± (22.38 - 22.45) ms22.43 ± (22.40 - 22.47) ms+0.1%✅⬆️
process.time_to_main_ms85.79 ± (85.59 - 85.99) ms85.04 ± (84.85 - 85.23) ms-0.9%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.89 ± (10.88 - 10.89) MB10.95 ± (10.94 - 10.96) MB+0.6%✅⬆️
runtime.dotnet.threads.count13 ± (13 - 13)13 ± (13 - 13)+0.0%
.NET Core 3.1 - CallTarget+Inlining+NGEN
process.internal_duration_ms214.21 ± (213.41 - 215.01) ms214.21 ± (213.36 - 215.05) ms-0.0%
process.time_to_main_ms529.00 ± (527.64 - 530.37) ms528.07 ± (526.67 - 529.47) ms-0.2%
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed47.85 ± (47.82 - 47.88) MB47.94 ± (47.91 - 47.97) MB+0.2%✅⬆️
runtime.dotnet.threads.count28 ± (28 - 28)28 ± (28 - 28)-0.1%
.NET 6 - Baseline
process.internal_duration_ms21.67 ± (21.60 - 21.73) ms21.58 ± (21.51 - 21.64) ms-0.4%
process.time_to_main_ms76.00 ± (75.67 - 76.32) ms76.26 ± (75.91 - 76.60) ms+0.3%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.62 ± (10.62 - 10.62) MB10.63 ± (10.63 - 10.64) MB+0.1%✅⬆️
runtime.dotnet.threads.count10 ± (10 - 10)10 ± (10 - 10)+0.0%
.NET 6 - Bailout
process.internal_duration_ms21.42 ± (21.36 - 21.47) ms21.37 ± (21.33 - 21.41) ms-0.2%
process.time_to_main_ms75.15 ± (74.90 - 75.40) ms75.67 ± (75.44 - 75.89) ms+0.7%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed10.73 ± (10.72 - 10.73) MB10.74 ± (10.74 - 10.74) MB+0.2%✅⬆️
runtime.dotnet.threads.count11 ± (11 - 11)11 ± (11 - 11)+0.0%
.NET 6 - CallTarget+Inlining+NGEN
process.internal_duration_ms380.48 ± (378.49 - 382.47) ms380.85 ± (379.03 - 382.66) ms+0.1%✅⬆️
process.time_to_main_ms529.95 ± (528.70 - 531.21) ms535.86 ± (534.61 - 537.10) ms+1.1%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed49.18 ± (49.15 - 49.20) MB49.44 ± (49.42 - 49.47) MB+0.5%✅⬆️
runtime.dotnet.threads.count28 ± (28 - 28)28 ± (28 - 28)+0.1%✅⬆️
.NET 8 - Baseline
process.internal_duration_ms19.57 ± (19.54 - 19.61) ms19.72 ± (19.67 - 19.78) ms+0.8%✅⬆️
process.time_to_main_ms72.97 ± (72.82 - 73.13) ms74.22 ± (73.98 - 74.47) ms+1.7%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed7.67 ± (7.66 - 7.68) MB7.65 ± (7.64 - 7.66) MB-0.3%
runtime.dotnet.threads.count10 ± (10 - 10)10 ± (10 - 10)+0.0%
.NET 8 - Bailout
process.internal_duration_ms20.00 ± (19.95 - 20.06) ms20.11 ± (20.04 - 20.17) ms+0.5%✅⬆️
process.time_to_main_ms76.75 ± (76.45 - 77.05) ms77.68 ± (77.39 - 77.98) ms+1.2%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed7.73 ± (7.73 - 7.74) MB7.70 ± (7.69 - 7.70) MB-0.4%
runtime.dotnet.threads.count11 ± (11 - 11)11 ± (11 - 11)+0.0%
.NET 8 - CallTarget+Inlining+NGEN
process.internal_duration_ms299.46 ± (297.27 - 301.65) ms300.03 ± (297.63 - 302.43) ms+0.2%✅⬆️
process.time_to_main_ms491.31 ± (490.23 - 492.39) ms492.68 ± (491.42 - 493.93) ms+0.3%✅⬆️
runtime.dotnet.exceptions.count0 ± (0 - 0)0 ± (0 - 0)+0.0%
runtime.dotnet.mem.committed36.49 ± (36.46 - 36.51) MB36.50 ± (36.47 - 36.52) MB+0.0%✅⬆️
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
duration203.19 ± (203.30 - 204.63) ms203.81 ± (204.32 - 206.01) ms+0.3%✅⬆️
.NET Framework 4.8 - Bailout
duration206.72 ± (206.65 - 207.75) ms206.98 ± (207.23 - 208.56) ms+0.1%✅⬆️
.NET Framework 4.8 - CallTarget+Inlining+NGEN
duration1204.13 ± (1204.12 - 1211.12) ms1219.69 ± (1218.87 - 1225.92) ms+1.3%✅⬆️
.NET Core 3.1 - Baseline
process.internal_duration_ms197.31 ± (196.69 - 197.92) ms197.24 ± (196.62 - 197.86) ms-0.0%
process.time_to_main_ms85.66 ± (85.33 - 85.99) ms85.51 ± (85.17 - 85.85) ms-0.2%
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed16.06 ± (16.04 - 16.08) MB15.96 ± (15.94 - 15.98) MB-0.6%
runtime.dotnet.threads.count20 ± (20 - 20)20 ± (20 - 20)+0.3%✅⬆️
.NET Core 3.1 - Bailout
process.internal_duration_ms196.71 ± (196.16 - 197.27) ms196.64 ± (195.94 - 197.34) ms-0.0%
process.time_to_main_ms86.88 ± (86.65 - 87.12) ms87.33 ± (87.01 - 87.65) ms+0.5%✅⬆️
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed16.09 ± (16.07 - 16.10) MB16.08 ± (16.06 - 16.10) MB-0.1%
runtime.dotnet.threads.count21 ± (21 - 21)21 ± (21 - 21)-0.0%
.NET Core 3.1 - CallTarget+Inlining+NGEN
process.internal_duration_ms394.37 ± (393.12 - 395.62) ms394.97 ± (393.51 - 396.43) ms+0.2%✅⬆️
process.time_to_main_ms535.10 ± (533.86 - 536.33) ms542.36 ± (540.80 - 543.92) ms+1.4%✅⬆️
runtime.dotnet.exceptions.count3 ± (3 - 3)3 ± (3 - 3)+0.0%
runtime.dotnet.mem.committed58.53 ± (58.41 - 58.66) MB58.46 ± (58.33 - 58.58) MB-0.1%
runtime.dotnet.threads.count30 ± (30 - 30)30 ± (30 - 30)-0.2%
.NET 6 - Baseline
process.internal_duration_ms201.71 ± (201.16 - 202.25) ms203.51 ± (202.82 - 204.20) ms+0.9%✅⬆️
process.time_to_main_ms74.24 ± (73.98 - 74.49) ms74.89 ± (74.61 - 75.18) ms+0.9%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed16.29 ± (16.27 - 16.31) MB16.27 ± (16.25 - 16.29) MB-0.1%
runtime.dotnet.threads.count19 ± (19 - 19)19 ± (19 - 19)+0.1%✅⬆️
.NET 6 - Bailout
process.internal_duration_ms201.03 ± (200.47 - 201.60) ms205.97 ± (205.17 - 206.77) ms+2.5%✅⬆️
process.time_to_main_ms75.21 ± (74.98 - 75.43) ms76.48 ± (76.17 - 76.80) ms+1.7%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed16.34 ± (16.32 - 16.36) MB16.26 ± (16.25 - 16.28) MB-0.5%
runtime.dotnet.threads.count20 ± (20 - 20)20 ± (20 - 20)+0.9%✅⬆️
.NET 6 - CallTarget+Inlining+NGEN
process.internal_duration_ms593.14 ± (590.35 - 595.93) ms595.87 ± (593.41 - 598.32) ms+0.5%✅⬆️
process.time_to_main_ms534.30 ± (533.12 - 535.47) ms539.54 ± (538.11 - 540.96) ms+1.0%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed60.90 ± (60.80 - 61.01) MB60.95 ± (60.84 - 61.05) MB+0.1%✅⬆️
runtime.dotnet.threads.count31 ± (31 - 31)31 ± (31 - 31)+0.0%✅⬆️
.NET 8 - Baseline
process.internal_duration_ms199.26 ± (198.80 - 199.72) ms200.47 ± (199.82 - 201.13) ms+0.6%✅⬆️
process.time_to_main_ms73.53 ± (73.29 - 73.77) ms74.25 ± (73.96 - 74.54) ms+1.0%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed11.62 ± (11.61 - 11.64) MB11.58 ± (11.57 - 11.60) MB-0.3%
runtime.dotnet.threads.count19 ± (18 - 19)19 ± (19 - 19)+0.4%✅⬆️
.NET 8 - Bailout
process.internal_duration_ms196.86 ± (196.37 - 197.35) ms200.78 ± (199.98 - 201.58) ms+2.0%✅⬆️
process.time_to_main_ms73.95 ± (73.76 - 74.14) ms75.43 ± (75.12 - 75.73) ms+2.0%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed11.69 ± (11.67 - 11.71) MB11.66 ± (11.64 - 11.67) MB-0.3%
runtime.dotnet.threads.count19 ± (19 - 19)19 ± (19 - 19)+0.3%✅⬆️
.NET 8 - CallTarget+Inlining+NGEN
process.internal_duration_ms517.49 ± (514.73 - 520.26) ms521.77 ± (518.43 - 525.11) ms+0.8%✅⬆️
process.time_to_main_ms489.46 ± (488.40 - 490.53) ms500.17 ± (498.77 - 501.57) ms+2.2%✅⬆️
runtime.dotnet.exceptions.count4 ± (4 - 4)4 ± (4 - 4)+0.0%
runtime.dotnet.mem.committed50.19 ± (50.15 - 50.22) MB50.27 ± (50.23 - 50.30) MB+0.2%✅⬆️
runtime.dotnet.threads.count30 ± (30 - 30)30 ± (30 - 30)+0.4%✅⬆️
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 (8533) - mean (76ms)  : 71, 80
    master - mean (76ms)  : 72, 79

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

    section CallTarget+Inlining+NGEN
    This PR (8533) - mean (1,089ms)  : 1016, 1162
    master - mean (1,081ms)  : 1024, 1138

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 (8533) - mean (116ms)  : 108, 123
    master - mean (118ms)  : 112, 125

    section Bailout
    This PR (8533) - mean (114ms)  : 112, 117
    master - mean (115ms)  : 112, 118

    section CallTarget+Inlining+NGEN
    This PR (8533) - mean (780ms)  : 757, 804
    master - mean (780ms)  : 755, 805

Loading
FakeDbCommand (.NET 6)
gantt
    title Execution time (ms) FakeDbCommand (.NET 6)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (8533) - mean (105ms)  : 98, 111
    master - mean (104ms)  : 98, 111

    section Bailout
    This PR (8533) - mean (104ms)  : 100, 108
    master - mean (103ms)  : 98, 108

    section CallTarget+Inlining+NGEN
    This PR (8533) - mean (942ms)  : 910, 974
    master - mean (939ms)  : 900, 977

Loading
FakeDbCommand (.NET 8)
gantt
    title Execution time (ms) FakeDbCommand (.NET 8)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (8533) - mean (102ms)  : 97, 107
    master - mean (101ms)  : 96, 105

    section Bailout
    This PR (8533) - mean (106ms)  : 101, 111
    master - mean (105ms)  : 99, 110

    section CallTarget+Inlining+NGEN
    This PR (8533) - mean (825ms)  : 778, 872
    master - mean (824ms)  : 783, 864

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 (8533) - mean (205ms)  : 193, 218
    master - mean (204ms)  : 194, 214

    section Bailout
    This PR (8533) - mean (208ms)  : 198, 218
    master - mean (207ms)  : 199, 215

    section CallTarget+Inlining+NGEN
    This PR (8533) - mean (1,222ms)  : 1172, 1273
    master - mean (1,208ms)  : 1156, 1259

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 (8533) - mean (295ms)  : 276, 313
    master - mean (293ms)  : 280, 306

    section Bailout
    This PR (8533) - mean (295ms)  : 278, 312
    master - mean (294ms)  : 283, 305

    section CallTarget+Inlining+NGEN
    This PR (8533) - mean (974ms)  : 943, 1005
    master - mean (966ms)  : 929, 1002

Loading
HttpMessageHandler (.NET 6)
gantt
    title Execution time (ms) HttpMessageHandler (.NET 6)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (8533) - mean (289ms)  : 274, 304
    master - mean (286ms)  : 272, 299

    section Bailout
    This PR (8533) - mean (293ms)  : 275, 310
    master - mean (286ms)  : 273, 299

    section CallTarget+Inlining+NGEN
    This PR (8533) - mean (1,166ms)  : 1128, 1204
    master - mean (1,158ms)  : 1114, 1202

Loading
HttpMessageHandler (.NET 8)
gantt
    title Execution time (ms) HttpMessageHandler (.NET 8)
    dateFormat  x
    axisFormat %Q
    todayMarker off
    section Baseline
    This PR (8533) - mean (287ms)  : 273, 301
    master - mean (283ms)  : 273, 292

    section Bailout
    This PR (8533) - mean (289ms)  : 272, 306
    master - mean (281ms)  : 273, 289

    section CallTarget+Inlining+NGEN
    This PR (8533) - mean (1,055ms)  : 987, 1124
    master - mean (1,040ms)  : 991, 1089

Loading

@r1viollet
r1viollet marked this pull request as draft April 28, 2026 14:17
@r1viollet r1viollet added the area:profiler Issues related to the continous-profiler label Apr 28, 2026

@gleocadie gleocadie left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM

@r1viollet
r1viollet force-pushed the r1viollet/profiler-bug-fixes-followup branch from 69b640a to b0e719b Compare April 28, 2026 14:33
bool _canReplaceSignalHandler;
int32_t _signalToSend;
HandlerFn_t _handler;
std::atomic<HandlerFn_t> _handler;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@gleocadie I realize that this was not an atomic, so re-reading the current had no effect (compiler optimized it away)

@r1viollet
r1viollet marked this pull request as ready for review April 28, 2026 15:00
@r1viollet
r1viollet marked this pull request as draft April 28, 2026 15:02
r1viollet and others added 6 commits April 28, 2026 17:19
_probability (double) and _samplesBudget (int64_t) were declared volatile
but written by the timer thread in RollWindow() while being read concurrently
by Sample() on arbitrary CLR threads.  C++ volatile provides no memory-model
guarantees: no happens-before, no atomicity, no ordering.  The compiler is
free to reorder or cache these accesses, and on ARM64 a 64-bit non-atomic
store is not guaranteed to be read-consistent by other cores.  TSAN detects
this as a data race.

Replace both fields with std::atomic<> using relaxed ordering.  The existing
comment in RollWindow() acknowledges intentional looseness in the count/budget
window accounting; relaxed atomics preserve that intent while eliminating the
formal undefined behaviour and ARM64 correctness risk.

Add ConcurrentSampleAndRollWindow_NoDataRace test: 4 threads calling Sample()
while a writer thread calls RollWindow() in a tight loop.  With the volatile
code this reliably triggers a TSAN report; with the fix it is clean.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <[email protected]>
…ager

RegisterHandler() used a classic DCL pattern but the inner guard (after
acquiring the mutex) checked the stale pre-lock local `current` instead of
re-reading `_handler`:

    HandlerFn_t current = _handler;   // read without lock
    if (current != nullptr) return;
    lock.acquire();
    if (current != nullptr) return;   // BUG: stale, always nullptr here

Two threads that both observe _handler==nullptr before the lock race to
acquire the mutex sequentially.  The second caller's inner check still sees
the pre-lock value (nullptr) and calls SetupSignalHandler() a second time.
That second sigaction() call saves the profiler's own handler into
_previousAction; on teardown UnRegisterHandler() then restores the profiler
handler instead of the original one, creating an infinite signal chain.

Fix: read _handler again inside the mutex.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <[email protected]>
AddContentionSample() declared `static uint64_t failureCount` and then
both read and incremented it from multiple concurrent CLR callback threads
(the synchronous ICorProfilerCallback path and the async ETW path run on
different threads simultaneously).  This is a plain C++ data race.

Replace with `static std::atomic<uint64_t>` and use fetch_add so that the
threshold check and increment are a single atomic operation, avoiding the
secondary race between the modulo check and the increment.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <[email protected]>
GetCodeInfo2 can theoretically return a code range with size==0 (e.g. during
tier-transition races or for degenerate JIT stubs).  GetCodeRanges computed:

    endAddress = startAddress + size - 1

Without a size==0 guard this underflows.  For startAddress==0 it produces
endAddress==UINTPTR_MAX, and the subsequent page-insertion loop:

    for (page = startPage; page <= endPage; ++page)

iterates from 0 to ~UINTPTR_MAX/pageSize (billions of iterations), hanging
the background worker thread permanently and starving IsManaged() callers.
For non-zero startAddress the loop is silently a no-op (endPage < startPage)
but the degenerate CodeRange still pollutes the sorted range vector.

Fix: skip entries where size==0 before constructing the CodeRange.

Add two regression tests:
- ZeroSizeRange_DoesNotPolluteCacheNonZeroBase: verifies IsManaged returns
  false for all IPs near a zero-size registration.
- ZeroSizeRangeAtAddressZero_WorkerDoesNotHang: verifies the background
  worker completes within the normal timeout (detects the hang path).

The previous test AddFunction_ZeroSizeRange_HandledGracefully did `(void)result`
with no assertion — it was replaced by the two tests above.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <[email protected]>
…RegisterHandler

Restyle the DCL fix to keep `current` as the sole variable checked throughout
the function, making the intent clearer: after acquiring the mutex, refresh
`current` from `_handler` so the inner guard sees any write that a racing
thread may have completed between the outer check and the lock acquisition.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <[email protected]>
_handler is written by RegisterHandler() (main thread, under mutex) and read
concurrently from the signal handler via CallCustomHandler() and from the
pre-lock fast path in RegisterHandler() — both without any lock.  A plain
pointer gives no memory-model guarantees: the compiler may cache it in a
register and the CPU may observe a stale value on ARM64.

Make _handler std::atomic<HandlerFn_t>:
- load(memory_order_acquire) at every read point, including the pre-lock fast
  path and the re-read after acquiring the mutex.
- store(memory_order_release) at every write point.

The acquire/release pair ensures that Thread B's post-lock re-read is
guaranteed to observe Thread A's store, giving the DCL its required
happens-before edge without relying on the mutex flush as a side effect.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <[email protected]>
@r1viollet
r1viollet force-pushed the r1viollet/profiler-bug-fixes-followup branch from b0e719b to 35c3174 Compare April 28, 2026 15:20
@r1viollet
r1viollet changed the base branch from r1viollet/profiler-bug-fixes to master April 28, 2026 15:20
@r1viollet
r1viollet marked this pull request as ready for review April 29, 2026 14:51

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

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.

Reviewed commit: 35c31742d4

ℹ️ 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".

{
// avoid the case where the ClrStackWalk event has been missed for the ContentionStart
if ((stack.size() == 0) && (failureCount % 1000 == 0))
if ((stack.size() == 0) && (failureCount.fetch_add(1) % 1000 == 0))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Return on every empty-stack contention failure

When a CLR contention event arrives without a stack, this condition increments the counter but only returns on failures where the previous count is divisible by 1000. The other 999 failures fall through and call Add() with an empty rawSample.Stack, even though this block is meant to drop missed stack walks; the same fetch_add() % 1000 pattern above has the same effect for synchronous stack-walk failures. Keep the log rate-limited, but return on every empty-stack failure.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good call!

The previous condition combined the empty-stack check with the
rate-limited log check using &&, so the early return only fired on
every 1000th failure.  The other 999 calls fell through and passed an
empty rawSample.Stack to Add(), emitting a corrupt sample with no
frames.

Separate the two concerns: always return when the stack is empty, and
only log every 1000 occurrences.  Applies to both the synchronous
stack-walk path and the async ETW path.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <[email protected]>
@r1viollet
r1viollet force-pushed the r1viollet/profiler-bug-fixes-followup branch from 6272369 to 3149a14 Compare April 29, 2026 15:22
uint32_t hrCollectStack = E_FAIL;
const auto result = pStackFramesCollector->CollectStackSample(threadInfo.get(), &hrCollectStack);
if ((result->GetFramesCount() == 0) && (failureCount % 1000 == 0))
if (result->GetFramesCount() == 0)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@gleocadie I changed this part (from feedback of codex), I think it is better ?

@r1viollet r1viollet changed the title fix(profiler): follow-up fixes from code review fix(profiler): minor thread safety / managed code cache fixes Apr 29, 2026
@r1viollet r1viollet changed the title fix(profiler): minor thread safety / managed code cache fixes fix(profiler): five native profiler bug fixes Apr 29, 2026
@r1viollet
r1viollet enabled auto-merge (squash) April 29, 2026 15:35
@r1viollet
r1viollet merged commit 27142fd into master Apr 29, 2026
144 checks passed
@r1viollet
r1viollet deleted the r1viollet/profiler-bug-fixes-followup branch April 29, 2026 16:47
@github-actions github-actions Bot added this to the vNext-v3 milestone Apr 29, 2026
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 type:bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants