Skip to content

bench: criterion suite for the extension hot paths - #1474

Open
duncanista wants to merge 34 commits into
mainfrom
jordan.gonzalez/bench-suite/feature
Open

duncanista wants to merge 34 commits into
mainfrom
jordan.gonzalez/bench-suite/feature

Conversation

@duncanista

@duncanista duncanista commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

TL;DR: Criterion benchmarks for the hot paths: log processing, trace processing, invocation parsing, enhanced metrics, config load and init.

Why: The extension runs on about 0.07 vCPU at 128 MB, so per-line and per-span costs show up in the customer's billed duration. We need before and after numbers for each performance fix.

Overview

Jira: SVLS-9977

The extension runs at about 0.07 vCPU at 128 MB, so per-line, per-span and per-invocation
costs show up in billed duration. This PR adds 6 criterion benches (bottlecap/benches/):
logs, traces, invocation, enhanced_metrics, config, init. Benches named alt_*
measure an alternative from the review, as the target for a fix.

  • bottlecap/benches/README.md: what each bench measures, how to run and compare it, noise
    control, and a map from each review item to its bench id. It has no measured numbers: the
    investigation numbers are in the Confluence page "Bottlecap review: combined findings", and
    the bench CI workflow (ci: informational benchmark workflow #1475) has the current ones. No baseline is committed.
  • scripts/bench-compare.sh: save, compare and export criterion baselines with critcmp.
    scripts/bench-docker-arm64.sh: the suite in a 2-CPU Linux arm64 container (Debian-based
    image). Both source scripts/bench-note.sh, which writes the note of each baseline: the
    machine, the profile and Rust flag overrides, the git revision before the run, a mark when a
    tracked file changed during the run, and the cargo arguments. export copies the note next
    to the JSON.
  • tests/fixtures: LogKind::max_events_per_post(), the most events one Telemetry POST holds
    (600 for the JSON shapes, under the 1 MiB maxBytes). The corpus and the logs benches use it.
  • Cargo.toml: criterion 0.5 as a dev-dependency (no plotters, no rayon), the 6 [[bench]]
    targets, and bench = false on the lib and binaries so cargo bench runs only criterion.
  • Production code: 9 items become #[doc(hidden)] pub so the benches can reach them
    (is_oom_error, the /proc readers *_from_path, startup::build_tag_replace_rules).
    No behavior change.
  • .gitignore: the Linux arm64 target dir.

Size: 3281 insertions and 20 deletions in total. Production code: 32 changed lines in src/.
Scripts: 377 lines. The rest is benches, fixtures, docs and Cargo.lock.

Testing

  • applies on the previous PR of the stack: pass
  • cargo fmt --all -- --check: pass
  • cargo metadata --locked: pass
  • cargo clippy --workspace --all-targets --features default -- -D warnings: pass
  • cargo clippy --workspace --all-targets --features default,test-mode -- -D warnings: pass
  • cargo nextest run --workspace: pass
  • cargo bench --no-run (LTO off, 16 codegen units): pass
  • cargo bench --no-run and cargo bench -- --test, production profile: pass
  • cargo test --test fixtures_corpus: pass
  • cargo deny --locked check: pass
  • cargo machete: pass
  • dd-rust-license-tool check: pass
  • shellcheck 0.11.0 on the 3 scripts (also with -x), and bash -n on /bin/bash 3.2: pass
  • functional tests of both scripts with fake cargo, critcmp and docker (notes, overrides,
    edit during the run, export with the note, image check): pass
  • a real Docker run of bench-docker-arm64.sh with a stub Debian-based image, and the Alpine
    image check: pass
  • Linux arm64 in Docker (rust 1.93.1), on the tree at the end of the stack: cargo clippy --workspace --all-targets --no-default-features --features fips -- -D warnings: pass. It cannot run on macOS (libddwaf-sys load error).

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-10T18:22:18.119115Z 355e0ec New commits
🔒 Security Review ✅ Completed 2026-11-10T18:23:09.354768Z 355e0ec New commits
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@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: 341f23b39d

ℹ️ 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 scripts/bench-docker-arm64.sh Resolved
Comment thread scripts/bench-compare.sh Resolved
Comment thread scripts/bench-compare.sh Resolved
@datadog-prod-us1-4

datadog-prod-us1-4 Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Pipelines

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 355e0ec | Docs | Give us feedback!

@duncanista duncanista changed the title [SVLS-9977] bench: criterion suite for the extension hot paths bench: criterion suite for the extension hot paths Oct 28, 2026
- bench-docker-arm64.sh: pass the cargo arguments to the container shell as
  positional parameters, so criterion filters are not re-parsed.
- bench-compare.sh: make a relative CARGO_TARGET_DIR absolute before cd, so
  cargo, critcmp and the baseline notes use the same directory.
- bench-compare.sh: record a dirty marker and a hash of the uncommitted diff
  in the baseline notes.
- benches/README.md: drop the old branch name.
- dogstatsd: advance the metric name every 100 lines so n lines give min(n, 5000) contexts
- traces: set BASE_NS to 2026-10-27T12:00:00Z and encode meta/metrics in key order
- events: pad the SQS body to the exact size and put the LWA deadline 60 s from now
- telemetry: emit extension logs in the logger::Formatter JSON shape
- fault_injection_test: measure the /next budget from when the INVOKE was queued
- harness: shutdown_cleanly asserts the exit came within the SHUTDOWN deadline
- write_corpus: 600 events for the JSON shapes so each POST fits the 1 MiB maxBytes
- traces: TRACE_HEADERS matches the reference payload's 100 traces
- oversized trace: wait for /next against the 10 s INVOKE deadline, and assert
  the rejected trace is never sent again after the rejection is lifted
- lifecycle: read the intake before SHUTDOWN so the final flush cannot hide a
  missing end-of-invocation flush
Keep the #1467 dependency pins without ddsketch-agent, regenerate Cargo.lock
and LICENSE-3rdparty.csv, and list libddwaf-sys in the cargo-machete ignore
list: it is a dependency only to enable its aws-lc-rs feature.
…TDOWN, deliver telemetry only after an accepted subscribe
…h-suite/feature

Adapt the benches to what the merge brings in from main and the fixtures:
- init: the fixtures build the enrichment tags with enrich_tags(), not ENRICH_TAGS.
- traces: the libdatadog bump (#1467) renamed obfuscate_span to obfuscate_pb_span, HttpConfig.remove_paths_with_digits to remove_path_digits, and new_without_connection_pooling to new_periodic. tag_replace_rules is now built by startup::build_tag_replace_rules, made doc(hidden) pub so the bench builds it as production does.
duncanista added a commit that referenced this pull request Nov 5, 2026
**TL;DR:** One shared set of generated test inputs: Telemetry API
batches, Lambda log lines, traces, DogStatsD packets and trigger events.

**Why:** The fault-injection harness (#1473) and the benchmarks (#1474)
need the same realistic inputs. Today each test builds its own by hand.
The extension does not change.

## Overview

Jira: [SVLS-9977](https://datadoghq.atlassian.net/browse/SVLS-9977)

Stacked on #1471 (`jordan.gonzalez/cargo-machete/feature`). This PR does
not need the CI PRs below it. It sits on this stack so that the bench PR
can build on both.

### Why this PR

We are adding test tools for the extension:
- criterion benchmarks for the hot paths (#1474)
- a fault-injection harness that runs the real `bottlecap` binary
against a fake Lambda API and an intake that fails on demand (#1473)
- later, a local Lambda simulator

All of them need the same realistic inputs: Telemetry API batches,
Lambda log lines, trace payloads, DogStatsD packets and trigger events.
Today each test builds its own inputs by hand. This PR adds one small
set of generators for those inputs, so every tool tests and measures the
same shapes. Large inputs, such as a 220 KB SQS batch, are generated at
test time instead of being checked into git.

On its own, this PR only adds test code. The extension does not change.
The only non-test change is 9 lines that make the existing `stitch`
module `#[doc(hidden)] pub`, so integration tests and benches can call
it.

What to check here: that the generated shapes match what Lambda sends
(for example the split-record format that the stitcher reassembles since
#1415), and the self-test in `tests/fixtures_corpus.rs`.

### What is in it

`bottlecap/tests/fixtures/` generates the inputs that the benches, the
fault-injection
harness and the Lambda simulator share, so no large blob is in git:

- `telemetry`: Telemetry API batches (platform events, function logs in
3 formats, split
records for the stitcher, `runtimeDone` with or without metrics,
`logsDropped`, unknown
  events);
- `logs`: Lambda text and JSON lines, one OOM line per runtime;
- `traces`: synthetic traces and the 2000-span v0.4 msgpack payload, at
a fixed base time;
- `dogstatsd`: datagrams for 50 metric names x 100 endpoints;
- `events`: the checked-in trigger payloads plus a 220 KB SQS and a
100-record DynamoDB event.

`tests/fixtures_corpus.rs` checks the generators (for example, a split
record stitches back).
It needs `extension::telemetry::stitch` from the integration tests, so
the module and
`FragmentBuffer` become `#[doc(hidden)] pub`. No behavior change.

Size: 13 core lines, 1058 lines in total.

## Testing

- applies on the previous PR of the stack: pass
- `cargo fmt --all -- --check`: pass
- `cargo clippy --workspace --all-targets --features default -- -D
warnings`: pass
- `cargo clippy --workspace --all-targets --features default,test-mode
-- -D warnings`: pass
- `cargo nextest run --workspace`: pass



[SVLS-9977]:
https://datadoghq.atlassian.net/browse/SVLS-9977?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
Base automatically changed from jordan.gonzalez/fault-harness/feature to main November 6, 2026 20:32
Copilot AI balanced review requested due to automatic review settings November 6, 2026 20:44

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

ℹ️ 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 scripts/bench-docker-arm64.sh Resolved
Comment thread bottlecap/benches/init.rs Resolved

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

🟡 Changes recommended

The trace benchmark filters out every chunk, while the initialization benchmark drops clients before RSS sampling and includes teardown in its timing, making the performance and memory comparisons misleading.

4 open issues
What changed in this PR

Adds Criterion benchmarks for the Lambda extension’s hot paths, using shared fixtures from the preceding test work to support before-and-after performance comparisons. Production changes expose existing helpers without changing behavior.

Changes:

  • Adds six benchmark targets covering logs, traces, invocation parsing, enhanced metrics, configuration, and initialization.
  • Adds baseline comparison tooling and a Linux arm64 Docker runner.
  • Documents measurement practices, initial results, and benchmark coverage.
File Description
scripts/​bench-docker-arm64.sh Runs benchmarks in an isolated Linux arm64 container.
scripts/​bench-compare.sh Saves, compares, exports, and lists baselines.
bottlecap/​src/​startup.rs Exposes tag-replacement rule construction.
bottlecap/​src/​proc/​mod.rs Exposes path-based readers for fixture benchmarks.
bottlecap/​src/​logs/​lambda/​processor.rs Exposes the OOM detection helper.
bottlecap/​Cargo.toml Adds Criterion and registers six benchmark targets.
bottlecap/​Cargo.lock Locks Criterion and its dependencies.
bottlecap/​benches/​traces.rs Benchmarks trace decoding, processing, stats, and flushing.
bottlecap/​benches/​README.md Documents execution, comparisons, coverage, and baseline results.
bottlecap/​benches/​logs.rs Benchmarks log processing, stitching, batching, and compression.
bottlecap/​benches/​invocation.rs Benchmarks trigger identification and payload handling.
bottlecap/​benches/​init.rs Measures initialization components and client construction.
bottlecap/​benches/​enhanced_metrics.rs Benchmarks resource readers and metric tag construction.
bottlecap/​benches/​config.rs Benchmarks configuration loading and rule compilation.
bottlecap/​benches/​common/​mod.rs Shares allocator, runtime, configuration, and benchmark setup.
bottlecap/​benches/​baselines/​mac-main.txt Records initial baseline metadata.
.gitignore Excludes baseline exports and arm64 build output.

Review effort: Balanced

Comment thread bottlecap/benches/init.rs Resolved
Comment thread bottlecap/benches/traces.rs Resolved
Comment thread bottlecap/benches/README.md Resolved
Comment thread bottlecap/benches/README.md Resolved
- bench-docker-arm64.sh writes the baseline-<name>.txt note (machine, container, load,
  profile, commit) that bench-compare.sh compare prints; fix its BENCH_FAST profile label.
- bench-compare.sh records every CARGO_PROFILE_BENCH_* override in the note.
- init: read RSS from /proc/self/status on Linux, so images without ps work. Keep what each
  step builds alive, and drop the warm-build clients outside the measurement.
- traces: the regex require filter matches the fixture service; assert that every span is kept.
- The shared setup and the config bench take the function identity from the fixtures and do
  not set the variables Lambda gives only to the runtime (AWS_EXECUTION_ENV, LAMBDA_TASK_ROOT
  and others). The config benches drop their results outside the measurement.
- README: per-element time is the batch time divided by the count, the FIPS command needs
  --no-default-features, and the numbers recorded before these fixes are marked pre-fix.

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

ℹ️ 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 scripts/bench-compare.sh Resolved
Comment thread scripts/bench-compare.sh Resolved
Comment thread bottlecap/benches/common/mod.rs Resolved
Comment thread scripts/bench-docker-arm64.sh Resolved
…fuse emulated arm64

- bench-compare.sh save: capture the git revision before cargo bench, and flag the note
  when the tree changes during the run. Record the cargo arguments in the note.
- save and bench-docker-arm64.sh: remove every result and the note saved under the same
  baseline name before the run, so a baseline holds one run. Reject names that are not
  plain directory names.
- bench-docker-arm64.sh: stop when the Docker daemon is not arm64 (QEMU or binfmt
  emulation). BENCH_ALLOW_EMULATION=1 runs anyway and marks the note as emulated.
- profile note: also flag CARGO_PROFILE_RELEASE_* and RUSTFLAGS overrides, which the bench
  profile inherits.
- benches/common: setup_env removes AWS_EXECUTION_ENV and the other runtime-only variables
  that Lambda does not give to extensions.

@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: 1db5865481

ℹ️ 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 scripts/bench-compare.sh Resolved
Comment thread scripts/bench-docker-arm64.sh Resolved
Comment thread scripts/bench-docker-arm64.sh Resolved
Comment thread scripts/bench-docker-arm64.sh Resolved
Comment thread bottlecap/benches/logs.rs Resolved
…s, drop numbers

- scripts/bench-note.sh holds the baseline note for bench-compare.sh and
  bench-docker-arm64.sh: name check, removal of an older baseline, git
  revision before the run, post-run edit check, profile and Rust flag
  overrides, machine and container, and the note file. The Docker run
  sources it inside the container, and a second container marks the note
  when a tracked file changed during the run.
- export copies the note next to the JSON as <file>.txt.
- bench-docker-arm64.sh checks the image for bash, and apt-get when it has
  no protoc, before the run; a custom RUST_IMAGE must be Debian-based.
- logs benches over a Telemetry POST use LogKind::max_events_per_post, the
  cap the fixture corpus uses: 600 JSON events stay under the 1 MiB
  maxBytes. Throughput uses the count per shape.
- benches/README.md no longer has measured numbers: the findings table maps
  review items to bench ids, and points to the Confluence page and the
  bench CI workflow for numbers. benches/baselines/mac-main.txt is removed.

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

ℹ️ 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 scripts/bench-note.sh Resolved
Comment thread scripts/bench-compare.sh Resolved
Comment thread bottlecap/benches/README.md Resolved
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