Skip to content

Conversation

@andrewlock
Copy link
Member

@andrewlock andrewlock commented Oct 14, 2025

Summary of changes

  • Adds some unit tests for some of the APM_TRACING logic in DynamicConfigurationManager
  • Reduce duration of lock Remove lock
  • Minor reduction in allocations

Reason for change

Rebasing #7525 after #7536 flagged that there were some conflicts. In working out how to resolve them, noted some possibilities for minor improvements

Implementation details

  • Extracted existing functionality into a testable method
  • Added unit tests for the existing behaviour
  • Tweaks

Technically I believe this is always single-threaded, so we should be able to remove the lock and also reduce some ToList() etc, but we don't explicitly enforce that, so I'm not sure whether to do it or not tbh 🤔 Thoughts? Given this comment I'm inclined to remove it entirely. EDIT: we removed the lock entirely in the end for simplicity

Test coverage

More now

Other details

Reviewing commit-by-commit shows the changes more clearly 🙂

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a 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

Comment on lines 203 to 221
private ApplyDetails[] ConfigurationUpdated(
Dictionary<string, List<RemoteConfiguration>> configByProduct,
Dictionary<string, List<RemoteConfigurationPath>>? removedConfigByProduct)
{
lock (_configLock)
{
var applyDetailsResult = new List<ApplyDetails>();

try
{
// Phase 1: Handle explicit removals from removedConfigByProduct
if (removedConfigByProduct?.TryGetValue(ProductName, out var removedConfigs) == true)
{
foreach (var removedConfig in removedConfigs)
{
if (_activeConfigurations.Remove(removedConfig.Id))
{
Log.Debug("Explicitly removed APM_TRACING configuration {ConfigId}", removedConfig.Id);
applyDetailsResult.Add(ApplyDetails.FromOk(removedConfig.Path));
}
}
}

// Phase 2: Handle new/updated configurations and implicit removals
if (configByProduct.TryGetValue(ProductName, out var apmLibrary))
// Technically we're single threaded here so locking should not be necessary, but playing it safe
List<RemoteConfiguration> valuesToApply;
lock (_configLock)
{
var receivedConfigIds = new HashSet<string>();

// Add/update configurations
foreach (var config in apmLibrary)
{
receivedConfigIds.Add(config.Path.Id);
_activeConfigurations[config.Path.Id] = config;
applyDetailsResult.Add(ApplyDetails.FromOk(config.Path.Path));
}

// Remove configurations not in this update
var configsToRemove = _activeConfigurations.Keys
.Where(configId => !receivedConfigIds.Contains(configId))
.ToList();

foreach (var configId in configsToRemove)
{
_activeConfigurations.Remove(configId);
Log.Debug("Implicitly removed APM_TRACING configuration {ConfigId} (not in update)", configId);
}
valuesToApply = CombineApmTracingConfiguration(_activeConfigurations, configByProduct, removedConfigByProduct, applyDetailsResult);
}

// Phase 3: Apply merged configuration
ApplyMergedConfiguration();
ApplyMergedConfiguration(valuesToApply);

Choose a reason for hiding this comment

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

P1 Badge ApplyMergedConfiguration must run under _configLock

The previous implementation held _configLock across both the mutation of _activeConfigurations and the call to ApplyMergedConfiguration. After the refactor the lock now wraps only CombineApmTracingConfiguration, while ApplyMergedConfiguration(valuesToApply) runs without synchronization. If two configuration updates arrive at about the same time, one thread can capture valuesToApply for an older configuration, release the lock, another thread updates the dictionary and applies the new configuration, and then the first thread applies the stale snapshot. The tracer ends up running with an out-of-date configuration while _activeConfigurations contains the newer state, and _configurationTelemetry is mutated concurrently as well. Please keep the ApplyMergedConfiguration call inside the lock (or provide equivalent ordering guarantees) so updates remain serialized.

Useful? React with 👍 / 👎.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, that's fair, it suggests to me that we should just drop the lock entirely 🤔 This is called in a single-threaded manner by the Remote config manager anyway 🤔

Copy link
Collaborator

Choose a reason for hiding this comment

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

It looks reasonable to me

Fine if we do, fine if we don't though

Copy link
Member Author

Choose a reason for hiding this comment

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

I remove the lock entirely as it seemed more likely to add a veneer of thread-safety without technically being safe

Copy link
Contributor

@dudikeleti dudikeleti left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks!

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

Execution-Time Benchmarks Report ⏱️

Execution-time results for samples comparing the following branches/commits:

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 shown 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).

gantt
    title Execution time (ms) FakeDbCommand (.NET Framework 4.8) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Bailout
    This PR (7652) - mean (73ms)  : 72, 74
     .   : milestone, 73,
    master - mean (72ms)  : 70, 73
     .   : milestone, 72,

    section Baseline
    This PR (7652) - mean (71ms)  : 63, 80
     .   : milestone, 71,
    master - mean (68ms)  : 66, 70
     .   : milestone, 68,

    section CallTarget+Inlining+NGEN
    This PR (7652) - mean (1,055ms)  : 1018, 1092
     .   : milestone, 1055,
    master - mean (1,052ms)  : 996, 1109
     .   : milestone, 1052,

Loading
gantt
    title Execution time (ms) FakeDbCommand (.NET Core 3.1) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Bailout
    This PR (7652) - mean (110ms)  : 108, 111
     .   : milestone, 110,
    master - mean (107ms)  : 106, 108
     .   : milestone, 107,

    section Baseline
    This PR (7652) - mean (109ms)  : 106, 111
     .   : milestone, 109,
    master - mean (106ms)  : 104, 109
     .   : milestone, 106,

    section CallTarget+Inlining+NGEN
    This PR (7652) - mean (749ms)  : 725, 773
     .   : milestone, 749,
    master - mean (745ms)  : 723, 768
     .   : milestone, 745,

Loading
gantt
    title Execution time (ms) FakeDbCommand (.NET 6) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Bailout
    This PR (7652) - mean (104ms)  : 102, 106
     .   : milestone, 104,
    master - mean (101ms)  : 100, 102
     .   : milestone, 101,

    section Baseline
    This PR (7652) - mean (103ms)  : 100, 106
     .   : milestone, 103,
    master - mean (101ms)  : 98, 103
     .   : milestone, 101,

    section CallTarget+Inlining+NGEN
    This PR (7652) - mean (788ms)  : 736, 839
     .   : milestone, 788,
    master - mean (778ms)  : 742, 814
     .   : milestone, 778,

Loading
gantt
    title Execution time (ms) FakeDbCommand (.NET 8) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Bailout
    This PR (7652) - mean (96ms)  : 94, 98
     .   : milestone, 96,
    master - mean (93ms)  : 92, 95
     .   : milestone, 93,

    section Baseline
    This PR (7652) - mean (95ms)  : 92, 97
     .   : milestone, 95,
    master - mean (93ms)  : 91, 95
     .   : milestone, 93,

    section CallTarget+Inlining+NGEN
    This PR (7652) - mean (665ms)  : 651, 679
     .   : milestone, 665,
    master - mean (662ms)  : 648, 676
     .   : milestone, 662,

Loading
gantt
    title Execution time (ms) HttpMessageHandler (.NET Framework 4.8) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Bailout
    This PR (7652) - mean (198ms)  : 195, 201
     .   : milestone, 198,
    master - mean (196ms)  : 194, 197
     .   : milestone, 196,

    section Baseline
    This PR (7652) - mean (195ms)  : 190, 199
     .   : milestone, 195,
    master - mean (193ms)  : 189, 197
     .   : milestone, 193,

    section CallTarget+Inlining+NGEN
    This PR (7652) - mean (1,176ms)  : 1108, 1245
     .   : milestone, 1176,
    master - mean (1,162ms)  : 1107, 1217
     .   : milestone, 1162,

Loading
gantt
    title Execution time (ms) HttpMessageHandler (.NET Core 3.1) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Bailout
    This PR (7652) - mean (281ms)  : 273, 289
     .   : milestone, 281,
    master - mean (279ms)  : 273, 284
     .   : milestone, 279,

    section Baseline
    This PR (7652) - mean (281ms)  : 276, 287
     .   : milestone, 281,
    master - mean (278ms)  : 273, 283
     .   : milestone, 278,

    section CallTarget+Inlining+NGEN
    This PR (7652) - mean (956ms)  : 921, 991
     .   : milestone, 956,
    master - mean (939ms)  : 899, 979
     .   : milestone, 939,

Loading
gantt
    title Execution time (ms) HttpMessageHandler (.NET 6) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Bailout
    This PR (7652) - mean (284ms)  : 279, 288
     .   : milestone, 284,
    master - mean (281ms)  : 275, 288
     .   : milestone, 281,

    section Baseline
    This PR (7652) - mean (286ms)  : 279, 292
     .   : milestone, 286,
    master - mean (282ms)  : 274, 290
     .   : milestone, 282,

    section CallTarget+Inlining+NGEN
    This PR (7652) - mean (1,003ms)  : 964, 1042
     .   : milestone, 1003,
    master - mean (994ms)  : 957, 1031
     .   : milestone, 994,

Loading
gantt
    title Execution time (ms) HttpMessageHandler (.NET 8) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Bailout
    This PR (7652) - mean (272ms)  : 268, 277
     .   : milestone, 272,
    master - mean (268ms)  : 264, 272
     .   : milestone, 268,

    section Baseline
    This PR (7652) - mean (275ms)  : 266, 283
     .   : milestone, 275,
    master - mean (268ms)  : 263, 273
     .   : milestone, 268,

    section CallTarget+Inlining+NGEN
    This PR (7652) - mean (859ms)  : 838, 880
     .   : milestone, 859,
    master - mean (849ms)  : 828, 869
     .   : milestone, 849,

Loading

@datadog-datadog-prod-us1

This comment has been minimized.

Copy link
Collaborator

@bouwkast bouwkast left a comment

Choose a reason for hiding this comment

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

Thanks!

@pr-commenter
Copy link

pr-commenter bot commented Oct 15, 2025

Benchmarks

Benchmarks Report for benchmark platform 🐌

Benchmarks for #7652 compared to master:

  • 2 benchmarks are faster, with geometric mean 1.123
  • 1 benchmarks are slower, with geometric mean 2.414
  • 7 benchmarks have fewer allocations
  • 7 benchmarks have more allocations

The following thresholds were used for comparing the benchmark speeds:

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

Allocation changes below 0.5% are ignored.

Benchmark details

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

Fewer allocations 🎉 in #7652

Benchmark Base Allocated Diff Allocated Change Change %
Benchmarks.Trace.ActivityBenchmark.StartStopWithChild‑net472 6.1 KB 6 KB -104 B -1.70%

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master StartStopWithChild net6.0 10.6μs 59.4ns 381ns 0 0 0 5.52 KB
master StartStopWithChild netcoreapp3.1 13.4μs 65.5ns 293ns 0 0 0 5.72 KB
master StartStopWithChild net472 22.3μs 126ns 855ns 0.955 0.212 0 6.1 KB
#7652 StartStopWithChild net6.0 10.5μs 54.6ns 278ns 0 0 0 5.52 KB
#7652 StartStopWithChild netcoreapp3.1 13.9μs 71.6ns 328ns 0 0 0 5.72 KB
#7652 StartStopWithChild net472 22μs 116ns 625ns 1.01 0.403 0.101 6 KB
Benchmarks.Trace.AgentWriterBenchmark - Same speed ✔️ More allocations ⚠️

More allocations ⚠️ in #7652

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

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master WriteAndFlushEnrichedTraces net6.0 929μs 88.8ns 332ns 0 0 0 2.71 KB
master WriteAndFlushEnrichedTraces netcoreapp3.1 1.03ms 635ns 2.46μs 0 0 0 2.7 KB
master WriteAndFlushEnrichedTraces net472 1.21ms 2.01μs 7.79μs 0 0 0 3.31 KB
#7652 WriteAndFlushEnrichedTraces net6.0 932μs 184ns 690ns 0 0 0 2.71 KB
#7652 WriteAndFlushEnrichedTraces netcoreapp3.1 1.01ms 169ns 610ns 0 0 0 2.7 KB
#7652 WriteAndFlushEnrichedTraces net472 1.2ms 49.3ns 178ns 0 0 0 3.35 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 348μs 1.19μs 4.59μs 0 0 0 178.25 KB
master AllCycleSimpleBody netcoreapp3.1 514μs 2.52μs 10.1μs 0 0 0 184.01 KB
master AllCycleSimpleBody net472 458μs 114ns 425ns 31.2 0 0 203.96 KB
master AllCycleMoreComplexBody net6.0 355μs 519ns 2.01μs 0 0 0 181.77 KB
master AllCycleMoreComplexBody netcoreapp3.1 503μs 1.03μs 5.15μs 0 0 0 187.44 KB
master AllCycleMoreComplexBody net472 470μs 96.1ns 360ns 32.4 0 0 207.5 KB
master ObjectExtractorSimpleBody net6.0 323ns 1.55ns 6.18ns 0 0 0 280 B
master ObjectExtractorSimpleBody netcoreapp3.1 407ns 2.22ns 12.5ns 0 0 0 272 B
master ObjectExtractorSimpleBody net472 303ns 0.0854ns 0.331ns 0.0443 0 0 281 B
master ObjectExtractorMoreComplexBody net6.0 6.29μs 23.6ns 91.3ns 0 0 0 3.78 KB
master ObjectExtractorMoreComplexBody netcoreapp3.1 7.79μs 37.6ns 159ns 0 0 0 3.69 KB
master ObjectExtractorMoreComplexBody net472 6.76μs 5.09ns 19.7ns 0.571 0 0 3.8 KB
#7652 AllCycleSimpleBody net6.0 345μs 1.59μs 6.56μs 0 0 0 178.25 KB
#7652 AllCycleSimpleBody netcoreapp3.1 522μs 1.43μs 5.55μs 0 0 0 184.01 KB
#7652 AllCycleSimpleBody net472 461μs 224ns 867ns 31.2 0 0 203.96 KB
#7652 AllCycleMoreComplexBody net6.0 358μs 1.71μs 7.05μs 0 0 0 181.77 KB
#7652 AllCycleMoreComplexBody netcoreapp3.1 536μs 2.48μs 9.9μs 0 0 0 187.44 KB
#7652 AllCycleMoreComplexBody net472 470μs 87.1ns 326ns 32.4 0 0 207.5 KB
#7652 ObjectExtractorSimpleBody net6.0 326ns 1.59ns 6.92ns 0 0 0 280 B
#7652 ObjectExtractorSimpleBody netcoreapp3.1 387ns 2.19ns 15ns 0 0 0 272 B
#7652 ObjectExtractorSimpleBody net472 295ns 0.0233ns 0.0901ns 0.0433 0 0 281 B
#7652 ObjectExtractorMoreComplexBody net6.0 6.42μs 33.9ns 166ns 0 0 0 3.79 KB
#7652 ObjectExtractorMoreComplexBody netcoreapp3.1 7.67μs 40.4ns 202ns 0 0 0 3.69 KB
#7652 ObjectExtractorMoreComplexBody net472 6.75μs 2ns 7.5ns 0.574 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 75.8μs 242ns 904ns 0 0 0 32.4 KB
master EncodeArgs netcoreapp3.1 97.9μs 155ns 601ns 0 0 0 32.4 KB
master EncodeArgs net472 109μs 11ns 42.4ns 4.92 0 0 32.51 KB
master EncodeLegacyArgs net6.0 141μs 30.2ns 113ns 0 0 0 2.15 KB
master EncodeLegacyArgs netcoreapp3.1 199μs 195ns 754ns 0 0 0 2.14 KB
master EncodeLegacyArgs net472 263μs 17.8ns 66.4ns 0 0 0 2.17 KB
#7652 EncodeArgs net6.0 76.8μs 52ns 195ns 0 0 0 32.4 KB
#7652 EncodeArgs netcoreapp3.1 97μs 229ns 889ns 0 0 0 32.4 KB
#7652 EncodeArgs net472 109μs 10.3ns 39.9ns 4.89 0 0 32.51 KB
#7652 EncodeLegacyArgs net6.0 143μs 14.6ns 54.7ns 0 0 0 2.15 KB
#7652 EncodeLegacyArgs netcoreapp3.1 197μs 115ns 415ns 0 0 0 2.14 KB
#7652 EncodeLegacyArgs net472 262μs 28.2ns 109ns 0 0 0 2.16 KB
Benchmarks.Trace.Asm.AppSecWafBenchmark - Slower ⚠️ Same allocations ✔️

Slower ⚠️ in #7652

Benchmark diff/base Base Median (ns) Diff Median (ns) Modality
Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmarkWithAttack‑netcoreapp3.1 2.414 298,583.93 720,773.48

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master RunWafRealisticBenchmark net6.0 398μs 51.6ns 193ns 0 0 0 4.55 KB
master RunWafRealisticBenchmark netcoreapp3.1 420μs 332ns 1.15μs 0 0 0 4.48 KB
master RunWafRealisticBenchmark net472 431μs 69.5ns 269ns 0 0 0 4.66 KB
master RunWafRealisticBenchmarkWithAttack net6.0 288μs 22.5ns 84.1ns 0 0 0 2.24 KB
master RunWafRealisticBenchmarkWithAttack netcoreapp3.1 299μs 52.4ns 189ns 0 0 0 2.22 KB
master RunWafRealisticBenchmarkWithAttack net472 308μs 26.7ns 103ns 0 0 0 2.29 KB
#7652 RunWafRealisticBenchmark net6.0 395μs 91.7ns 355ns 0 0 0 4.55 KB
#7652 RunWafRealisticBenchmark netcoreapp3.1 409μs 391ns 1.41μs 0 0 0 4.48 KB
#7652 RunWafRealisticBenchmark net472 429μs 39.3ns 152ns 0 0 0 4.66 KB
#7652 RunWafRealisticBenchmarkWithAttack net6.0 285μs 38.8ns 145ns 0 0 0 2.24 KB
#7652 RunWafRealisticBenchmarkWithAttack netcoreapp3.1 680μs 9.77μs 97.7μs 0 0 0 2.22 KB
#7652 RunWafRealisticBenchmarkWithAttack net472 309μs 29.8ns 115ns 0 0 0 2.29 KB
Benchmarks.Trace.AspNetCoreBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master SendRequest net6.0 60.9μs 42.2ns 152ns 0 0 0 14.52 KB
master SendRequest netcoreapp3.1 71.5μs 58.1ns 225ns 0 0 0 17.42 KB
master SendRequest net472 0.000559ns 0.000559ns 0.00216ns 0 0 0 0 b
#7652 SendRequest net6.0 61.2μs 51.4ns 185ns 0 0 0 14.52 KB
#7652 SendRequest netcoreapp3.1 72μs 91.2ns 353ns 0 0 0 17.42 KB
#7652 SendRequest net472 0.00901ns 0.00291ns 0.0113ns 0 0 0 0 b
Benchmarks.Trace.CharSliceBenchmark - Faster 🎉 More allocations ⚠️

Faster 🎉 in #7652

Benchmark base/diff Base Median (ns) Diff Median (ns) Modality
Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSliceWithPool‑netcoreapp3.1 1.128 955,821.43 847,733.04
Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSlice‑net6.0 1.119 1,500,582.99 1,341,100.69

More allocations ⚠️ in #7652

Benchmark Base Allocated Diff Allocated Change Change %
Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSlice‑net472 73 B 85 B 12 B 16.44%

Fewer allocations 🎉 in #7652

Benchmark Base Allocated Diff Allocated Change Change %
Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSliceWithPool‑net472 48 B 47 B -1 B -2.08%
Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSlice‑net6.0 7 B 4 B -3 B -42.86%
Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSliceWithPool‑net6.0 4 B 2 B -2 B -50.00%

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master OriginalCharSlice net6.0 1.94ms 4.14μs 15.5μs 0 0 0 640.01 KB
master OriginalCharSlice netcoreapp3.1 2.05ms 6.45μs 24.1μs 0 0 0 640 KB
master OriginalCharSlice net472 2.58ms 122ns 440ns 100 0 0 641.95 KB
master OptimizedCharSlice net6.0 1.5ms 130ns 488ns 0 0 0 7 B
master OptimizedCharSlice netcoreapp3.1 1.72ms 144ns 559ns 0 0 0 1 B
master OptimizedCharSlice net472 1.91ms 336ns 1.3μs 0 0 0 73 B
master OptimizedCharSliceWithPool net6.0 832μs 32ns 124ns 0 0 0 4 B
master OptimizedCharSliceWithPool netcoreapp3.1 956μs 259ns 1μs 0 0 0 1 B
master OptimizedCharSliceWithPool net472 1.15ms 78.1ns 302ns 0 0 0 48 B
#7652 OriginalCharSlice net6.0 1.92ms 5.28μs 19.7μs 0 0 0 640.01 KB
#7652 OriginalCharSlice netcoreapp3.1 2.1ms 6.39μs 23.9μs 0 0 0 640 KB
#7652 OriginalCharSlice net472 2.72ms 1.67μs 6.25μs 100 0 0 641.95 KB
#7652 OptimizedCharSlice net6.0 1.34ms 95.6ns 370ns 0 0 0 4 B
#7652 OptimizedCharSlice netcoreapp3.1 1.7ms 1.06μs 4.11μs 0 0 0 1 B
#7652 OptimizedCharSlice net472 2.07ms 171ns 641ns 0 0 0 85 B
#7652 OptimizedCharSliceWithPool net6.0 809μs 40ns 150ns 0 0 0 2 B
#7652 OptimizedCharSliceWithPool netcoreapp3.1 848μs 156ns 604ns 0 0 0 1 B
#7652 OptimizedCharSliceWithPool net472 1.14ms 164ns 637ns 0 0 0 47 B
Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark - Same speed ✔️ More allocations ⚠️

More allocations ⚠️ in #7652

Benchmark Base Allocated Diff Allocated Change Change %
Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark.WriteAndFlushEnrichedTraces‑netcoreapp3.1 41.96 KB 43.25 KB 1.29 KB 3.08%
Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark.WriteAndFlushEnrichedTraces‑net6.0 42.2 KB 42.46 KB 265 B 0.63%

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master WriteAndFlushEnrichedTraces net6.0 699μs 1.47μs 5.69μs 0 0 0 42.2 KB
master WriteAndFlushEnrichedTraces netcoreapp3.1 780μs 2.26μs 8.74μs 0 0 0 41.96 KB
master WriteAndFlushEnrichedTraces net472 903μs 4.34μs 16.8μs 8.33 0 0 56.18 KB
#7652 WriteAndFlushEnrichedTraces net6.0 693μs 1.08μs 4.05μs 0 0 0 42.46 KB
#7652 WriteAndFlushEnrichedTraces netcoreapp3.1 788μs 6.19μs 60.7μs 0 0 0 43.25 KB
#7652 WriteAndFlushEnrichedTraces net472 878μs 2.93μs 10.9μs 4.46 0 0 55.97 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.97μs 2.76ns 9.58ns 0 0 0 1.02 KB
master ExecuteNonQuery netcoreapp3.1 2.68μs 1.76ns 6.83ns 0 0 0 1.02 KB
master ExecuteNonQuery net472 2.82μs 2.86ns 11.1ns 0.153 0.014 0 987 B
#7652 ExecuteNonQuery net6.0 1.89μs 7.12ns 27.6ns 0 0 0 1.02 KB
#7652 ExecuteNonQuery netcoreapp3.1 2.74μs 4.33ns 16.2ns 0 0 0 1.02 KB
#7652 ExecuteNonQuery net472 2.83μs 4.28ns 16ns 0.153 0.0139 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.87μs 5.83ns 22.6ns 0 0 0 1.03 KB
master CallElasticsearch netcoreapp3.1 2.34μs 6.9ns 26.7ns 0 0 0 1.03 KB
master CallElasticsearch net472 3.44μs 1.19ns 4.59ns 0.155 0 0 1.04 KB
master CallElasticsearchAsync net6.0 1.91μs 1.1ns 4.13ns 0 0 0 1.01 KB
master CallElasticsearchAsync netcoreapp3.1 2.45μs 11.9ns 51.9ns 0 0 0 1.08 KB
master CallElasticsearchAsync net472 3.68μs 4.32ns 16.7ns 0.165 0 0 1.1 KB
#7652 CallElasticsearch net6.0 1.73μs 9.06ns 43.4ns 0 0 0 1.03 KB
#7652 CallElasticsearch netcoreapp3.1 2.26μs 8.38ns 30.2ns 0 0 0 1.03 KB
#7652 CallElasticsearch net472 3.52μs 4.42ns 17.1ns 0.158 0 0 1.04 KB
#7652 CallElasticsearchAsync net6.0 1.92μs 9.66ns 43.2ns 0 0 0 1.01 KB
#7652 CallElasticsearchAsync netcoreapp3.1 2.45μs 11.5ns 44.5ns 0 0 0 1.08 KB
#7652 CallElasticsearchAsync net472 3.9μs 5.73ns 22.2ns 0.156 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.81μs 0.527ns 2.04ns 0 0 0 952 B
master ExecuteAsync netcoreapp3.1 2.39μs 1.43ns 5.14ns 0 0 0 952 B
master ExecuteAsync net472 2.6μs 2.56ns 9.92ns 0.142 0 0 915 B
#7652 ExecuteAsync net6.0 1.86μs 8.23ns 29.7ns 0 0 0 952 B
#7652 ExecuteAsync netcoreapp3.1 2.26μs 6.1ns 23.6ns 0 0 0 952 B
#7652 ExecuteAsync net472 2.52μs 2.22ns 8.6ns 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.28μs 16.4ns 63.6ns 0 0 0 2.36 KB
master SendAsync netcoreapp3.1 8.65μs 37.2ns 144ns 0 0 0 2.9 KB
master SendAsync net472 12.3μs 12.8ns 49.6ns 0.492 0 0 3.18 KB
#7652 SendAsync net6.0 6.74μs 9.77ns 36.6ns 0 0 0 2.36 KB
#7652 SendAsync netcoreapp3.1 8.19μs 19.1ns 73.9ns 0 0 0 2.9 KB
#7652 SendAsync net472 12.4μs 6.19ns 23.2ns 0.496 0 0 3.18 KB
Benchmarks.Trace.Iast.StringAspectsBenchmark - Same speed ✔️ More allocations ⚠️

More allocations ⚠️ in #7652

Benchmark Base Allocated Diff Allocated Change Change %
Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark‑netcoreapp3.1 255.22 KB 276.32 KB 21.1 KB 8.27%
Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark‑net6.0 256 KB 273.98 KB 17.98 KB 7.02%
Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark‑net472 279.5 KB 289.62 KB 10.13 KB 3.62%

Fewer allocations 🎉 in #7652

Benchmark Base Allocated Diff Allocated Change Change %
Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatBenchmark‑net6.0 46.42 KB 44.6 KB -1.82 KB -3.93%
Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatBenchmark‑net472 65.54 KB 57.34 KB -8.19 KB -12.50%
Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatBenchmark‑netcoreapp3.1 87.84 KB 42.64 KB -45.2 KB -51.46%

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master StringConcatBenchmark net6.0 44.6μs 155ns 822ns 0 0 0 46.42 KB
master StringConcatBenchmark netcoreapp3.1 50.7μs 300ns 2.72μs 0 0 0 87.84 KB
master StringConcatBenchmark net472 57μs 270ns 1.05μs 0 0 0 65.54 KB
master StringConcatAspectBenchmark net6.0 447μs 2.22μs 9.91μs 0 0 0 256 KB
master StringConcatAspectBenchmark netcoreapp3.1 491μs 1.84μs 6.63μs 0 0 0 255.22 KB
master StringConcatAspectBenchmark net472 409μs 2.17μs 11.1μs 0 0 0 279.5 KB
#7652 StringConcatBenchmark net6.0 44.7μs 224ns 975ns 0 0 0 44.6 KB
#7652 StringConcatBenchmark netcoreapp3.1 47.1μs 227ns 1.33μs 0 0 0 42.64 KB
#7652 StringConcatBenchmark net472 56.4μs 273ns 1.09μs 0 0 0 57.34 KB
#7652 StringConcatAspectBenchmark net6.0 459μs 830ns 2.87μs 0 0 0 273.98 KB
#7652 StringConcatAspectBenchmark netcoreapp3.1 535μs 2.47μs 9.87μs 0 0 0 276.32 KB
#7652 StringConcatAspectBenchmark net472 405μs 2.14μs 11.1μs 0 0 0 289.62 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.48μs 13.3ns 70.5ns 0 0 0 1.7 KB
master EnrichedLog netcoreapp3.1 3.53μs 2.46ns 9.52ns 0 0 0 1.7 KB
master EnrichedLog net472 3.83μs 4.21ns 16.3ns 0.247 0 0 1.64 KB
#7652 EnrichedLog net6.0 2.55μs 11.1ns 42.9ns 0 0 0 1.7 KB
#7652 EnrichedLog netcoreapp3.1 3.51μs 1.21ns 4.69ns 0 0 0 1.7 KB
#7652 EnrichedLog net472 3.78μs 3.28ns 12.7ns 0.246 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 124μs 53.4ns 200ns 0 0 0 4.31 KB
master EnrichedLog netcoreapp3.1 128μs 175ns 631ns 0 0 0 4.31 KB
master EnrichedLog net472 167μs 38.1ns 142ns 0 0 0 4.52 KB
#7652 EnrichedLog net6.0 123μs 60.1ns 217ns 0 0 0 4.31 KB
#7652 EnrichedLog netcoreapp3.1 128μs 107ns 399ns 0 0 0 4.31 KB
#7652 EnrichedLog net472 169μs 389ns 1.51μs 0 0 0 4.52 KB
Benchmarks.Trace.NLogBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master EnrichedLog net6.0 4.79μs 18.7ns 70.1ns 0 0 0 2.26 KB
master EnrichedLog netcoreapp3.1 6.71μs 5.44ns 21.1ns 0 0 0 2.26 KB
master EnrichedLog net472 7.7μs 9.66ns 36.1ns 0.308 0 0 2.08 KB
#7652 EnrichedLog net6.0 4.97μs 23.1ns 89.4ns 0 0 0 2.26 KB
#7652 EnrichedLog netcoreapp3.1 6.54μs 25.9ns 96.9ns 0 0 0 2.26 KB
#7652 EnrichedLog net472 7.74μs 5.66ns 21.9ns 0.309 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μs 10.3ns 49.2ns 0 0 0 1.2 KB
master SendReceive netcoreapp3.1 2.68μs 12.7ns 52.4ns 0 0 0 1.2 KB
master SendReceive net472 3.11μs 2.09ns 7.83ns 0.187 0 0 1.2 KB
#7652 SendReceive net6.0 2.06μs 10.5ns 44.7ns 0 0 0 1.2 KB
#7652 SendReceive netcoreapp3.1 2.62μs 12.6ns 48.9ns 0 0 0 1.2 KB
#7652 SendReceive net472 3.16μs 1.5ns 5.61ns 0.191 0 0 1.2 KB
Benchmarks.Trace.SerilogBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master EnrichedLog net6.0 4.09μs 6.93ns 26.9ns 0 0 0 1.58 KB
master EnrichedLog netcoreapp3.1 5.49μs 14.6ns 56.5ns 0 0 0 1.63 KB
master EnrichedLog net472 6.56μs 5.22ns 20.2ns 0.294 0 0 2.03 KB
#7652 EnrichedLog net6.0 4.03μs 2.97ns 11.5ns 0 0 0 1.58 KB
#7652 EnrichedLog netcoreapp3.1 5.34μs 11ns 41.3ns 0 0 0 1.63 KB
#7652 EnrichedLog net472 6.54μs 7.15ns 27.7ns 0.294 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 742ns 3.85ns 17.7ns 0 0 0 576 B
master StartFinishSpan netcoreapp3.1 913ns 4.16ns 16.7ns 0 0 0 576 B
master StartFinishSpan net472 884ns 0.26ns 1.01ns 0.0892 0 0 578 B
master StartFinishScope net6.0 887ns 4.29ns 17.1ns 0 0 0 696 B
master StartFinishScope netcoreapp3.1 1.16μs 0.846ns 3.28ns 0 0 0 696 B
master StartFinishScope net472 1.06μs 0.943ns 3.65ns 0.101 0 0 658 B
#7652 StartFinishSpan net6.0 748ns 2.03ns 7.84ns 0 0 0 576 B
#7652 StartFinishSpan netcoreapp3.1 923ns 4.46ns 18.4ns 0 0 0 576 B
#7652 StartFinishSpan net472 881ns 0.176ns 0.659ns 0.0879 0 0 578 B
#7652 StartFinishScope net6.0 901ns 4.12ns 15.4ns 0 0 0 696 B
#7652 StartFinishScope netcoreapp3.1 1.18μs 5.77ns 25.1ns 0 0 0 696 B
#7652 StartFinishScope net472 1.05μs 0.381ns 1.37ns 0.101 0 0 658 B
Benchmarks.Trace.TraceAnnotationsBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master RunOnMethodBegin net6.0 1.05μs 5.05ns 18.9ns 0 0 0 696 B
master RunOnMethodBegin netcoreapp3.1 1.37μs 5.58ns 21.6ns 0 0 0 696 B
master RunOnMethodBegin net472 1.42μs 1.94ns 7.5ns 0.0991 0 0 658 B
#7652 RunOnMethodBegin net6.0 1.03μs 0.607ns 2.19ns 0 0 0 696 B
#7652 RunOnMethodBegin netcoreapp3.1 1.4μs 6.98ns 29.6ns 0 0 0 696 B
#7652 RunOnMethodBegin net472 1.43μs 0.946ns 3.41ns 0.101 0 0 658 B

@andrewlock andrewlock merged commit 8ad16a0 into master Oct 15, 2025
153 of 154 checks passed
@andrewlock andrewlock deleted the andrew/refactor-dynamic-config-manager branch October 15, 2025 09:53
@github-actions github-actions bot added this to the vNext-v3 milestone Oct 15, 2025
andrewlock added a commit that referenced this pull request Oct 15, 2025
## Summary of changes

Rebuild and re-assign `MutableSettings` when dynamic config (remote or
config in code) changes.

## Reason for change

This is part of a general stack to extract the "mutable" configuration
from static config that is fixed for the lifetime of the app. In the
[previous PR](#7522) we
moved mutable settings to their own type, but otherwise left things
unchanged and just rebuilt everything whenever anything changes.

In this PR we move towards combining the dynamic/code configuration,
handling changes by _only_ rebuilding the `MutableSettings` (not
`TracerSettings`) and handling all the fallout that causes for
telemetry.

This is very much still a "stop gap"; we still rebuild everything
(_except_ the `TracerSettings` object) when these settings changes.

## Implementation details

- Create "global" config sources for dynamic settings and code settings
- There's actually a bug today where we clobber dynamic settings if we
change things in code because we're not storing the sources globally.
- When dynamic config or config in code changes
- Create a new `MutableSettings` object based only on dynamic sources
(with a fallback for the "static" values)
  - For config in code, we also check for changes to `ExporterSettings`
- If there's no discernable changes, bail out - no need to tear down the
world
- If there _are_ changes, Mutate `TracerSettings`, and do the normal
"reconfigure everything"
- Remove the (now unused `ImmutableDynamicSettingsTests`)

Note that there are technically some behaviour changes in this PR:
- `useDefaultSources: false` only ignores env vars etc for values that
can be set through code. Other settings will always use the default
sources.
- `StatsComutationEnabled` can not be _set_ via code.

## Test coverage

This is still all technically a "refactoring", so should be covered by
existing tests 🤞

## Other details


https://datadoghq.atlassian.net/browse/LANGPLAT-819

Part of a config stack
- #7522
- #7652
- #7525 👈
- #7530
- #7532
- #7543
- #7544
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants