Skip to content

fix(bench): write random-access Parquet with zstd level 3 - #10157

Merged
joseph-isaacs merged 2 commits into
developfrom
ji/random-access-parquet-row-groups
Oct 1, 2026
Merged

joseph-isaacs merged 2 commits into
developfrom
ji/random-access-parquet-row-groups

Conversation

@joseph-isaacs

@joseph-isaacs joseph-isaacs commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Split out of #9412 so the change to the benchmark data files lands on its own and the random-access baseline reset is attributed to it, rather than to the S3 variant.

The three synthetic random-access generators (feature_vectors, nested_lists, nested_structs) passed no writer properties to parquet-rs, so their files were uncompressed. #10103 moved the other generators from Snappy to zstd level 3 but did not cover these, since they never set a codec at all.

Changes

  • Add random_access_writer_properties in vortex-bench, which sets zstd level 3 and leaves row group and page sizes at the parquet-rs defaults.
  • Use it in the three synthetic generators.
  • A unit test pins the codec.

The Parquet-to-Vortex conversion is unaffected, so the derived Vortex files are byte-identical.

The three synthetic random-access generators (feature_vectors,
nested_lists, nested_structs) wrote Parquet with default writer
properties: uncompressed and, since every dataset is under the 1Mi-row
default, one row group per file. Readers select row groups before rows,
so a point lookup had to decode the whole file.

Write them with 32Ki-row row groups, 1024-row data pages and zstd level 3,
matching the other benchmark data generators. The row group size is a
whole multiple of the 1024-row batches the Parquet-to-Vortex conversion
reads, so the derived Vortex files are byte-identical.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L627uApatcD62FGrQPutCL
Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
@codspeed

codspeed Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Merging this PR will improve performance by 12.21%

⚠️ Unknown Walltime execution environment detected

Using the Walltime instrument on standard Hosted Runners will lead to inconsistent data.

For the most accurate results, we recommend using CodSpeed Macro Runners: bare-metal machines fine-tuned for performance measurement consistency.

⚡ 1 improved benchmark
✅ 2069 untouched benchmarks
⏩ 503 skipped benchmarks1

Performance Changes

Mode Benchmark BASE HEAD Efficiency
⚡ WallTime dict_canonicalize_gt_u8_neon[1000000] 548.2 µs 488.5 µs +12.21%

Tip

Curious why performance improved? Comment @codspeedbot explain why performance improved on this PR, or directly use the CodSpeed MCP with your agent.


Comparing ji/random-access-parquet-row-groups (2036089) with develop (91285b8)

Open in CodSpeed

Footnotes

  1. 503 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

@joseph-isaacs joseph-isaacs changed the title fix(bench): write random-access Parquet with row groups and zstd fix(bench): write random-access Parquet with zstd level 3 Sep 30, 2026
…arquet

Only the codec changes: zstd level 3 like the other generators. Row group
and data page sizes stay at the parquet-rs defaults.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L627uApatcD62FGrQPutCL
Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
@joseph-isaacs joseph-isaacs added the action/bench-random-access Run only the random-access benchmark on this PR label Sep 30, 2026
@github-actions github-actions Bot removed the action/bench-random-access Run only the random-access benchmark on this PR label Sep 30, 2026
@github-actions

github-actions Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Polar Signals Profiling Results

Latest Run

Status Commit Job Attempt Link
🟢 Done 2036089 random-access-bench 1 Explore Profiling Data

Powered by Polar Signals Cloud

@github-actions

Copy link
Copy Markdown
Contributor

Benchmarks: Random Access 📖

Commits: PR 20360896 vs base 91285b8c
Verdict: No clear signal (environment too noisy confidence)
Attributed Vortex impact: -33.7%
Engines: random-access No clear signal (-33.7%, environment too noisy confidence)
Vortex (geomean): hot 0.990x ➖
Parquet (geomean): hot 1.495x ❌
Shifts: Parquet (control) +49.5% · Median polish +2.5%

How to read Verdict and Engines
  • Verdict: Overall PR-level signal after subtracting baseline drift estimated from Parquet control rows. It can be Likely improvement, Likely regression, or No clear signal.
  • Engines: Per-engine attribution. DataFusion is compared against DataFusion/Parquet controls; DuckDB is compared against DuckDB/Parquet controls. This answers whether each engine improved or regressed independently.
  • Confidence: Based on directional consistency, share of rows above the noise floor, and control-run noise.
  • Hot vs cold: Every measurement is run several times. The first run is reported as the cold run, and the median of the runs after it is reported as the hot run. The verdict and significance use hot runs; each target's geomean reports hot and cold beside each other where the individual runs were recorded and hot alone where they were not, the cold column shows first-run cost per row, and hot/cold is how much of each run the warm path saves. Rows whose results predate per-run reporting show only one value, taken from the value the runner reported.
  • Table cells: Each cell reads PR / base / %diff. The hot and cold columns mark a change as 🔴 slower or 🟢 faster once it clears this suite's threshold; anything smaller is noise here and is left unmarked, as is hot/cold, because a shift in the warm-up ratio is not a win or a loss by itself.

vortex / arrow-ipc / ns (0.981x ➖, 0↑ 0↓)
name ns (PR / base / %diff)
random-access/arrow-tokio-local-disk 67904 / 69434 / -2.2%
random-access/arrow-tokio-local-disk-footer 161975 / 162357 / -0.2%
random-access/feature-vectors/correlated/arrow-tokio-local-disk 1330885 / 1349601 / -1.4%
random-access/feature-vectors/correlated/arrow-tokio-local-disk-footer 3231763 / 3412668 / -5.3%
random-access/feature-vectors/uniform/arrow-tokio-local-disk 32022788 / 30997598 / +3.3%
random-access/feature-vectors/uniform/arrow-tokio-local-disk-footer 55344249 / 56219990 / -1.6%
random-access/nested-lists/correlated/arrow-tokio-local-disk 58334 / 58437 / -0.2%
random-access/nested-lists/correlated/arrow-tokio-local-disk-footer 100357 / 98911 / +1.5%
random-access/nested-lists/uniform/arrow-tokio-local-disk 1076433 / 1043223 / +3.2%
random-access/nested-lists/uniform/arrow-tokio-local-disk-footer 1152851 / 1060873 / +8.7%
random-access/nested-structs/correlated/arrow-tokio-local-disk 50821 / 54605 / -6.9%
random-access/nested-structs/correlated/arrow-tokio-local-disk-footer 89966 / 92426 / -2.7%
random-access/nested-structs/uniform/arrow-tokio-local-disk 827108 / 876290 / -5.6%
random-access/nested-structs/uniform/arrow-tokio-local-disk-footer 882134 / 921207 / -4.2%
random-access/taxi/correlated/arrow-tokio-local-disk 115256 / 117169 / -1.6%
random-access/taxi/correlated/arrow-tokio-local-disk-footer 209352 / 220033 / -4.9%
random-access/taxi/uniform/arrow-tokio-local-disk 2561890 / 2834107 / -9.6%
random-access/taxi/uniform/arrow-tokio-local-disk-footer 2863105 / 2956946 / -3.2%
random-access / vortex-file-compressed / ns (0.990x ➖, 1↑ 0↓)
name ns (PR / base / %diff)
random-access/feature-vectors/correlated/vortex-tokio-local-disk 242372 / 245456 / -1.3%
random-access/feature-vectors/correlated/vortex-tokio-local-disk-footer 1257460 / 1241259 / +1.3%
random-access/feature-vectors/uniform/vortex-tokio-local-disk 1432167 / 1457437 / -1.7%
random-access/feature-vectors/uniform/vortex-tokio-local-disk-footer 2706165 / 2750319 / -1.6%
random-access/nested-lists/correlated/vortex-tokio-local-disk 228527 / 211451 / +8.1%
random-access/nested-lists/correlated/vortex-tokio-local-disk-footer 374109 / 365685 / +2.3%
random-access/nested-lists/uniform/vortex-tokio-local-disk 713756 / 692635 / +3.0%
random-access/nested-lists/uniform/vortex-tokio-local-disk-footer 915185 / 968329 / -5.5%
random-access/nested-structs/correlated/vortex-tokio-local-disk 253065 / 282627 / -10.5% 🟢
random-access/nested-structs/correlated/vortex-tokio-local-disk-footer 525181 / 531047 / -1.1%
random-access/nested-structs/uniform/vortex-tokio-local-disk 630374 / 667473 / -5.6%
random-access/nested-structs/uniform/vortex-tokio-local-disk-footer 897453 / 951347 / -5.7%
random-access/taxi/correlated/vortex-tokio-local-disk 667268 / 675919 / -1.3%
random-access/taxi/correlated/vortex-tokio-local-disk-footer 1479268 / 1428150 / +3.6%
random-access/taxi/uniform/vortex-tokio-local-disk 2689090 / 2646661 / +1.6%
random-access/taxi/uniform/vortex-tokio-local-disk-footer 3884938 / 3833705 / +1.3%
random-access/vortex-tokio-local-disk 445168 / 455259 / -2.2%
random-access/vortex-tokio-local-disk-footer 1072802 / 1078087 / -0.5%
random-access / parquet / ns (1.495x ❌, 1↑ 4↓)
name ns (PR / base / %diff)
random-access/feature-vectors/correlated/parquet-tokio-local-disk 119330577943 / 109593386583 / +8.9%
random-access/feature-vectors/correlated/parquet-tokio-local-disk-footer 108584754302 / 109505610295 / -0.8%
random-access/feature-vectors/uniform/parquet-tokio-local-disk 106454115344 / 153419307247 / -30.6% 🟢
random-access/feature-vectors/uniform/parquet-tokio-local-disk-footer 114347927016 / 105119664949 / +8.8%
random-access/nested-lists/correlated/parquet-tokio-local-disk 145044562 / 132888710 / +9.1%
random-access/nested-lists/correlated/parquet-tokio-local-disk-footer 143714365 / 131873439 / +9.0%
random-access/nested-lists/uniform/parquet-tokio-local-disk 143756870 / 133797670 / +7.4%
random-access/nested-lists/uniform/parquet-tokio-local-disk-footer 143269696 / 134202869 / +6.8%
random-access/nested-structs/correlated/parquet-tokio-local-disk 44995370 / 7515111 / +498.7% 🔴
random-access/nested-structs/correlated/parquet-tokio-local-disk-footer 45007984 / 7451159 / +504.0% 🔴
random-access/nested-structs/uniform/parquet-tokio-local-disk 44912405 / 7276954 / +517.2% 🔴
random-access/nested-structs/uniform/parquet-tokio-local-disk-footer 45002556 / 7834213 / +474.4% 🔴
random-access/parquet-tokio-local-disk 120577098 / 118657312 / +1.6%
random-access/parquet-tokio-local-disk-footer 118821841 / 121263552 / -2.0%
random-access/taxi/correlated/parquet-tokio-local-disk 178252350 / 181935808 / -2.0%
random-access/taxi/correlated/parquet-tokio-local-disk-footer 178250269 / 181807978 / -2.0%
random-access/taxi/uniform/parquet-tokio-local-disk 191827152 / 192079274 / -0.1%
random-access/taxi/uniform/parquet-tokio-local-disk-footer 194158123 / 190464261 / +1.9%
random-access / lance / ns (1.002x ➖, 0↑ 0↓)
name ns (PR / base / %diff)
random-access/feature-vectors/correlated/lance-tokio-local-disk 289953 / 290033 / -0.0%
random-access/feature-vectors/correlated/lance-tokio-local-disk-footer 1277286 / 1242705 / +2.8%
random-access/feature-vectors/uniform/lance-tokio-local-disk 1044442 / 1033399 / +1.1%
random-access/feature-vectors/uniform/lance-tokio-local-disk-footer 2030049 / 1979220 / +2.6%
random-access/lance-tokio-local-disk 523724 / 530927 / -1.4%
random-access/lance-tokio-local-disk-footer 1492714 / 1495434 / -0.2%
random-access/nested-lists/correlated/lance-tokio-local-disk 154746 / 154663 / +0.1%
random-access/nested-lists/correlated/lance-tokio-local-disk-footer 726168 / 727924 / -0.2%
random-access/nested-lists/uniform/lance-tokio-local-disk 859948 / 836630 / +2.8%
random-access/nested-lists/uniform/lance-tokio-local-disk-footer 1459365 / 1429865 / +2.1%
random-access/nested-structs/correlated/lance-tokio-local-disk 272124 / 270761 / +0.5%
random-access/nested-structs/correlated/lance-tokio-local-disk-footer 631102 / 659807 / -4.4%
random-access/nested-structs/uniform/lance-tokio-local-disk 2237941 / 2249001 / -0.5%
random-access/nested-structs/uniform/lance-tokio-local-disk-footer 2692349 / 2656113 / +1.4%
random-access/taxi/correlated/lance-tokio-local-disk 750906 / 752869 / -0.3%
random-access/taxi/correlated/lance-tokio-local-disk-footer 2038962 / 2049822 / -0.5%
random-access/taxi/uniform/lance-tokio-local-disk 8136157 / 8167600 / -0.4%
random-access/taxi/uniform/lance-tokio-local-disk-footer 8864516 / 9030878 / -1.8%

@joseph-isaacs
joseph-isaacs merged commit 400064c into develop Oct 1, 2026
115 checks passed
@joseph-isaacs
joseph-isaacs deleted the ji/random-access-parquet-row-groups branch October 1, 2026 13:26
robert3005 pushed a commit that referenced this pull request Oct 5, 2026
## Summary

The random-access benchmark only ever read its data from local NVMe,
which hides the cost that matters most for point lookups: how many bytes
and round trips a format needs against an object store. This adds an S3
variant of the same benchmark so Vortex, Parquet, and Lance random
access can be tracked against remote storage, both on `develop` and on
demand for PRs.

The synthetic Parquet files keep the parquet-rs default row group and
page sizes; only the codec (zstd level 3, from #10157) is set.

## Changes

- `random-access-bench` gains `--remote-data-dir s3://bucket/prefix/`
and `--prepare-data`. Data is materialized locally as before, uploaded
verbatim, and then opened through `object_store` (Vortex and Parquet) or
Lance's own `s3://` provider. Remote measurements are named
`...-tokio-s3` and tagged with `s3` storage so they form a separate
series from the local-disk numbers. Arrow IPC has no object-store reader
and is skipped for remote runs.
- v3 ingest records have no storage field and their measurement ID
hashes only commit, dataset, format and open mode, so S3 runs use an
`-s3` dataset suffix (e.g. `taxi-s3/uniform`). This keeps them from
overwriting the local-disk rows without a schema change; local-disk IDs
are unchanged.
- `vortex-bench` adds `RemoteDataDir`, which maps a local data path to
its object key, plus `open_object_store` constructors for the Vortex and
Parquet accessors. The Parquet accessor keeps its cached footer and
re-opens through a boxed `AsyncFileReader` on each take, so the local
and object-store paths share one read path.
- CI: new `pr-bench-random-access-s3.yml` reusable workflow, wired into
`pr-bench-dispatch.yml` behind the `action/bench-random-access-s3` label
and `action/bench-all`. `pr-bench-runner.yml` learns `variant_id` and
`remote_data_dir` inputs, uploads the data before the run and deletes it
afterwards. `develop-bench.yml` gains a `Random Access (S3)` matrix
entry that refreshes
`s3://vortex-ci-benchmark-datasets/develop/random-access/` on every run.
- `lance-bench` enables Lance's `aws` feature so `Dataset::open` accepts
`s3://` URIs.
- Docs: README section for running against S3 and the new label in the
benchmarking guide.

Unit tests cover the key and URI mapping of `RemoteDataDir` and the
separate S3 ingest dataset.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01L627uApatcD62FGrQPutCL

---------

Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk>
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog/fix A bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants