Two pre-existing CI failures (unrelated to codegen/install-zap): - minrust 1.81: quickcheck 1.1.0 pulls rand 0.10 -> rand_core 0.10.1, whose Cargo.toml requires the edition2024 feature (unstable on Cargo 1.81). Pin quickcheck to =1.0.3 (last version on rand 0.8 / rand_core 0.6.4) — within MSRV, no major bump. Fresh-resolve verified: rand_core 0.10.1 leaves the graph. - formatting: ran 'cargo +nightly fmt --all'; the CI check (--check --unstable-features --error-on-unformatted, nightly) now passes.
ZAP benchmark suite
Canonical end-to-end performance harness for the ZAP Rust SDK. Runs the three classic serialization-codec test cases — carsales (random struct trees with sums), catrank (search-result re-ranking), eval (arithmetic expression evaluator) — across:
- modes:
object(in-memory),bytes(sliced buffer),pipe(stdin/stdout child) - compression:
none,packed - scratch:
reuse(carsales only),no-reuse
Quick start
git clone https://github.com/zap-proto/rust
cd rust
bash ./benchmark/bench.sh quick # ~10 sec sanity
bash ./benchmark/bench.sh default # ~15 sec — original ZAP iters
bash ./benchmark/bench.sh full # ~3 min — 10× iters
Each run writes one JSON file bench-results/$(hostname)-$(timestamp).json
plus prints a summary table. Schema documented below.
Parallel saturation
saturate.sh runs N worker copies of the encoder workload in parallel
and reports REAL parallel efficiency by comparing against a recorded
single-worker baseline.
# step 1 — record single-worker baseline
PRESET=full bash ./benchmark/saturate.sh baseline
# single-baseline: 6.003s for 2,000,000 iters = 333,183 ops/s
# step 2 — saturate with N=ncpu workers (default), compute real speedup
PRESET=full bash ./benchmark/saturate.sh
# per-worker p50 : 10.991s (181,963 ops/s under contention)
# aggregate ops/s : 1,745,201
# baseline (single) : 6.003s (333,183 ops/s/core)
# REAL speedup : 5.24× (= single × N / wall)
# effective cores : 5.24 of 10
# parallel efficiency: 52%
# step 3 — see CPU was actually busy
tail bench-results/saturate-ra-*/cpu.log
# t+04s total= 406.5% procs=23 hottest= 43.8%
# t+06s total= 473.4% procs=23 hottest= 51.1%
# t+08s total= 556.8% procs=23 hottest= 69.2%
# t+10s total= 529.1% procs=23 hottest= 53.4%
What to look for:
- Real speedup < N: normal. On M-class Macs you'll see 4-6× speedup on 10 cores due to macOS QoS scheduling (subprocesses get throttled to efficiency cores) and system allocator contention.
- CPU sampler total ≈ 100 × speedup: the math should match. If
pssays 500% and speedup is 5×, that's coherent.
Skip pipe mode for saturation: pipe mode forks a child per RPC, so
under N workers you spawn N × iters_count children, and the bottleneck
is the OS fork rate, not the encoder. The encoder workload is
eval bytes none — pure marshal + unmarshal, no process boundaries.
Output schema
{
"schema_version": 1,
"host": {"hostname":"...","os":"linux","arch":"x86_64"},
"toolchain": {"rustc":"rustc 1.95.0 ..."},
"iters": {"carsales":10000,"catrank":1000,"eval":200000},
"runs": [
{"case":"carsales","mode":"object","compression":"none",
"scratch":"reuse","iters":10000,"elapsed_secs":0.42,
"throughput_ops_per_sec":23809.5},
...
]
}
Twenty runs per file (5 carsales × 2 scratch + 5 catrank + 5 eval).
Contributing results across hardware
The intent is multi-machine comparison:
- Pull this repo on each machine
bash ./benchmark/bench.sh default- Open a PR adding the resulting
bench-results/*.jsonto this directory
The schema is stable; downstream tools (and zap-proto.dev/docs/benchmarks)
aggregate any future submission by reading the runs array.
What each case stresses
carsales — large, deeply-nested message tree. Tests encoding bandwidth and allocation cost. Stress allocators.
catrank — moderate-size strings + ranking arithmetic on read. Tests zero-copy access vs. copy-decode.
eval — small, recursive structure. Tests per-message overhead and dispatch.
The three together give a fair picture of where the encoder spends its budget on your hardware.
Background
The carsales / catrank / eval workload set is the de-facto benchmark shape across ZAP, Protobuf, and FlatBuffers ports — what's run here in the Rust SDK is the same shape, ported to ZAP's encoder. Numbers should be comparable across language ports of the same suite (see zap-proto/cpp-core/c++/src/benchmark, zap-proto/java/benchmark, zap-proto/py/benchmark).