Skip to content

feat(profiling)!: add gc-time sample type - #2442

Draft
vlad-scherbich wants to merge 1 commit into
mainfrom
vlad/prof-gc-time-type
Draft

feat(profiling)!: add gc-time sample type#2442
vlad-scherbich wants to merge 1 commit into
mainfrom
vlad/prof-gc-time-type

Conversation

@vlad-scherbich

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds first-class GcTime / GcSamples to SampleType (Rust + CXX FFI):

  • GcTime("gc-time", "nanoseconds")
  • GcSamples("gc-samples", "count") (same pairing as wall/cpu)

Encode and decode both ways. House round-trip test covers the new variants. C headers are generated from cxx.rs in CI.

If this merges and nothing else lands: the type exists in libdatadog. No tracer emits it. No intake/CompView listing.

Layer Meaning PR
Compiled into artifact SampleType + FFI this PR
Armed at runtime tracer push_* dd-trace-py after a libdatadog bump
Observable in product CompView / intake allow-list follow-up

Motivation

DataDog/dd-trace-py#19940 piggybacks GC pauses on wall-time (default-off). It stays that way until this type exists here and the tracer can push_* it.

Additional Notes

Timeline (STW) and intake/CompView availableProfileTypes are follow-up. Not eBPF, not DogStatsD, not T #19190 CPU leaf frames. Frames stay gc.collect[gen=N].

BREAKING CHANGE: additive variants on a public exhaustive SampleType enum. Existing discriminants unchanged (appended after Custom5).

How to test the change?

cargo test -p libdd-profiling --lib api::sample_type

Map to pprof ("gc-time", "nanoseconds") and ("gc-samples", "count") so
language tracers can export exact GC pause events on a first-class
value type instead of experimental slots.
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

📚 Documentation Check Results

⚠️ 649 documentation warning(s) found

📦 libdd-profiling - 649 warning(s)


Updated: 2026-09-01 15:20:19 UTC | Commit: 8da3ee1 | missing-docs job results

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

🔒 Cargo Deny Results

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

📦 libdd-profiling - 6 error(s)

Show output
error[unsound]: `Bitmap::try_from(&[u8])` can create invalid values
   ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:14:1
   │
14 │ bitmaps 3.2.1 registry+https://github.com/rust-lang/crates.io-index
   │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ unsound advisory detected
   │
   ├ ID: RUSTSEC-2025-0167
   ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2025-0167
   ├ The `TryFrom<&[u8]>` implementation for `Bitmap<SIZE>` copies the input bytes
     into an uninitialized backing store and calls `assume_init()` without
     validating that the bytes form a valid value of the backing store type. For
     `SIZE = 1` the backing store is a `bool`, so any input byte other than `0x00`
     or `0x01` produces an invalid value, which is immediate undefined behavior.
     
     The `AsMut<[u8]>` implementation has the same problem, as it allows safe code
     to write invalid bit patterns into the backing store through the returned slice.
     
     No fixed version is available, as the crate is unmaintained; its GitHub
     repository was archived by the owner on 2026-05-03.
   ├ Announcement: https://github.com/bodil/bitmaps/issues/35
   ├ Solution: No safe upgrade is available!
   ├ bitmaps v3.2.1
     └── libdd-profiling v1.0.0
         └── (dev) libdd-profiling v1.0.0 (*)

error[unmaintained]: bitmaps is unmaintained
   ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:14:1
   │
14 │ bitmaps 3.2.1 registry+https://github.com/rust-lang/crates.io-index
   │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ unmaintained advisory detected
   │
   ├ ID: RUSTSEC-2026-0247
   ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0247
   ├ The bitmaps crate is unmaintained; all versions are affected. The GitHub
     repository was archived by the owner on 2026-05-03.
     
     Recommended alternatives:
     
     * [fixedbitset](https://crates.io/crates/fixedbitset)
     * [bitvec](https://crates.io/crates/bitvec)
   ├ Announcement: https://github.com/bodil/bitmaps
   ├ Solution: No safe upgrade is available!
   ├ bitmaps v3.2.1
     └── libdd-profiling v1.0.0
         └── (dev) libdd-profiling v1.0.0 (*)

error[vulnerability]: Invalid pointer dereference in `fmt::Pointer` impl for `Atomic` and `Shared` when the underlying pointer is invalid
   ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:48:1
   │
48 │ crossbeam-epoch 0.9.18 registry+https://github.com/rust-lang/crates.io-index
   │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ security vulnerability detected
   │
   ├ ID: RUSTSEC-2026-0204
   ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0204
   ├ Affected versions of `fmt::Display` dereference the underlying pointer. This causes a invalid pointer dereference e.g., when a pointer created with `Atomic::null` or `Shared::null`. `fmt::Debug` impls and pre-0.9 `fmt::Display` impls, which do not dereference pointers, are not affected by this issue.
   ├ Announcement: https://github.com/crossbeam-rs/crossbeam/pull/1276
   ├ Solution: Upgrade to >=0.9.20 (try `cargo update -p crossbeam-epoch`)
   ├ crossbeam-epoch v0.9.18
     ├── crossbeam-deque v0.8.5
     │   └── rayon-core v1.12.1
     │       └── rayon v1.10.0
     │           └── criterion v0.5.1
     │               └── (dev) libdd-profiling v1.0.0
     │                   └── (dev) libdd-profiling v1.0.0 (*)
     └── moka v0.12.13
         └── hickory-resolver v0.25.2
             └── reqwest v0.13.2
                 ├── libdd-common v5.2.0
                 │   └── libdd-profiling v1.0.0 (*)
                 └── libdd-profiling v1.0.0 (*)

error[vulnerability]: NSEC3 closest-encloser proof validation enters unbounded loop on cross-zone responses
   ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:78:1
   │
78 │ hickory-proto 0.25.2 registry+https://github.com/rust-lang/crates.io-index
   │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ security vulnerability detected
   │
   ├ ID: RUSTSEC-2026-0118
   ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0118
   ├ The NSEC3 closest-encloser proof validation in `hickory-proto`'s
     `DnssecDnsHandle` walks from the QNAME up to the SOA owner name, building a
     list of candidate encloser names. The iterator used assumes the
     QNAME is a descendant of the SOA owner, terminating only when the current
     candidate equals the SOA name. When the SOA in a response's authority section
     is not an ancestor of the QNAME, the loop stalls at the DNS root and never
     terminates, repeatedly calling `Name::base_name()` and pushing newly allocated
     `Name` and hashed-name entries into the candidate `Vec`.
     
     The bug is reachable by any caller of `DnssecDnsHandle` — including the
     resolver, recursor, and client — when built with the `dnssec-ring` or
     `dnssec-aws-lc-rs` feature and configured to perform DNSSEC validation. It is
     triggered while validating a NoData or NXDomain response whose authority
     section contains an SOA record from a zone other than an ancestor of the
     QNAME, on a code path that requires NSEC3 closest-encloser proof. In practice
     this can be reached through an insecure CNAME chain that crosses zone
     boundaries into a DNSSEC-signed zone returning NoData, but the minimum
     condition is just a mismatched SOA owner on a response requiring NSEC3
     validation.
     
     A `debug_assert_ne!(name, Name::root())` guards the loop body, so debug builds
     abort with a panic on the first iteration past the root. Release builds
     compile the assertion out and run the loop unbounded, allocating until the
     process exhausts available memory (OOM). A reachable upstream attacker who
     can return such a response can therefore crash a debug-built validator or
     exhaust memory on a release-built one.
     
     The affected code was migrated from `hickory-proto` to `hickory-net` as part of
     the 0.26.0 release. The `hickory-proto` 0.26.x release no longer offers
     `DnssecDnsHandle` and so we recommend all affected users update to `hickory-net`
     0.26.1 when the implementation of that type is required.
   ├ Announcement: https://github.com/hickory-dns/hickory-dns/security/advisories/GHSA-3v94-mw7p-v465
   ├ Solution: No safe upgrade is available!
   ├ hickory-proto v0.25.2
     └── hickory-resolver v0.25.2
         └── reqwest v0.13.2
             ├── libdd-common v5.2.0
             │   └── libdd-profiling v1.0.0
             │       └── (dev) libdd-profiling v1.0.0 (*)
             └── libdd-profiling v1.0.0 (*)

error[vulnerability]: CPU exhaustion during message encoding due to O(n²) name compression
   ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:78:1
   │
78 │ hickory-proto 0.25.2 registry+https://github.com/rust-lang/crates.io-index
   │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ security vulnerability detected
   │
   ├ ID: RUSTSEC-2026-0119
   ├ Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0119
   ├ During message encoding, `hickory-proto`'s `BinEncoder` stores pointers to
     labels that are candidates for name compression in a `Vec<(usize, Vec<u8>)>`.
     The name compression logic then searches for matches with a linear scan.
     
     A malicious message with many records can both introduce many candidate labels,
     and invoke this linear scan many times. This can amplify CPU exhaustion in DoS
     attacks.
     
     This is similar to
     [CVE-2024-8508](https://www.nlnetlabs.nl/downloads/unbound/CVE-2024-8508.txt).
     
     We recommend all affected users update to `hickory-proto` 0.26.1 for the fix.
   ├ Announcement: https://github.com/hickory-dns/hickory-dns/security/advisories/GHSA-q2qq-hmj6-3wpp
   ├ Solution: Upgrade to >=0.26.1 (try `cargo update -p hickory-proto`)
   ├ hickory-proto v0.25.2
     └── hickory-resolver v0.25.2
         └── reqwest v0.13.2
             ├── libdd-common v5.2.0
             │   └── libdd-profiling v1.0.0
             │       └── (dev) libdd-profiling v1.0.0 (*)
             └── libdd-profiling v1.0.0 (*)

error[unsound]: Rand is unsound with a custom logger using `rand::rng()`
    ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:156:1
    │
156 │ 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
      ├── libdd-common v5.2.0
      │   └── libdd-profiling v1.0.0
      │       └── (dev) libdd-profiling v1.0.0 (*)
      ├── libdd-profiling v1.0.0 (*)
      └── proptest v1.5.0
          ├── (dev) libdd-common v5.2.0 (*)
          └── (dev) libdd-profiling v1.0.0 (*)

advisories FAILED, bans ok, sources ok

Updated: 2026-09-01 15:21:55 UTC | Commit: 8da3ee1 | dependency-check job results

@pr-commenter

pr-commenter Bot commented Sep 1, 2026

Copy link
Copy Markdown

Benchmarks

Comparison

Candidate

Candidate benchmark details

Baseline

Baseline benchmark details

@datadog-datadog-prod-us1

Copy link
Copy Markdown
Contributor

Tests

All CI checks and tests passed.

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 66.67%
Overall Coverage: 76.96% (+0.01%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: b92c672 | Docs | View more details | Give us feedback!

@dd-octo-sts

dd-octo-sts Bot commented Sep 1, 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.a 90.77 MB 90.77 MB +0% (+1.13 KB) 👌
/aarch64-alpine-linux-musl/lib/libdatadog_profiling.so 8.39 MB 8.39 MB 0% (0 B) 👌
aarch64-unknown-linux-gnu
Artifact Baseline Commit Change
/aarch64-unknown-linux-gnu/lib/libdatadog_profiling.a 101.99 MB 101.99 MB +0% (+1.16 KB) 👌
/aarch64-unknown-linux-gnu/lib/libdatadog_profiling.so 11.29 MB 11.29 MB +0% (+96 B) 👌
libdatadog-x64-windows
Artifact Baseline Commit Change
/libdatadog-x64-windows/debug/dynamic/datadog_profiling_ffi.dll 27.03 MB 27.03 MB +0% (+512 B) 👌
/libdatadog-x64-windows/debug/dynamic/datadog_profiling_ffi.lib 96.08 KB 96.08 KB 0% (0 B) 👌
/libdatadog-x64-windows/debug/dynamic/datadog_profiling_ffi.pdb 181.70 MB 181.70 MB 0% (0 B) 👌
/libdatadog-x64-windows/debug/static/datadog_profiling_ffi.lib 766.69 MB 766.31 MB --.04% (-381.69 KB) 💪
/libdatadog-x64-windows/release/dynamic/datadog_profiling_ffi.dll 8.91 MB 8.91 MB 0% (0 B) 👌
/libdatadog-x64-windows/release/dynamic/datadog_profiling_ffi.lib 96.08 KB 96.08 KB 0% (0 B) 👌
/libdatadog-x64-windows/release/dynamic/datadog_profiling_ffi.pdb 26.05 MB 26.05 MB 0% (0 B) 👌
/libdatadog-x64-windows/release/static/datadog_profiling_ffi.lib 51.84 MB 51.84 MB +0% (+834 B) 👌
libdatadog-x86-windows
Artifact Baseline Commit Change
/libdatadog-x86-windows/debug/dynamic/datadog_profiling_ffi.dll 23.57 MB 23.57 MB +0% (+512 B) 👌
/libdatadog-x86-windows/debug/dynamic/datadog_profiling_ffi.lib 97.58 KB 97.58 KB 0% (0 B) 👌
/libdatadog-x86-windows/debug/dynamic/datadog_profiling_ffi.pdb 186.77 MB 186.76 MB -0% (-8.00 KB) 👌
/libdatadog-x86-windows/debug/static/datadog_profiling_ffi.lib 754.57 MB 754.43 MB --.01% (-144.00 KB) 💪
/libdatadog-x86-windows/release/dynamic/datadog_profiling_ffi.dll 6.88 MB 6.88 MB 0% (0 B) 👌
/libdatadog-x86-windows/release/dynamic/datadog_profiling_ffi.lib 97.58 KB 97.58 KB 0% (0 B) 👌
/libdatadog-x86-windows/release/dynamic/datadog_profiling_ffi.pdb 28.00 MB 28.00 MB 0% (0 B) 👌
/libdatadog-x86-windows/release/static/datadog_profiling_ffi.lib 49.34 MB 49.34 MB +0% (+766 B) 👌
x86_64-alpine-linux-musl
Artifact Baseline Commit Change
/x86_64-alpine-linux-musl/lib/libdatadog_profiling.a 80.93 MB 80.94 MB +0% (+1000 B) 👌
/x86_64-alpine-linux-musl/lib/libdatadog_profiling.so 9.33 MB 9.33 MB 0% (0 B) 👌
x86_64-unknown-linux-gnu
Artifact Baseline Commit Change
/x86_64-unknown-linux-gnu/lib/libdatadog_profiling.a 96.69 MB 96.69 MB +0% (+952 B) 👌
/x86_64-unknown-linux-gnu/lib/libdatadog_profiling.so 11.37 MB 11.37 MB 0% (0 B) 👌

Copilot AI 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.

🟢 Approval recommended

The new enum variants are consistently implemented across Rust API conversions and the CXX bridge, and existing round-trip tests will automatically cover the added variants.

Pull request overview

Adds two new first-class GC-related sample types to libdd-profiling’s public SampleType enum and wires them through the existing Rust ↔︎ ValueType conversion layer and the CXX bridge, enabling downstream tracers to emit GC pause metrics with explicit type/unit semantics.

Changes:

  • Extend api::SampleType with GcTime and GcSamples.
  • Map the new variants to/from pprof (type, unit) pairs: ("gc-time","nanoseconds") and ("gc-samples","count").
  • Extend the CXX FFI SampleType enum and its conversion into api::SampleType to support round-tripping across the bridge.
File summaries
File Description
libdd-profiling/src/cxx.rs Adds GcTime/GcSamples to the CXX bridge SampleType and maps them into api::SampleType.
libdd-profiling/src/api/sample_type.rs Adds GcTime/GcSamples variants and updates SampleType ↔︎ ValueType encoding/decoding (and round-trip test coverage via enum iteration).
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

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.

2 participants