perf(memtrack): reduce serialization bottleneck#436
Conversation
Merging this PR will improve performance by 44.86%
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| ⚡ | Simulation | write_events[1000000] |
2.1 s | 1.4 s | +47.8% |
| ⚡ | Simulation | write_events[100000] |
207.3 ms | 141.3 ms | +46.74% |
| ⚡ | Simulation | write_events[10000] |
20 ms | 13.9 ms | +43.69% |
| ⚡ | Simulation | write_events[500000] |
1,036.6 ms | 733.6 ms | +41.31% |
| 🆕 | Simulation | encode_events_realistic[16] |
N/A | 1.2 s | N/A |
| 🆕 | Simulation | encode_events_realistic[8] |
N/A | 1.2 s | N/A |
| 🆕 | Simulation | encode_events_realistic[4] |
N/A | 1.2 s | N/A |
Tip
Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.
Comparing cod-3071-fix-serialization-bottleneck (99b9b68) with main (58d994a)
381bac8 to
9be9b22
Compare
Greptile SummaryThis PR replaces the single-threaded memtrack writer with a windowed parallel encoder: events are collected into fixed-size batches (
Confidence Score: 5/5Safe to merge; the parallel encoding pipeline is correct, event ordering is preserved, and the poller lifecycle is properly handled through the new Drop impl. The core changes are well-tested: concatenated-frame decoding, ordering across window boundaries, empty-source handling, and byte-identical serialization are all covered by new tests. The RingBufferPoller Drop impl correctly signals and joins the poll thread before tx is dropped, so stop_polling() reliably closes the channel. No data correctness or liveness issues were found in the production path. No files require special attention in the production path. The benchmark file inflates per-iteration timings by creating the Rayon pool inside the timed loop, but this does not affect production correctness. Important Files Changed
|
a225638 to
9561cdd
Compare
9561cdd to
9292b3f
Compare
…t zstd compression bottleneck
Callers that encode a frame into an in-memory buffer need the buffer back after the zstd stream is finalized, so frames can be composed into a larger artifact stream. Refs COD-3071
Group events into fixed-size frames and compress them across a rayon pool, writing windows in input order. Bounds peak memory regardless of run length and removes the single-threaded compression bottleneck. Refs COD-3071
…race Generate a seeded malloc/free/realloc/mmap workload with a live-heap model instead of uniform random events, and sweep worker counts. Refs COD-3071
Forward ring buffer events over a crossbeam channel directly instead of through an extra keep-alive forwarding thread. On shutdown, consume the ring buffer once more so events emitted after the last poll are not lost, then close the channel. Refs COD-3071
Feed the poller's event channel straight into encode_events on one thread, sized to available parallelism. Shutdown is now deterministic: stop the poller, which drains stragglers and closes the channel, then join the pipeline. Fixes COD-3071
itertools::chunks erases the iterator size hint, so collecting each window grew by doubling (~29% of encode driver time in reallocation). A single pre-sized buffer reused across windows removes the growth and the chunk-adapter bookkeeping: encode_events_realistic median drops 21%/17%/9% at 16/8/4 workers.
346a162 to
99b9b68
Compare
Summary
MemtrackEventserialization with a byte-identical manual serializerMemtrackWriter::finishreturn encoded frame bytes for batchingVerification
cargo test -p runner-shared artifacts::memtrackcargo test -p runner-sharedcargo check -p runner-sharedcargo test --manifest-path crates/memtrack/Cargo.tomlvia Nix shell with libclang/build deps; eBPF integration cases compiled but were ignored becauseGITHUB_ACTIONSwas unsetcargo bench -p runner-shared --bench memtrack_writerNotes
memtrack_writerbench measures the Phase A single-writer encoder path only, not the full parallel memtrack pipeline.