bench: cover four inbound/group hot paths for CodSpeed baselines - #858
Conversation
Adds divan benchmarks (no production code change) for receive-path hot paths that had no coverage, so CodSpeed can establish baselines and a flamegraph can show where to optimize: - parse_message_info: stanza->MessageInfo metadata parse, once per inbound message. Input is a marshal round-trip decoded back to OwnedNodeRef, so JID attrs arrive wire-typed (ValueRef::Jid) exactly as the decoder hands them to the receive loop — not string-parsed, which production never does. - decode_record: per-mutation app-state decode (AES-CBC + content/index HMAC + prost + JSON index), up to ~1000x per resume patch. process_patch covered the loop but never isolated this inner per-record cost. - group out-of-order decrypt worst case: a ~2000-deep skipped-key backlog, the full out-of-order decrypt (backlog-sized record clone + signature check dominate; the O(n) remove_sender_message_key scan is a smaller slice). Baseline, not a scan-isolating microbench. - process_sender_key_distribution_message: SKDM ingest into a fresh store, the first-group-message-per-sender cost, previously only run in setup. All inputs black_boxed and outputs fully observed (the thin-LTO DCE lesson from the reporting-token bench); expensive setup stays in with_inputs. Drafted and adversarially verified via workflow.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📝 WalkthroughSummary by CodeRabbit
WalkthroughThis PR adds three independent benchmark suites to measure critical inbound data path performance: app state record decoding ("star" and "contact" shapes), message metadata parsing (DM, group, status broadcast, self-sent), and libsignal group decryption (worst-case out-of-order backlog plus SKDM ingest). All use Divan parameterization. ChangesInbound Data Path Benchmarking
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Merging this PR will improve performance by 28.6%
Performance ChangesTip Curious why this is faster? Comment Comparing |
Why
Establishes CodSpeed baselines for four receive-path hot paths that had no benchmark coverage, so a flamegraph can then point at where to optimize. No production code changes — benchmarks only. (#856 already covered the two biggest inbound gaps, plaintext decode and the appstate index-MAC dedup; this fills the rest.)
What it adds
bench_parse_message_info(message_utils_benchmark) — the stanza→MessageInfometadata parse that runs once per inbound message before any Signal work, across four shapes (DM, LID group, status broadcast, self-sent). The input is a marshal round-trip decoded back into anOwnedNodeRef, so JID attributes arrive wire-typed (ValueRef::Jid) exactly as the decoder hands them to the receive loop — not string-parsed viaJid::from_str, which production never does. Each shape carries an<enc>child so theget_optional_childscans run.bench_decode_record(appstate_benchmark) — the per-mutation app-state decode (AES-256-CBC + content HMAC-SHA512 + index HMAC-SHA256 + prost + JSON index parse), up to ~1000× per resume patch.process_patchcovered the whole loop but never isolated this inner per-record cost. Two shapes (5-part STAR index, contact-name) built viaencode_recordso MAC validation runs the success path.bench_group_out_of_order_decrypt_worst_case(libsignal_benchmark) — a ~2000-deep skipped-key backlog, the full out-of-order group decrypt. Honest framing in the doc: the backlog-sizedSenderKeyRecordclone inload_sender_keyand the signature check are the bulk of it, with the O(n)remove_sender_message_keyscan a smaller slice — a baseline, not a scan-isolating microbench. (The clone showing up this large is itself a lead worth a flamegraph look.)bench_process_sender_key_distribution_message(libsignal_benchmark) — SKDM ingest into a fresh store, the first-group-message-per-sender cost, previously executed only in other benches' setup.Precision
Every bench black_boxes its inputs and fully observes its output (the thin-LTO dead-code-elimination lesson from the reporting-token bench), and keeps all expensive setup in
with_inputs(untimed). Drafted in parallel and then adversarially verified via a workflow — that pass caught and fixed the two issues above (the string-typed vs wire-typed JID realism gap inparse_message_info, which had overstated it ~25-43% and skewed the profile toward afrom_strthe receive loop never runs; and the misleading scan-only framing of the group OOO bench). NoCargo.tomlchanges (all bench targets already registered);cargo clippy --workspace --all-targetsclean.