Skip to content

bench(parquet): add same-projection predicate chain benchmark - #11007

Merged
alamb merged 4 commits into
apache:mainfrom
haohuaijin:bench-arrow-reader-predicate-fusion
Sep 19, 2026
Merged

alamb merged 4 commits into
apache:mainfrom
haohuaijin:bench-arrow-reader-predicate-fusion

Conversation

@haohuaijin

@haohuaijin haohuaijin commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

Related to #10926.

Rationale for this change

RowFilter evaluates each ArrowPredicate separately, so consecutive predicates on the same projection decode that column, or replay it from the predicate cache, once per predicate. #10859 fuses such chains. Per the contributing guide, the benchmark is submitted separately so it can run on the automated runner and serve as the baseline for that change.

What changes are included in this PR?

A criterion benchmark, parquet/benches/arrow_reader_predicate_fusion.rs, that scans an in-memory Snappy Parquet file of 262,144 rows through the async reader. Case names are type/layout/cache/predicates/profile:

  • 4/all99 chains across both column types (int64, string), layouts (fragmented, clustered), and cache modes (cached, uncached): 8 cases
  • fragmented 1/all99 controls, 2/all99, and 2/all50 chains across both types and cache modes: 12 cases
  • clustered uncached 2/all50 and 4/all50 chains across both types, retaining cases where fusion has shown regressions: 4 cases
  • int64/fragmented/4 with early1 and late1 across both cache modes, covering predicate ordering: 4 cases
  • a selection_boundary group with run lengths 16 and 64 on either side of the default row selection policy threshold: 2 cases

30 cases in total. Each case is validated once outside measurement for the expected row count and predicate cache use. Run-length cases also validate the predicate mask run lengths.

Are these changes tested?

The benchmark builds and all 30 cases pass with cargo bench -p parquet --bench arrow_reader_predicate_fusion --features "arrow async snap" --locked -- --test.

Are there any user-facing changes?

No.

Add a criterion benchmark for RowFilter chains whose predicates share one
projection. It scans an in-memory Snappy Parquet file of 262,144 rows
through the async reader and covers int64 and string filter columns in
fragmented and clustered layouts, with the filter column either projected
(predicate cache) or not, chains of one, two and four predicates, and
survivor profiles that keep 99% or 50% per predicate or 1% in the first or
last predicate. A selection_boundary group probes run lengths around the
row selection policy threshold.
@github-actions github-actions Bot added the parquet Changes to the parquet crate label Sep 6, 2026
@haohuaijin
haohuaijin marked this pull request as ready for review September 6, 2026 13:27
@alamb

alamb commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

This looks good except it makes 75 benchmarks

cargo bench --bench arrow_reader_predicate_fusion --features="arrow async snap"
...
.00%) high severe
same_projection_filter/string/clustered/cached/1/all99
                        time:   [1.6653 ms 1.6686 ms 1.6722 ms]
                        thrpt:  [156.77 Melem/s 157.11 Melem/s 157.42 Melem/s]
Found 10 outliers among 100 measurements (10.00%)
  4 (4.00%) high mild
  6 (6.00%) high severe
same_projection_filter/string/clustered/cached/2/all99
                        time:   [2.5275 ms 2.5337 ms 2.5405 ms]
                        thrpt:  [103.18 Melem/s 103.46 Melem/s 103.72 Melem/s]
Found 4 outliers among 100 measurements (4.00%)
  3 (3.00%) high mild
  1 (1.00%) high severe
same_projection_filter/string/clustered/cached/2/all50
                        time:   [2.8156 ms 2.8271 ms 2.8381 ms]
                        thrpt:  [92.366 Melem/s 92.725 Melem/s 93.104 Melem/s]
Found 17 outliers among 100 measurements (17.00%)
  11 (11.00%) low severe
  6 (6.00%) high severe
same_projection_filter/string/clustered/cached/2/early1
                        time:   [1.3208 ms 1.3229 ms 1.3253 ms]
                        thrpt:  [197.80 Melem/s 198.16 Melem/s 198.47 Melem/s]
Found 8 outliers among 100 measurements (8.00%)
  6 (6.00%) high mild
  2 (2.00%) high severe
same_projection_filter/string/clustered/cached/2/late1
                        time:   [2.0176 ms 2.0224 ms 2.0277 ms]
                        thrpt:  [129.28 Melem/s 129.62 Melem/s 129.93 Melem/s]
Found 17 outliers among 100 measurements (17.00%)
  1 (1.00%) high mild
  16 (16.00%) high severe
same_projection_filter/string/clustered/cached/4/all99
                        time:   [4.3241 ms 4.3359 ms 4.3489 ms]
                        thrpt:  [60.278 Melem/s 60.459 Melem/s 60.624 Melem/s]
Found 8 outliers among 100 measurements (8.00%)
  5 (5.00%) high mild
  3 (3.00%) high severe
same_projection_filter/string/clustered/cached/4/all50
                        time:   [3.3406 ms 3.3495 ms 3.3579 ms]
                        thrpt:  [78.068 Melem/s 78.263 Melem/s 78.472 Melem/s]
Found 11 outliers among 100 measurements (11.00%)
  3 (3.00%) low severe
  8 (8.00%) high severe
same_projection_filter/string/clustered/cached/4/early1
                        time:   [1.4078 ms 1.4143 ms 1.4211 ms]
                        thrpt:  [184.46 Melem/s 185.35 Melem/s 186.21 Melem/s]
Found 1 outliers among 100 measurements (1.00%)
  1 (1.00%) high mild
same_projection_filter/string/clustered/cached/4/late1
                        time:   [3.8255 ms 3.8473 ms 3.8698 ms]
                        thrpt:  [67.742 Melem/s 68.138 Melem/s 68.526 Melem/s]
Found 4 outliers among 100 measurements (4.00%)
  4 (4.00%) high mild

same_projection_filter/selection_boundary/int64/uncached/4/run16
                        time:   [6.3433 ms 6.3583 ms 6.3741 ms]
                        thrpt:  [41.127 Melem/s 41.229 Melem/s 41.326 Melem/s]
Found 2 outliers among 100 measurements (2.00%)
  2 (2.00%) high mild
same_projection_filter/selection_boundary/int64/uncached/4/run32
                        time:   [6.0143 ms 6.0268 ms 6.0399 ms]
                        thrpt:  [43.402 Melem/s 43.496 Melem/s 43.587 Melem/s]
Found 2 outliers among 100 measurements (2.00%)
  2 (2.00%) high mild
same_projection_filter/selection_boundary/int64/uncached/4/run64
                        time:   [5.7467 ms 5.7677 ms 5.7904 ms]
                        thrpt:  [45.272 Melem/s 45.451 Melem/s 45.617 Melem/s]
Found 3 outliers among 100 measurements (3.00%)
  2 (2.00%) high mild
  1 (1.00%) high severe

Do we really need them all?

@alamb alamb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me -- thank you @haohuaijin . My only potential concern is has 75 combinations -- do we really need all of them?

cargo bench --bench arrow_reader_predicate_fusion --features="arrow async snap"
...
.00%) high severe
same_projection_filter/string/clustered/cached/1/all99
                        time:   [1.6653 ms 1.6686 ms 1.6722 ms]
                        thrpt:  [156.77 Melem/s 157.11 Melem/s 157.42 Melem/s]
Found 10 outliers among 100 measurements (10.00%)
  4 (4.00%) high mild
  6 (6.00%) high severe
same_projection_filter/string/clustered/cached/2/all99
                        time:   [2.5275 ms 2.5337 ms 2.5405 ms]
                        thrpt:  [103.18 Melem/s 103.46 Melem/s 103.72 Melem/s]
Found 4 outliers among 100 measurements (4.00%)
  3 (3.00%) high mild
  1 (1.00%) high severe
same_projection_filter/string/clustered/cached/2/all50
                        time:   [2.8156 ms 2.8271 ms 2.8381 ms]
                        thrpt:  [92.366 Melem/s 92.725 Melem/s 93.104 Melem/s]
Found 17 outliers among 100 measurements (17.00%)
  11 (11.00%) low severe
  6 (6.00%) high severe
same_projection_filter/string/clustered/cached/2/early1
                        time:   [1.3208 ms 1.3229 ms 1.3253 ms]
                        thrpt:  [197.80 Melem/s 198.16 Melem/s 198.47 Melem/s]
Found 8 outliers among 100 measurements (8.00%)
  6 (6.00%) high mild
  2 (2.00%) high severe
same_projection_filter/string/clustered/cached/2/late1
                        time:   [2.0176 ms 2.0224 ms 2.0277 ms]
                        thrpt:  [129.28 Melem/s 129.62 Melem/s 129.93 Melem/s]
Found 17 outliers among 100 measurements (17.00%)
  1 (1.00%) high mild
  16 (16.00%) high severe
same_projection_filter/string/clustered/cached/4/all99
                        time:   [4.3241 ms 4.3359 ms 4.3489 ms]
                        thrpt:  [60.278 Melem/s 60.459 Melem/s 60.624 Melem/s]
Found 8 outliers among 100 measurements (8.00%)
  5 (5.00%) high mild
  3 (3.00%) high severe
same_projection_filter/string/clustered/cached/4/all50
                        time:   [3.3406 ms 3.3495 ms 3.3579 ms]
                        thrpt:  [78.068 Melem/s 78.263 Melem/s 78.472 Melem/s]
Found 11 outliers among 100 measurements (11.00%)
  3 (3.00%) low severe
  8 (8.00%) high severe
same_projection_filter/string/clustered/cached/4/early1
                        time:   [1.4078 ms 1.4143 ms 1.4211 ms]
                        thrpt:  [184.46 Melem/s 185.35 Melem/s 186.21 Melem/s]
Found 1 outliers among 100 measurements (1.00%)
  1 (1.00%) high mild
same_projection_filter/string/clustered/cached/4/late1
                        time:   [3.8255 ms 3.8473 ms 3.8698 ms]
                        thrpt:  [67.742 Melem/s 68.138 Melem/s 68.526 Melem/s]
Found 4 outliers among 100 measurements (4.00%)
  4 (4.00%) high mild

same_projection_filter/selection_boundary/int64/uncached/4/run16
                        time:   [6.3433 ms 6.3583 ms 6.3741 ms]
                        thrpt:  [41.127 Melem/s 41.229 Melem/s 41.326 Melem/s]
Found 2 outliers among 100 measurements (2.00%)
  2 (2.00%) high mild
same_projection_filter/selection_boundary/int64/uncached/4/run32
                        time:   [6.0143 ms 6.0268 ms 6.0399 ms]
                        thrpt:  [43.402 Melem/s 43.496 Melem/s 43.587 Melem/s]
Found 2 outliers among 100 measurements (2.00%)
  2 (2.00%) high mild
same_projection_filter/selection_boundary/int64/uncached/4/run64
                        time:   [5.7467 ms 5.7677 ms 5.7904 ms]
                        thrpt:  [45.272 Melem/s 45.451 Melem/s 45.617 Melem/s]
Found 3 outliers among 100 measurements (3.00%)
  2 (2.00%) high mild
  1 (1.00%) high severe

Do we really need them all?

@haohuaijin

Copy link
Copy Markdown
Contributor Author

Do we really need them all?

Good point! i added 75 cases because i want to have good cover for benchmark, but it can be reduce. I've reduce the case down from 75 to 30 cases while keeping the main scenarios covered.

@alamb
alamb merged commit a7b89dd into apache:main Sep 19, 2026
32 of 33 checks passed
@alamb

alamb commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Thanks @haohuaijin

@haohuaijin
haohuaijin deleted the bench-arrow-reader-predicate-fusion branch September 19, 2026 09:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

parquet Changes to the parquet crate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants