Skip to content

Execute primitive numeric operators with RowFn - #9345

Draft
connortsui20 wants to merge 1 commit into
ct/row-fn-frameworkfrom
ct/row-fn-numeric-operators
Draft

Execute primitive numeric operators with RowFn#9345
connortsui20 wants to merge 1 commit into
ct/row-fn-frameworkfrom
ct/row-fn-numeric-operators

Conversation

@connortsui20

@connortsui20 connortsui20 commented Aug 11, 2026

Copy link
Copy Markdown
Member

Rationale for this change

Makes primitive arithmetic the first production user of RowFn. Binary keeps its registered identity and existing scalar-function hooks.

What changes are included in this PR?

Checked add, subtract, and multiply reduce compact failure evidence outside their vector loops. Integer division stops at the first failure and writes directly into uninitialized output. Decimal arithmetic remains on its existing columnar path.

With Rust 1.97.1 and LLVM 22.1.6, optimized IR and assembly confirm that mixed-constant add, subtract, and multiply vectorize under the 16-CGU, no-LTO benchmark profile. The earlier 4.6–7.5x mixed-constant regressions were measured before the output-iterator fix in #9353 and no longer describe this branch.

What APIs are changed? Are there any user-facing changes?

There are no public API changes. Primitive arithmetic delegates execution to the private NumericBinary row kernel.

@connortsui20 connortsui20 changed the title ct/row fn numeric operators Execute primitive numeric operators with RowFn Aug 11, 2026
@codspeed-hq

codspeed-hq Bot commented Aug 11, 2026

Copy link
Copy Markdown

Merging this PR will degrade performance by 11.49%

⚠️ 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
❌ 33 regressed benchmarks
✅ 1966 untouched benchmarks
🆕 25 new benchmarks
⏩ 89 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation linestrings 163.4 µs 194.7 µs -16.06%
Simulation points 161.6 µs 191.7 µs -15.72%
Simulation polygons 164.8 µs 195.3 µs -15.63%
Simulation mul_u8_nonnull 162.1 µs 191.6 µs -15.41%
Simulation two_vertex_lines 279.9 µs 326.6 µs -14.29%
Simulation multipolygon_random_nulls 743.6 µs 866.1 µs -14.15%
Simulation take[small_m/shuffled/primitive/nonnull/chunks=1024/indices=256] 2.1 ms 2.4 ms -13.03%
Simulation take[small_m/shuffled/primitive/nonnull/chunks=16384/indices=1000] 9.3 ms 10.6 ms -12.9%
Simulation nullable_two_vertex_lines 325.6 µs 373.6 µs -12.85%
Simulation take_filter_list_small_random_mask_random_indices[256, 10] 203.6 µs 233.5 µs -12.82%
Simulation take[small_m/shuffled/primitive/nonnull/chunks=1024/indices=1000] 5.5 ms 6.3 ms -12.81%
Simulation take_filter_list_small_uncached_random_mask_random_indices[256, 10] 203.9 µs 233.8 µs -12.81%
Simulation take_filter_list_slice_mask_random_indices[256, 50] 208 µs 238.4 µs -12.72%
Simulation take_filter_list_random_mask_sequential_indices[768, 50] 205.5 µs 235.2 µs -12.61%
Simulation list_i32_large 214.4 µs 245.3 µs -12.57%
Simulation take_filter_list_small_uncached_random_mask_random_indices[768, 10] 211.6 µs 241.9 µs -12.55%
Simulation take[small_m/shuffled/primitive/nonnull/chunks=16384/indices=256] 3.1 ms 3.5 ms -12.26%
Simulation take_filter_list_slice_mask_random_indices[768, 50] 209.9 µs 239.2 µs -12.22%
Simulation take_filter_list_small_random_mask_random_indices[768, 10] 213.1 µs 242.7 µs -12.21%
Simulation take_filter_list_random_mask_sequential_indices[256, 50] 210.3 µs 239.3 µs -12.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 ct/row-fn-numeric-operators (413796d) with ct/row-fn-framework (8d7edf3)

Open in CodSpeed

Footnotes

  1. 89 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.

@connortsui20
connortsui20 force-pushed the ct/row-fn-numeric-operators branch from ab0697a to b63ded4 Compare August 11, 2026 16:04
@connortsui20
connortsui20 marked this pull request as ready for review August 11, 2026 16:05
@connortsui20
connortsui20 marked this pull request as draft August 11, 2026 16:24
connortsui20 added a commit that referenced this pull request Aug 11, 2026
## Rationale for this change

Lets indexed lane sources return borrowed or otherwise non-`Copy` items.
RowFn needs this for typed row inputs without adding a second kernel
abstraction.

- Progress towards: #9129

## What changes are included in this PR?

Removes the `Copy` bound from `IndexedSource::Item`. It also makes
`LaneZip` fields private, validates lengths once in `LaneZip::new`, and
removes the repeated assertion from its inline `len` method.

This is a prerequisite only. The first production RowFn adopter is in
#9345, so there is no meaningful RowFn performance comparison at this
layer.

## What APIs are changed? Are there any user-facing changes?

`LaneZip` must now be constructed with `LaneZip::new` instead of tuple
syntax. The workspace has no direct field construction outside this
module.

Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
@connortsui20
connortsui20 force-pushed the ct/row-fn-numeric-operators branch 3 times, most recently from f8670a8 to f108cdd Compare August 11, 2026 19:36
@connortsui20

Copy link
Copy Markdown
Member Author

Here are the local arithmetic benchmark results from the final Rust 1.97.1 run.

The comparison used a develop baseline with benchmark-only backfills (1edd0fca) and the full RowFn stack (8ca9fc73). Later stack layers do not change the primitive arithmetic source, but unrelated code-placement effects can still affect these binaries.

The machine was an AMD Ryzen 9 7950X running Linux. The build used rustc 1.97.1, LLVM 22.1.6, one CGU, fat LTO, and -C target-cpu=native. Each target used two warm runs and seven alternating measured pairs. Each process used 100 samples with a 0.25–0.5 second measurement window on CPU 4.

Negative changes are faster. The values are medians across the seven paired runs.

The main results are:

  • Large per-row add, subtract, and multiply range from 2.67% faster to 4.84% slower.
  • Large mixed-constant multiply improves by 18.66–19.46%.
  • LLVM 22 does not vectorize the large mixed-constant add and subtract loops. These cases are 4.62–5.22x slower.
  • mul_i32_constant is 7.46x slower for the same LLVM 22 code-generation problem.
  • Small batches expose the fixed cost of RowFn dispatch and output construction.

A separate comparison covered the later naming and structural cleanup. All 24 RowFn matrix cases remained between 2.59% faster and 1.09% slower.

RowFn arithmetic matrix: 24 cases
Operator Rows Inputs Baseline RowFn Change
Add 128 per-row × per-row 672.2 ns 879.7 ns +30.87%
Add 128 per-row × constant 687.2 ns 1.499 µs +116.56%
Add 128 constant × per-row 739.7 ns 1.519 µs +105.35%
Add 128 per-row × nullable constant 729.7 ns 1.799 µs +146.54%
Add 32,768 per-row × per-row 7.029 µs 7.309 µs +4.84%
Add 32,768 per-row × constant 4.599 µs 22.820 µs +395.76%
Add 32,768 constant × per-row 4.619 µs 24.120 µs +421.76%
Add 32,768 per-row × nullable constant 4.609 µs 23.150 µs +402.27%
Subtract 128 per-row × per-row 667.2 ns 859.7 ns +28.85%
Subtract 128 per-row × constant 682.2 ns 1.499 µs +118.79%
Subtract 128 constant × per-row 729.7 ns 1.519 µs +109.54%
Subtract 128 per-row × nullable constant 694.7 ns 1.809 µs +160.84%
Subtract 32,768 per-row × per-row 7.149 µs 7.319 µs +3.28%
Subtract 32,768 per-row × constant 4.639 µs 22.130 µs +377.04%
Subtract 32,768 constant × per-row 4.639 µs 23.570 µs +407.87%
Subtract 32,768 per-row × nullable constant 4.649 µs 22.450 µs +382.90%
Multiply 128 per-row × per-row 754.7 ns 929.7 ns +23.19%
Multiply 128 per-row × constant 794.7 ns 1.499 µs +91.03%
Multiply 128 constant × per-row 839.7 ns 1.519 µs +81.12%
Multiply 128 per-row × nullable constant 794.7 ns 1.809 µs +126.37%
Multiply 32,768 per-row × per-row 24.790 µs 24.140 µs -2.67%
Multiply 32,768 per-row × constant 29.280 µs 23.570 µs -19.41%
Multiply 32,768 constant × per-row 29.310 µs 23.580 µs -19.46%
Multiply 32,768 per-row × nullable constant 29.280 µs 23.870 µs -18.66%
Existing arithmetic cases and controls: 28 cases
Benchmark Baseline RowFn stack Change
mul_i32_constant 3.609 µs 26.910 µs +645.64%
add_i64_constant 4.499 µs 22.780 µs +406.33%
sub_i64_constant 4.819 µs 22.260 µs +361.92%
mul_i8_nonnull 1.789 µs 1.959 µs +9.45%
mul_i16_nonnull 2.409 µs 2.599 µs +7.89%
mul_u8_nonnull 1.849 µs 1.999 µs +7.53%
mul_u16_nonnull 2.149 µs 2.319 µs +7.45%
add_i32_nonnull 3.569 µs 3.739 µs +5.04%
mul_i32_nonnull 4.099 µs 4.309 µs +4.89%
mul_u32_nonnull 3.649 µs 3.839 µs +4.40%
add_u32_nonnull 3.609 µs 3.739 µs +3.61%
add_i64_nonnull 6.459 µs 6.659 µs +3.08%
and_bool_nullable 2.019 µs 2.069 µs +2.46%
mul_i32_nullable 4.969 µs 5.049 µs +1.40%
div_i64_nonnull 44.730 µs 44.900 µs +0.34%
mul_decimal_i128_nullable 63.420 µs 63.610 µs +0.27%
lt_i64_nullable 4.709 µs 4.719 µs +0.21%
add_decimal_i128_nullable 121.200 µs 121.400 µs +0.17%
mul_decimal_i64_nonnull 16.100 µs 16.120 µs +0.12%
add_decimal_i64_nonnull 65.620 µs 65.590 µs +0.05%
div_decimal_i64_nonnull 63.960 µs 63.960 µs +0.02%
add_i64_nullable 7.449 µs 7.449 µs -0.27%
div_decimal_i128_nullable 166.600 µs 165.900 µs -0.36%
eq_i64_constant 2.719 µs 2.709 µs -0.37%
or_bool_constant 869.7 ns 859.7 ns -1.15%
mul_i64_nonnull 24.680 µs 23.970 µs -2.80%
mul_u64_nonnull 19.300 µs 18.640 µs -3.42%
div_i64_nullable not present 40.610 µs candidate only

div_i64_nullable was new in the candidate inventory, so it has no paired develop result.

@connortsui20
connortsui20 force-pushed the ct/row-fn-numeric-operators branch 2 times, most recently from b2495de to c1584a6 Compare August 12, 2026 17:53
@connortsui20
connortsui20 force-pushed the ct/row-fn-numeric-operators branch from c1584a6 to b722af5 Compare August 12, 2026 18:09
@connortsui20
connortsui20 force-pushed the ct/row-fn-numeric-operators branch from b722af5 to eea857d Compare August 12, 2026 18:46
@connortsui20
connortsui20 force-pushed the ct/row-fn-numeric-operators branch 2 times, most recently from 0e8ab1d to 7693f90 Compare August 12, 2026 20:26
@connortsui20
connortsui20 force-pushed the ct/row-fn-numeric-operators branch 2 times, most recently from 1dd63b9 to 9be3db4 Compare August 12, 2026 21:03
@connortsui20
connortsui20 force-pushed the ct/row-fn-numeric-operators branch 2 times, most recently from a517965 to 2d2af5d Compare August 13, 2026 14:45
@connortsui20
connortsui20 force-pushed the ct/row-fn-numeric-operators branch from 2d2af5d to dfd648d Compare August 13, 2026 15:40
@connortsui20
connortsui20 force-pushed the ct/row-fn-numeric-operators branch 2 times, most recently from 425e336 to adcff3b Compare August 13, 2026 18:37
@connortsui20
connortsui20 force-pushed the ct/row-fn-numeric-operators branch from adcff3b to b7eb750 Compare August 13, 2026 18:54
@joseph-isaacs
joseph-isaacs force-pushed the ct/row-fn-numeric-operators branch from b7eb750 to 8003cbb Compare August 14, 2026 09:36
@connortsui20
connortsui20 force-pushed the ct/row-fn-numeric-operators branch from 8003cbb to d0f1b2d Compare August 14, 2026 17:06
@connortsui20 connortsui20 added the changelog/performance A performance improvement label Aug 14, 2026
Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
@connortsui20
connortsui20 force-pushed the ct/row-fn-numeric-operators branch from d0f1b2d to 413796d Compare August 14, 2026 22:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog/performance A performance improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant