Repository navigation
bench(ffi-gen): compare BoltFFI with UniFFI on a moq-ffi slice - #5736
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A standalone crate binds one slice of moq-net (origin, track, groups, write_frame/read_frame, an async read loop, and a QUIC client) with either generator, and run.sh measures call overhead, payload throughput, async cost, and output size from Python and Kotlin, with a Rust floor. The README holds the results, BoltFFI's gaps, each base's carrying cost, and a recommendation to fork UniFFI. Completes quest/m1/boltffi.md: the quest is deleted and the fork, Kotlin calls, and browser generator quests point at the report. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Coordination from #5838, the browser generator comparison. It builds on this PR's
(Written by Claude Opus 5.5) |
The spike's quests moved to m2 on main; delete quest/m2/boltffi.md and carry this PR's edits onto the moved files. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…feature #5776 put uniffi-bindgen's binary behind a `cli` feature, so run.sh now runs it through `cargo run --features cli` like rs/moq-ffi/build.sh. `just bench-ffi-gen` takes several steps, and `size` builds the moq-ffi and moq-wasm references only it needs. The nightly runs `build bench` so #5478 and #5838 can reuse a slice that still builds. Also fixes clippy on the standalone crate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks for the coordination from #5838.
(Written by Claude Opus 5.5) |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 50d857b458
ℹ️ 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".
| ("slice, UniFFI", files("cargo/uniffi/release/libmoq_ffi_gen.*[so]")), | ||
| ("slice, BoltFFI", files("cargo/boltffi/release/libmoq_ffi_gen.*[so]")), |
There was a problem hiding this comment.
Include dylibs in native-size inputs
On the explicitly supported *-apple-* host path, these globs reject the generated libmoq_ffi_gen.dylib because [so] matches only a final s or o. Consequently, just bench-ffi-gen and its size step exit from files() with “nothing matches” on macOS before producing the size comparison; match .dylib as well as .so.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in the latest push: size.py now matches libmoq_ffi_gen.so or libmoq_ffi_gen.dylib. size still runs strip --strip-all, which is GNU syntax, so the macOS size path stays unverified, as the README says.
(Written by Claude Opus 5.5)
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
WalkthroughThe pull request adds a Rust FFI slice with UniFFI and BoltFFI build paths, plus Rust, Python, and Kotlin benchmark runners. It adds scripts to build bindings, run benchmarks, compare results, and report artifact sizes. A nightly workflow runs the build and benchmark steps and uploads the results. The README records benchmark and size findings. Quest documents now refer to those findings and update the generator-selection text. Priority: ⬇️ Low Merge Risk: ⚪ Minimal · up to
|
The `.*[so]` glob matched `.so` but not `.dylib`, so `size` failed on the apple host run.sh supports. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Merging at c7932af with the decisions recorded in the PR body:
Follow-up: watch the first nightly run of the new leg against the 60-minute job limit. The bench crate is its own workspace pinned to a fixed upstream revision, so the main commits since the last CI run (including the (Written by Claude Opus 5.5) |
Completes the BoltFFI or UniFFI spike: a reproducible comparison of BoltFFI 0.31.1 and UniFFI 0.32 on one moq-ffi slice, to pick the base for the generator fork. Neither generator is adopted or forked here. The full report is
bench/ffi-gen/README.md.What's here
bench/ffi-gen/: a standalone crate, so BoltFFI never enters the root lockfile. It binds one moq-net slice: an origin, a track, groups,write_frame/read_frame, an async read loop, a QUIC client, and the async constructorMoqSession::dial. Either generator binds it from one source: BoltFFI's markers are literal, anduniffi-shim/maps them to UniFFI's.just bench-ffi-gen [build|bench|size|all]...(bench/ffi-gen/run.sh):buildbuilds both generators' Python, Kotlin, Swift, and wasm outputs;benchruns Python and Kotlin runners with a Rust floor;sizebuilds moq-ffi and moq-wasm for reference and prints the size tables.just bench-ffi-gen build benchand keeps the results as thebench-ffi-genartifact. It skipssize, whose reference builds take as long as the rest.Requiredentry;Results (medians of 3 rounds on a shared host)
write_frame, 100 B recordA single-round rerun after merging main on 2026-10-17 landed within the same ranges.
Size:
.wasm, stripped and gzipped: 174 KiB for UniFFI vs 155 KiB for BoltFFI, which adds 25 KiB of gzipped JS.The speed gap comes from backend calling conventions: a CPython extension vs ctypes, JNI vs JNA, and a bulk vs per-byte
Vec<u8>copy. Both share the same async model.BoltFFI failed in 11 ways on the roughly 300-line slice. Among them:
cfg_attr;cfg;Arc<T>;Option<Class>;The README has each one with the cost of fixing it in a fork. #5838 found three more on the browser side (
Sendfutures on wasm32, host-built metadata, and objects inside records).Not measured:
platform.yml's macOS job.Decisions
A sub-agent iterated this draft unattended and took the recommended option for each. The maintainer confirms or overrides them at merge.
uniffi-bindgen's binary behind aclifeature hours after this PR was pushed.browser.patchinto the slice here?Changes in this iteration
run.shfor chore(uniffi-bindgen): skip the generator fork in a plain check #5776: it runsuniffi-bindgenthroughcargo run --features cli, asrs/moq-ffi/build.shdoes, instead of locating the binary throughcargo metadata.run.shtakes several steps, andsizenow builds the moq-ffi and moq-wasm references it alone needs.just bench-ffi-genand the nightly entry.DefaultforMoqBroadcastProducer, two lints in the Rust bench).size.pynow matches the slice's.dylibon macOS as well as.so.Suggested follow-ups
cfg_attrscanning,#[path]resolution, the thiserror#[error]heuristic, the async panic abort, PythonOption<Class>). These need approval, since boltffi/boltffi is outside our orgs.Public API: none. Wire: none.
Checks
just checkandquest checkpass.-D warningspasses on the standalone crate under both features.just bench-ffi-gen build bench(one round) andjust bench-ffi-gen sizeran end to end on Linux. The slice's sizes are unchanged.MoqSession.dialandMoqClient.connectran from Python under both generators, returning the expected connection error.buildtook about 23 minutes cold and onebenchround about 3.(Written by Claude Opus 5.5)
🤖 Generated with Claude Code