Skip to content

feat(ffe): send the split serial id on exposure events [EX-3425] - #4135

Merged
danyal002 merged 1 commit into
masterfrom
danyal.khan/EX-3425
Aug 26, 2026
Merged

feat(ffe): send the split serial id on exposure events [EX-3425]#4135
danyal002 merged 1 commit into
masterfrom
danyal.khan/EX-3425

Conversation

@danyal002

@danyal002 danyal002 commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Description

Sends the split serial id on the exposure events that dd-trace-php emits. The exposures intake uses the serial id to find the holdout an allocation comes from. The compiler rewrites a holdout into an ordinary allocation before an SDK receives it, so the serial id is the only link back to it.

The serial id travels from the evaluation result, through the exposure buffer, into the sidecar FFI struct. Serial ids are zero-based per organization, so 0 is a real value and cannot signal absence. The value therefore carries a separate presence flag, matching the existing FfeResult convention in this file.

File Change
tracer/functions.c pass result.serial_id and result.has_serial_id into the recorder
tracer/ffe.c hold both on the buffered exposure, set both on ddog_FfeExposure
tracer/ffe.h recorder signature
libdatadog advance to 0c0c60b96
components-rs/common.h, components-rs/sidecar.h, Cargo.lock regenerated

Serialization, the wire key, and exposure deduplication live in libdatadog and are done there: DataDog/libdatadog#2402. That PR also fixed the deduplication cache, which compared only allocation key and variant, so a serial id that appeared or changed on an otherwise unchanged assignment was suppressed.

The submodule bump is required, not incidental: ddog_FfeExposure gains its two fields in 0c0c60b96, so the header and the compiled Rust struct must move together.

components-rs/sidecar.h and Cargo.lock are generated output, regenerated here with make cbindgen. Their churn is accumulated drift rather than a consequence of this change. The checked-in headers were last regenerated in 018f212, and the submodule pointer has advanced twice since then (#4118, #4123) without a regeneration, so this run sweeps up everything in between. Concretely, sidecar.h gains two additive ddog_sidecar_send_trace_v1_* declarations from 69df7ed9b, which nothing in this repo calls, and Cargo.lock gains the zrip crates. Reviewing tracer/ plus the three added lines in common.h covers the whole behavioural change.

This overlaps #4125, which bumps to a commit that predates 0c0c60b96; whichever lands second needs a rebase.

No validation is applied to the value. The flag configuration layer owns that.

Testing

PHP 8.3 debug on bookworm, submodule at 0c0c60b96:

  • make -j4 all links ffe.o and functions.o with no new warnings
  • make test_c TESTS=tests/ext/ffe passes 6/6, none skipped
  • an evaluation on a split declaring serialId: 0 reports serialId=0 with doLog=true, a split omitting it reports null, and flush_ffe_exposures() hands the batch to the sidecar

No test here covers the buffer-to-FFI hop. The exposure buffer is not observable from PHP, and no test in this repo asserts an exposure reaching the agent. Cross-language coverage comes from system-tests, where Test_FFE_Exposure_Serial_Id and the three serial-id caching classes already exist; manifests/php.yml gets flipped off missing_feature (EX-3425) in a follow-up once this ships.

Reviewer checklist

  • Test coverage seems ok.
  • Appropriate labels assigned.

This description was generated by Claude.

The exposures intake uses the serial id to find the holdout an allocation
comes from. The compiler rewrites a holdout into an ordinary allocation
before an SDK receives it, so the serial id is the only link back to it.

Carry the serial id from the evaluation result through the exposure buffer
into the sidecar FFI struct. Serial ids are zero-based per organization, so
0 is a real value and cannot signal absence; the value travels with a
separate presence flag, matching the existing FfeResult convention.

Advance libdatadog to 0c0c60b96, which adds the two fields to
ddog_FfeExposure and owns serialization, the wire key, and exposure
deduplication. Regenerate the affected headers with make cbindgen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@danyal002
danyal002 force-pushed the danyal.khan/EX-3425 branch from 39b2adc to 13f46a7 Compare August 25, 2026 18:15
@datadog-datadog-prod-us1

datadog-datadog-prod-us1 Bot commented Aug 25, 2026

Copy link
Copy Markdown

Pipelines  Tests

⚠️ Warnings

Your PR has failed checks. Please review the issues below and take necessary action before merging.

🚦 2 Pipeline jobs failed

DataDog/apm-reliability/dd-trace-php | merge-gate

View more details · View in GitLab

DataDog/apm-reliability/dd-trace-php | publish docker image for system tests

View more details · View in GitLab

ℹ️ Info

No other issues found (see more)

🧪 All tests passed
❄️ No new flaky tests detected

🔄 Datadog auto-retried 1 job - 1 passed on retry View in Datadog

🎯 Code Coverage (details)
Patch Coverage: 100.00%
Overall Coverage: 60.63% (+0.00%)

Useful? React with 👍 / 👎

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

@danyal002
danyal002 marked this pull request as ready for review August 25, 2026 19:00
@danyal002
danyal002 requested review from a team as code owners August 25, 2026 19:00
@danyal002
danyal002 requested review from pavlokhrebto and sameerank and removed request for a team August 25, 2026 19:00
@pr-commenter

pr-commenter Bot commented Aug 25, 2026

Copy link
Copy Markdown

Benchmarks [ tracer ]

Benchmark execution time: 2026-08-25 19:37:57

Comparing candidate commit 13f46a7 in PR branch danyal.khan/EX-3425 with baseline commit 8d9060c in branch master.

Found 4 performance improvements and 0 performance regressions! Performance is the same for 190 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:MessagePackSerializationBench/benchMessagePackSerialization

  • 🟩 execution_time [-4.647µs; -3.433µs] or [-4.100%; -3.029%]

scenario:MessagePackSerializationBench/benchMessagePackSerialization-opcache

  • 🟩 execution_time [-5.508µs; -4.532µs] or [-4.870%; -4.007%]

scenario:TraceFlushBench/benchFlushTrace

  • 🟩 execution_time [-18.697µs; -10.103µs] or [-5.425%; -2.931%]

scenario:TraceSerializationBench/benchSerializeTrace

  • 🟩 execution_time [-21.025µs; -9.975µs] or [-4.722%; -2.240%]

Comment thread tracer/ffe.c
@danyal002
danyal002 merged commit 24ba555 into master Aug 26, 2026
2169 of 2172 checks passed
@danyal002
danyal002 deleted the danyal.khan/EX-3425 branch August 26, 2026 15:09
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.

3 participants