-
Notifications
You must be signed in to change notification settings - Fork 20
feat: cross-language LTO to inline C TLS shim into Rust FFI #1982
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
Open
yannham
wants to merge
18
commits into
main
Choose a base branch
from
yannham/thread-ctx-inlining-exp
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
1b9a82c
feat: cross-language LTO to inline C TLS shim into Rust FFI
yannham 15ad936
doc: add README for the FFI crate
yannham 08ca7ae
chore: move script to appropriate crate
yannham e6d27c2
doc: improve otel thread ctx ffi README
yannham 7d56511
feat: add post-build sanity check to build-optimized.sh
yannham 87cff7b
doc: explain why the wrapper script is needed
yannham 0692dbf
chore: self-review misc fixes
yannham a4188dd
fix: wrong env variable handling
yannham 806545a
refactor: move find_rust_lld_dir to build_common
yannham 74353e1
chore: self-review
yannham 537b9a1
doc: put back CentOS LLVM example
yannham 9cfe9d0
doc: document optimized build without using the script
yannham b9f5fcd
feat: warn if sanity check can't be run
yannham 15d9532
fix: preserve RUST_FLAGS in the build script
yannham a15526f
build: panic on unsupported archs for otel-thread-ctx
yannham 924a878
chore: fatal warning -> error
yannham 31a7e9c
refactor: require -> resolve
yannham f83339b
fix: auto-fix clippy issues
yannham File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| # libdd-otel-thread-ctx-ffi | ||
|
|
||
| FFI bindings for the OTel thread-level context publisher. Exposes a C API for | ||
| attaching, detaching, and updating per-thread OpenTelemetry context records | ||
| that external readers (e.g. the eBPF profiler) can discover. | ||
|
|
||
| Currently Linux-only (x86-64 and aarch64). | ||
|
|
||
| ## Optimized build (cross-language inlining) | ||
|
|
||
| The OTel thread-level context sharing specification requires the use of the | ||
| TLSDESC dialect for the thread-local variable that holds the current context. | ||
| Because (stable) `rustc` doesn't currently provide a way to control the TLS | ||
| dialect, we need to use a small C shim that defines the variable and expose a | ||
| one-line getter. This unfortunately adds one level of indirection (a function | ||
| call) when attaching or detaching a context. | ||
|
|
||
| With the right toolchain, it's possible to use Link-Time Optimization (LTO) to | ||
| inline the C wrapper at link time. The requirements are: | ||
|
|
||
| - `clang` is available to compile the C shim to LLVM IR (version requirements | ||
| aren't clear -- tested with clang18 and clang20, but ideally the version | ||
| should be the same or close to the LLVM version shipped with `rustc`) | ||
| - Either the Rust toolchain ships `lld` or there's a system-wide `lld` install | ||
| (Rust has been shipping `rust-lld` for a long time now, something like since | ||
| 1.53+, however some musl-based distro like Alpine might have the Rust | ||
| toolchain without `rust-lld`) | ||
| - `lld` version is at least 18.1 (TLSDESC support) | ||
|
|
||
| **If those requirements are met, setting the environment variables | ||
| `CARGO_TARGET_<TARGET>_RUSTFLAGS=-Clinker-plugin-lto -Clinker=clang` and | ||
| `LIBDD_OTEL_THREAD_CTX_INLINE=1` when calling to `cargo` will trigger the | ||
| optimized build where the C shim is inlined.** Here, `<TARGET>` is the target | ||
| triple in screaming snake case. | ||
|
|
||
| External environment variables are needed because cross-language LTO requires | ||
| two `rustc` codegen flags (`-Clinker-plugin-lto` and `-Clinker=clang`) that | ||
| cannot be set from a Cargo build script: they must come from `RUSTFLAGS` or | ||
| `.cargo/config.toml`, which can't be entirely automated from Rust only. We | ||
| advise to set those flags via the target-scoped | ||
| `CARGO_TARGET_<TARGET>_RUSTFLAGS` env var so they don't leak to build scripts | ||
| or proc-macros if cross-compiling. | ||
|
|
||
| ### Build script | ||
|
|
||
| The `build-optimized.sh` wrapper script is provided as a convenience and as an | ||
| example. | ||
|
|
||
| #### Usage | ||
|
|
||
| ```bash | ||
| ./build-optimized.sh | ||
| ``` | ||
|
|
||
| The script auto-detects the host triple. To cross-compile: | ||
|
|
||
| ```bash | ||
| ./build-optimized.sh --target aarch64-unknown-linux-gnu | ||
| ``` | ||
|
|
||
| Extra arguments are forwarded to `cargo build`. | ||
|
yannham marked this conversation as resolved.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| #!/usr/bin/env bash | ||
|
yannham marked this conversation as resolved.
|
||
| # Copyright 2026-Present Datadog, Inc. https://www.datadoghq.com/ | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| # | ||
| # Build libdd-otel-thread-ctx-ffi with cross-language LTO so the C TLS shim is | ||
| # inlined into the Rust FFI functions, eliminating a function-call indirection | ||
| # on every TLS access. | ||
| # | ||
| # Requirements: clang, lld (rust-lld from the toolchain is used automatically). | ||
| # The requirements are checked by the build.rs script. | ||
| # | ||
| # Usage: | ||
| # # auto-detect host triple | ||
| # ./build-optimized.sh | ||
| # # explicit target | ||
| # ./build-optimized.sh --target aarch64-unknown-linux-gnu | ||
| # | ||
| # Any extra arguments are forwarded to `cargo build`. | ||
| set -euo pipefail | ||
|
|
||
| # Parse --target from args, or auto-detect the host triple. | ||
| TARGET="" | ||
| EXTRA_ARGS=() | ||
| while [[ $# -gt 0 ]]; do | ||
| case "$1" in | ||
| --target) | ||
| TARGET="$2"; shift 2 ;; | ||
| --target=*) | ||
| TARGET="${1#--target=}"; shift ;; | ||
| *) | ||
| EXTRA_ARGS+=("$1"); shift ;; | ||
| esac | ||
| done | ||
|
|
||
| if [[ -z "$TARGET" ]]; then | ||
| TARGET=$(rustc -vV | sed -n 's/host: //p') | ||
| fi | ||
|
|
||
| # CARGO_TARGET_<TRIPLE>_RUSTFLAGS scopes the flags to the target only, keeping | ||
| # build scripts and proc-macros unaffected. | ||
| TARGET_ENV=$(echo "$TARGET" | tr 'a-z-' 'A-Z_') | ||
| FLAGS_VAR="CARGO_TARGET_${TARGET_ENV}_RUSTFLAGS" | ||
| EXISTING_FLAGS="${!FLAGS_VAR:-}" | ||
| export "$FLAGS_VAR=${EXISTING_FLAGS:+$EXISTING_FLAGS }-Clinker-plugin-lto -Clinker=clang" | ||
| export LIBDD_OTEL_THREAD_CTX_INLINE=1 | ||
|
|
||
| cargo build --release \ | ||
| --target "$TARGET" \ | ||
| -p libdd-otel-thread-ctx-ffi \ | ||
| "${EXTRA_ARGS[@]}" | ||
|
|
||
| # Sanity-check that the C shim was actually inlined, if `nm` is available. | ||
|
yannham marked this conversation as resolved.
|
||
| if ! command -v nm &>/dev/null; then | ||
| echo >&2 "WARNING: skipping sanity check that the C TLS shim was inlined (\`nm\` not found)" | ||
| else | ||
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" | ||
| SO="$REPO_ROOT/target/$TARGET/release/liblibdd_otel_thread_ctx_ffi.so" | ||
|
|
||
| if [[ -f "$SO" ]]; then | ||
| if ! NM_OUTPUT=$(nm "$SO" 2>&1); then | ||
| echo >&2 "WARNING: command \`nm\` failed on $SO. Skipping sanity check that the C TLS shim was inlined." | ||
| elif echo "$NM_OUTPUT" | grep -q 'libdd_get_otel_thread_ctx'; then | ||
| echo >&2 "ERROR: build succeeded but the C TLS shim (libdd_get_otel_thread_ctx_v1) was NOT inlined." | ||
| echo >&2 "Cross-language LTO may not be working. Check that clang and lld versions are recent enough and compatible with the Rust toolchain's LLVM." | ||
| exit 1 | ||
| fi | ||
| fi | ||
| fi | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.