Skip to content

perf: add benchmark tooling and reduce fixed overhead - #5

Merged
vbasky merged 5 commits into
vbasky:mainfrom
Else00:revelo-mediainfo-gap-investigation
Jul 5, 2026
Merged

vbasky merged 5 commits into
vbasky:mainfrom
Else00:revelo-mediainfo-gap-investigation

Conversation

@Else00

@Else00 Else00 commented Jul 1, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This follows up on #4 with Rust-native benchmark tooling plus the small constant-factor fixes found while investigating the remaining Revelo vs MediaInfo gap.

#4 made large-file parsing bounded and measurable. This PR keeps the follow-up focused on two things:

  • reproducible benchmark evidence that can live in the Revelo repo without Python tooling;
  • fixed-overhead reductions that showed up during the MediaInfo comparison.

Runtime fixes included here:

  • avoid spawning date +%z on Unix for local file time formatting;
  • reduce generic tag-scan overhead after known media containers have already parsed their own metadata;
  • keep the WASM dependency graph free of desktop defaults.

Review cleanup after the maintainer feedback:

  • removed the parse_rle detect-table change from this PR;
  • removed the moov-first QuickTime parser change from this PR;
  • removed the ID3v2 trailing-padding parser change from this PR;
  • changed the tags.rs policy from a scan allowlist to a conservative skip policy: known audio/video/container outputs skip expensive generic embedded scans, but unlisted formats keep the legacy scan path;
  • aligned revelo-diff with the CLI metadata path so the oracle harness now runs computed fields, duplicate-stream detection and parse_tags() before XML export.

Current head after that cleanup is ec0d04c.

Rust-Native Tooling

This replaces the earlier Python prototype with:

  • crates/revelo-bench, a dev-only workspace binary with generate-fixtures, compare, render-table, evidence and self-test subcommands;
  • crates/revelo-cli/examples/perf_probe.rs, a dev-only phase probe emitting line-oriented JSON;
  • just bench-compare for manifest-driven Hyperfine comparisons;
  • just bench-evidence for comparison plus table generation with one shared run id;
  • just bench-compare-table and just bench-compare-png for regenerating HTML/PNG from existing sanitized JSON;
  • just bench-wasm for a Rust-native revelo-wasm build check on wasm32-unknown-unknown;
  • scripts/perf/manifest.example.json, scripts/perf/manifest.extended.example.json, scripts/perf/table.config.example.json and scripts/perf/README.md.

Generated fixtures, local real-media manifests, raw outputs and screenshots are not committed. Default output remains under target/perf-investigation/ and target/perf-fixtures/.

The PNG path is optional: revelo-bench renders HTML/CSS from results.json, then captures that same HTML through a locally installed Chrome/Chromium/Edge via CDP. If no compatible browser is available, JSON/HTML still generate and the JSON records that PNG capture was skipped.

Benchmark Evidence

Latest full generated run:

  • run id: 20260704Tcurrent-rust-native-extended-v2;
  • benchmarked branch commit: cf9a7b5;
  • current PR head after review cleanup: ec0d04c;
  • runner: Hyperfine 1.20.0;
  • samples: 2 warmups + 10 measured runs;
  • matrix: Revelo 0.4.6, 0.5.0, 0.5.1, this PR branch, MediaInfo and ffprobe;
  • cases: 38 generated sparse fixtures from the committed extended manifest;
  • logical fixture size: 10.19 GiB, stored sparsely;
  • machine: MacBook Pro, Apple M3 Max, 16 CPU cores, macOS 26.5.1;
  • Rust: rustc 1.96.0 / cargo 1.96.0 from Homebrew;
  • tools: MediaInfoLib 26.05, ffprobe 8.1.2.

The post-review cleanup removed non-performance parser semantics and made the tag-scan policy more conservative for unlisted formats. The full 38-row timing matrix was not rerun after that cleanup; the benchmarked media cases remain known media container/audio/image rows that still take the bounded path.

Headline results from that run, median milliseconds:

Tool Min Median Max
Revelo 0.4.6 337.0 ms 654.0 ms 3710.5 ms
Revelo 0.5.0 323.2 ms 653.5 ms 3658.1 ms
Revelo 0.5.1 17.7 ms 19.0 ms 25.5 ms
This PR 2.6 ms 3.4 ms 7.7 ms
MediaInfo 8.6 ms 14.5 ms 119.8 ms
ffprobe 21.4 ms 27.7 ms 1415.5 ms

Across the generated matrix:

  • this PR is under 10 ms on 38/38 rows;
  • slowest PR row is 7.7 ms;
  • this PR is slower than MediaInfo on 0/38 rows;
  • this PR is slower than ffprobe on 0/38 rows.

The generated artifacts are local and uncommitted:

  • JSON: target/perf-investigation/20260704Tcurrent-rust-native-extended-v2/results.json;
  • PNG: target/perf-investigation/20260704Tcurrent-rust-native-extended-v2/benchmark-table.png.

One clarification about the previous #4 screenshot: that table was captured from a mid-review performance branch and an earlier benchmark pipeline. The new table measures the final published v0.5.1 release and this PR with the Rust-native pipeline on one shared manifest, so the fair comparison is inside this new run rather than row-by-row against the old screenshot.

Oracle And WASM Notes

  • revelo-diff now exercises parse_tags() before XML export, so it can cover the tags.rs gating path.
  • Strict revelo-diff remains the right gate for parser output semantics. The review response below includes a small representative run for the remaining tags.rs change.
  • WASM coverage here is a build/feature-graph check via just bench-wasm; it is not a browser or runtime timing benchmark.

Verification

Local gates run on this branch after the review cleanup:

  • cargo fmt --all --check;
  • cargo test --workspace --all-targets;
  • cargo clippy --workspace --all-targets (passes with existing non-fatal warnings; CI does not use -D warnings);
  • RUSTDOCFLAGS='-D warnings' cargo doc --workspace --no-deps;
  • cargo build -p revelo-cli --examples --release;
  • cargo build -p revelo-diff --release;
  • cargo run -p revelo-bench -- self-test;
  • RUSTC="$(rustup which rustc)" cargo check -p revelo-wasm --target wasm32-unknown-unknown;
  • full generated benchmark run 20260704Tcurrent-rust-native-extended-v2 with 2 warmups + 10 runs, before the review cleanup described above.

@vbasky

vbasky commented Jul 4, 2026

Copy link
Copy Markdown
Owner

Thanks for the benchmark reproducibility work — the evidence pipeline and fixture matrix are valuable.

One request before merge: please refactor the Python scripts under scripts/perf/ to Rust.

The PR currently adds several .py tools (generate_fixtures, run_benchmark_evidence, render_benchmark_table, run_wasm_probe, run_oracle_parity, etc.). I would prefer not to introduce Python into this repo. Revelo is Rust-native, and perf/benchmark tooling should stay in Rust as well — ideally as just targets and/or small workspace binaries (e.g. a revelo-bench crate or extensions to revelo-cli).

Happy to review a Rust port with the same functionality. Once that is in place, we can merge without a Python dependency.

@Else00
Else00 force-pushed the revelo-mediainfo-gap-investigation branch 2 times, most recently from e2af135 to cf9a7b5 Compare July 4, 2026 17:27
@Else00

Else00 commented Jul 4, 2026 •

Copy link
Copy Markdown
Contributor Author

I pushed a cleaned-up Rust-native version and force-updated the branch to keep the history reviewable.

What changed since your review comment:

  • the PR history is now 4 commits instead of the earlier Python-prototype sequence;
  • the committed benchmark tooling is all Rust-native: crates/revelo-bench, perf_probe, just targets and JSON config/examples;
  • the previous Python scripts/templates/tests are gone from the PR diff;
  • table PNG capture is handled by Rust through Chrome/Chromium/Edge CDP and is optional;
  • the table renderer now fails if section config would drop benchmark rows, percent-encodes local file:// paths for CDP and keeps only implemented config fields;
  • the PR body has been rewritten with the current Rust-native run from commit cf9a7b5.

Latest generated evidence is 20260704Tcurrent-rust-native-extended-v2: 38 generated sparse fixtures, 2 warmups + 10 measured runs, Revelo 0.4.6 / 0.5.0 / 0.5.1 / this PR / MediaInfo / ffprobe. This PR is under 10 ms on 38/38 rows and slower than MediaInfo on 0/38 rows.

One precision on WASM: this PR now provides a Rust-native just bench-wasm build/feature-graph check. It does not claim browser/runtime WASM timing; that should stay a separate follow-up if needed.

Small non-blocking credit/contact note: #4 was a substantial contribution: GitHub reports +4,206/-1,039 across 91 files, and it is the basis for the v0.5.1 large-file bounded-access fix. This follow-up PR is another +4,678/-34 across 32 files. On the generated benchmark matrix, the combined work moves the median from roughly 654 ms in 0.4.6/0.5.0 to 19.0 ms in 0.5.1, and this PR brings it to 3.4 ms (~192x faster than 0.4.6/0.5.0, ~5.6x faster than 0.5.1; slowest row 7.7 ms, 38/38 under 10 ms). Given that contribution size and impact, would you be open to adding me to the v0.5.1 release notes/credits, and also to the next release notes if this PR is merged?

Also, I noticed from your public profile/repos that you have several media-focused Rust projects besides Revelo, including viser, cathar and sheathe. We are also working on Rust media crates, and this is an area I care about. If you are open to it, could I reach out by Telegram, Signal, Element, SimpleX or another contact channel you prefer?

@vbasky

vbasky commented Jul 5, 2026

Copy link
Copy Markdown
Owner

Thanks — and happy to add you to the credits.

One thing before merge: this PR bundles the dev tooling with a few parser output-semantics changes — dropping parse_rle from the detect table, the moov-first QuickTime path, the ID3v2 padding skip, and (biggest) gating the embedded-metadata scans in tags.rs behind a format allowlist. As you noted yourself, output-parity changes belong behind the revelo-diff oracle gate — could you attach a revelo-diff parity run over a representative corpus covering those four? My specific worry is the tags.rs allowlist silently dropping embedded metadata for any format not in the list.

On reaching out — I don't use Telegram/Signal/Element/SimpleX, but I'm on WhatsApp if you'd like to connect there.

senpai added 5 commits July 5, 2026 14:15
Use libc time/localtime_r on Unix for local date fields and keep the date subprocess as a fallback. The CLI computes this per analyzed file, so avoiding process spawn removes fixed overhead without changing exported field shape.\n\nConstraint: Keep non-Unix fallback behavior unchanged.\nConfidence: high\nScope-risk: narrow\nTested: cargo fmt --all --check\nTested: cargo test -p revelo-parsers-tag parse_tags_\nTested: cargo test -p revelo-diff\nTested: cargo run -p revelo-bench -- self-test\nNot-tested: Full workspace gate not rerun yet after history rewrite.
Disable default features on internal parser dependencies so the WASM package can traverse the parser graph without accidentally enabling desktop-only core defaults.\n\nConstraint: Keep public crate defaults unchanged.\nConfidence: high\nScope-risk: moderate\nTested: RUSTC="/Users/else/.rustup/toolchains/1.95.0-aarch64-apple-darwin/bin/rustc" cargo check -p revelo-wasm --target wasm32-unknown-unknown
Generic tag scans are useful for standalone metadata/image-like files, but expensive after container parsers have already identified audio/video media. Gate only the expensive generic scans for known media containers and streams, while keeping unlisted formats on the legacy scan path so embedded metadata is not silently dropped.\n\nConstraint: Preserve embedded metadata scans for image streams and unlisted formats.\nRejected: Pure scan allowlist | too easy to drop metadata for an unlisted parser.\nConfidence: medium\nScope-risk: moderate\nTested: cargo test -p revelo-parsers-tag parse_tags_\nNot-tested: Full representative real-media oracle corpus remains summarized separately in target/oracle-parity.
Run computed fields, duplicate stream detection and generic tag parsing in revelo-diff before XML export. The maintainer requested oracle evidence for tag-scan changes, so the diff harness must exercise the same metadata path as the CLI.\n\nConstraint: Keep the existing MediaInfo XML comparison flow and strict mode.\nConfidence: medium\nScope-risk: moderate\nTested: cargo test -p revelo-diff\nTested: target/release/revelo-diff --strict target/oracle-parity/20260705-tags-gate/mp4-title.mp4
Provide a Rust-native benchmark pipeline for generated and local manifest-driven media cases, including fixture generation, Hyperfine comparison, perf probe records, HTML table rendering and optional Chrome CDP PNG capture. This replaces the earlier local Python prototype with workspace-native tooling.\n\nConstraint: Keep private media paths and raw outputs out of git.\nRejected: Python benchmark scripts | maintainer requested Rust-native tooling only.\nConfidence: high\nScope-risk: moderate\nTested: cargo run -p revelo-bench -- self-test\nTested: target/perf-investigation/20260704Tcurrent-rust-native-extended-v2/results.json generated before the review cleanup.\nNot-tested: Full benchmark matrix not rerun after removing non-performance parser semantics.
@Else00
Else00 force-pushed the revelo-mediainfo-gap-investigation branch from cf9a7b5 to ec0d04c Compare July 5, 2026 12:17
@Else00

Else00 commented Jul 5, 2026

Copy link
Copy Markdown
Contributor Author

I updated the branch for this review and force-pushed a cleaned history at ec0d04c.

What changed for the four parser-semantics items:

  • parse_rle removal: removed from this PR; the detect table is back to the upstream shape.
  • moov-first QuickTime path: removed from this PR.
  • ID3v2 trailing-padding skip: removed from this PR.
  • tags.rs embedded-metadata gating: kept, but changed from a scan allowlist to a conservative skip policy. Known media containers / audio-video outputs skip the expensive generic embedded scans; unlisted formats keep the legacy scan path. I also added a regression that an unlisted Format=PDF still scans and surfaces XMP.

I also updated revelo-diff so it now follows the CLI metadata path before XML export: computed fields, duplicate-stream detection and parse_tags(). Before this, the diff harness did not actually exercise the tags.rs path you were asking about.

Representative revelo-diff --strict run on the current branch, generated locally with MediaInfoLib 26.05:

Case What it covers Match Oracle-only Rust-only Note
mp4-title.mp4 known media container, container title 97 5 11 Title is present on both sides; remaining gaps are existing bitrate/frame-rate/extra-field differences.
mkv-title.mkv known media container, Matroska tags 68 29 13 Non-byte-equal due existing MKV/container fidelity gaps; no generic embedded scan is needed for this path.
mp3-title.mp3 audio tag path 40 2 3 Same result with/without the removed ID3 padding change; remaining gaps are existing title/track mapping and derived fields.
flac-title.flac audio/Vorbis-comment path 40 3 5 Track metadata is still present; remaining gaps are existing field-name/channel-layout differences.
jpeg-xmp.jpg image embedded metadata scan kept 29 1 4 XMP-derived metadata is still surfaced by Rust.
png-comment.png image/text metadata scan kept 28 11 4 PNG parser remains on the metadata-scan path; remaining differences are existing PNG text/bit-depth/stream-size gaps.

So the PR no longer carries the three unrelated parser-output changes, and the remaining performance change no longer has the risky “only scan listed formats” behavior. The strict oracle run is still not byte-equal for every generated row because these formats have existing output-fidelity gaps, but the tags.rs concern is now covered in two ways: unlisted formats still scan by default, and revelo-diff now actually runs parse_tags().

I also updated the PR body to describe the review cleanup and to distinguish the latest full timing run (cf9a7b5) from the current cleaned head (ec0d04c).

Verification after the cleanup:

  • cargo fmt --all --check
  • cargo test --workspace --all-targets
  • cargo clippy --workspace --all-targets (passes with existing non-fatal warnings)
  • RUSTDOCFLAGS='-D warnings' cargo doc --workspace --no-deps
  • cargo build -p revelo-cli --examples --release
  • cargo build -p revelo-diff --release
  • cargo run -p revelo-bench -- self-test
  • RUSTC="$(rustup which rustc)" cargo check -p revelo-wasm --target wasm32-unknown-unknown

And yes, WhatsApp works for me. Since this is a public PR thread, I will avoid posting phone details here; use whichever non-public channel you prefer.

@vbasky
vbasky merged commit b0e282d into vbasky:main Jul 5, 2026
2 checks passed
@vbasky

vbasky commented Jul 5, 2026

Copy link
Copy Markdown
Owner

Merged — thank you. This was a clean, thorough response: dropping the three unrelated parser-output changes, reworking tags.rs to a conservative skip that defaults to the full scan for anything unlisted, and wiring revelo-diff through parse_tags() so the path is actually exercised. The regression tests and the --strict oracle run made it easy to sign off. Genuinely appreciate the care and the interest you've taken in improving Revelo — both here and in #4.

You'll be in the release notes for the large-file work in #4 and this benchmark/perf work in the next release.

On connecting: rather than swap contact details on a public thread, feel free to reach me at the email on my GitHub profile — happy to talk Rust media crates there.

@Else00
Else00 deleted the revelo-mediainfo-gap-investigation branch July 19, 2026 09:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants