test: trace reductions and executions of scan ops over complex and compressed arrays#8828
Conversation
…mplex arrays Promote the trace test harness module to a directory module (test_harness/trace/mod.rs + trace/tests.rs) and add snapshot tests that trace how the optimizer and executor handle common operations over complex arrays: - take (DictArray) over a chunked array: no reduce rule fires; execution canonicalizes the chunked values chunk-by-chunk before the dict take kernel runs. - filter over a struct array with complex children (dict-of-strings and chunked fields): FilterStructRule pushes the filter into each field and FilterReduceAdaptor(Dict) rewrites the dict field at optimize time. - compare (Binary Eq vs constant) over a dict array: DictionaryScalarFnValuesPushDownRule reduces the compare into the dict values; execution shows the values-side binary kernel and the dict decode kernel. - like (vs constant pattern) over a dict-of-strings array: LikeReduceAdaptor(Dict) reduces the like into the dict values. Also add equivalent trace tests for run-end arrays in vortex-runend (with insta as a new dev-dependency): compare reduces via RunEndScalarFnRule at optimize time, while filter and take execute via the FilterExecuteAdaptor/TakeExecuteAdaptor parent kernels. Signed-off-by: "Joe Isaacs" <joe.isaacs@live.co.uk> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RMBcCiwpC3dbGLXRbK7UuR
Generate TPC-H lineitem with tpchgen (SF 0.001, 4096 rows, deterministic),
compress it with the BtrBlocks compressor, and snapshot-trace the reduce
rules and execute kernels that fire for the scan operations TPC-H queries
perform over the resulting encodings:
- l_shipdate >= const over ext(date) -> for -> bitpacked: no reduce rule;
the extension compare kernel fires at execution time, with
CastReduceAdaptor(FoR)/(BitPacked) reductions inside the arrow fallback.
- l_quantity < const over decimal_byte_parts -> dict -> bitpacked: the
decimal_byte_parts compare kernel pushes into the byte-parts dictionary,
where DictionaryScalarFnValuesPushDownRule reduces the compare to the 50
dictionary values before decode.
- l_shipmode = const over dict -> {bitpacked codes, fsst values}:
DictionaryScalarFnValuesPushDownRule reduces at optimize time; the FSST
compare kernel and dict decode kernel run at execution time.
- l_comment LIKE over fsst: the FSST like kernel matches in compressed
space with no reduction.
- filter over a struct of compressed columns: FilterStructRule plus
per-encoding pushdown via DecimalBytePartsFilterPushDownRule,
ExtensionFilterPushDownRule, FoRFilterPushDownRule, and
FilterReduceAdaptor(Dict), leaving execution a no-op.
- take over a struct of compressed columns: TakeReduceAdaptor(Struct)
absorbs the take entirely at optimize time.
Each test also asserts the canonical result matches running the same
operation over the uncompressed column. A 1MiB text pool replaces the
spec-default 300MiB one, cutting per-test setup from ~9s to ~0.5s without
changing the traces. Adds insta, tpchgen, tpchgen-arrow, and arrow-array
as vortex-btrblocks dev-dependencies.
Signed-off-by: "Joe Isaacs" <joe.isaacs@live.co.uk>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RMBcCiwpC3dbGLXRbK7UuR
CodSpeed builds compile with --cfg codspeed, under which vortex-array's test_harness::trace module is configured out, so the new trace_tests modules in vortex-btrblocks and vortex-runend failed to resolve their imports. Gate both modules with #[cfg(all(test, not(codspeed)))] to match the harness's own gating. Signed-off-by: "Joe Isaacs" <joe.isaacs@live.co.uk> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RMBcCiwpC3dbGLXRbK7UuR
clippy's tests_outside_test_module lint only recognizes a bare #[cfg(test)] attribute, not #[cfg(all(test, not(codspeed)))]. Stack the two cfg attributes instead; the gating semantics are identical. Signed-off-by: "Joe Isaacs" <joe.isaacs@live.co.uk> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RMBcCiwpC3dbGLXRbK7UuR
Merging this PR will improve performance by 15.28%
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| ⚡ | Simulation | chunked_varbinview_canonical_into[(1000, 10)] |
199.6 µs | 163 µs | +22.51% |
| ⚡ | Simulation | chunked_varbinview_into_canonical[(1000, 10)] |
215.1 µs | 178.7 µs | +20.4% |
| ⚡ | Simulation | chunked_varbinview_canonical_into[(100, 100)] |
322.2 µs | 287.8 µs | +11.95% |
| ⚡ | Simulation | bitwise_not_vortex_buffer_mut[128] |
275.3 ns | 246.1 ns | +11.85% |
| ⚡ | Simulation | chunked_varbinview_into_canonical[(100, 100)] |
376 µs | 341 µs | +10.26% |
Tip
Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.
Comparing claude/tracing-reductions-executions-96t2p6 (4835772) with adamg/execution-tests (7d3ca20)
Footnotes
-
15 benchmarks were run, but are now archived. If they were deleted in another branch, consider rebasing to remove them from the report. Instead if they were added back, click here to restore them. ↩
DCO Remediation Commit for Joe Isaacs <joe.isaacs@live.co.uk> I, Joe Isaacs <joe.isaacs@live.co.uk>, hereby add my Signed-off-by to this commit: 3111cda I, Joe Isaacs <joe.isaacs@live.co.uk>, hereby add my Signed-off-by to this commit: be141ea I, Joe Isaacs <joe.isaacs@live.co.uk>, hereby add my Signed-off-by to this commit: a9c088a I, Joe Isaacs <joe.isaacs@live.co.uk>, hereby add my Signed-off-by to this commit: bc55dd7 Signed-off-by: Joe Isaacs <joe.isaacs@live.co.uk> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RMBcCiwpC3dbGLXRbK7UuR
Summary
Stacked on #7814 (the
trace_opexecution/optimization tracing harness).Builds out trace-test coverage for how take/filter/compare/like reduce and execute over complex arrays, using the harness from the base PR:
vortex-array (promotes
test_harness/trace.rsto a directory moduletrace/mod.rs+trace/tests.rs; harness source unchanged):DictArray) over a chunked array — no reduce rule fires; execution canonicalizes the chunked values chunk-by-chunk before the dict take kernel runs.FilterStructRulepushes the filter into each field,FilterReduceAdaptor(Dict)rewrites the dict field at optimize time.BinaryEq vs constant) over a dict —DictionaryScalarFnValuesPushDownRulereduces the compare into the dictionary values.LikeReduceAdaptor(Dict)reduces into the dictionary values.vortex-runend (new
trace_tests.rs,instaadded as dev-dependency):RunEndScalarFnRuleat optimize time; filter and take execute via theFilterExecuteAdaptor/TakeExecuteAdaptorparent kernels.vortex-btrblocks (new
trace_tests.rs;insta,tpchgen,tpchgen-arrow,arrow-arrayadded as dev-dependencies): generates TPC-H lineitem (SF 0.001, 4096 rows, deterministic — tpchgen and the compressor's sampling seed are both fixed), compresses it withBtrBlocksCompressor, and traces TPC-H-style scan predicates over the resulting encodings:l_shipdate >= constoverext(date) → for → bitpacked— extension compare kernel at execution time, withCastReduceAdaptor(FoR)/(BitPacked)reductions inside the arrow fallback.l_quantity < constoverdecimal_byte_parts → dict → bitpacked— the decimal_byte_parts compare kernel pushes into the byte-parts dictionary, whereDictionaryScalarFnValuesPushDownRulereduces the compare to the 50 dictionary values before decode.l_shipmode = constover dict-of-FSST — dict pushdown at optimize time, FSST compare kernel + dict decode at execution time.l_comment LIKEover FSST — the FSST like kernel matches in compressed space.FilterStructRuleplus per-encoding pushdown viaDecimalBytePartsFilterPushDownRule,ExtensionFilterPushDownRule,FoRFilterPushDownRule, andFilterReduceAdaptor(Dict), leaving execution a no-op.TakeReduceAdaptor(Struct)absorbs the take entirely at optimize time.Each btrblocks test also asserts the canonical result matches running the same operation over the uncompressed column. A 1MiB TPC-H text pool replaces the spec-default 300MiB one, cutting per-test setup from ~9s to ~0.5s without changing the traces.
Testing
This PR is tests-only; no production code changes.
cargo nextest run -p vortex-array— 2961 passed (includes the 8 trace tests, run in parallel to confirm the thread-local recorder is deterministic).cargo nextest run -p vortex-runend— 61 passed.cargo nextest run -p vortex-btrblocks— 43 passed.cargo clippy --all-targetson the three touched crates — clean.cargo +nightly fmt --allandgit diff --check— clean.🤖 Generated with Claude Code
https://claude.ai/code/session_01RMBcCiwpC3dbGLXRbK7UuR
Generated by Claude Code