Skip to content

Move scalar functions out of vortex-array into vortex-functions - #10762

Draft
robert3005 wants to merge 2 commits into
developfrom
rk/split-array-06-scalar-fns
Draft

robert3005 wants to merge 2 commits into
developfrom
rk/split-array-06-scalar-fns

Conversation

@robert3005

Copy link
Copy Markdown
Contributor

vortex-array keeps the scalar function machinery (the ScalarFnVTable trait, binding, reduction, execution, the session registry and kernel registry) and the few functions its own arrays, validity and expressions are built on: literal, get_item and pack, is_null, is_not_null, not and the binary operators, and cast, mask and fill_null, which canonical arrays apply to their own children. That module is renamed from scalar_fn::fns to scalar_fn::builtin, matching ArrayBuiltins. Every other scalar function moves to the new vortex-functions crate:

  • byte_length, case_when, ext_storage, list_length, list_sum, merge, replace_time_zone, select, dynamic, stat, between, like, list_contains, variant_get, is_nan and zip, with their expression constructors in vortex_functions::expr (and expr::bound)
  • the kernels and parent-reduce rules for vortex-array's encodings, which vortex_functions::initialize now registers with a session's kernel registry instead of the encodings' static rule sets
  • the ArrayBuiltins/ExprBuiltins methods for the moved functions, which become the ArrayFunctions/ExprFunctions extension traits

apply_reduce_parent_rule lets a crate register a typed parent-reduce rule for an encoding it does not own. ArrayHaystack, LazyBitBufferBuilder, DeduplicatedBuffers::{extend_from_iter, finish}, ListScalar::element_values, is_not_null_node, build_row_comparator and merge_typed_scalar_as_variant become public for the moved kernels.

@robert3005 robert3005 added the changelog/break A breaking API change label Oct 23, 2026
@robert3005
robert3005 marked this pull request as draft October 23, 2026 22:47
@robert3005
robert3005 force-pushed the rk/split-array-06-scalar-fns branch from 714ed9d to fd2bbf1 Compare October 23, 2026 22:57
@codspeed

codspeed Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Merging this PR will degrade performance by 21.09%

3 warnings, 1 note

⚠️ Walltime results may be unreliable

Some benchmarks used the Walltime instrument outside CodSpeed Macro Runners, which can make the results inconsistent.

Learn more about Macro Runners

See affected benchmarks

⚠️ 53 benchmarks are dominated by system calls

System calls cannot be simulated consistently and are left out of the measure. The reported value understates the real cost. Switch to the Walltime instrument to measure them.

Learn more about system calls

See affected benchmarks

⚠️ Base and head ran on different runner types

Some benchmarks with significant performance changes were compared across different runner types, so the changes might not come from the code. Run base and head on the same runner type, or use CodSpeed Macro Runners for more stable results.

Learn more about Macro Runners

Open the report in CodSpeed to investigate

ℹ️ 40 benchmarks have no flamegraph

The flamegraph wasn't generated: the symbols of the profiling trace could not be resolved, because no information about the language frames was collected.

See affected benchmarks

⚡ 15 improved benchmarks
❌ 542 regressed benchmarks
✅ 1787 untouched benchmarks
🆕 199 new benchmarks
⏩ 76 skipped benchmarks1
🗄️ 43 archived benchmarks run2

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
❌ CPU Simulation take[small_m/shuffled/primitive/nonnull/chunks=2048/indices=1] 40.6 µs 2,438.3 µs -98.34%
❌ CPU Simulation take[small_m/shuffled/primitive/nonnull/chunks=2048/indices=16] 215.5 µs 2,600.2 µs -91.71%
❌ CPU Simulation take[small_m/shuffled/primitive/nonnull/chunks=256/indices=1] 40.4 µs 341.5 µs -88.16%
❌ CPU Simulation take[small_m/shuffled/primitive/nonnull/chunks=2048/indices=64] 429.1 µs 2,778.6 µs -84.56%
❌ CPU Simulation canonicalize_sparse_fixed_size_list[(1024, 17, 8)] 469.4 µs 1,699.1 µs -72.37%
❌ CPU Simulation take[value_shape/duplicate99/struct8/nonnull/chunks=16/indices=100] 114.8 µs 366.4 µs -68.67%
❌ CPU Simulation take[small_m/shuffled/primitive/nonnull/chunks=256/indices=16] 137.7 µs 427.1 µs -67.77%
❌ CPU Simulation canonicalize_sparse_fixed_size_list[(512, 7, 4)] 477.5 µs 1,265 µs -62.25%
❌ CPU Simulation canonicalize[256, 32] 67.9 µs 174.1 µs -61.01%
❌ CPU Simulation canonicalize[1024, 32] 67.9 µs 174 µs -60.99%
❌ CPU Simulation canonicalize[16, 32] 67.9 µs 174.2 µs -60.99%
❌ CPU Simulation canonicalize_sparse_list[(512, 7, 4)] 464.3 µs 1,052.8 µs -55.9%
❌ CPU Simulation canonicalize_sparse_list[(1024, 17, 8)] 404.3 µs 890.2 µs -54.59%
❌ CPU Simulation filter_ultra_sparse[10000] 8.6 µs 18.1 µs -52.44%
❌ CPU Simulation take[value_shape/shuffled/struct8/nonnull/chunks=16/indices=100] 2.7 ms 5.7 ms -52.23%
❌ CPU Simulation take[value_shape/duplicate99/fsl8/nonnull/chunks=16/indices=100] 130.3 µs 262.8 µs -50.4%
❌ CPU Simulation filter_powerlaw_by_power_law[1000] 8.8 µs 17.7 µs -50.1%
❌ Walltime add_constant_shapes_avx2[(32768, PerRowNullableConstant)] 12.4 µs 24.6 µs -49.59%
❌ CPU Simulation filter_random_by_power_law[1000] 9 µs 17.7 µs -49.11%
❌ CPU Simulation filter_powerlaw_by_mostly_false[1000] 9.2 µs 17.8 µs -48.27%
... ... ... ... ... ...

ℹ️ Only the first 20 benchmarks are displayed. Go to the app to view all benchmarks.

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing rk/split-array-06-scalar-fns (e33c436) with develop (747928a)

Open in CodSpeed

Footnotes

  1. 76 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. ↩

  2. 43 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. ↩

@robert3005
robert3005 added this pull request to stack #10770 October 24, 2026 12:37
@robert3005
robert3005 force-pushed the rk/split-array-06-scalar-fns branch 3 times, most recently from 137c718 to 0713434 Compare October 26, 2026 10:44
The session-less `ArrayOptimizer::optimize` is removed. `optimize(session)`
and `optimize_recursive(session)` are the only entry points, so every
rewrite sees the session's registered kernels.

`slice`, `filter`, `take`, `apply` and the builtins such as `cast` and
`fill_null` no longer optimize the node they build; they return the lazy
wrapper. Optimization happens where a session is available instead:

- `execute_until` runs `optimize_recursive` before it starts and again over
  the array execution produced, so canonical results do not keep lazy
  children such as a filtered validity;
- single-step execution optimizes with the session instead of trying only
  the static reduce rules;
- whenever a rule rewrites a node, the nodes the rule built are optimized
  too, while subtrees that already existed are left alone, so inverse rules
  (slice over get_item and get_item over slice) cannot loop;
- the few call sites that need a concrete encoding before execution, such
  as list element slices and the dictionary writer's remainder, optimize
  with the session they are given.

Errors that constructors used to raise eagerly, such as invalid casts, now
surface on execution. An empty chunked array of Variant dtype no longer
reduces to a canonical empty array, which Variant does not have. FSST
slicing slices its codes through `VarBin` instead of downcasting a lazy
slice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps4mp7KF5c4p66aoSoXx5j
Signed-off-by: Claude <noreply@anthropic.com>
vortex-array keeps the scalar function machinery (the `ScalarFnVTable` trait,
binding, reduction, execution, the session registry and kernel registry) and
the few functions its own arrays, validity and expressions are built on:
literal, get_item and pack, is_null, is_not_null, not and the binary
operators, and cast, mask and fill_null, which canonical arrays apply to their
own children. That module is renamed from `scalar_fn::fns` to
`scalar_fn::builtin`, matching `ArrayBuiltins`. Every other scalar function
moves to the new `vortex-functions` crate:

- byte_length, case_when, ext_storage, list_length, list_sum, merge,
  replace_time_zone, select, dynamic, stat, between, like, list_contains,
  variant_get, is_nan and zip, with their expression constructors in
  `vortex_functions::expr` (and `expr::bound`)
- the kernels and parent-reduce rules for vortex-array's encodings, which
  `vortex_functions::initialize` now registers with a session's kernel
  registry instead of the encodings' static rule sets
- the `ArrayBuiltins`/`ExprBuiltins` methods for the moved functions, which
  become the `ArrayFunctions`/`ExprFunctions` extension traits

`apply_reduce_parent_rule` lets a crate register a typed parent-reduce rule for
an encoding it does not own. `ArrayHaystack`, `LazyBitBufferBuilder`,
`DeduplicatedBuffers::{extend_from_iter, finish}`, `ListScalar::element_values`,
`is_not_null_node`, `build_row_comparator` and `merge_typed_scalar_as_variant`
become public for the moved kernels.

The umbrella crate re-exports the moved constructors under `vortex::expr` and
the crate as `vortex::functions`.

The CodSpeed workflow builds `vortex-functions` in the main-library shard, so
the moved benchmarks stay measured, and picks up `vortex-onpair` and
`vortex-arrow`, whose benchmarks no shard built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ps4mp7KF5c4p66aoSoXx5j
Signed-off-by: Claude <noreply@anthropic.com>
@robert3005
robert3005 force-pushed the rk/split-array-06-scalar-fns branch from 0713434 to e33c436 Compare October 26, 2026 11:25

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog/break A breaking API change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants