Skip to content
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

Bail out if we're in a no-dynamic-code scenario #6362

Merged
merged 1 commit into from
Nov 28, 2024

Conversation

andrewlock
Copy link
Member

Summary of changes

Bail out in the managed loader if we're in a no-dynamic code scenario

Reason for change

Our automatic instrumentation is currently inherently tied to emitting dynamic code (Duck typing). In no-dynamic-code scenarios we will likely end up crashing (or giving a very degraded experience, with a performance hit at the very least). It's better to bail out early than do that

Implementation details

Check for the System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported app context switch in the managed loader. This controls the RuntimeFeature.IsDynamicCodeSupported flag, which in turn determines whether the app auto-bails out in .NET 8+.

Note that this flag is set when you add <PublishAot> to your project even if you don't publish with AOT. I imagine there are some other environments (pre .NET 8) in which dynamic code is not available, but I don't know if we need to worry about them

Test coverage

Added an integration tests that sets the flag and confirms we don't get traces when the flag is set to false

Other details

I had to add a helper to the TestHelper to pass runtime arguments to dotnet

@andrewlock andrewlock added area:tracer The core tracer library (Datadog.Trace, does not include OpenTracing, native code, or integrations) area:automatic-instrumentation Automatic instrumentation managed C# code (Datadog.Trace.ClrProfiler.Managed) identified-by:telemetry labels Nov 27, 2024
@andrewlock andrewlock requested review from a team as code owners November 27, 2024 13:16
Copy link
Member

@tonyredondo tonyredondo left a comment

Choose a reason for hiding this comment

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

This will work in the current structure, but how this will work when the CallTarget integrations move to the native side? we need to tell the profiler somehow to avoid rewriting.

@kevingosse
Copy link
Collaborator

This will work in the current structure, but how this will work when the CallTarget integrations move to the native side? we need to tell the profiler somehow to avoid rewriting.

I believe we don't do any rewriting (other than the startup hook) until Datadog.Trace is loaded? Since we're preventing it from being loaded, it should be fine.

@tonyredondo
Copy link
Member

This will work in the current structure, but how this will work when the CallTarget integrations move to the native side? we need to tell the profiler somehow to avoid rewriting.

I believe we don't do any rewriting (other than the startup hook) until Datadog.Trace is loaded? Since we're preventing it from being loaded, it should be fine.

is this true @daniel-romano-DD ?

@datadog-ddstaging
Copy link

datadog-ddstaging bot commented Nov 27, 2024

Datadog Report

Branch report: andrew/bail-out-if-dynamic-code-unavailable
Commit report: c2c6227
Test service: dd-trace-dotnet

✅ 0 Failed, 450418 Passed, 2749 Skipped, 19h 38m 57.06s Total Time

@andrewlock
Copy link
Member Author

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.6.2) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Baseline
    This PR (6362) - mean (69ms)  : 66, 72
     .   : milestone, 69,
    master - mean (69ms)  : 66, 72
     .   : milestone, 69,

    section CallTarget+Inlining+NGEN
    This PR (6362) - mean (980ms)  : 953, 1007
     .   : milestone, 980,
    master - mean (976ms)  : 950, 1002
     .   : milestone, 976,

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

    section CallTarget+Inlining+NGEN
    This PR (6362) - mean (678ms)  : 663, 694
     .   : milestone, 678,
    master - mean (678ms)  : 664, 693
     .   : milestone, 678,

Loading
gantt
    title Execution time (ms) FakeDbCommand (.NET 6) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Baseline
    This PR (6362) - mean (91ms)  : 89, 93
     .   : milestone, 91,
    master - mean (91ms)  : 89, 93
     .   : milestone, 91,

    section CallTarget+Inlining+NGEN
    This PR (6362) - mean (626ms)  : 610, 643
     .   : milestone, 626,
    master - mean (632ms)  : 617, 647
     .   : milestone, 632,

Loading
gantt
    title Execution time (ms) HttpMessageHandler (.NET Framework 4.6.2) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Baseline
    This PR (6362) - mean (191ms)  : 187, 196
     .   : milestone, 191,
    master - mean (191ms)  : 186, 196
     .   : milestone, 191,

    section CallTarget+Inlining+NGEN
    This PR (6362) - mean (1,099ms)  : 1062, 1137
     .   : milestone, 1099,
    master - mean (1,094ms)  : 1062, 1126
     .   : milestone, 1094,

Loading
gantt
    title Execution time (ms) HttpMessageHandler (.NET Core 3.1) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Baseline
    This PR (6362) - mean (278ms)  : 274, 283
     .   : milestone, 278,
    master - mean (275ms)  : 270, 280
     .   : milestone, 275,

    section CallTarget+Inlining+NGEN
    This PR (6362) - mean (873ms)  : 844, 901
     .   : milestone, 873,
    master - mean (872ms)  : 846, 898
     .   : milestone, 872,

Loading
gantt
    title Execution time (ms) HttpMessageHandler (.NET 6) 
    dateFormat  X
    axisFormat %s
    todayMarker off
    section Baseline
    This PR (6362) - mean (266ms)  : 262, 270
     .   : milestone, 266,
    master - mean (266ms)  : 260, 271
     .   : milestone, 266,

    section CallTarget+Inlining+NGEN
    This PR (6362) - mean (846ms)  : 812, 879
     .   : milestone, 846,
    master - mean (850ms)  : 816, 885
     .   : milestone, 850,

Loading

@andrewlock
Copy link
Member Author

Benchmarks Report for tracer 🐌

Benchmarks for #6362 compared to master:

  • 2 benchmarks are slower, with geometric mean 1.129
  • All benchmarks have the same allocations

The following thresholds were used for comparing the benchmark speeds:

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

Allocation changes below 0.5% are ignored.

Benchmark details

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

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master StartStopWithChild net6.0 8.1μs 45ns 302ns 0.0162 0.00812 0 5.61 KB
master StartStopWithChild netcoreapp3.1 10.2μs 55.7ns 315ns 0.0206 0.0103 0 5.79 KB
master StartStopWithChild net472 16.4μs 36.8ns 138ns 1.04 0.313 0.0989 6.21 KB
#6362 StartStopWithChild net6.0 8.12μs 43.5ns 285ns 0.0171 0.00855 0 5.61 KB
#6362 StartStopWithChild netcoreapp3.1 10.2μs 54.9ns 285ns 0.0253 0.0101 0 5.8 KB
#6362 StartStopWithChild net472 16.4μs 49ns 183ns 1.05 0.314 0.108 6.2 KB
Benchmarks.Trace.AgentWriterBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master WriteAndFlushEnrichedTraces net6.0 492μs 441ns 1.65μs 0 0 0 2.7 KB
master WriteAndFlushEnrichedTraces netcoreapp3.1 651μs 186ns 720ns 0 0 0 2.7 KB
master WriteAndFlushEnrichedTraces net472 838μs 293ns 1.1μs 0.419 0 0 3.3 KB
#6362 WriteAndFlushEnrichedTraces net6.0 497μs 274ns 1.06μs 0 0 0 2.7 KB
#6362 WriteAndFlushEnrichedTraces netcoreapp3.1 647μs 459ns 1.72μs 0 0 0 2.7 KB
#6362 WriteAndFlushEnrichedTraces net472 839μs 499ns 1.93μs 0.419 0 0 3.3 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 150μs 975ns 9.55μs 0.15 0 0 14.47 KB
master SendRequest netcoreapp3.1 168μs 947ns 8.31μs 0.161 0 0 17.27 KB
master SendRequest net472 0.00249ns 0.00101ns 0.00392ns 0 0 0 0 b
#6362 SendRequest net6.0 147μs 901ns 8.78μs 0.139 0 0 14.47 KB
#6362 SendRequest netcoreapp3.1 169μs 991ns 9.76μs 0.164 0 0 17.27 KB
#6362 SendRequest net472 0.00198ns 0.000918ns 0.00355ns 0 0 0 0 b
Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master WriteAndFlushEnrichedTraces net6.0 579μs 3.11μs 17.9μs 0.568 0 0 41.71 KB
master WriteAndFlushEnrichedTraces netcoreapp3.1 706μs 4.01μs 27.5μs 0.353 0 0 41.74 KB
master WriteAndFlushEnrichedTraces net472 867μs 2.79μs 10.1μs 8.36 2.64 0.44 53.3 KB
#6362 WriteAndFlushEnrichedTraces net6.0 573μs 3.1μs 17μs 0.558 0 0 41.61 KB
#6362 WriteAndFlushEnrichedTraces netcoreapp3.1 669μs 2.77μs 12.1μs 0.332 0 0 41.63 KB
#6362 WriteAndFlushEnrichedTraces net472 890μs 2.95μs 11.4μs 8.15 2.26 0.453 53.33 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.31μs 1.6ns 5.97ns 0.0143 0 0 1.02 KB
master ExecuteNonQuery netcoreapp3.1 1.82μs 1.7ns 6.34ns 0.0135 0 0 1.02 KB
master ExecuteNonQuery net472 2.11μs 1.79ns 6.95ns 0.156 0.00105 0 987 B
#6362 ExecuteNonQuery net6.0 1.33μs 1.16ns 4.49ns 0.014 0 0 1.02 KB
#6362 ExecuteNonQuery netcoreapp3.1 1.82μs 1.46ns 5.64ns 0.0136 0 0 1.02 KB
#6362 ExecuteNonQuery net472 2.09μs 4.74ns 18.4ns 0.156 0.00103 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.22μs 0.793ns 2.97ns 0.0138 0 0 976 B
master CallElasticsearch netcoreapp3.1 1.53μs 0.963ns 3.73ns 0.0134 0 0 976 B
master CallElasticsearch net472 2.48μs 2.68ns 10.4ns 0.157 0 0 995 B
master CallElasticsearchAsync net6.0 1.26μs 0.662ns 2.56ns 0.0131 0 0 952 B
master CallElasticsearchAsync netcoreapp3.1 1.69μs 1.93ns 7.46ns 0.0133 0 0 1.02 KB
master CallElasticsearchAsync net472 2.6μs 1.63ns 5.88ns 0.166 0 0 1.05 KB
#6362 CallElasticsearch net6.0 1.19μs 0.477ns 1.78ns 0.0138 0 0 976 B
#6362 CallElasticsearch netcoreapp3.1 1.52μs 0.916ns 3.43ns 0.0128 0 0 976 B
#6362 CallElasticsearch net472 2.66μs 3.24ns 12.5ns 0.157 0 0 995 B
#6362 CallElasticsearchAsync net6.0 1.34μs 1.42ns 5.31ns 0.0134 0 0 952 B
#6362 CallElasticsearchAsync netcoreapp3.1 1.61μs 1.95ns 7.31ns 0.0136 0 0 1.02 KB
#6362 CallElasticsearchAsync net472 2.62μs 1.27ns 4.92ns 0.166 0 0 1.05 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.28μs 0.388ns 1.45ns 0.0132 0 0 952 B
master ExecuteAsync netcoreapp3.1 1.6μs 0.609ns 2.2ns 0.0128 0 0 952 B
master ExecuteAsync net472 1.88μs 0.658ns 2.46ns 0.145 0 0 915 B
#6362 ExecuteAsync net6.0 1.24μs 0.753ns 2.82ns 0.0132 0 0 952 B
#6362 ExecuteAsync netcoreapp3.1 1.62μs 0.558ns 2.16ns 0.0129 0 0 952 B
#6362 ExecuteAsync net472 1.85μs 0.457ns 1.71ns 0.145 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 4.47μs 9.96ns 38.6ns 0.031 0 0 2.31 KB
master SendAsync netcoreapp3.1 5.28μs 5.49ns 21.3ns 0.037 0 0 2.85 KB
master SendAsync net472 7.37μs 1.81ns 7.02ns 0.493 0 0 3.12 KB
#6362 SendAsync net6.0 4.46μs 1.45ns 5.62ns 0.0334 0 0 2.31 KB
#6362 SendAsync netcoreapp3.1 5.3μs 3.45ns 13.4ns 0.0371 0 0 2.85 KB
#6362 SendAsync net472 7.25μs 2.17ns 8.41ns 0.493 0 0 3.12 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 1.54μs 1.01ns 3.78ns 0.023 0 0 1.64 KB
master EnrichedLog netcoreapp3.1 2.3μs 0.696ns 2.6ns 0.0228 0 0 1.64 KB
master EnrichedLog net472 2.54μs 0.824ns 2.97ns 0.25 0 0 1.57 KB
#6362 EnrichedLog net6.0 1.54μs 1.41ns 5.27ns 0.0226 0 0 1.64 KB
#6362 EnrichedLog netcoreapp3.1 2.14μs 1.05ns 4.08ns 0.0227 0 0 1.64 KB
#6362 EnrichedLog net472 2.49μs 1.42ns 5.32ns 0.25 0 0 1.57 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 120μs 125ns 485ns 0.06 0 0 4.28 KB
master EnrichedLog netcoreapp3.1 125μs 100ns 362ns 0 0 0 4.28 KB
master EnrichedLog net472 151μs 208ns 806ns 0.681 0.227 0 4.46 KB
#6362 EnrichedLog net6.0 120μs 159ns 594ns 0 0 0 4.28 KB
#6362 EnrichedLog netcoreapp3.1 124μs 222ns 861ns 0 0 0 4.28 KB
#6362 EnrichedLog net472 153μs 120ns 465ns 0.685 0.228 0 4.46 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 3.05μs 0.844ns 3.27ns 0.0302 0 0 2.2 KB
master EnrichedLog netcoreapp3.1 4.14μs 4.86ns 18.8ns 0.0293 0 0 2.2 KB
master EnrichedLog net472 4.86μs 1.25ns 4.68ns 0.32 0 0 2.02 KB
#6362 EnrichedLog net6.0 2.9μs 0.926ns 3.59ns 0.0305 0 0 2.2 KB
#6362 EnrichedLog netcoreapp3.1 4.4μs 2.14ns 8.28ns 0.0287 0 0 2.2 KB
#6362 EnrichedLog net472 4.81μs 1.26ns 4.89ns 0.319 0 0 2.02 KB
Benchmarks.Trace.RedisBenchmark - Same speed ✔️ Same allocations ✔️

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master SendReceive net6.0 1.38μs 0.811ns 3.14ns 0.0158 0 0 1.14 KB
master SendReceive netcoreapp3.1 1.75μs 1.04ns 3.74ns 0.0149 0 0 1.14 KB
master SendReceive net472 2.11μs 2.8ns 10.8ns 0.183 0 0 1.16 KB
#6362 SendReceive net6.0 1.32μs 0.742ns 2.88ns 0.0159 0 0 1.14 KB
#6362 SendReceive netcoreapp3.1 1.75μs 1.25ns 4.86ns 0.0157 0 0 1.14 KB
#6362 SendReceive net472 2.03μs 1.75ns 6.54ns 0.183 0 0 1.16 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 2.81μs 1.38ns 5.35ns 0.0225 0 0 1.6 KB
master EnrichedLog netcoreapp3.1 3.73μs 1.28ns 4.96ns 0.0224 0 0 1.65 KB
master EnrichedLog net472 4.49μs 3.58ns 13.9ns 0.322 0 0 2.04 KB
#6362 EnrichedLog net6.0 2.82μs 1.24ns 4.81ns 0.0226 0 0 1.6 KB
#6362 EnrichedLog netcoreapp3.1 3.83μs 0.905ns 3.26ns 0.021 0 0 1.65 KB
#6362 EnrichedLog net472 4.49μs 2.7ns 10.4ns 0.322 0 0 2.04 KB
Benchmarks.Trace.SpanBenchmark - Slower ⚠️ Same allocations ✔️

Slower ⚠️ in #6362

Benchmark diff/base Base Median (ns) Diff Median (ns) Modality
Benchmarks.Trace.SpanBenchmark.StartFinishSpan‑netcoreapp3.1 1.146 565.65 648.06
Benchmarks.Trace.SpanBenchmark.StartFinishSpan‑net6.0 1.113 407.73 453.90

Raw results

Branch Method Toolchain Mean StdError StdDev Gen 0 Gen 1 Gen 2 Allocated
master StartFinishSpan net6.0 408ns 0.135ns 0.487ns 0.00799 0 0 576 B
master StartFinishSpan netcoreapp3.1 565ns 1.49ns 5.78ns 0.00779 0 0 576 B
master StartFinishSpan net472 676ns 0.404ns 1.56ns 0.0915 0 0 578 B
master StartFinishScope net6.0 487ns 0.241ns 0.934ns 0.00965 0 0 696 B
master StartFinishScope netcoreapp3.1 676ns 0.274ns 0.986ns 0.00934 0 0 696 B
master StartFinishScope net472 880ns 0.46ns 1.78ns 0.104 0 0 658 B
#6362 StartFinishSpan net6.0 454ns 0.204ns 0.765ns 0.00803 0 0 576 B
#6362 StartFinishSpan netcoreapp3.1 645ns 2.1ns 8.12ns 0.0078 0 0 576 B
#6362 StartFinishSpan net472 625ns 0.478ns 1.85ns 0.0916 0 0 578 B
#6362 StartFinishScope net6.0 485ns 0.336ns 1.3ns 0.0097 0 0 696 B
#6362 StartFinishScope netcoreapp3.1 742ns 0.567ns 2.19ns 0.00941 0 0 696 B
#6362 StartFinishScope net472 910ns 0.395ns 1.53ns 0.105 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 686ns 0.519ns 2.01ns 0.00971 0 0 696 B
master RunOnMethodBegin netcoreapp3.1 931ns 1.24ns 4.79ns 0.00901 0 0 696 B
master RunOnMethodBegin net472 1.13μs 0.561ns 2.17ns 0.105 0 0 658 B
#6362 RunOnMethodBegin net6.0 663ns 0.214ns 0.828ns 0.00961 0 0 696 B
#6362 RunOnMethodBegin netcoreapp3.1 934ns 0.437ns 1.63ns 0.00938 0 0 696 B
#6362 RunOnMethodBegin net472 1.09μs 0.396ns 1.53ns 0.105 0 0 658 B

@andrewlock
Copy link
Member Author

Throughput/Crank Report ⚡

Throughput results for AspNetCoreSimpleController comparing the following branches/commits:

Cases where throughput results for the PR are worse than latest master (5% drop or greater), results are shown in red.

Note that these results are based on a single point-in-time result for each branch. For full results, see one of the many, many dashboards!

gantt
    title Throughput Linux x64 (Total requests) 
    dateFormat  X
    axisFormat %s
    section Baseline
    This PR (6362) (11.354M)   : 0, 11354041
    master (11.171M)   : 0, 11171321
    benchmarks/2.9.0 (11.033M)   : 0, 11032866

    section Automatic
    This PR (6362) (7.309M)   : 0, 7309149
    master (7.220M)   : 0, 7220293
    benchmarks/2.9.0 (7.786M)   : 0, 7785853

    section Trace stats
    master (7.672M)   : 0, 7672287

    section Manual
    master (11.297M)   : 0, 11297089

    section Manual + Automatic
    This PR (6362) (6.671M)   : 0, 6670901
    master (6.666M)   : 0, 6665729

    section DD_TRACE_ENABLED=0
    master (10.155M)   : 0, 10155271

Loading
gantt
    title Throughput Linux arm64 (Total requests) 
    dateFormat  X
    axisFormat %s
    section Baseline
    This PR (6362) (9.638M)   : 0, 9638059
    master (9.792M)   : 0, 9792239
    benchmarks/2.9.0 (9.495M)   : 0, 9494821

    section Automatic
    This PR (6362) (6.504M)   : 0, 6503694
    master (6.460M)   : 0, 6460434

    section Trace stats
    master (6.580M)   : 0, 6580287

    section Manual
    master (9.509M)   : 0, 9508789

    section Manual + Automatic
    This PR (6362) (5.904M)   : 0, 5903531
    master (5.968M)   : 0, 5968264

    section DD_TRACE_ENABLED=0
    master (8.863M)   : 0, 8863124

Loading
gantt
    title Throughput Windows x64 (Total requests) 
    dateFormat  X
    axisFormat %s
    section Baseline
    This PR (6362) (10.114M)   : 0, 10114056
    master (9.925M)   : 0, 9924990
    benchmarks/2.9.0 (10.020M)   : 0, 10019592

    section Automatic
    This PR (6362) (6.674M)   : 0, 6673595
    master (6.383M)   : 0, 6383332
    benchmarks/2.9.0 (7.255M)   : 0, 7255257

    section Trace stats
    master (7.050M)   : 0, 7050172

    section Manual
    master (9.974M)   : 0, 9974221

    section Manual + Automatic
    This PR (6362) (6.380M)   : 0, 6379711
    master (5.768M)   : 0, 5768402

    section DD_TRACE_ENABLED=0
    master (9.135M)   : 0, 9134686

Loading

Copy link
Contributor

@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.

👍

@andrewlock
Copy link
Member Author

This will work in the current structure, but how this will work when the CallTarget integrations move to the native side? we need to tell the profiler somehow to avoid rewriting.

I believe we don't do any rewriting (other than the startup hook) until Datadog.Trace is loaded? Since we're preventing it from being loaded, it should be fine.

is this true @daniel-romano-DD ?

I've confirmed it's true. The native side still waits for a call from the managed side (to know what to enable apart from anything else)

https://github.com/DataDog/dd-trace-dotnet/blob/master/tracer/src/Datadog.Trace/ClrProfiler/Instrumentation.cs#L143

Plus... that code is already merged, and this works so... 😄

@daniel-romano-DD
Copy link
Contributor

This will work in the current structure, but how this will work when the CallTarget integrations move to the native side? we need to tell the profiler somehow to avoid rewriting.

I believe we don't do any rewriting (other than the startup hook) until Datadog.Trace is loaded? Since we're preventing it from being loaded, it should be fine.

Yes, initialization is still done when managed library is loaded and calls similar methods as before, but withouth marshalling all the definitions, which are retrieved from the native side directly. But the root methods keep being the same, so, the same behavior should be expected.

Copy link
Contributor

@daniel-romano-DD daniel-romano-DD left a comment

Choose a reason for hiding this comment

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

👍

@andrewlock andrewlock merged commit 959f006 into master Nov 28, 2024
77 checks passed
@andrewlock andrewlock deleted the andrew/bail-out-if-dynamic-code-unavailable branch November 28, 2024 12:57
@github-actions github-actions bot added this to the vNext-v3 milestone Nov 28, 2024
veerbia pushed a commit that referenced this pull request Dec 16, 2024
## Summary of changes

Bail out in the managed loader if we're in a no-dynamic code scenario

## Reason for change

Our automatic instrumentation is currently inherently tied to emitting
dynamic code (Duck typing). In no-dynamic-code scenarios we will likely
end up crashing (or giving a very degraded experience, with a
performance hit at the very least). It's better to bail out early than
do that

## Implementation details

Check for the
`System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeSupported`
app context switch in the managed loader. This controls the
`RuntimeFeature.IsDynamicCodeSupported` flag, which in turn determines
whether the app auto-bails out in .NET 8+.

Note that this flag is set when you add `<PublishAot>` to your project
_even if you don't publish with AOT_. I imagine there are some other
environments (pre .NET 8) in which dynamic code is not available, but I
don't know if we need to worry about them

## Test coverage

Added an integration tests that sets the flag and confirms we don't get
traces when the flag is set to `false`

## Other details

I had to add a helper to the `TestHelper` to pass runtime arguments to
`dotnet`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:automatic-instrumentation Automatic instrumentation managed C# code (Datadog.Trace.ClrProfiler.Managed) area:tracer The core tracer library (Datadog.Trace, does not include OpenTracing, native code, or integrations) identified-by:telemetry
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants