Skip to content

[NativeAOT] Instrument NativeAOT applications at build time - #9400

Draft
tonyredondo wants to merge 155 commits into
codex/ducktyping-nativeaotfrom
tony/nativeaot-tracer
Draft

tonyredondo wants to merge 155 commits into
codex/ducktyping-nativeaotfrom
tony/nativeaot-tracer

Conversation

@tonyredondo

@tonyredondo tonyredondo commented Oct 13, 2026 •

Copy link
Copy Markdown
Member

Summary of changes

Adds NativeAOT support to the tracer: the Datadog.Trace.Aot NuGet package instruments applications published with PublishAot=true at build time.

Reason for change

NativeAOT applications have no JIT and no dynamic code: the profiler can't rewrite methods, and the tracer can't create its CallTarget adapters and duck typing proxies at runtime.

Implementation details

  • dd-trace aot instrument hosts Datadog.Tracer.Native offline (the ICorProfilerInfo subset it uses, emulated over dnlib) and rewrites the application and its references before ILC, like the profiler does at runtime.
  • The code the tracer creates at runtime is generated at publish instead: CallTarget registrations and a DuckType AOT registry (on top of feat(ducktyping): add NativeAOT registry generation and parity gates #8252). The duck typing mappings created from runtime types are declared next to their proxies ([DuckType]/[DuckCopy] targets, IncludeDerivedTypes, open generic targets).
  • Datadog.Trace.Aot.targets plugs it into dotnet publish, and the application's module initializer starts the tracer (Instrumentation.InitializeAot).
  • The begin of a method with more than 8 arguments looks the proxies of its arguments up by runtime type: the registry has the proxy of each type assignable to the static type, except for a proxy that binds no member (a marker interface), which the proxy of System.Object serves for every type. An object argument would otherwise get a proxy per type of the application (7,301 in CallTargetNativeTest), and ILC overflows the 1 MB stack of Windows on them.
  • The Datadog.Trace.Aot package of a pull request build has the build id in its version (<version>-prerelease.<BUILD_BUILDID>): NuGet keeps the first package of a version it extracts, so testing the package of a newer build used the old one. Local, master and release builds keep <version>-prerelease.
  • Duck typing parity for the runtime types a declared proxy serves: the instantiations over value types of open generic targets (e.g. Kafka's Producer<int, string>), which NativeAOT can't build from the generic proxy, get closed proxies (the search of generic instantiations also follows the code that calls the targets' constructors); and the classes of the application deriving from an IncludeDerivedTypes target that declare a member the proxy binds (a new member, a new member, a field with the same name) get proxies of their own, bound like dynamic duck typing binds them.
  • Products NativeAOT applications don't have are left out of the binary: Test Optimization (CI Visibility, feature switch Datadog.Trace.TestOptimization.IsSupported), the runtime debugger products (Dynamic Instrumentation, Exception Replay, Symbol Database; Code Origin stays) and their JSON models. The Samples.HttpMessageHandler binary goes from 28.8 MB to 24.4 MB, and its startup is 3.4 ms faster.
  • Design, status and per-sample results: docs/development/NativeAOT.md, NativeAOT.Plan.md, NativeAOT.Tracker.md, NativeAOT.Samples.md, NativeAOT.Integrations.md.

NativeAOT support

Per integration, from the e2e samples (JIT with the profiler compared with NativeAOT), a NativeAOT publish of the 94 applicable samples with the instrumentation reports and ILC warnings, and whether each library declares AOT compatibility. Details in docs/development/NativeAOT.Integrations.md.

When something fails

What fails At build time At runtime How it shows
Binding an integration method (a missing member, the duck typing of a constraint) The CallTarget registration records the failure The first call throws CallTargetInvokerException, which disables the integration for that type A warning in the tracer log and the IntegrationDisabledDueToError telemetry; the application keeps running
A duck typing mapping that isn't declared nor comes from a constraint — (CheckAotDuckTypeDeclarations fails in CI for the mappings the integration tests record) DuckTypeAotMissingProxyRegistrationException where the proxy is created The integration's own error handling (usually a warning in the log)
A duck typing mapping that also fails with dynamic duck typing The registry replays the failure The same exception as under JIT Same as under JIT
The search of generic instantiations is cut (a generic cycle, or its limit) and instrumented generic methods need them The warning DDAOT001 lists the methods (an error with DatadogAotFailOnError) Their integrations don't trace the instantiations that are missing (CallTargetInvokerException on the first call, the integration disabled for that type) The build warning, and the report's GenericInstantiations
A method ILC can't compile ILC prints Method '...' will always throw The method throws The package tests fail when it's a method of Datadog.Trace
A library that doesn't support NativeAOT Usually trimming/AOT warnings of the library The library fails, also without Datadog The application's own errors

Integrations

Status: Supported (same spans and tags as under JIT); Supported, library partial (what the library runs in NativeAOT
has parity, the rest fails also without Datadog); Not supported (library) (the library doesn't run in NativeAOT);
Not verified (no NativeAOT run yet); Not applicable; Deferred (decided not to support yet). "AOT-annotated"
is whether the library's latest version declares trimming/AOT compatibility; a library that doesn't can still work.

Integration Library (versions run) Status AOT-annotated Evidence and limits
AdoNet ADO.NET providers Supported — FakeDbCommand 112/112 and the providers below
SqlClient System.Data.SqlClient 4.9.1, Microsoft.Data.SqlClient 7.1.0 Supported No (7.x partly) Parity on the typed phase of the samples
Npgsql 10.0.3 Supported Yes Parity
MySql MySql.Data, MySqlConnector 2.6.2 Supported No / Yes Parity (MySql.Data needs a reflection descriptor of its own)
Oracle Oracle.ManagedDataAccess.Core Supported No Parity against Oracle Free; Oracle.DataAccess (unmanaged) is .NET Framework only
Sqlite Microsoft.Data.Sqlite 10, System.Data.SQLite.Core Supported No (partly) 126/126 both
Aerospike 8.5.0 Supported No 19/19
AspNetCore ASP.NET Core (Kestrel, minimal APIs with the request delegate generator) Supported Yes Spans, AppSec (WAF, blocking, remote activation), RASP, IAST and Code Origin. MVC and Razor Pages don't run in NativeAOT (the framework), so the integration's MVC parts (actions, model binding for AppSec and IAST) don't apply
AwsSdk, AwsS3, AwsSqs, AwsSns, AwsDynamoDb, AwsEventBridge, AwsKinesis, AwsStepFunctions AWSSDK v4 Supported Yes Parity, also DSM. AWSSDK v3 creates its services by reflection (the library). Kinesis GetRecords needs StreamARN, also under JIT
AwsLambda Amazon.Lambda.RuntimeSupport 2.x Supported Yes Serverless, manual and HTTP spans per invocation
AzureEventHubs Azure.Messaging.EventHubs 5.12.2 Supported Yes The four modes of its test
AzureServiceBus Azure.Messaging.ServiceBus 7.17.5 Supported Yes Five scenarios of its test
AzureFunctions, ServerlessCompat Microsoft.Azure.Functions.Worker 2.x, Datadog.Serverless.Compat Not verified No Needs the Functions host; NativeAOT in the isolated worker isn't officially documented
CosmosDb Microsoft.Azure.Cosmos 3.56 Supported, library partial No CRUD with parity; queries fail in the SDK (query plan with Newtonsoft and MakeGenericType of value types)
Couchbase CouchbaseNetClient 2.7.27 / 3.x Supported (2.x) / Not supported (library, 3.x) No 3.x creates Logger<T> with MakeGenericType in its DI
DatadogTraceManual Manual API, OpenTracing Supported — Manual instrumentation 47/47, OpenTracing, manual DSM
DatadogTraceVersionConflict Datadog.Trace 1.x/2.x from NuGet Not applicable — By design: the publish asks for the manual API of the current version
ElasticsearchNet NEST 5/6/7, Elasticsearch.Net Not supported (library) No Converters and responses by reflection; 7.x emits IL
GraphQL GraphQL.NET 2.x, 3.x, 7.x / 4.x-5.x Supported, library partial / Not supported (library, 4.x-5.x) Partly Same spans; some resolvers of the library fail by reflection; 4.x-5.x build their types with MakeGenericType
Grpc Grpc.Net 2.67, Grpc.Core 2.45 Supported Yes / No 80/80 and parity
Hangfire 1.7.0 Supported No With the context propagation through the job parameter
HotChocolate 13-15 Not supported (library) No Its DI doesn't find constructors
HttpMessageHandler (sockets, curl, WinHttp) System.Net.Http Supported Yes 222/222 on net8.0 to net11.0
WebRequest System.Net.Requests Supported Yes 134/134
Process System.Diagnostics.Process Supported Yes 10/10 with command collection
IbmMq IBMMQDotnetClient (amqmdnetstd) Not verified No No sample
ILogger Microsoft.Extensions.Logging Supported Yes Logs injection and direct submission. Microsoft.Extensions.Telemetry (ExtendedLogger) doesn't run in NativeAOT (DI by reflection, the library)
Serilog 4.x Supported Yes Logs injection and direct submission
NLog 6.x Supported Partly Logs injection and direct submission with NLog 6. Not verified in NativeAOT: the NLog 4 contexts (MDC, MDLC), JSON layouts and a run without configuration file (they keep their ILC warnings)
Log4Net log4net Not supported (library) Partly Doesn't create its appenders in NativeAOT
Kafka Confluent.Kafka 1.9.2, 2.15.1 Supported No Producers and consumers with parity against a broker (spans and tags, with and without delivery handler, value-type keys, cluster id, DSM checkpoints and backlogs); the package keeps the librdkafka bindings the library looks up by reflection (it doesn't start without them in NativeAOT). The application's own reflection (e.g. deserializing its messages with Newtonsoft) needs its own descriptors
MongoDb MongoDB.Driver 3.12 Supported, library partial No The first commands with parity; the driver fails in its serializers (MakeGenericType of value types)
OpenFeature 2.3.0 Supported Yes Remote Configuration FFE_FLAGS and exposures
OpenTelemetry OpenTelemetry SDK 1.18 / OpenTelemetry.Api 1.3.1 Supported / Not supported (library, 1.3.1) Yes With DD_TRACE_OTEL_ENABLED and the resource; OTLP export of traces (JSON and protobuf, also on .NET 8 since H-73)
Protobuf Google.Protobuf Supported Yes DSM
RabbitMQ RabbitMQ.Client 7.2.2 Supported Yes 108/108 and DSM
Quartz (activities) Quartz 3.22 Supported Yes Through the activity listener
ServiceStackRedis ServiceStack.Redis Supported No Parity on the typed phase
StackExchangeRedis 2.1 to 3.3 Supported No Also two versions in the same application
IAST and RASP call sites, HashAlgorithm, SymmetricAlgorithm BCL Supported — Weak cipher, deduplication, LFI/path traversal; the call sites are instrumented at build time
Ssrf, Xss, StackTraceLeak, NHibernate (IAST) RestSharp, ASP.NET Core, NHibernate Not verified No (RestSharp) No specific sample
TraceAnnotations [Trace], DD_TRACE_METHODS Supported — 68/68
ServiceRemoting Service Fabric Not supported (library) No Service Fabric Remoting emits its proxies with Reflection.Emit; NativeAOT applications don't start it
Dapper with Dapper.AOT (through the ADO.NET integrations) Dapper 2.1.89 + Dapper.AOT 1.1.0, Microsoft.Data.Sqlite 10 Supported Yes (Dapper.AOT) Same spans and tags as under JIT (Execute, Query, QuerySingle, ExecuteScalar, sync and async); Dapper alone emits IL at runtime and doesn't run in NativeAOT
EF Core with a compiled model and precompiled queries (through the ADO.NET integrations) Microsoft.EntityFrameworkCore.Sqlite 10.0.13 (EFOptimizeContext, queries precompiled when publishing) Supported Experimental (EF Core) Same spans and tags as under JIT (SaveChanges with its transaction, Where/SingleAsync, CountAsync, OrderBy/ToListAsync, raw SQL); EF Core's NativeAOT support is experimental (no dynamic queries, no EnsureCreated/migrations at runtime)
Ocelot, YARP, MassTransit, Rebus, Dapper without Dapper.AOT, EF Core without precompiled queries (no integration of their own) — Not supported (library) No, except YARP DI and middlewares by reflection, Reflection.Emit
AspNet, AspNetMvc, AspNetWebApi2, Wcf, Msmq, Remoting .NET Framework Not applicable — NativeAOT is .NET 8+
XUnit, NUnit, MsTestV2, DotnetTest, Selenium, TestPlatformAssemblyResolver Test frameworks Deferred (CI Visibility) — The NativeAOT mode of xUnit v3 runs the tests with other assemblies (xunit.v3.core.aot); MSTest's is alpha. Test Optimization isn't compiled in NativeAOT applications
Dynamic Instrumentation, Exception Replay, Symbol Database — Deferred — They rewrite methods or read the assemblies' files at runtime: not compiled in NativeAOT applications
Continuous Profiler — Not applicable — Needs the CLR profiling API

Findings in the tracer

Finding Status
H-72: the instrumentation logged [ERR] ... Expected a null constant (GraphQL, Rebus): dnlib reads the local PDB constants of an enum type it can't resolve as class constants, which its writer rejects Fixed: they're written as enum constants
H-73: ILC 8 can't compile EnumerateTags<TagWriter<__Canon>>: the OTLP export of traces in JSON threw InvalidProgramException on .NET 8 Fixed (the state is a struct); the package tests fail on any will always throw of Datadog.Trace
H-74: will always throw of the ASP.NET Core observers in the samples without ASP.NET Core (ILC 8) Test-only: the samples' helper looks up Datadog.Trace types by name, which keeps them; applications don't
H-75: ILC warnings of Datadog.Trace in real applications (49 in the samples) Explained where verified (see below); the unverified paths keep theirs
H-76: the search of generic instantiations spent its budget (50,000 contexts) on the framework first and left out the instantiations of the packages in large applications: in an ASP.NET Core application with MongoDB, the mongodb.query spans had no command and the ASP.NET Core route tags were missing Fixed: the search only follows the generic code that leads to instrumented generic methods (1,294 contexts instead of a cut at 50,000 in Security.AspNetCore5; MongoDB 0 → 12 instantiations, AWS SDK 0 → 71), cuts generic cycles, and warns (DDAOT001) when cut
H-77: the Kafka client handle proxy was only declared for Producer<Null, Null>: no cluster id with other types Fixed (open generic Producer<,> and Consumer<,>)
H-84: the tracer's overhead in NativeAOT (Samples.HttpMessageHandler, locally: 26 ms without the tracer, 267 ms with it) is mostly its shutdown: two sleeps nothing interrupts (the DogStatsD worker and the trace serialization thread), also under JIT The sleeps are fixed for JIT and NativeAOT in #9419 (267 → 68 ms in this sample with its prototype); the startup is faster (registry, products left out)
H-85: ILC overflowed the 1 MB stack of Windows on the 7,301 duck typing proxies of an object argument of the slow begin path (every proxy implements a generic virtual method, which ILC hashes recursively), and the macOS publish passed 5 minutes Fixed: a proxy that binds no member is registered once for System.Object
H-86: a generic proxy only serves reference type arguments in NativeAOT: without a recorded map, Producer<int, string> had no proxy (Kafka client handle, cluster id) Fixed: closed proxies for the instantiations over value types the application creates
H-87: Kafka producers over value types that the application only uses with ProduceAsync: the default delivery handler's MakeGenericType of DeliveryReport<TKey, TValue> had no code, and the exception in the producer constructor's integration left the spans without bootstrap servers and cluster id Fixed: the runner keeps those instantiations (Datadog.Trace.Kafka.rd.xml)
H-88: IncludeDerivedTypes proxies served the derived classes bound to the base type's members (a member only a derived class has, or that hides the base's, was bound differently than under JIT) Fixed: those classes get proxies of their own

ILC warnings left

The paths that keep their ILC warning because NativeAOT didn't run them:

Warning Code Why it's not verified
IL2026 NLog DiagnosticContextHelper.GetMdcProxy, GetMdlcProxy Logs injection with NLog 4 (MDC, MDLC); NLog 5+ uses ScopeContext
IL2077 NLog LogsInjectionHelper.AddAttributeToJson4Layout Logs injection into a JSON layout
IL2091 NLog LoggingConfigurationFileLoaderLoadInstrumentation.OnMethodEnd An NLog 6 run without configuration file
IL3050 Log4Net Log4NetCommon.TryAddAppenderToResponse log4net doesn't run in NativeAOT
IL2026, IL2067, IL2070, IL3050 AppSec ObjectExtractor Only reached by MVC model binding, which doesn't run in NativeAOT

Known issues

Bugs found and not fixed, detailed in NativeAOT.KnownIssues.md:

Issue Affects Status
An instrumented method returning a subclass of Task<TResult> (e.g. PairTask<TResult, TTag> : Task<TResult>) that isn't completed gets the continuation, a Task<TResult>, converted to the subclass with Unsafe.As: a cast or a member of the subclass then fails JIT (every version with continuations) and NativeAOT NativeAOT behaves like JIT; the fix (return the original task, observe its completion) changes JIT and goes in its own PR
Duck typing method selection ignores the proxy method's BindingFlags when it adapts the arguments (e.g. a proxy restricted to public methods selects a private one through duck chaining); with fallback names, such a method of the first name wins Duck typing in JIT (every version) and NativeAOT NativeAOT generates the same selection; the fix changes dynamic duck typing. No proxy of Datadog.Trace restricts its binding flags
The duck typing discovery recorder (DD_DUCKTYPE_DISCOVERY_OUTPUT_PATH, tests) writes the map without its lock when it can't take it within 30 s or can't open the lock file; another process that read the map before and writes it after drops those mappings Recording of mappings, not applications Not fixed: negligible window (see #8252)

Test coverage

  • Runner unit tests: offline host emulation, CallTarget registry generation, parity of the generated duck typing with dynamic duck typing; DuckType engine tests.
  • RunNativeAotInstrumentationGate: native host and NativeAOT publish tests on Linux x64/arm64, macOS and Windows, among them CallTargetNativeTest (every CallTarget shape) published with NativeAOT, which must behave as with the profiler.
  • CheckAotDuckTypeDeclarations: the Linux integration tests record the duck typing mappings their samples create, and the check fails when one isn't declared.
  • Integration samples compared between JIT and NativeAOT (NativeAOT.Samples.md).
  • RunNativeAotPackageTests: once the package is built, the application of the package published with NativeAOT for .NET 8 and .NET 10 (manual API, AppSec, RASP, IAST, binary size, no trimming/AOT warning of Datadog.Trace, no method of Datadog.Trace compiled to throw).
  • RunNativeAotPackageTests also compares the spans of the same application published with NativeAOT (with the package) and run under JIT (with the profiler and the tracer home): ASP.NET Core, HttpClient, the manual API, AppSec/RASP/IAST, SQLite with Dapper.AOT and errors, for .NET 8 and .NET 10.
  • Execution benchmarks: Samples.HttpMessageHandler and Samples.FakeDbCommand published with NativeAOT for .NET 8 and .NET 10 on a hosted Windows agent (publish_nativeaot_samples), Baseline (without the tracer) and CallTarget+NativeAOT scenarios, in the execution benchmarks report. First CI results (.NET 8): FakeDbCommand 23 → 105 ms, HttpMessageHandler 115 → 359 ms, with the shutdown sleeps [Tracer] Wake up the trace serialization and DogStatsD threads at shutdown #9419 removes. No overhead threshold until [Tracer] Wake up the trace serialization and DogStatsD threads at shutdown #9419 is merged.

Other details

Stacked on #8252 (base codex/ducktyping-nativeaot). Draft, to run CI.

@tonyredondo tonyredondo added type:enhancement Improvement to an existing feature area:tracer The core tracer library (Datadog.Trace, does not include OpenTracing, native code, or integrations) labels Oct 13, 2026
@pr-commenter

pr-commenter Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

LLM Validation

LLM Validation Gate — dotnet-tracer-agent

🟡 WARN

  • 1 blocking case(s) regressed (candidate win-rate < 45%) but not confidently enough to block.

Analysis

Changed instruction file(s): AGENTS.md.

Warning — 1 case(s) regressed, but none crossed the blocking bar.

  • dotnet-tracer-confirm-instrumentation-011: won 41% of blind comparisons, quality -2.9.
    • Asked: How can I check whether a given library method is auto-instrumented, from its source declaration through runtime instrumentation? Explain what the repo and
    • Baseline answer: Here's a stage-by-stage method for confirming a given library method is auto-instrumented, with what each source of evidence actually proves — and, just as importantly, what it doesn't. ## Stage 0 — Source declaration (what the repo proves) Before touching runtime, establish that the method is supposed to be
    • Candidate answer: Here's a complete verification path for "is method X auto-instrumented?", mapped to the stages you named. The key theme: each stage's evidence only proves that stage; the gaps between them are where you need additional confirmation, because a method can pass one stage and silently fall out at the next. ## Stage 0 —

Results

  • Pairwise win-rate: 49% [45%–53%] — candidate's share of blind comparisons (90% CI; spanning 50% = no clear difference)
  • Overall quality: 86.3 → 86.9 (/100, +0.6)
  • Bad signals introduced (advisory): 0
  • Candidate criteria coverage (advisory): 19/21 (90%) — expected_criteria the candidate met; does not affect the gate
  • Blocking-case regressions: 1

Cases

Case Mode Quality Δ Win-rate (90% CI) Safety
dotnet-tracer-repo-nav-integration-001 block +2.7 56% [49%–63%] ok
dotnet-tracer-logging-terminology-004 block +0.6 50% [50%–50%] ok
dotnet-tracer-nuget-scope-hallucination-008 block +1.0 50% [50%–50%] ok
dotnet-tracer-confirm-instrumentation-011 🟡 block -2.9 41% [29%–52%] ok
dotnet-tracer-control-context-propagation-016 warn +1.4 50% [35%–65%] ok

Per-dimension scores, token usage, latency, and estimated cost are in the CI job logs.

@dd-trace-dotnet-ci-bot

dd-trace-dotnet-ci-bot Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Execution-Time Benchmarks Report ⏱️

Execution-time results for samples comparing This PR (9400) and master.

✅ No regressions detected

📄 View the full report (charts + all metrics) →

@pr-commenter

pr-commenter Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-10-15 20:58:48

Comparing candidate commit 39bc463 in PR branch tony/nativeaot-tracer with baseline commit c31cfdf in branch master.

📊 Benchmarking dashboard

Found 3 performance improvements and 6 performance regressions! Performance is the same for 63 metrics, 0 unstable metrics, 75 known flaky benchmarks, 51 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 ----------------------------------'

scenario:Benchmarks.Trace.DbCommandBenchmark.ExecuteNonQuery net472

  • 🟩 allocated_mem [-121 bytes; -120 bytes] or [-12.778%; -12.768%]

scenario:Benchmarks.Trace.DbCommandBenchmark.ExecuteNonQuery net6.0

  • 🟩 allocated_mem [-120 bytes; -119 bytes] or [-12.199%; -12.189%]

scenario:Benchmarks.Trace.DbCommandBenchmark.ExecuteNonQuery netcoreapp3.1

  • 🟩 allocated_mem [-112 bytes; -111 bytes] or [-11.481%; -11.471%]

scenario:Benchmarks.Trace.HttpClientBenchmark.SendAsync net472

  • 🟥 allocated_mem [+271 bytes; +272 bytes] or [+9.338%; +9.348%]
  • 🟥 throughput [-9274.647op/s; -8915.374op/s] or [-10.588%; -10.178%]

scenario:Benchmarks.Trace.HttpClientBenchmark.SendAsync net6.0

  • 🟥 allocated_mem [+199 bytes; +200 bytes] or [+9.426%; +9.438%]
  • 🟥 throughput [-9115.162op/s; -8098.548op/s] or [-6.192%; -5.501%]

scenario:Benchmarks.Trace.HttpClientBenchmark.SendAsync netcoreapp3.1

  • 🟥 allocated_mem [+199 bytes; +200 bytes] or [+7.569%; +7.581%]
  • 🟥 throughput [-13102.278op/s; -11357.414op/s] or [-10.397%; -9.013%]

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.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_AddEvent_Sampled net472

  • 🟩 throughput [+10198.538op/s; +11467.474op/s] or [+6.181%; +6.950%]

scenario:Benchmarks.Trace.ActivityBenchmark.StartStopWithChild net472

  • 🟥 throughput [-8470.643op/s; -7933.936op/s] or [-10.044%; -9.407%]

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

  • 🟥 throughput [-9325.570op/s; -7063.909op/s] or [-7.839%; -5.937%]

scenario:Benchmarks.Trace.ActivityBenchmark.StartStopWithChild netcoreapp3.1

  • 🟥 throughput [-12227.727op/s; -11011.150op/s] or [-12.433%; -11.196%]

scenario:Benchmarks.Trace.AgentWriterBenchmark.WriteAndFlushEnrichedTraces net472

  • 🟥 allocated_mem [+1.605KB; +1.605KB] or [+48.760%; +48.776%]
  • 🟥 execution_time [+306.575ms; +309.458ms] or [+152.133%; +153.564%]
  • 🟥 throughput [-55.492op/s; -51.194op/s] or [-9.984%; -9.211%]

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

  • 🟥 allocated_mem [+1.011KB; +1.011KB] or [+37.485%; +37.498%]
  • 🟥 execution_time [+379.125ms; +382.333ms] or [+299.532%; +302.066%]
  • 🟩 throughput [+72.085op/s; +76.163op/s] or [+9.504%; +10.042%]

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

  • 🟥 allocated_mem [+1.088KB; +1.088KB] or [+40.343%; +40.355%]
  • 🟥 execution_time [+389.462ms; +395.098ms] or [+344.659%; +349.647%]

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

  • 🟥 allocated_mem [+4.756KB; +4.757KB] or [+100.134%; +100.150%]
  • 🟥 throughput [-61123.715op/s; -60557.749op/s] or [-47.557%; -47.117%]

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

  • 🟥 allocated_mem [+3.880KB; +3.880KB] or [+82.058%; +82.072%]
  • 🟩 execution_time [-15.369ms; -11.193ms] or [-7.178%; -5.228%]
  • 🟥 throughput [-60167.371op/s; -57408.595op/s] or [-43.919%; -41.905%]

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

  • 🟥 allocated_mem [+4.608KB; +4.608KB] or [+99.641%; +99.654%]
  • 🟥 throughput [-48835.388op/s; -46584.812op/s] or [-44.153%; -42.118%]

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

  • 🟥 allocated_mem [+1.380KB; +1.380KB] or [+111.648%; +111.662%]
  • 🟥 throughput [-310813.031op/s; -287951.416op/s] or [-31.736%; -29.401%]

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

  • 🟥 allocated_mem [+543 bytes; +544 bytes] or [+44.437%; +44.446%]
  • 🟩 execution_time [-26.598ms; -21.712ms] or [-11.862%; -9.683%]
  • 🟥 throughput [-142481.192op/s; -118475.656op/s] or [-15.221%; -12.657%]

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

  • 🟥 allocated_mem [+1.344KB; +1.344KB] or [+111.253%; +111.267%]
  • 🟥 throughput [-191305.912op/s; -175396.272op/s] or [-27.487%; -25.201%]

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

  • 🟥 allocated_mem [+3.378KB; +3.378KB] or [+89.003%; +89.017%]
  • 🟥 throughput [-76968.206op/s; -75274.245op/s] or [-51.799%; -50.659%]

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

  • 🟥 allocated_mem [+3.336KB; +3.336KB] or [+88.150%; +88.161%]
  • 🟥 throughput [-72936.482op/s; -70048.804op/s] or [-46.408%; -44.571%]

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

  • 🟥 allocated_mem [+3.264KB; +3.264KB] or [+88.493%; +88.506%]
  • 🟥 throughput [-56092.685op/s; -53478.392op/s] or [-44.685%; -42.602%]

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

  • 🟩 throughput [+297009.988op/s; +317636.437op/s] or [+9.904%; +10.591%]

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

  • 🟩 execution_time [-18.887ms; -14.549ms] or [-8.706%; -6.706%]

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

  • 🟩 allocated_mem [-13.759KB; -13.756KB] or [-42.324%; -42.316%]
  • 🟥 execution_time [+299.921ms; +300.705ms] or [+149.860%; +150.252%]
  • 🟩 throughput [+1068.354op/s; +1093.729op/s] or [+11.800%; +12.080%]

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

  • 🟩 allocated_mem [-13.722KB; -13.718KB] or [-42.341%; -42.329%]
  • 🟥 execution_time [+302.668ms; +313.248ms] or [+152.636%; +157.972%]
  • 🟩 throughput [+1996.684op/s; +2328.903op/s] or [+15.272%; +17.813%]

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

  • 🟩 allocated_mem [-13.722KB; -13.718KB] or [-42.341%; -42.329%]
  • 🟥 execution_time [+300.986ms; +304.098ms] or [+151.613%; +153.181%]
  • 🟩 throughput [+1773.717op/s; +1907.936op/s] or [+17.124%; +18.420%]

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

  • 🟥 execution_time [+294.421ms; +295.801ms] or [+144.608%; +145.286%]
  • 🟩 throughput [+525.661op/s; +541.068op/s] or [+13.935%; +14.344%]

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

  • 🟥 execution_time [+296.916ms; +298.330ms] or [+145.151%; +145.843%]
  • 🟩 throughput [+2633.848op/s; +2729.973op/s] or [+38.265%; +39.661%]

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

  • 🟥 execution_time [+300.873ms; +301.561ms] or [+150.376%; +150.720%]
  • 🟩 throughput [+1360.334op/s; +1381.693op/s] or [+27.002%; +27.426%]

scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmark net472

  • 🟩 execution_time [-144.744µs; -140.580µs] or [-29.718%; -28.863%]
  • 🟩 throughput [+837.122op/s; +865.158op/s] or [+40.772%; +42.137%]

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

  • 🟩 execution_time [-126.899µs; -96.124µs] or [-29.104%; -22.046%]
  • 🟩 throughput [+716.304op/s; +881.255op/s] or [+31.142%; +38.313%]

scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmark netcoreapp3.1

  • 🟩 execution_time [-142.142µs; -120.026µs] or [-30.454%; -25.716%]
  • 🟩 throughput [+771.321op/s; +856.348op/s] or [+35.606%; +39.531%]

scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmarkWithAttack net472

  • 🟩 execution_time [-125.551µs; -121.477µs] or [-33.898%; -32.798%]
  • 🟩 throughput [+1329.280op/s; +1374.375op/s] or [+49.230%; +50.900%]

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

  • 🟩 execution_time [-99.226µs; -75.497µs] or [-31.678%; -24.102%]
  • 🟩 throughput [+1118.621op/s; +1325.461op/s] or [+34.871%; +41.319%]

scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmarkWithAttack netcoreapp3.1

  • 🟩 execution_time [-137.907µs; -115.509µs] or [-37.726%; -31.599%]
  • 🟩 throughput [+1332.555op/s; +1469.842op/s] or [+47.820%; +52.747%]

scenario:Benchmarks.Trace.AspNetCoreBenchmark.SendRequest net472

  • 🟥 execution_time [+299.677ms; +300.453ms] or [+149.569%; +149.957%]

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

  • unstable execution_time [+332.684ms; +392.238ms] or [+361.475%; +426.183%]

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

  • unstable execution_time [+284.545ms; +338.575ms] or [+216.052%; +257.077%]

scenario:Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark.WriteAndFlushEnrichedTraces net472

  • unstable execution_time [+327.514ms; +373.203ms] or [+150.588%; +171.595%]
  • 🟥 throughput [-591.627op/s; -533.136op/s] or [-53.607%; -48.307%]

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

  • unstable execution_time [+202.489ms; +335.758ms] or [+86.292%; +143.086%]
  • 🟥 throughput [-670.751op/s; -587.329op/s] or [-44.739%; -39.175%]

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

  • 🟥 execution_time [+333.603ms; +341.057ms] or [+199.533%; +203.992%]
  • 🟥 throughput [-381.616op/s; -346.033op/s] or [-26.571%; -24.094%]

scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSlice netcoreapp3.1

  • unstable throughput [+15.000op/s; +52.627op/s] or [+4.312%; +15.128%]

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

  • 🟩 execution_time [-166.047µs; -135.367µs] or [-8.411%; -6.857%]
  • 🟩 throughput [+38.218op/s; +46.385op/s] or [+7.545%; +9.157%]

scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearch net472

  • 🟥 allocated_mem [+96 bytes; +97 bytes] or [+12.092%; +12.103%]
  • 🟥 execution_time [+301.823ms; +303.516ms] or [+151.993%; +152.845%]

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

  • 🟥 allocated_mem [+95 bytes; +96 bytes] or [+12.114%; +12.124%]
  • 🟥 execution_time [+303.797ms; +309.914ms] or [+152.233%; +155.298%]
  • 🟥 throughput [-55286.455op/s; -47766.302op/s] or [-8.716%; -7.531%]

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

  • 🟥 allocated_mem [+95 bytes; +96 bytes] or [+12.114%; +12.124%]
  • 🟥 execution_time [+302.834ms; +306.781ms] or [+152.131%; +154.114%]
  • 🟥 throughput [-35989.235op/s; -27988.365op/s] or [-7.581%; -5.896%]

scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearchAsync net472

  • 🟥 allocated_mem [+95 bytes; +96 bytes] or [+11.165%; +11.177%]
  • 🟥 execution_time [+302.002ms; +303.834ms] or [+151.655%; +152.575%]

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

  • 🟥 allocated_mem [+95 bytes; +96 bytes] or [+12.493%; +12.506%]
  • 🟥 execution_time [+297.883ms; +301.376ms] or [+147.290%; +149.017%]
  • 🟥 throughput [-54328.132op/s; -49541.283op/s] or [-8.753%; -7.982%]

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

  • 🟥 allocated_mem [+95 bytes; +96 bytes] or [+11.422%; +11.434%]
  • 🟥 execution_time [+302.942ms; +307.264ms] or [+153.544%; +155.735%]

scenario:Benchmarks.Trace.GraphQLBenchmark.ExecuteAsync net472

  • 🟥 allocated_mem [+96 bytes; +97 bytes] or [+11.197%; +11.208%]
  • 🟥 execution_time [+300.280ms; +302.827ms] or [+150.713%; +151.992%]
  • 🟥 throughput [-33731.223op/s; -31293.575op/s] or [-8.751%; -8.118%]

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

  • 🟥 allocated_mem [+95 bytes; +96 bytes] or [+10.618%; +10.631%]
  • 🟥 execution_time [+300.323ms; +308.924ms] or [+149.684%; +153.970%]

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

  • 🟥 allocated_mem [+95 bytes; +96 bytes] or [+10.618%; +10.631%]
  • 🟥 execution_time [+299.387ms; +311.703ms] or [+148.942%; +155.069%]
  • 🟥 throughput [-40292.537op/s; -29573.264op/s] or [-9.537%; -7.000%]

scenario:Benchmarks.Trace.ILoggerBenchmark.EnrichedLog net472

  • 🟥 allocated_mem [+96 bytes; +97 bytes] or [+6.002%; +6.011%]
  • 🟥 throughput [-24094.623op/s; -22731.207op/s] or [-9.689%; -9.141%]

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

  • 🟥 allocated_mem [+95 bytes; +96 bytes] or [+5.627%; +5.636%]

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

  • 🟥 allocated_mem [+95 bytes; +96 bytes] or [+5.605%; +5.617%]

scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark net472

  • unstable execution_time [+14.927µs; +58.236µs] or [+3.687%; +14.385%]

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

  • 🟩 allocated_mem [-18.592KB; -18.568KB] or [-6.782%; -6.773%]
  • unstable execution_time [-23.852µs; +32.530µs] or [-4.714%; +6.429%]

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

  • 🟩 allocated_mem [-17.266KB; -17.246KB] or [-6.294%; -6.287%]
  • unstable execution_time [-78.443µs; -18.634µs] or [-13.594%; -3.229%]

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

  • unstable execution_time [+6.914µs; +11.540µs] or [+16.344%; +27.277%]
  • 🟥 throughput [-5107.436op/s; -3242.468op/s] or [-21.501%; -13.650%]

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

  • unstable execution_time [-14.377µs; -6.769µs] or [-22.305%; -10.503%]
  • unstable throughput [+1682.047op/s; +3331.147op/s] or [+10.320%; +20.438%]

scenario:Benchmarks.Trace.Log4netBenchmark.EnrichedLog net472

  • 🟥 execution_time [+301.707ms; +303.537ms] or [+152.500%; +153.424%]

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

  • 🟥 execution_time [+300.488ms; +306.352ms] or [+152.947%; +155.932%]

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

  • 🟥 execution_time [+299.024ms; +301.561ms] or [+149.698%; +150.969%]

scenario:Benchmarks.Trace.RedisBenchmark.SendReceive net472

  • 🟥 allocated_mem [+95 bytes; +96 bytes] or [+9.197%; +9.208%]
  • 🟥 throughput [-27171.610op/s; -24757.287op/s] or [-7.522%; -6.853%]

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

  • 🟥 allocated_mem [+95 bytes; +96 bytes] or [+9.226%; +9.238%]

scenario:Benchmarks.Trace.RedisBenchmark.SendReceive netcoreapp3.1

  • 🟥 allocated_mem [+95 bytes; +96 bytes] or [+9.226%; +9.238%]
  • 🟥 throughput [-37698.886op/s; -28342.694op/s] or [-8.922%; -6.708%]

scenario:Benchmarks.Trace.SerilogBenchmark.EnrichedLog net472

  • 🟥 execution_time [+299.097ms; +301.243ms] or [+149.073%; +150.143%]

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

  • 🟥 allocated_mem [+96 bytes; +96 bytes] or [+6.000%; +6.010%]
  • 🟥 execution_time [+302.246ms; +303.658ms] or [+151.773%; +152.482%]

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

  • 🟥 allocated_mem [+95 bytes; +96 bytes] or [+5.819%; +5.828%]
  • 🟥 execution_time [+302.133ms; +304.360ms] or [+153.223%; +154.352%]

scenario:Benchmarks.Trace.SingleSpanAspNetCoreBenchmark.SingleSpanAspNetCore net472

  • 🟥 execution_time [+299.532ms; +300.185ms] or [+149.408%; +149.734%]
  • 🟩 throughput [+61205814.834op/s; +61491134.530op/s] or [+44.574%; +44.782%]

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

  • 🟥 execution_time [+426.296ms; +431.260ms] or [+530.175%; +536.348%]

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

  • 🟥 execution_time [+299.055ms; +300.139ms] or [+149.162%; +149.702%]

scenario:Benchmarks.Trace.SpanBenchmark.StartFinishScope net472

  • 🟥 allocated_mem [+31 bytes; +32 bytes] or [+5.244%; +5.256%]
  • 🟥 throughput [-103660.855op/s; -97462.617op/s] or [-11.569%; -10.877%]

scenario:Benchmarks.Trace.SpanBenchmark.StartFinishSpan net472

  • 🟥 allocated_mem [+31 bytes; +32 bytes] or [+6.037%; +6.047%]
  • 🟥 throughput [-132858.816op/s; -128857.890op/s] or [-12.162%; -11.795%]

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

  • 🟥 allocated_mem [+31 bytes; +32 bytes] or [+6.057%; +6.065%]

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

  • 🟥 allocated_mem [+31 bytes; +32 bytes] or [+6.059%; +6.069%]

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

  • 🟩 throughput [+32747.838op/s; +40612.747op/s] or [+5.946%; +7.375%]

scenario:Benchmarks.Trace.TraceAnnotationsBenchmark.RunOnMethodBegin net472

  • 🟥 allocated_mem [+95 bytes; +96 bytes] or [+15.733%; +15.745%]
  • 🟥 throughput [-86755.788op/s; -81151.479op/s] or [-12.697%; -11.877%]

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

  • 🟥 allocated_mem [+95 bytes; +96 bytes] or [+14.810%; +14.823%]

scenario:Benchmarks.Trace.TraceAnnotationsBenchmark.RunOnMethodBegin netcoreapp3.1

  • 🟥 allocated_mem [+95 bytes; +96 bytes] or [+14.810%; +14.821%]
  • 🟥 throughput [-80895.193op/s; -64972.340op/s] or [-11.295%; -9.072%]

Known flaky benchmarks without significant changes:

  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_AddEvent_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_AddEvent_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_GetContext_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_GetContext_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_GetContext_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_SetAttributes_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_SetAttributes_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_SetAttributes_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_SetStatus_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_SetStatus_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_SetStatus_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_UpdateName_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_UpdateName_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_UpdateName_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_AddEvent_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_AddEvent_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_AddEvent_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_GetContext_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_GetContext_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_GetContext_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_RecordException_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_RecordException_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_RecordException_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_SetAttributes_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_SetAttributes_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_SetAttributes_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_SetStatus_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_SetStatus_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_SetStatus_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_UpdateName_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_UpdateName_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_UpdateName_Sampled netcoreapp3.1
  • scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorSimpleBody net472
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSlice net472
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSlice net6.0
  • 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.Iast.StringAspectsBenchmark.StringConcatBenchmark net472
  • scenario:Benchmarks.Trace.SpanBenchmark.StartFinishScope net6.0
  • scenario:Benchmarks.Trace.SpanBenchmark.StartFinishScope netcoreapp3.1
  • scenario:Benchmarks.Trace.SpanBenchmark.StartFinishTwoScopes net472
  • scenario:Benchmarks.Trace.SpanBenchmark.StartFinishTwoScopes netcoreapp3.1

tonyredondo and others added 12 commits October 15, 2026 17:53
Handler static constructors first consult generic holders filled by a
NativeAOT registry, then fall back to IntegrationMapper. The Invoke paths
are unchanged, so JIT behavior and performance stay the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dd-trace aot instrument hosts Datadog.Tracer.Native in-process and drives
it through an emulated CLR (ICorProfilerInfo and IMetaData* over dnlib),
so assemblies are rewritten exactly like at runtime. Replaces the broken
apply-aot command. Instrumentation can be verified with ILSpy, JIT
preparation and ILVerify.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tion factories

A registration can record that an integration method can't be bound, so the
handler fails like it does when IntegrationMapper throws. The continuation
holder keeps a factory, so the generator is still created from the end
handler's static constructor. CallTargetAotRegistry has the runtime checks
and the error log the generated registrations use.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ssemblies

`dd-trace aot instrument` adds a registration type per rewritten method to the
instrumented assembly, generic over the method's generic context, and calls it
at the method entry. Its static constructor binds the integration methods the
way IntegrationMapper does, so the handlers don't need dynamic code. Shapes with
duck typing constraints aren't registered yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tions

`dd-trace aot instrument` generates a DuckType AOT registry with the proxies the
integration methods' duck typing constraints need, and the adapters create them
like IntegrationMapper does. Generic targets get registrations for the closed
instantiations found in the instrumented assemblies. The instrumented module
initializer enables the AOT mode of duck typing.

Also stop the DuckType AOT registry emitter from looking up its generated types
in quadratic time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`dd-trace aot instrument --ducktype-map` adds the mappings dynamic duck typing
recorded at runtime (DD_DUCKTYPE_DISCOVERY_OUTPUT_PATH) to the DuckType AOT
registry, for the proxies created from the runtime type of a value.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eAOT instrumentation

A publish passes the application and every assembly ILC compiles, most of them
framework references without instrumentation: only the rewritten ones are
written, and the closed instantiations are only looked for when a generic
method was rewritten.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hout the native tracer

An application instrumented at build time has its CallTarget instrumentation
compiled in and no native tracer: Instrumentation.InitializeAot only starts the
managed parts (tracer, security, diagnostic observers, Activity and
OpenTelemetry) and never throws.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…'s module initializer

The application's assembly is always written, with a module initializer that
enables the DuckType AOT registry and calls Instrumentation.InitializeAot, each
step isolated so a failure is logged and the application starts anyway.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Datadog.Trace.Aot.targets runs `dd-trace aot instrument` after ILC computes its
inputs and swaps the application and the referenced assemblies the native
tracer rewrote, plus the DuckType AOT registry. Only `dotnet publish` with
PublishAot is affected; a failure publishes the application uninstrumented with
a warning unless DatadogAotFailOnError is set. An opt-in test publishes an
ASP.NET Core application and checks its spans reach the agent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Referencing Datadog.Trace.Aot instruments `dotnet publish -p:PublishAot=true`
without any setting: the package brings the targets, the dd-trace runner, the
native tracer of the build host, the full Datadog.Trace.dll ILC compiles when
the application only references the manual API, and a catalog of the duck typing
mappings Datadog.Trace looks up from runtime types. The instrumentation is
incremental, and recorded mappings of assemblies the application doesn't use are
skipped. An opt-in test publishes a manual API application with the package.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The native tracer gives no IL map for CallTarget, but the original instructions
are still in the rewritten body, in order: they are aligned and keep their
sequence points, the prologue gets the first line and a replaced ret gives its
line to the leave that replaced it, as with the original PDB at runtime. Stack
traces and debug information of instrumented methods have their lines again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tonyredondo
tonyredondo force-pushed the codex/ducktyping-nativeaot branch from 83572bc to d31a301 Compare October 15, 2026 16:03
@tonyredondo
tonyredondo force-pushed the tony/nativeaot-tracer branch from cc59c54 to c3609ad Compare October 15, 2026 16:03

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:tracer The core tracer library (Datadog.Trace, does not include OpenTracing, native code, or integrations) type:enhancement Improvement to an existing feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant