Skip to content

refactor(otel-thread-ctx): use inline assembly instead of C shim#2197

Open
yannham wants to merge 24 commits into
mainfrom
yannham/thread-ctx-inline-asm
Open

refactor(otel-thread-ctx): use inline assembly instead of C shim#2197
yannham wants to merge 24 commits into
mainfrom
yannham/thread-ctx-inline-asm

Conversation

@yannham

@yannham yannham commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

This revives #2129, which has been merged in a different branch than main. Uses inline assembly instead of a C shim to enable TLSDESC access from Rust.

Motivation

This get rids of all toolchain-related issues, at the cost of some inline ASM. See the original PR for more discussion.

@yannham
yannham requested review from a team as code owners July 6, 2026 09:22
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

📚 Documentation Check Results

⚠️ 454 documentation warning(s) found

📦 libdd-otel-thread-ctx-ffi - 280 warning(s)

📦 libdd-otel-thread-ctx - 1 warning(s)

📦 tools - 173 warning(s)


Updated: 2026-07-17 16:21:32 UTC | Commit: 1eea534 | missing-docs job results

Comment thread libdd-otel-thread-ctx-ffi/tests/elf_properties.rs Outdated
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

🔒 Cargo Deny Results

⚠️ 4 issue(s) found, showing only errors (advisories, bans, sources)

📦 libdd-otel-thread-ctx-ffi - 1 error(s)

Show output
error[unsound]: Rand is unsound with a custom logger using `rand::rng()`
    ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:109:1
    │
109 │ rand 0.8.5 registry+https://github.com/rust-lang/crates.io-index
    │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ unsound advisory detected
    │
    ├ ID: RUSTSEC-2026-0097
    ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0097
    ├ It has been reported (by [@lopopolo](https://github.com/lopopolo)) that the `rand` library is [unsound](https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#soundness-of-code--of-a-library) (i.e. that safe code using the public API can cause Undefined Behaviour) when all the following conditions are met:
      
      - The `log` and `thread_rng` features are enabled
      - A [custom logger](https://docs.rs/log/latest/log/#implementing-a-logger) is defined
      - The custom logger accesses `rand::rng()` (previously `rand::thread_rng()`) and calls any `TryRng` (previously `RngCore`) methods on `ThreadRng`
      - The `ThreadRng` (attempts to) reseed while called from the custom logger (this happens every 64 kB of generated data)
      - Trace-level logging is enabled or warn-level logging is enabled and the random source (the `getrandom` crate) is unable to provide a new seed
      
      `TryRng` (previously `RngCore`) methods for `ThreadRng` use `unsafe` code to cast `*mut BlockRng<ReseedingCore>` to `&mut BlockRng<ReseedingCore>`. When all the above conditions are met this results in an aliased mutable reference, violating the Stacked Borrows rules. Miri is able to detect this violation in sample code. Since construction of [aliased mutable references is Undefined Behaviour](https://doc.rust-lang.org/stable/nomicon/references.html), the behaviour of optimized builds is hard to predict.
    ├ Announcement: https://github.com/rust-random/rand/pull/1763
    ├ Solution: Upgrade to >=0.10.1 OR <0.10.0, >=0.9.3 OR <0.9.0, >=0.8.6 (try `cargo update -p rand`)
    ├ rand v0.8.5
      └── (dev) libdd-common v5.1.0
          └── libdd-common-ffi v37.0.0
              └── libdd-otel-thread-ctx-ffi v1.0.0

advisories FAILED, bans ok, sources ok

📦 libdd-otel-thread-ctx - ✅ No issues

📦 tools - 3 error(s)

Show output
error[vulnerability]: Quadratic run time when checking a start tag for duplicate attribute names
   ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:72:1
   │
72 │ quick-xml 0.37.5 registry+https://github.com/rust-lang/crates.io-index
   │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ security vulnerability detected
   │
   ├ ID: RUSTSEC-2026-0194
   ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0194
   ├ `BytesStart::attributes()` returns an `Attributes` iterator which, by default
     (`with_checks(true)`), rejects a start tag that repeats an attribute name. For
     each attribute yielded, the iterator compared the new name against every name
     seen so far in the same tag using a linear scan, so a start tag with `N`
     distinct attribute names cost `O(N²)` byte comparisons. There was no bound on
     `N` other than the size of the buffered start tag.
     
     ## Impact
     
     Any code that parses untrusted XML and iterates a start tag's attributes with
     the default duplicate check enabled can be made to spend CPU time quadratic in
     the number of attributes on a single tag. Because the check is pure computation
     with no `.await`/I/O, an I/O-based timeout on the consumer (for example a read
     or request timeout) cannot interrupt it while it runs.
     
     Measured cost of a single start tag, release build:
     
     | Attributes on one tag | Time |
     |---|---|
     | 80,000  | ~6 s   |
     | 800,000 | ~10 min |
     
     The cost grows with the square of the attribute count, so a start tag of a few
     tens of megabytes can stall a parsing thread for hours. No memory is exhausted
     and the parser does not crash; the effect is CPU exhaustion on the thread doing
     the parsing: a single crafted start tag can pin a CPU core for minutes to hours,
     denying service to that worker. A deployment that places a wall-clock bound on
     parsing, or confines it to a non-critical thread, may consider the availability
     impact lower.
     
     ## Affected code paths
     
     * `BytesStart::attributes()` / `Attributes` iterated with checks enabled (the
       default), and `BytesStart::try_get_attribute`.
     * `NsReader`, which resolves namespaces by iterating a tag's attributes and so
       reaches the same check internally.
     
     Consumers that iterate attributes with `.attributes().with_checks(false)` and do
     not use `NsReader` are not affected.
     
     This was reported as reachable by a remote, unauthenticated attacker in a
     real-world RPKI relying party (NLnet Labs Routinator) via a crafted RRDP
     `snapshot.xml`.
     
     ## Remediation
     
     Upgrade to `quick-xml >= 0.41.0`, where the duplicate check keeps the linear
     scan for start tags with a small number of attributes and switches to an `O(1)`
     hash pre-filter above a threshold, making the whole tag `O(N)`. The reported
     `AttrError::Duplicated` positions are unchanged.
     
     If upgrading is not possible and duplicate-name detection is not required,
     disable it with `.attributes().with_checks(false)` (this does not help
     `NsReader` consumers, which have no equivalent opt-out before 0.41.0).
   ├ Announcement: https://github.com/tafia/quick-xml/issues/969
   ├ Solution: Upgrade to >=0.41.0 (try `cargo update -p quick-xml`)
   ├ quick-xml v0.37.5
     └── tools v37.0.0

error[vulnerability]: Unbounded namespace-declaration allocation in `NsReader` enables memory-exhaustion denial of service
   ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:72:1
   │
72 │ quick-xml 0.37.5 registry+https://github.com/rust-lang/crates.io-index
   │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ security vulnerability detected
   │
   ├ ID: RUSTSEC-2026-0195
   ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0195
   ├ `NsReader` resolves namespaces by calling `NamespaceResolver::push` for every
     `Start`/`Empty` event *before* the event is returned to the caller. `push`
     iterated all `xmlns` / `xmlns:*` attributes on the start tag and, for each one,
     appended the prefix bytes to an internal buffer and pushed a `NamespaceBinding`
     (32 bytes on 64-bit) to an internal `Vec`, with no upper bound on the number of
     declarations.
     
     ## Impact
     
     A start tag with `N` namespace declarations drove roughly `3×` the tag's byte
     size in `NamespaceResolver` heap, allocated *inside* `quick-xml` before the
     `NsReader` consumer ever received the event and could inspect or reject it. A
     consumer that bounds its *input* size therefore still cannot bound this
     allocation: an `M`-byte start tag yields on the order of `3 × M` bytes of
     resolver heap the caller never sees.
     
     On untrusted XML this lets a remote, unauthenticated attacker force large heap
     allocations with a single start tag. With several `NsReader`s running
     concurrently on independent inputs (a common server pattern), the allocations
     stack and can exhaust process memory, causing the operating system to kill the
     process (OOM). This was confirmed against a real-world RPKI relying party (NLnet
     Labs Routinator), where concurrent RRDP validation workers parsing a crafted
     `snapshot.xml` exceeded the memory limit and the process was OOM-killed.
     
     ## Affected code paths
     
     Consumers using `NsReader` (which always calls `NamespaceResolver::push` before
     yielding `Start`/`Empty`), or calling `NamespaceResolver::push` directly. A plain
     `Reader` that does not perform namespace resolution is not affected.
     
     ## Remediation
     
     Upgrade to `quick-xml >= 0.41.0`. `NamespaceResolver::push` now rejects a start
     tag that declares more than `DEFAULT_MAX_DECLARATIONS_PER_ELEMENT` (256)
     namespace bindings, returning the new `NamespaceError::TooManyDeclarations`
     instead of allocating without limit. The limit is configurable via
     `NamespaceResolver::set_max_declarations_per_element` (use `usize::MAX` to
     restore the previous unbounded behavior), and `NsReader::resolver_mut()` is
     provided to reach it.
     
     There is no clean workaround for `NsReader` consumers before 0.41.0, as the
     allocation happens inside the reader with no configuration knob to cap it.
   ├ Announcement: https://github.com/tafia/quick-xml/issues/970
   ├ Solution: Upgrade to >=0.41.0 (try `cargo update -p quick-xml`)
   ├ quick-xml v0.37.5
     └── tools v37.0.0

error[unsound]: Rand is unsound with a custom logger using `rand::rng()`
   ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:75:1
   │
75 │ rand 0.8.5 registry+https://github.com/rust-lang/crates.io-index
   │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ unsound advisory detected
   │
   ├ ID: RUSTSEC-2026-0097
   ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0097
   ├ It has been reported (by [@lopopolo](https://github.com/lopopolo)) that the `rand` library is [unsound](https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#soundness-of-code--of-a-library) (i.e. that safe code using the public API can cause Undefined Behaviour) when all the following conditions are met:
     
     - The `log` and `thread_rng` features are enabled
     - A [custom logger](https://docs.rs/log/latest/log/#implementing-a-logger) is defined
     - The custom logger accesses `rand::rng()` (previously `rand::thread_rng()`) and calls any `TryRng` (previously `RngCore`) methods on `ThreadRng`
     - The `ThreadRng` (attempts to) reseed while called from the custom logger (this happens every 64 kB of generated data)
     - Trace-level logging is enabled or warn-level logging is enabled and the random source (the `getrandom` crate) is unable to provide a new seed
     
     `TryRng` (previously `RngCore`) methods for `ThreadRng` use `unsafe` code to cast `*mut BlockRng<ReseedingCore>` to `&mut BlockRng<ReseedingCore>`. When all the above conditions are met this results in an aliased mutable reference, violating the Stacked Borrows rules. Miri is able to detect this violation in sample code. Since construction of [aliased mutable references is Undefined Behaviour](https://doc.rust-lang.org/stable/nomicon/references.html), the behaviour of optimized builds is hard to predict.
   ├ Announcement: https://github.com/rust-random/rand/pull/1763
   ├ Solution: Upgrade to >=0.10.1 OR <0.10.0, >=0.9.3 OR <0.9.0, >=0.8.6 (try `cargo update -p rand`)
   ├ rand v0.8.5
     └── (dev) libdd-common v5.1.0
         └── tools v37.0.0

advisories FAILED, bans ok, sources ok

Updated: 2026-07-17 16:22:55 UTC | Commit: 1eea534 | dependency-check job results

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d726f8d89d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread libdd-otel-thread-ctx/src/lib.rs Outdated
Comment on lines +145 to +147
// x1 is guaranteed not to be clobbered by the call
"blr x2",
"add x0, x1, x0",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Re-read TP after the AArch64 TLSDESC resolver

On AArch64 this keeps the thread pointer in x1 across blr x2, but the TLSDESC resolver calling convention allows the resolver to clobber x1 (only registers other than x0, x1, x30, and flags must be saved). On loaders/resolvers that use that freedom, add x0, x1, x0 computes the TLS slot from a trashed register, so attach/update/detach can read or write an invalid address; read tpidr_el0 after the TLSDESC call or preserve the TP somewhere the resolver must not clobber.

Useful? React with 👍 / 👎.

@yannham yannham Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Indeed, and what's more ARM ABI actually mandates the exact uses of register as well, and we should use x1 instead of x2. Swapping the two in dbb0eeb.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Though it's surprising that the check for the exact sequence of instructions succeeded in the CI before 🤔

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ok, so after investigation, the previous sequence was the exact one generated by a relatively oldish GCC version (the one we have on CI basically on Alpine and CentOS). The new one is the clang version, exactly. Some GCC versions also move the TP offset calculation around a bit.

For now I've rooted for the clang version, because Rust uses LLVM under the hood, it clobbers one less register, and respect the ABI described above byte per byte. However cc is often gcc in the test, so I've extended the test to make it a bit more lax and accommodate for different compilers.

But it starts to be a lot of code, just for testing something "static" (and just because it's annoying to ensure clang in the CI). I start to question the usefulness of this check: somehow it only has to be tested "once".

@ivoanjo ivoanjo Jul 7, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

TBH I wouldn't go too much into "try to support all compilers in CI"; I would instead suggest going the "gold/known version" approach, e.g. something like:

  • In CI we only assert that "assembly -> matches some known hash". If you change the assembly, you need to update the "some known hash"

  • And then we have some script/test that can recalculate the hash; and next to it is a comment saying "To get the latest assembly hash, we ran this on some standard docker image (ubuntu 26.06 with clang XX)"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I like that idea, implemented in latest version. It doesn't remove so much code (some of it has just moved to the gen_tls_shim_hash executable), but the annoying part (compiling the C shim with the exact right toolchain) has been offloaded to this run-once-for-a-long-time-outside-of-tests executable to generate hash, which is indeed win for tests.

Comment thread libdd-otel-thread-ctx-ffi/tests/elf_properties.rs Outdated
@datadog-prod-us1-5

datadog-prod-us1-5 Bot commented Jul 6, 2026

Copy link
Copy Markdown

Tests

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 61.20%
Overall Coverage: 74.67% (-0.05%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 6b39e91 | Docs | Datadog PR Page | Give us feedback!

@dd-octo-sts

dd-octo-sts Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Artifact Size Benchmark Report

aarch64-alpine-linux-musl
Artifact Baseline Commit Change
/aarch64-alpine-linux-musl/lib/libdatadog_profiling.so 7.88 MB 7.88 MB 0% (0 B) 👌
/aarch64-alpine-linux-musl/lib/libdatadog_profiling.a 86.33 MB 86.33 MB 0% (0 B) 👌
aarch64-unknown-linux-gnu
Artifact Baseline Commit Change
/aarch64-unknown-linux-gnu/lib/libdatadog_profiling.a 97.54 MB 97.54 MB 0% (0 B) 👌
/aarch64-unknown-linux-gnu/lib/libdatadog_profiling.so 10.62 MB 10.62 MB 0% (0 B) 👌
libdatadog-x64-windows
Artifact Baseline Commit Change
/libdatadog-x64-windows/debug/dynamic/datadog_profiling_ffi.dll 25.58 MB 25.58 MB 0% (0 B) 👌
/libdatadog-x64-windows/debug/dynamic/datadog_profiling_ffi.lib 89.18 KB 89.18 KB 0% (0 B) 👌
/libdatadog-x64-windows/debug/dynamic/datadog_profiling_ffi.pdb 185.53 MB 185.52 MB -0% (-8.00 KB) 👌
/libdatadog-x64-windows/debug/static/datadog_profiling_ffi.lib 958.60 MB 958.60 MB 0% (0 B) 👌
/libdatadog-x64-windows/release/dynamic/datadog_profiling_ffi.dll 8.37 MB 8.37 MB 0% (0 B) 👌
/libdatadog-x64-windows/release/dynamic/datadog_profiling_ffi.lib 89.18 KB 89.18 KB 0% (0 B) 👌
/libdatadog-x64-windows/release/dynamic/datadog_profiling_ffi.pdb 24.76 MB 24.76 MB 0% (0 B) 👌
/libdatadog-x64-windows/release/static/datadog_profiling_ffi.lib 49.28 MB 49.28 MB 0% (0 B) 👌
libdatadog-x86-windows
Artifact Baseline Commit Change
/libdatadog-x86-windows/debug/dynamic/datadog_profiling_ffi.dll 22.23 MB 22.23 MB 0% (0 B) 👌
/libdatadog-x86-windows/debug/dynamic/datadog_profiling_ffi.lib 90.58 KB 90.58 KB 0% (0 B) 👌
/libdatadog-x86-windows/debug/dynamic/datadog_profiling_ffi.pdb 189.98 MB 189.98 MB 0% (0 B) 👌
/libdatadog-x86-windows/debug/static/datadog_profiling_ffi.lib 946.54 MB 946.54 MB 0% (0 B) 👌
/libdatadog-x86-windows/release/dynamic/datadog_profiling_ffi.dll 6.47 MB 6.47 MB 0% (0 B) 👌
/libdatadog-x86-windows/release/dynamic/datadog_profiling_ffi.lib 90.58 KB 90.58 KB 0% (0 B) 👌
/libdatadog-x86-windows/release/dynamic/datadog_profiling_ffi.pdb 26.58 MB 26.58 MB 0% (0 B) 👌
/libdatadog-x86-windows/release/static/datadog_profiling_ffi.lib 46.89 MB 46.89 MB 0% (0 B) 👌
x86_64-alpine-linux-musl
Artifact Baseline Commit Change
/x86_64-alpine-linux-musl/lib/libdatadog_profiling.a 77.08 MB 77.08 MB 0% (0 B) 👌
/x86_64-alpine-linux-musl/lib/libdatadog_profiling.so 8.83 MB 8.83 MB 0% (0 B) 👌
x86_64-unknown-linux-gnu
Artifact Baseline Commit Change
/x86_64-unknown-linux-gnu/lib/libdatadog_profiling.a 92.50 MB 92.50 MB 0% (0 B) 👌
/x86_64-unknown-linux-gnu/lib/libdatadog_profiling.so 10.74 MB 10.74 MB 0% (0 B) 👌

@pawelchcki pawelchcki left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Drive By review

Looks good. I looked for some alternatives and this seems like a solid option

@yannham
yannham force-pushed the yannham/thread-ctx-inline-asm branch from 53e627a to 7976952 Compare July 16, 2026 16:01
@yannham
yannham requested a review from ivoanjo July 16, 2026 16:02
@yannham
yannham requested a review from a team as a code owner July 16, 2026 16:07
@pr-commenter

pr-commenter Bot commented Jul 16, 2026

Copy link
Copy Markdown

Benchmarks

Comparison

Benchmark execution time: 2026-07-17 16:51:00

Comparing candidate commit 6b39e91 in PR branch yannham/thread-ctx-inline-asm with baseline commit 0c6e2a5 in branch main.

Found 0 performance improvements and 2 performance regressions! Performance is the same for 140 metrics, 0 unstable metrics.

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:profiles_dictionary/profile_string_inserts/threads/1

  • 🟥 execution_time [+14.360µs; +16.472µs] or [+4.691%; +5.381%]
  • 🟥 throughput [-171360.951op/s; -149449.646op/s] or [-5.122%; -4.467%]

Benchmark execution time: 2026-07-17 17:06:22

Comparing candidate commit 6b39e91 in PR branch yannham/thread-ctx-inline-asm with baseline commit 0c6e2a5 in branch main.

Found 3 performance improvements and 4 performance regressions! Performance is the same for 170 metrics, 10 unstable metrics.

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:alloc_free/sampled_system_fast_path/4096

  • 🟥 execution_time [+6.890ns; +7.078ns] or [+7.135%; +7.330%]

scenario:alloc_free/sampled_system_slow_path/4096

  • 🟥 execution_time [+16.649ns; +16.757ns] or [+10.917%; +10.988%]

scenario:alloc_free/system/4096

  • 🟥 execution_time [+10.104ns; +10.271ns] or [+11.998%; +12.195%]

scenario:datadog_sample_span/name_pattern_rule_not_matching/wall_time

  • 🟩 execution_time [-14.083ns; -13.910ns] or [-8.259%; -8.158%]

scenario:glob_matcher/ascii_wildcard_question_match/wall_time

  • 🟩 execution_time [-21.641ns; -21.622ns] or [-36.982%; -36.950%]

scenario:glob_matcher/ascii_wildcard_star_match/wall_time

  • 🟩 execution_time [-21.138ns; -21.118ns] or [-36.436%; -36.402%]

scenario:receiver_entry_point/report/2644

  • 🟥 execution_time [+180.804µs; +191.838µs] or [+5.018%; +5.324%]

Candidate

Omitted due to size.

Baseline

Omitted due to size.

@ivoanjo ivoanjo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

👍 Looks great, no concerns (only my usual smattering of small suggestions), and thanks @cataphract for all the work in the previous #2129 .

Comment thread libdd-otel-thread-ctx/src/test_utils/tls_shim_window.rs Outdated
Comment thread libdd-otel-thread-ctx/src/test_utils/tls_shim_window.rs Outdated
Comment thread libdd-otel-thread-ctx/src/test_utils/tls_shim_window.rs Outdated
Comment thread libdd-otel-thread-ctx/src/test_utils/tls_shim_window.rs Outdated
Comment thread libdd-otel-thread-ctx/src/test_utils/tls_shim_window.rs Outdated
Comment thread libdd-otel-thread-ctx/src/lib.rs
Comment thread libdd-otel-thread-ctx/src/bin/gen_tls_shim_bytes.rs
Comment thread libdd-otel-thread-ctx/tests/tlsdesc_inline_sequence.rs Outdated
Comment thread libdd-otel-thread-ctx/tests/tlsdesc_inline_sequence.rs Outdated
cataphract and others added 16 commits July 17, 2026 16:11
Co-authored-by: Yann Hamdaoui <yann.hamdaoui@gmail.com>
The libdd-otel-thread-ctx build script only validated the target OS/arch and
panicked on unsupported Linux architectures. Move that into a compile_error!
gated on cfg and drop the build script entirely. The linux module is now also
gated on x86_64/aarch64 so an unsupported Linux arch produces a single clean
error instead of a cascade from the module body.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Ivo Anjo <ivo.anjo@datadoghq.com>
Co-authored-by: Ivo Anjo <ivo.anjo@datadoghq.com>
@yannham
yannham force-pushed the yannham/thread-ctx-inline-asm branch from 786ea19 to 9d7d17a Compare July 17, 2026 14:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants