Skip to content

Deprecate the session-less optimize and keep constructors lazy - #11091

Open
robert3005 wants to merge 3 commits into
developfrom
rk/deprecate-sessionless-optimize
Open

robert3005 wants to merge 3 commits into
developfrom
rk/deprecate-sessionless-optimize

Conversation

@robert3005

@robert3005 robert3005 commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

ArrayOptimizer::optimize uses only the static rules of the encodings, so it misses the kernels that a session registers. This PR deprecates it, and array constructors no longer optimize the arrays they build.

Changes

  • optimize_ctx and optimize_recursive take &impl AsOptimizerKernels, which is a VortexSession or an ExecutionCtx created from one. Existing optimize_ctx(&session) callers compile without changes.
  • Constructors such as slice, filter, take, cast, fill_null, get_item and apply return lazy arrays. Execution optimizes each node it reaches (Optimize arrays top down as execution reaches them, and retry a parent when its children change #11090). Callers that read the encoding of an array directly now optimize it with their session first: scan tasks, plan v2 operators, the dict layout writer, the FFI scan and CUDA dispatch.
  • The default append_to_builder optimizes the array first. It then appends through the encoding the array reduces to, so a lazy slice of a constant appends as a constant.
  • Tests now call optimize_ctx(&SESSION) instead of optimize().

API Changes

  • ArrayOptimizer::optimize is deprecated. Use optimize_ctx with the session or an ExecutionCtx.
  • ArrayOptimizer::optimize_ctx and optimize_recursive are generic over AsOptimizerKernels.
  • ArrayRef::slice, filter, take and the ArrayBuiltins methods no longer return an optimized array.

@robert3005
robert3005 added this pull request to stack #11093 November 2, 2026 12:06
@robert3005 robert3005 added the changelog/deprecation A change that introduces a series of API deprecations label Nov 2, 2026
@robert3005
robert3005 force-pushed the rk/deprecate-sessionless-optimize branch 2 times, most recently from b724ab6 to 083a5b5 Compare November 2, 2026 12:28
@robert3005
robert3005 force-pushed the rk/deprecate-sessionless-optimize branch 2 times, most recently from 9d26236 to 45724a5 Compare November 2, 2026 15:11
@robert3005
robert3005 force-pushed the rk/deprecate-sessionless-optimize branch from 45724a5 to f9f348f Compare November 2, 2026 16:53
@robert3005
robert3005 force-pushed the rk/deprecate-sessionless-optimize branch from f9f348f to 37c91a6 Compare November 2, 2026 19:18
@robert3005
robert3005 force-pushed the rk/deprecate-sessionless-optimize branch from 37c91a6 to 02090f0 Compare November 3, 2026 13:16
Base automatically changed from rk/optimize-execute-loop to develop November 4, 2026 14:13
robert3005 added a commit that referenced this pull request Nov 4, 2026
With a session, the optimizer now works bottom up, and execution
optimizes each node that it reaches. This prepares for lazy constructors
in #11091.

## Changes

- `optimize_ctx` optimizes the children of a node that were never
optimized before it tries the rules of the node. It does the same for
the nodes that each rewrite builds. It does not visit marked subtrees,
and it marks every array that it returns. Thus inverse rules, such as
`slice(get_item)` and `get_item(slice)`, cannot loop.
- One optimize call rewrites a shared node only once, for example the
struct below every field of a projection.
- `optimize_recursive` is now the same as `optimize_ctx`.
- The session-less `optimize` still rewrites only the root and does not
mark the result. Thus a later `optimize_ctx` still tries the session
kernels.
- `execute_until` optimizes the root before it starts, each child that
execution focuses, the result of each `Done` step, and the array that it
returns. Single-step execution optimizes with the session, instead of
trying only the static reduce and parent-reduce rules.
- `Chunked::reduce` does not reduce an empty variant array, because
`Variant` has no empty canonical form.

---------

Signed-off-by: Robert Kruszewski <github@robertk.io>
@robert3005
robert3005 force-pushed the rk/deprecate-sessionless-optimize branch from 02090f0 to 89bc44c Compare November 4, 2026 14:31
@robert3005
robert3005 marked this pull request as ready for review November 4, 2026 14:32
@codspeed

codspeed Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Merging this PR will degrade performance by 10.05%

2 warnings

⚠️ 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

⚠️ 1 benchmark is 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

⚡ 11 improved benchmarks
❌ 33 regressed benchmarks
✅ 1726 untouched benchmarks
⏩ 47 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
❌ CPU Simulation filter_random_by_random[10000] 11.2 µs 38.7 µs -71.14%
❌ Walltime take_neon[small_m/shuffled/primitive/nonnull/chunks=256/indices=64] 41.7 µs 60.8 µs -31.43%
❌ Walltime take_neon[small_m/shuffled/primitive/nonnull/chunks=2048/indices=64] 51.9 µs 75.2 µs -30.93%
❌ CPU Simulation slice_dict_tight_loop[10000] 521 µs 743.9 µs -29.96%
❌ Walltime take_neon[small_m/shuffled/primitive/nonnull/chunks=256/indices=16] 14.7 µs 20.2 µs -27.23%
❌ Walltime take_neon[value_shape/shuffled/primitive/nonnull/chunks=16/indices=100] 15.8 µs 21.3 µs -25.71%
❌ Walltime take_neon[small_m/shuffled/primitive/nonnull/chunks=2048/indices=16] 17.8 µs 23.8 µs -25.03%
❌ CPU Simulation search_index_below_min_chunked 210 µs 274.8 µs -23.57%
❌ Walltime take_neon[core/shuffled/primitive/nonnull/chunks=16/indices=250] 18.6 µs 24.1 µs -23.17%
❌ CPU Simulation slice_primitive_tight_loop[10000] 345.3 µs 445.8 µs -22.55%
❌ CPU Simulation search_index_mixed_out_of_range_chunked 234.5 µs 300.2 µs -21.87%
❌ CPU Simulation search_index_full_range_random_chunked 240 µs 305.8 µs -21.54%
❌ Walltime take_neon[routing/grouped_chunks/primitive/nonnull/chunks=32/indices=1000] 41.7 µs 53.1 µs -21.36%
❌ Walltime take_neon[nullable/sorted/primitive/nullable_all_valid/chunks=16/indices=1000] 24.2 µs 29.5 µs -18.01%
❌ CPU Simulation search_index_in_range_chunked 336.1 µs 407.2 µs -17.45%
❌ CPU Simulation search_index_above_max_chunked 334.8 µs 405 µs -17.33%
❌ CPU Simulation missing_stats[16] 75.8 µs 91.4 µs -17.06%
❌ Walltime take_neon[core/shuffled/primitive/nonnull/chunks=16/indices=1000] 30 µs 36 µs -16.82%
❌ Walltime take_neon[duplicates/duplicate90/primitive/nonnull/chunks=16/indices=1000] 29.1 µs 34.7 µs -16.31%
❌ CPU Simulation bench_compare_varbin[(50000, 2)] 144.3 µs 170 µs -15.12%
... ... ... ... ... ...

ℹ️ 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/deprecate-sessionless-optimize (8e61ec4) with develop (068d819)

Open in CodSpeed

Footnotes

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

@robert3005
robert3005 force-pushed the rk/deprecate-sessionless-optimize branch 4 times, most recently from 07e02b8 to 1d0f0bc Compare November 4, 2026 19:36
robert3005 and others added 3 commits November 4, 2026 20:01
ArrayOptimizer::optimize uses only the static rules of the encodings, so
it misses the kernels a session registers. It is now deprecated in favour
of optimize_ctx, which takes the session or an ExecutionCtx created from
it through the new AsOptimizerKernels trait. optimize_recursive takes the
same argument.

Constructors such as slice, filter, take, cast, fill_null, get_item and
apply no longer optimize the arrays they build. Execution optimizes each
node it reaches, and the callers that read an array's encoding directly
optimize it with their session first: the scan tasks, the plan v2
operators, the dict layout writer, the FFI scan, and CUDA dispatch.

The default append_to_builder optimizes the array first and appends
through the encoding it reduces to, so a lazy slice of a constant appends
as a constant.

Signed-off-by: Robert Kruszewski <github@robertk.io>
A lazy array, such as a slice of a constant, now appends through the
encoding that it reduces to. Callers such as case_when and zip no longer
need to optimize the array before they append it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Robert Kruszewski <github@robertk.io>
Constructors such as slice, filter, take and the array builtins now
return lazy arrays. Code that inspects the encoding of the result, stores
it, or reads it row by row lost its fast paths or changed its output.
Optimize the result at those sites, and add a Dict rule that keeps only
the referenced value when the codes reduce to a constant.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Robert Kruszewski <github@robertk.io>
@robert3005
robert3005 force-pushed the rk/deprecate-sessionless-optimize branch from 1d0f0bc to 8e61ec4 Compare November 4, 2026 20:06
@robert3005

Copy link
Copy Markdown
Contributor Author

#11092 recovers majority of the regression, could merge them into one but this is a smaller change

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/deprecation A change that introduces a series of API deprecations

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant