Skip to content

feat(profiling)!: expose missing API in CXX - #2497

Open
danielsn wants to merge 4 commits into
mainfrom
better-cxx
Open

feat(profiling)!: expose missing API in CXX#2497
danielsn wants to merge 4 commits into
mainfrom
better-cxx

Conversation

@danielsn

@danielsn danielsn commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Updates the CXX API to expose APIs for

  • dictionary-backed samples
  • timestamped samples
  • split profile uploading

Motivation

I would like to use this API for Python, but currently we're missing this functionality so we have to use the old C api.

Additional Notes

Anything else we should know when reviewing?

How to test the change?

Describe here in detail how the change can be validated.

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

📚 Documentation Check Results

⚠️ 1419 documentation warning(s) found

📦 libdd-profiling-ffi - 770 warning(s)

📦 libdd-profiling - 649 warning(s)


Updated: 2026-09-10 20:21:10 UTC | Commit: 3f0efda | missing-docs job results

// NOTE: api2's Rust/C FFI datatype uses file_name, while pprof and
// the string-based CXX Function use filename. Keep file_name for now
// to match api2; revisit the CXX-facing name during PR review.
file_name: StringId2,

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.

Anyone have any thoughts here?

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

🔒 Cargo Deny Results

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

📦 libdd-profiling-ffi - 4 error(s)

Show output
error[unsound]: `Bitmap::try_from(&[u8])` can create invalid values
   ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:20:1
   │
20 │ 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 (*)
         └── libdd-profiling-ffi v1.0.0

error[unmaintained]: bitmaps is unmaintained
   ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:20:1
   │
20 │ 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 (*)
         └── libdd-profiling-ffi v1.0.0

error[vulnerability]: NSEC3 closest-encloser proof validation enters unbounded loop on cross-zone responses
   ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:91:1
   │
91 │ 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 v6.0.0
             │   ├── libdd-common-ffi v44.0.0
             │   │   └── libdd-profiling-ffi v1.0.0
             │   ├── libdd-profiling v1.0.0
             │   │   ├── (dev) libdd-profiling v1.0.0 (*)
             │   │   └── libdd-profiling-ffi v1.0.0 (*)
             │   └── libdd-profiling-ffi 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:91:1
   │
91 │ 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 v6.0.0
             │   ├── libdd-common-ffi v44.0.0
             │   │   └── libdd-profiling-ffi v1.0.0
             │   ├── libdd-profiling v1.0.0
             │   │   ├── (dev) libdd-profiling v1.0.0 (*)
             │   │   └── libdd-profiling-ffi v1.0.0 (*)
             │   └── libdd-profiling-ffi v1.0.0 (*)
             └── libdd-profiling v1.0.0 (*)

advisories FAILED, bans ok, sources ok

📦 libdd-profiling - 4 error(s)

Show output
error[unsound]: `Bitmap::try_from(&[u8])` can create invalid values
   ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:15:1
   │
15 │ 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:15:1
   │
15 │ 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]: NSEC3 closest-encloser proof validation enters unbounded loop on cross-zone responses
   ┌─ /home/runner/work/libdatadog/libdatadog/Cargo.lock:80:1
   │
80 │ 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 v6.0.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:80:1
   │
80 │ 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 v6.0.0
             │   └── libdd-profiling v1.0.0
             │       └── (dev) libdd-profiling v1.0.0 (*)
             └── libdd-profiling v1.0.0 (*)

advisories FAILED, bans ok, sources ok

Updated: 2026-09-10 20:22:38 UTC | Commit: 3f0efda | dependency-check job results

@danielsn
danielsn marked this pull request as ready for review September 9, 2026 19:18
@danielsn
danielsn requested review from a team as code owners September 9, 2026 19:18
@datadog-datadog-prod-us1

datadog-datadog-prod-us1 Bot commented Sep 9, 2026

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: 96.66%
Overall Coverage: 78.02% (+0.38%)

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

// SAFETY: all ids come from the profile's dictionary.
black_box(unsafe {
profile.try_add_sample2(&locations, &values, labels_iter, None)
profile.try_add_sample2(locations.iter().copied(), &values, labels_iter, None)

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.

Why did this have to change, by the way? I assume it's because &[Location] doesn't implement an iterator, but rather IntoIterator?

@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: 7aeac76d76

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +320 to +324
fn create_with_dictionary(
sample_types: Vec<SampleType>,
period: &Period,
dictionary: &ProfilesDictionary,
) -> Result<Box<Profile>>;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Provide a no-period dictionary profile constructor

Dictionary-backed CXX profiles now require a Period, so consumers of the existing Profile::create_no_period path cannot migrate to add_sample2; supplying a dummy period changes the serialized pprof by emitting period fields. The internal try_new_with_dictionary and C FFI dictionary constructor both support None, so expose an equivalent dictionary-backed no-period factory here.

Useful? React with 👍 / 👎.

@pr-commenter

pr-commenter Bot commented Sep 9, 2026

Copy link
Copy Markdown

Benchmarks

Comparison

Benchmark execution time: 2026-09-10 20:28:56

Comparing candidate commit bb7ab76 in PR branch better-cxx with baseline commit 8b0fa65 in branch main.

📊 Benchmarking dashboard

Found 0 performance improvements and 0 performance regressions! Performance is the same for 13 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 ----------------------------------'

Candidate

Candidate benchmark details

Group 1

cpu_model git_commit_sha git_commit_date git_branch
Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz bb7ab76 1789071525 better-cxx
scenario metric min mean ± sd median ± mad p75 p95 p99 max peak_to_median_ratio skewness kurtosis cv sem runs sample_size
profiles_dictionary/profile_string_inserts/threads/1 execution_time 374.306µs 375.407µs ± 0.877µs 375.219µs ± 0.604µs 375.944µs 376.755µs 376.815µs 376.830µs 0.43% 0.430 -1.019 0.22% 0.277µs 1 10
profiles_dictionary/profile_string_inserts/threads/1 throughput 2717402.651op/s 2727717.006op/s ± 6366.589op/s 2729070.565op/s ± 4403.500op/s 2731513.405op/s 2735475.402op/s 2735681.362op/s 2735732.852op/s 0.24% -0.424 -1.021 0.22% 2013.292op/s 1 10
profiles_dictionary/profile_string_inserts/threads/16 execution_time 1.989ms 2.001ms ± 0.005ms 2.002ms ± 0.003ms 2.003ms 2.006ms 2.007ms 2.007ms 0.27% -1.143 1.084 0.24% 0.002ms 1 10
profiles_dictionary/profile_string_inserts/threads/16 throughput 8162765.196op/s 8189930.994op/s ± 21162.055op/s 8184982.677op/s ± 12194.106op/s 8198383.151op/s 8221844.454op/s 8235839.831op/s 8239338.675op/s 0.66% 1.156 1.109 0.25% 6692.029op/s 1 10
profiles_dictionary/profile_string_inserts/threads/2 execution_time 635.919µs 639.286µs ± 3.136µs 638.742µs ± 1.429µs 639.729µs 644.725µs 644.976µs 645.038µs 0.99% 0.888 -0.434 0.47% 0.992µs 1 10
profiles_dictionary/profile_string_inserts/threads/2 throughput 3175005.395op/s 3203641.956op/s ± 15652.119op/s 3206300.735op/s ± 7180.489op/s 3214092.297op/s 3220093.251op/s 3220447.671op/s 3220536.276op/s 0.44% -0.877 -0.445 0.46% 4949.635op/s 1 10
profiles_dictionary/profile_string_inserts/threads/4 execution_time 814.065µs 817.919µs ± 3.567µs 817.132µs ± 2.652µs 820.490µs 823.165µs 823.460µs 823.533µs 0.78% 0.395 -1.355 0.41% 1.128µs 1 10
profiles_dictionary/profile_string_inserts/threads/4 throughput 4973691.562op/s 5007917.371op/s ± 21803.487op/s 5012655.987op/s ± 16268.677op/s 5027812.025op/s 5030248.012op/s 5031282.282op/s 5031540.849op/s 0.38% -0.389 -1.362 0.41% 6894.868op/s 1 10
scenario metric 95% CI mean Shapiro-Wilk pvalue Ljung-Box pvalue (lag=1) Dip test pvalue
profiles_dictionary/profile_string_inserts/threads/1 execution_time [374.864µs; 375.951µs] or [-0.145%; +0.145%] None None None
profiles_dictionary/profile_string_inserts/threads/1 throughput [2723771.025op/s; 2731662.986op/s] or [-0.145%; +0.145%] None None None
profiles_dictionary/profile_string_inserts/threads/16 execution_time [1.997ms; 2.004ms] or [-0.160%; +0.160%] None None None
profiles_dictionary/profile_string_inserts/threads/16 throughput [8176814.857op/s; 8203047.130op/s] or [-0.160%; +0.160%] None None None
profiles_dictionary/profile_string_inserts/threads/2 execution_time [637.342µs; 641.230µs] or [-0.304%; +0.304%] None None None
profiles_dictionary/profile_string_inserts/threads/2 throughput [3193940.850op/s; 3213343.061op/s] or [-0.303%; +0.303%] None None None
profiles_dictionary/profile_string_inserts/threads/4 execution_time [815.708µs; 820.130µs] or [-0.270%; +0.270%] None None None
profiles_dictionary/profile_string_inserts/threads/4 throughput [4994403.678op/s; 5021431.064op/s] or [-0.270%; +0.270%] None None None

Group 2

cpu_model git_commit_sha git_commit_date git_branch
Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz bb7ab76 1789071525 better-cxx
scenario metric min mean ± sd median ± mad p75 p95 p99 max peak_to_median_ratio skewness kurtosis cv sem runs sample_size
profile_add_sample_timestamped_x1000 execution_time 4.050ms 4.056ms ± 0.009ms 4.055ms ± 0.001ms 4.056ms 4.059ms 4.062ms 4.176ms 3.00% 12.076 157.210 0.22% 0.001ms 1 200
scenario metric 95% CI mean Shapiro-Wilk pvalue Ljung-Box pvalue (lag=1) Dip test pvalue
profile_add_sample_timestamped_x1000 execution_time [4.054ms; 4.057ms] or [-0.031%; +0.031%] None None None

Group 3

cpu_model git_commit_sha git_commit_date git_branch
Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz bb7ab76 1789071525 better-cxx
scenario metric min mean ± sd median ± mad p75 p95 p99 max peak_to_median_ratio skewness kurtosis cv sem runs sample_size
benching string interning on wordpress profile execution_time 123.703µs 124.813µs ± 0.468µs 124.741µs ± 0.141µs 124.898µs 125.374µs 126.467µs 128.915µs 3.35% 4.147 31.231 0.37% 0.033µs 1 200
scenario metric 95% CI mean Shapiro-Wilk pvalue Ljung-Box pvalue (lag=1) Dip test pvalue
benching string interning on wordpress profile execution_time [124.748µs; 124.878µs] or [-0.052%; +0.052%] None None None

Group 4

cpu_model git_commit_sha git_commit_date git_branch
Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz bb7ab76 1789071525 better-cxx
scenario metric min mean ± sd median ± mad p75 p95 p99 max peak_to_median_ratio skewness kurtosis cv sem runs sample_size
profile_serialize_compressed_pprof_timestamped_x1000 execution_time 953.238µs 957.056µs ± 2.692µs 956.468µs ± 0.818µs 957.379µs 961.650µs 963.923µs 980.184µs 2.48% 3.969 27.178 0.28% 0.190µs 1 200
scenario metric 95% CI mean Shapiro-Wilk pvalue Ljung-Box pvalue (lag=1) Dip test pvalue
profile_serialize_compressed_pprof_timestamped_x1000 execution_time [956.683µs; 957.429µs] or [-0.039%; +0.039%] None None None

Group 5

cpu_model git_commit_sha git_commit_date git_branch
Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz bb7ab76 1789071525 better-cxx
scenario metric min mean ± sd median ± mad p75 p95 p99 max peak_to_median_ratio skewness kurtosis cv sem runs sample_size
profile_add_sample_frames_x1000 execution_time 4.098ms 4.104ms ± 0.003ms 4.104ms ± 0.001ms 4.105ms 4.108ms 4.109ms 4.131ms 0.67% 4.218 34.686 0.07% 0.000ms 1 200
scenario metric 95% CI mean Shapiro-Wilk pvalue Ljung-Box pvalue (lag=1) Dip test pvalue
profile_add_sample_frames_x1000 execution_time [4.104ms; 4.104ms] or [-0.010%; +0.010%] None None None

Group 6

cpu_model git_commit_sha git_commit_date git_branch
Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz bb7ab76 1789071525 better-cxx
scenario metric min mean ± sd median ± mad p75 p95 p99 max peak_to_median_ratio skewness kurtosis cv sem runs sample_size
profile_add_sample2_frames_x1000 execution_time 688.298µs 689.652µs ± 0.491µs 689.654µs ± 0.314µs 689.974µs 690.466µs 690.751µs 691.267µs 0.23% 0.012 0.136 0.07% 0.035µs 1 200
scenario metric 95% CI mean Shapiro-Wilk pvalue Ljung-Box pvalue (lag=1) Dip test pvalue
profile_add_sample2_frames_x1000 execution_time [689.584µs; 689.720µs] or [-0.010%; +0.010%] None None None

Baseline

Baseline benchmark details

Group 1

cpu_model git_commit_sha git_commit_date git_branch
Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz 8b0fa65 1789070470 main
scenario metric min mean ± sd median ± mad p75 p95 p99 max peak_to_median_ratio skewness kurtosis cv sem runs sample_size
profiles_dictionary/profile_string_inserts/threads/1 execution_time 377.829µs 379.411µs ± 1.215µs 379.461µs ± 0.453µs 379.699µs 381.211µs 382.051µs 382.261µs 0.74% 1.123 1.224 0.30% 0.384µs 1 10
profiles_dictionary/profile_string_inserts/threads/1 throughput 2678796.696op/s 2698947.019op/s ± 8614.571op/s 2698565.431op/s ± 3221.426op/s 2704517.744op/s 2708687.729op/s 2709913.327op/s 2710219.727op/s 0.43% -1.105 1.190 0.30% 2724.167op/s 1 10
profiles_dictionary/profile_string_inserts/threads/16 execution_time 1.992ms 1.998ms ± 0.006ms 1.995ms ± 0.002ms 2.002ms 2.007ms 2.009ms 2.010ms 0.76% 0.875 -0.523 0.29% 0.002ms 1 10
profiles_dictionary/profile_string_inserts/threads/16 throughput 8151617.328op/s 8200937.774op/s ± 24612.006op/s 8213270.871op/s ± 10299.676op/s 8218355.862op/s 8223596.670op/s 8223784.757op/s 8223831.778op/s 0.13% -0.869 -0.537 0.28% 7783.000op/s 1 10
profiles_dictionary/profile_string_inserts/threads/2 execution_time 633.227µs 636.033µs ± 3.356µs 634.423µs ± 1.049µs 636.984µs 641.973µs 642.005µs 642.014µs 1.20% 1.098 -0.424 0.50% 1.061µs 1 10
profiles_dictionary/profile_string_inserts/threads/2 throughput 3189963.439op/s 3220040.175op/s ± 16899.659op/s 3228130.623op/s ± 5337.850op/s 3231005.222op/s 3233643.651op/s 3234111.949op/s 3234229.023op/s 0.19% -1.092 -0.434 0.50% 5344.141op/s 1 10
profiles_dictionary/profile_string_inserts/threads/4 execution_time 815.122µs 824.131µs ± 5.371µs 824.284µs ± 2.503µs 825.760µs 831.924µs 835.074µs 835.862µs 1.40% 0.628 0.845 0.62% 1.698µs 1 10
profiles_dictionary/profile_string_inserts/threads/4 throughput 4900329.649op/s 4970275.275op/s ± 32268.459op/s 4969160.750op/s ± 15080.510op/s 4987354.310op/s 5010214.911op/s 5022054.976op/s 5025014.992op/s 1.12% -0.582 0.805 0.62% 10204.183op/s 1 10
scenario metric 95% CI mean Shapiro-Wilk pvalue Ljung-Box pvalue (lag=1) Dip test pvalue
profiles_dictionary/profile_string_inserts/threads/1 execution_time [378.658µs; 380.164µs] or [-0.198%; +0.198%] None None None
profiles_dictionary/profile_string_inserts/threads/1 throughput [2693607.750op/s; 2704286.287op/s] or [-0.198%; +0.198%] None None None
profiles_dictionary/profile_string_inserts/threads/16 execution_time [1.994ms; 2.002ms] or [-0.186%; +0.186%] None None None
profiles_dictionary/profile_string_inserts/threads/16 throughput [8185683.375op/s; 8216192.174op/s] or [-0.186%; +0.186%] None None None
profiles_dictionary/profile_string_inserts/threads/2 execution_time [633.953µs; 638.113µs] or [-0.327%; +0.327%] None None None
profiles_dictionary/profile_string_inserts/threads/2 throughput [3209565.851op/s; 3230514.500op/s] or [-0.325%; +0.325%] None None None
profiles_dictionary/profile_string_inserts/threads/4 execution_time [820.802µs; 827.459µs] or [-0.404%; +0.404%] None None None
profiles_dictionary/profile_string_inserts/threads/4 throughput [4950275.444op/s; 4990275.105op/s] or [-0.402%; +0.402%] None None None

Group 2

cpu_model git_commit_sha git_commit_date git_branch
Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz 8b0fa65 1789070470 main
scenario metric min mean ± sd median ± mad p75 p95 p99 max peak_to_median_ratio skewness kurtosis cv sem runs sample_size
profile_add_sample_timestamped_x1000 execution_time 4.003ms 4.010ms ± 0.009ms 4.009ms ± 0.002ms 4.011ms 4.014ms 4.016ms 4.134ms 3.12% 12.100 158.771 0.23% 0.001ms 1 200
scenario metric 95% CI mean Shapiro-Wilk pvalue Ljung-Box pvalue (lag=1) Dip test pvalue
profile_add_sample_timestamped_x1000 execution_time [4.009ms; 4.011ms] or [-0.032%; +0.032%] None None None

Group 3

cpu_model git_commit_sha git_commit_date git_branch
Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz 8b0fa65 1789070470 main
scenario metric min mean ± sd median ± mad p75 p95 p99 max peak_to_median_ratio skewness kurtosis cv sem runs sample_size
benching string interning on wordpress profile execution_time 124.693µs 125.764µs ± 0.351µs 125.740µs ± 0.171µs 125.914µs 126.239µs 126.725µs 127.683µs 1.55% 1.432 8.315 0.28% 0.025µs 1 200
scenario metric 95% CI mean Shapiro-Wilk pvalue Ljung-Box pvalue (lag=1) Dip test pvalue
benching string interning on wordpress profile execution_time [125.716µs; 125.813µs] or [-0.039%; +0.039%] None None None

Group 4

cpu_model git_commit_sha git_commit_date git_branch
Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz 8b0fa65 1789070470 main
scenario metric min mean ± sd median ± mad p75 p95 p99 max peak_to_median_ratio skewness kurtosis cv sem runs sample_size
profile_serialize_compressed_pprof_timestamped_x1000 execution_time 934.759µs 937.933µs ± 2.100µs 937.419µs ± 0.889µs 938.432µs 941.713µs 944.371µs 951.152µs 1.46% 2.046 7.532 0.22% 0.148µs 1 200
scenario metric 95% CI mean Shapiro-Wilk pvalue Ljung-Box pvalue (lag=1) Dip test pvalue
profile_serialize_compressed_pprof_timestamped_x1000 execution_time [937.642µs; 938.224µs] or [-0.031%; +0.031%] None None None

Group 5

cpu_model git_commit_sha git_commit_date git_branch
Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz 8b0fa65 1789070470 main
scenario metric min mean ± sd median ± mad p75 p95 p99 max peak_to_median_ratio skewness kurtosis cv sem runs sample_size
profile_add_sample_frames_x1000 execution_time 4.006ms 4.014ms ± 0.002ms 4.014ms ± 0.002ms 4.016ms 4.018ms 4.020ms 4.021ms 0.17% -0.205 0.381 0.06% 0.000ms 1 200
scenario metric 95% CI mean Shapiro-Wilk pvalue Ljung-Box pvalue (lag=1) Dip test pvalue
profile_add_sample_frames_x1000 execution_time [4.014ms; 4.014ms] or [-0.009%; +0.009%] None None None

Group 6

cpu_model git_commit_sha git_commit_date git_branch
Intel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz 8b0fa65 1789070470 main
scenario metric min mean ± sd median ± mad p75 p95 p99 max peak_to_median_ratio skewness kurtosis cv sem runs sample_size
profile_add_sample2_frames_x1000 execution_time 712.829µs 714.374µs ± 0.620µs 714.354µs ± 0.416µs 714.777µs 715.408µs 715.854µs 716.604µs 0.31% 0.280 0.376 0.09% 0.044µs 1 200
scenario metric 95% CI mean Shapiro-Wilk pvalue Ljung-Box pvalue (lag=1) Dip test pvalue
profile_add_sample2_frames_x1000 execution_time [714.288µs; 714.460µs] or [-0.012%; +0.012%] None None None

@dd-octo-sts

dd-octo-sts Bot commented Sep 9, 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 91.32 MB 91.32 MB +0% (+784 B) 👌
/aarch64-alpine-linux-musl/lib/libdatadog_profiling.so 8.45 MB 8.45 MB 0% (0 B) 👌
aarch64-unknown-linux-gnu
Artifact Baseline Commit Change
/aarch64-unknown-linux-gnu/lib/libdatadog_profiling.a 102.61 MB 102.61 MB +0% (+840 B) 👌
/aarch64-unknown-linux-gnu/lib/libdatadog_profiling.so 11.38 MB 11.38 MB 0% (0 B) 👌
libdatadog-x64-windows
Artifact Baseline Commit Change
/libdatadog-x64-windows/debug/dynamic/datadog_profiling_ffi.dll 27.32 MB 27.32 MB +0% (+1.00 KB) 👌
/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 185.38 MB 185.40 MB +0% (+16.00 KB) 👌
/libdatadog-x64-windows/debug/static/datadog_profiling_ffi.lib 804.37 MB 804.45 MB +0% (+79.98 KB) 👌
/libdatadog-x64-windows/release/dynamic/datadog_profiling_ffi.dll 9.00 MB 9.00 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.20 MB 26.20 MB 0% (0 B) 👌
/libdatadog-x64-windows/release/static/datadog_profiling_ffi.lib 52.21 MB 52.21 MB -0% (-54 B) 👌
libdatadog-x86-windows
Artifact Baseline Commit Change
/libdatadog-x86-windows/debug/dynamic/datadog_profiling_ffi.dll 23.82 MB 23.82 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 190.43 MB 190.48 MB +.02% (+56.00 KB) 🔍
/libdatadog-x86-windows/debug/static/datadog_profiling_ffi.lib 785.15 MB 785.23 MB +.01% (+82.03 KB) 🔍
/libdatadog-x86-windows/release/dynamic/datadog_profiling_ffi.dll 6.96 MB 6.96 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.18 MB 28.18 MB 0% (0 B) 👌
/libdatadog-x86-windows/release/static/datadog_profiling_ffi.lib 49.70 MB 49.70 MB -0% (-28 B) 👌
x86_64-alpine-linux-musl
Artifact Baseline Commit Change
/x86_64-alpine-linux-musl/lib/libdatadog_profiling.a 81.48 MB 81.48 MB +0% (+48 B) 👌
/x86_64-alpine-linux-musl/lib/libdatadog_profiling.so 9.41 MB 9.41 MB 0% (0 B) 👌
x86_64-unknown-linux-gnu
Artifact Baseline Commit Change
/x86_64-unknown-linux-gnu/lib/libdatadog_profiling.a 97.21 MB 97.21 MB +0% (+496 B) 👌
/x86_64-unknown-linux-gnu/lib/libdatadog_profiling.so 11.46 MB 11.46 MB 0% (0 B) 👌

@danielsn danielsn changed the title feat(profiling): expose dictionary-backed samples in CXX API feat(profiling)!: expose missing API in CXX Sep 9, 2026
@danielsn
danielsn requested a review from a team as a code owner September 10, 2026 20:18

@ekump ekump left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM for the AGENTS.md change

Comment thread AGENTS.md

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.

I'm not sure why this file needs to be updated as a part of this PR.

/// borrowed only for the duration of this call. endtime_ns is an
/// optional end timestamp in nanoseconds; pass 0 to record the sample
/// without a timestamp.
fn add_sample2(self: &mut Profile, sample: &Sample2, endtime_ns: i64) -> Status;

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.

Since libdd_profiling::cxx::ffi is not intended for Rust callers, please make the bridge module and its Rust implementation surface crate-private. The current public visibility accidentally exposes an unsound safe API to downstream Rust, as demonstrated by this reproducer (https://gist.github.com/taegyunkim/8d0b2ff9fe8e95262299fd7ad40c3a1f), which uses #![forbid(unsafe_code)] but still segfaults through add_sample2.

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.

Can this also be tested in CI by adding it to .github/workflows/test-ffi.yml?

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