Related to #10676. This PR is independent of the RowFn stack.
Uses the existing fill-and-pack collector for `i64`, `u64`, and `f64`
array-pair comparisons on AArch64 with NEON. The dispatch and the
unchecked slice reads stay inside the private primitive kernel, where
equal lengths and the collector's index range establish the bounds
proof. Constant comparisons, other primitive types, and validity
handling retain their existing paths.
Extends bitmap-boundary tests to wide types with differently sliced
inputs, and checks floating-point total ordering through full words and
a tail.
Validation: 236 comparison tests and all-target, all-feature Clippy with
warnings denied pass on macOS ARM. Native ARM and AVX2 builds pass the
455-case probe (452 reference-array checks plus three unchanged Boolean
controls) and 3,456 comparison edge checks plus four arithmetic error
checks.
On Graviton3, the two counterbalanced full-suite sessions show the
following elapsed-time reductions in the long array-pair cohorts:
| Type | First session | Confirmation | Confirmation ratio and paired
95% interval |
| --- | --- | --- | --- |
| `i64` | 15.6% | 15.4% | `0.846 [0.843, 0.856]` |
| `u64` | 14.1% | 14.0% | `0.860 [0.858, 0.864]` |
| `f64` | 11.8% | 11.8% | `0.882 [0.880, 0.886]` |
Each cohort contains 32 cases. Ratios are candidate/baseline, with a
geometric mean across cases within a paired block and the median across
21 blocks. Intervals bootstrap those paired block ratios. Neither ARM
session has a case crossing the 3% regression threshold with its
interval above 1.
The AVX2 baseline and candidate `.text` sections are byte-for-byte
identical. Control timings still vary, so no x86 speedup is attributed
to this change. These are public-path microbenchmarks, not query
results. Release-profile and AVX-512 timing were not repeated for this
ARM-only variant.
<details>
<summary>Measurement protocol and reproduction</summary>
Baseline: `a59294e35e7109fac894a7a38a68f42db0c3c967`. Candidate:
`f018aaeef739145e1bc50079a441c5d9fd53404a`.
Uses rustc 1.99.1 (LLVM 23.1.1), the repository's bench profile (16
codegen units, no LTO), MiMalloc, and CPU 2. Graviton3 uses `-C
target-feature=+neon -C force-frame-pointers=yes`. The AVX2 control uses
`-C target-feature=+avx2 -C force-frame-pointers=yes` on AMD EPYC 7R13.
Optimized LLVM IR and assembly were emitted during both builds, and the
resulting executables were timed without instrumentation.
Both labels run the same full 455-case suite in the same order. Each
case has exactly 1,000 single-iteration samples. Each session has 21
baseline/baseline calibration blocks and 21 paired baseline/candidate
blocks with alternating executable order. Separate arithmetic control
binaries bracket the blocks. The two hosts are measured serially, and a
second session confirms the result. The confirmation session reverses
the starting order, so the combined sessions contain equal AB and BA
counts. Preliminary fixed-order source comparisons were excluded, while
valid identical-binary calibration was retained. The long-array cohorts
each contain 32 cases, including partially valid inputs and lengths
around the 16K boundary.
To reproduce, save the harness below as
`vortex-array/benches/interaction_probe.rs` on each revision and add
this target to `vortex-array/Cargo.toml`:
```toml
[[bench]]
name = "interaction_probe"
harness = false
```
Set `RUSTFLAGS` to the host flags above. Build both revisions with those
same flags, retain separate immutable executables, and alternate the
commands below. Unset `VORTEX_PERF_CHECK` for timing.
```sh
cargo +1.99.1 build --locked -p vortex-array --bench interaction_probe --profile bench
VORTEX_PERF_CHECK=1 "$binary" --test --color never
taskset -c 2 "$binary" --bench --color never --timer os --sample-count 1000 --sample-size 1 --skip-ext-time true
```
</details>
<details>
<summary>Exact benchmark harness</summary>
The measured harness SHA-256 is
`0a7de7999381d237ad0471716107f7e1972a7c6b11c0936a7d3b7d8c15b6c37d`.
```rust
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: Copyright the Vortex contributors
//! Common public-path inputs for the RowFn interaction experiments.
#![expect(clippy::unwrap_used)]
#![expect(clippy::cast_possible_truncation)]
#![expect(clippy::cast_precision_loss)]
use std::fmt;
use divan::Bencher;
use mimalloc::MiMalloc;
use vortex_array::{ArrayRef, Canonical, IntoArray, VortexSessionExecute};
use vortex_array::arrays::{BoolArray, ConstantArray, PrimitiveArray};
use vortex_array::builtins::ArrayBuiltins;
use vortex_array::dtype::NativePType;
use vortex_array::scalar::Scalar;
use vortex_array::scalar_fn::fns::operators::Operator;
use vortex_array::validity::Validity;
use vortex_buffer::Buffer;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
fn main() {
if check_enabled() { eprintln!("detected SIMD level: {:?}", fearless_simd::Level::new()); }
divan::main();
}
#[derive(Clone, Copy, Debug)]
enum Shape { Arrays, LeftConstant, RightConstant }
#[derive(Clone, Copy, Debug)]
enum InputValidity { Dense, AllValid, Nullable, Sparse }
#[derive(Clone, Copy, Debug)]
enum Comparison { Eq, Gte }
#[derive(Clone, Copy)]
struct Case { rows: usize, shape: Shape, validity: InputValidity, op: Comparison }
impl fmt::Display for Case {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "rows={},shape={:?},validity={:?},op={:?}", self.rows, self.shape, self.validity, self.op)
}
}
const CASES: &[Case] = &[
Case { rows: 64, shape: Shape::Arrays, validity: InputValidity::Dense, op: Comparison::Eq },
Case { rows: 64, shape: Shape::Arrays, validity: InputValidity::Dense, op: Comparison::Gte },
Case { rows: 64, shape: Shape::Arrays, validity: InputValidity::AllValid, op: Comparison::Eq },
Case { rows: 64, shape: Shape::Arrays, validity: InputValidity::AllValid, op: Comparison::Gte },
Case { rows: 64, shape: Shape::Arrays, validity: InputValidity::Nullable, op: Comparison::Eq },
Case { rows: 64, shape: Shape::Arrays, validity: InputValidity::Nullable, op: Comparison::Gte },
Case { rows: 64, shape: Shape::Arrays, validity: InputValidity::Sparse, op: Comparison::Eq },
Case { rows: 64, shape: Shape::Arrays, validity: InputValidity::Sparse, op: Comparison::Gte },
Case { rows: 64, shape: Shape::LeftConstant, validity: InputValidity::Dense, op: Comparison::Eq },
Case { rows: 64, shape: Shape::LeftConstant, validity: InputValidity::Dense, op: Comparison::Gte },
Case { rows: 64, shape: Shape::LeftConstant, validity: InputValidity::AllValid, op: Comparison::Eq },
Case { rows: 64, shape: Shape::LeftConstant, validity: InputValidity::AllValid, op: Comparison::Gte },
Case { rows: 64, shape: Shape::LeftConstant, validity: InputValidity::Nullable, op: Comparison::Eq },
Case { rows: 64, shape: Shape::LeftConstant, validity: InputValidity::Nullable, op: Comparison::Gte },
Case { rows: 64, shape: Shape::LeftConstant, validity: InputValidity::Sparse, op: Comparison::Eq },
Case { rows: 64, shape: Shape::LeftConstant, validity: InputValidity::Sparse, op: Comparison::Gte },
Case { rows: 64, shape: Shape::RightConstant, validity: InputValidity::Dense, op: Comparison::Eq },
Case { rows: 64, shape: Shape::RightConstant, validity: InputValidity::Dense, op: Comparison::Gte },
Case { rows: 64, shape: Shape::RightConstant, validity: InputValidity::AllValid, op: Comparison::Eq },
Case { rows: 64, shape: Shape::RightConstant, validity: InputValidity::AllValid, op: Comparison::Gte },
Case { rows: 64, shape: Shape::RightConstant, validity: InputValidity::Nullable, op: Comparison::Eq },
Case { rows: 64, shape: Shape::RightConstant, validity: InputValidity::Nullable, op: Comparison::Gte },
Case { rows: 64, shape: Shape::RightConstant, validity: InputValidity::Sparse, op: Comparison::Eq },
Case { rows: 64, shape: Shape::RightConstant, validity: InputValidity::Sparse, op: Comparison::Gte },
Case { rows: 8192, shape: Shape::Arrays, validity: InputValidity::Dense, op: Comparison::Eq },
Case { rows: 8192, shape: Shape::Arrays, validity: InputValidity::Dense, op: Comparison::Gte },
Case { rows: 8192, shape: Shape::Arrays, validity: InputValidity::AllValid, op: Comparison::Eq },
Case { rows: 8192, shape: Shape::Arrays, validity: InputValidity::AllValid, op: Comparison::Gte },
Case { rows: 8192, shape: Shape::Arrays, validity: InputValidity::Nullable, op: Comparison::Eq },
Case { rows: 8192, shape: Shape::Arrays, validity: InputValidity::Nullable, op: Comparison::Gte },
Case { rows: 8192, shape: Shape::Arrays, validity: InputValidity::Sparse, op: Comparison::Eq },
Case { rows: 8192, shape: Shape::Arrays, validity: InputValidity::Sparse, op: Comparison::Gte },
Case { rows: 8192, shape: Shape::LeftConstant, validity: InputValidity::Dense, op: Comparison::Eq },
Case { rows: 8192, shape: Shape::LeftConstant, validity: InputValidity::Dense, op: Comparison::Gte },
Case { rows: 8192, shape: Shape::LeftConstant, validity: InputValidity::AllValid, op: Comparison::Eq },
Case { rows: 8192, shape: Shape::LeftConstant, validity: InputValidity::AllValid, op: Comparison::Gte },
Case { rows: 8192, shape: Shape::LeftConstant, validity: InputValidity::Nullable, op: Comparison::Eq },
Case { rows: 8192, shape: Shape::LeftConstant, validity: InputValidity::Nullable, op: Comparison::Gte },
Case { rows: 8192, shape: Shape::LeftConstant, validity: InputValidity::Sparse, op: Comparison::Eq },
Case { rows: 8192, shape: Shape::LeftConstant, validity: InputValidity::Sparse, op: Comparison::Gte },
Case { rows: 8192, shape: Shape::RightConstant, validity: InputValidity::Dense, op: Comparison::Eq },
Case { rows: 8192, shape: Shape::RightConstant, validity: InputValidity::Dense, op: Comparison::Gte },
Case { rows: 8192, shape: Shape::RightConstant, validity: InputValidity::AllValid, op: Comparison::Eq },
Case { rows: 8192, shape: Shape::RightConstant, validity: InputValidity::AllValid, op: Comparison::Gte },
Case { rows: 8192, shape: Shape::RightConstant, validity: InputValidity::Nullable, op: Comparison::Eq },
Case { rows: 8192, shape: Shape::RightConstant, validity: InputValidity::Nullable, op: Comparison::Gte },
Case { rows: 8192, shape: Shape::RightConstant, validity: InputValidity::Sparse, op: Comparison::Eq },
Case { rows: 8192, shape: Shape::RightConstant, validity: InputValidity::Sparse, op: Comparison::Gte },
Case { rows: 65536, shape: Shape::Arrays, validity: InputValidity::Dense, op: Comparison::Eq },
Case { rows: 65536, shape: Shape::Arrays, validity: InputValidity::Dense, op: Comparison::Gte },
Case { rows: 65536, shape: Shape::Arrays, validity: InputValidity::AllValid, op: Comparison::Eq },
Case { rows: 65536, shape: Shape::Arrays, validity: InputValidity::AllValid, op: Comparison::Gte },
Case { rows: 65536, shape: Shape::Arrays, validity: InputValidity::Nullable, op: Comparison::Eq },
Case { rows: 65536, shape: Shape::Arrays, validity: InputValidity::Nullable, op: Comparison::Gte },
Case { rows: 65536, shape: Shape::Arrays, validity: InputValidity::Sparse, op: Comparison::Eq },
Case { rows: 65536, shape: Shape::Arrays, validity: InputValidity::Sparse, op: Comparison::Gte },
Case { rows: 65536, shape: Shape::LeftConstant, validity: InputValidity::Dense, op: Comparison::Eq },
Case { rows: 65536, shape: Shape::LeftConstant, validity: InputValidity::Dense, op: Comparison::Gte },
Case { rows: 65536, shape: Shape::LeftConstant, validity: InputValidity::AllValid, op: Comparison::Eq },
Case { rows: 65536, shape: Shape::LeftConstant, validity: InputValidity::AllValid, op: Comparison::Gte },
Case { rows: 65536, shape: Shape::LeftConstant, validity: InputValidity::Nullable, op: Comparison::Eq },
Case { rows: 65536, shape: Shape::LeftConstant, validity: InputValidity::Nullable, op: Comparison::Gte },
Case { rows: 65536, shape: Shape::LeftConstant, validity: InputValidity::Sparse, op: Comparison::Eq },
Case { rows: 65536, shape: Shape::LeftConstant, validity: InputValidity::Sparse, op: Comparison::Gte },
Case { rows: 65536, shape: Shape::RightConstant, validity: InputValidity::Dense, op: Comparison::Eq },
Case { rows: 65536, shape: Shape::RightConstant, validity: InputValidity::Dense, op: Comparison::Gte },
Case { rows: 65536, shape: Shape::RightConstant, validity: InputValidity::AllValid, op: Comparison::Eq },
Case { rows: 65536, shape: Shape::RightConstant, validity: InputValidity::AllValid, op: Comparison::Gte },
Case { rows: 65536, shape: Shape::RightConstant, validity: InputValidity::Nullable, op: Comparison::Eq },
Case { rows: 65536, shape: Shape::RightConstant, validity: InputValidity::Nullable, op: Comparison::Gte },
Case { rows: 65536, shape: Shape::RightConstant, validity: InputValidity::Sparse, op: Comparison::Eq },
Case { rows: 65536, shape: Shape::RightConstant, validity: InputValidity::Sparse, op: Comparison::Gte },
Case { rows: 16383, shape: Shape::Arrays, validity: InputValidity::Nullable, op: Comparison::Eq },
Case { rows: 16383, shape: Shape::Arrays, validity: InputValidity::Nullable, op: Comparison::Gte },
Case { rows: 16383, shape: Shape::Arrays, validity: InputValidity::Sparse, op: Comparison::Eq },
Case { rows: 16383, shape: Shape::Arrays, validity: InputValidity::Sparse, op: Comparison::Gte },
Case { rows: 16384, shape: Shape::Arrays, validity: InputValidity::Nullable, op: Comparison::Eq },
Case { rows: 16384, shape: Shape::Arrays, validity: InputValidity::Nullable, op: Comparison::Gte },
Case { rows: 16384, shape: Shape::Arrays, validity: InputValidity::Sparse, op: Comparison::Eq },
Case { rows: 16384, shape: Shape::Arrays, validity: InputValidity::Sparse, op: Comparison::Gte },
Case { rows: 16385, shape: Shape::Arrays, validity: InputValidity::Nullable, op: Comparison::Eq },
Case { rows: 16385, shape: Shape::Arrays, validity: InputValidity::Nullable, op: Comparison::Gte },
Case { rows: 16385, shape: Shape::Arrays, validity: InputValidity::Sparse, op: Comparison::Eq },
Case { rows: 16385, shape: Shape::Arrays, validity: InputValidity::Sparse, op: Comparison::Gte },
Case { rows: 32768, shape: Shape::Arrays, validity: InputValidity::Nullable, op: Comparison::Eq },
Case { rows: 32768, shape: Shape::Arrays, validity: InputValidity::Nullable, op: Comparison::Gte },
Case { rows: 32768, shape: Shape::Arrays, validity: InputValidity::Sparse, op: Comparison::Eq },
Case { rows: 32768, shape: Shape::Arrays, validity: InputValidity::Sparse, op: Comparison::Gte },
];
trait Input: NativePType + Into<Scalar> {
fn value(index: usize, offset: usize) -> Self;
}
macro_rules! input {
($($ty:ty),*) => {$(
impl Input for $ty {
fn value(index: usize, offset: usize) -> Self { ((index * 17 + offset * 31) % 251) as Self }
}
)*};
}
input!(u8, i64, u64, f32, f64);
fn validity(kind: InputValidity, rows: usize, offset: usize) -> Validity {
match kind {
InputValidity::Dense => Validity::NonNullable,
InputValidity::AllValid => Validity::AllValid,
InputValidity::Nullable => Validity::from_iter((0..rows).map(|i| (i + offset) % 10 != 0)),
InputValidity::Sparse => Validity::from_iter((0..rows).map(|i| i % 10 == 0)),
}
}
fn array<T: Input>(case: Case, offset: usize) -> ArrayRef {
PrimitiveArray::new((0..case.rows).map(|i| T::value(i,offset)).collect::<Buffer<_>>(), validity(case.validity,case.rows,offset)).into_array()
}
fn operands<T: Input>(case: Case) -> (ArrayRef, ArrayRef) {
let lhs=match case.shape { Shape::LeftConstant => ConstantArray::new(T::value(13,0),case.rows).into_array(), _ => array::<T>(case,0) };
let rhs=match case.shape { Shape::RightConstant => ConstantArray::new(T::value(13,0),case.rows).into_array(), _ => array::<T>(case,1) };
(lhs,rhs)
}
fn scalar_inputs<T: Input>(case: Case, index: usize) -> (T,T) {
let lhs=match case.shape { Shape::LeftConstant => T::value(13,0), _ => T::value(index,0) };
let rhs=match case.shape { Shape::RightConstant => T::value(13,0), _ => T::value(index,1) };
(lhs,rhs)
}
fn check_enabled() -> bool { std::env::var_os("VORTEX_PERF_CHECK").is_some() }
fn measure(bencher: Bencher, lhs: ArrayRef, rhs: ArrayRef, op: Operator) {
let session=vortex_session::VortexSession::empty();
bencher.with_inputs(|| (&lhs,&rhs,session.create_execution_ctx())).bench_refs(|(lhs,rhs,ctx)| {
lhs.clone().binary(rhs.clone(),op).unwrap().execute::<Canonical>(ctx).unwrap()
});
}
#[divan::bench(args=CASES, types=[u8,i64,u64,f32,f64])]
fn compare<T: Input>(bencher: Bencher, case: &Case) {
let case=*case;
let (lhs,rhs)=operands::<T>(case);
let op=match case.op { Comparison::Eq => Operator::Eq, Comparison::Gte => Operator::Gte };
if check_enabled() {
let session=vortex_session::VortexSession::empty();
let mut ctx=session.create_execution_ctx();
let actual=lhs.clone().binary(rhs.clone(),op).unwrap().execute::<Canonical>(&mut ctx).unwrap().into_array();
let expected_values=(0..case.rows).map(|i| { let(a,b)=scalar_inputs::<T>(case,i); match case.op {Comparison::Eq=>a.is_eq(b),Comparison::Gte=>a.is_ge(b)} }).collect();
let expected=BoolArray::new(expected_values,lhs.validity().unwrap().and(rhs.validity().unwrap()).unwrap()).into_array();
vortex_array::assert_arrays_eq!(&actual,&expected,&mut ctx);
}
measure(bencher,lhs,rhs,op);
}
trait Arithmetic: Input {
fn multiply(self, other: Self) -> Self;
fn add(self, other: Self) -> Self;
}
impl Arithmetic for i64 { fn multiply(self, other: Self)->Self{self*other} fn add(self,other:Self)->Self{self+other} }
impl Arithmetic for u64 { fn multiply(self, other: Self)->Self{self*other} fn add(self,other:Self)->Self{self+other} }
#[divan::bench(args=[64,8192,32768], types=[i64,u64])]
fn multiply<T: Arithmetic>(bencher: Bencher, rows: usize) {
let case=Case{rows,shape:Shape::Arrays,validity:InputValidity::Dense,op:Comparison::Eq};
let(lhs,rhs)=operands::<T>(case);
if check_enabled(){
let session=vortex_session::VortexSession::empty();let mut ctx=session.create_execution_ctx();
let actual=lhs.clone().binary(rhs.clone(),Operator::Mul).unwrap().execute::<Canonical>(&mut ctx).unwrap().into_array();
let expected=PrimitiveArray::new((0..rows).map(|i|{let(a,b)=scalar_inputs::<T>(case,i);a.multiply(b)}).collect::<Buffer<_>>(),Validity::NonNullable).into_array();
vortex_array::assert_arrays_eq!(&actual,&expected,&mut ctx);
}
measure(bencher,lhs,rhs,Operator::Mul);
}
#[divan::bench(args=[64,8192,32768], types=[i64,u64])]
fn add_nullable<T: Arithmetic>(bencher: Bencher, rows: usize) {
let case=Case{rows,shape:Shape::RightConstant,validity:InputValidity::Nullable,op:Comparison::Eq};
let(lhs,rhs)=operands::<T>(case);
if check_enabled(){
let session=vortex_session::VortexSession::empty();let mut ctx=session.create_execution_ctx();
let actual=lhs.clone().binary(rhs.clone(),Operator::Add).unwrap().execute::<Canonical>(&mut ctx).unwrap().into_array();
let expected=PrimitiveArray::new((0..rows).map(|i|{let(a,b)=scalar_inputs::<T>(case,i);Arithmetic::add(a,b)}).collect::<Buffer<_>>(),lhs.validity().unwrap()).into_array();
vortex_array::assert_arrays_eq!(&actual,&expected,&mut ctx);
}
measure(bencher,lhs,rhs,Operator::Add);
}
#[divan::bench(args=[64,8192,65536])]
fn bool_control(bencher: Bencher, rows: usize) {
let lhs=BoolArray::from_iter((0..rows).map(|i|i%3==0)).into_array();
let rhs=BoolArray::from_iter((0..rows).map(|i|i%5==0)).into_array();
measure(bencher,lhs,rhs,Operator::Eq);
}
```
</details>
Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
Tracking Issue: #9128
Summary
Moves primitive comparisons onto the shared RowFn executor from #10675, so comparison code only selects the predicate while the framework handles decoding, constants, validity, and Boolean output.
Changes
Preserves the public
Binaryidentity and floating-point total ordering. Uses borrowed operands and dtypes, and moves a constant left operand to the right with the swapped operator. Adds coverage for all six swapped operators across a bitmap boundary and keeps the existing comparison benchmarks.Based on #10675, rebased onto
developata5f574e69bbf9010029f0e62ca59d56cd0c4aa6e. Keeps the wide-type, sliced-input, bitmap-boundary, NaN, and signed-zero tests added upstream in #10843.Performance
Still draft. Earlier EC2 runs showed gains on some configurations and regressions on others. They measured an earlier accumulated stack, not this layer in isolation or the current head.
The baseline now includes #10843's private NEON packing optimization. This migration replaces that private kernel with RowFn execution, so its performance must be compared with the improved baseline. The old packing gains cannot be credited to this PR.
Historical EC2 accumulated-stack measurements
Ratios are the median of 21 paired candidate/baseline elapsed-time ratios. Below 1 is faster. This compares the earlier complete migration, M0
ddf8a16df6b7d7c20cfd860e5f23438d97ca4238, with D0291778db36809f77ce0219bf9850506d3cba3b6. That baseline predates #10843. The array-pair cases use all-valid nullable inputs. The addition case is an arithmetic control whose algorithm was unchanged.f32array-pair Gte, 8,192 rowsi64array-pair Gte, 8,192 rowsi64add, 32,768 rowsFor example, the old stack took about 10% less time for the ARM
i64comparison, but about 14% more for the same case on AVX2-only C6a. C6a nullablei64addition took about 12% more time. These whole-executable measurements do not establish that the comparison algorithm caused movement in arithmetic controls.In the four-label matrix, D ran before M0 in 11 blocks and after it in ten. The experimental one-pass decoder variants are excluded from this table.
EC2 C7g (Neoverse V1), C6a (EPYC 7R13), and C7i (Xeon Platinum 8488C). Rust 1.99.1 / LLVM 23.1.1, bench profile with 16 CGUs and no LTO, MiMalloc, CPU 2 pinned. The same 455-case public-path microbenchmark suite ran serially across hosts, with 21 paired blocks, 10 ms per case, A/A calibration, and a separate control executable. These are microbenchmarks, not query results. C7i can dispatch to AVX-512 at runtime even in its AVX2 build.
Saved evidence is in the local investigation archive
row-fn-evaluation-20261026:manifest.json,*-matrix-*-medians.csv,*-matrix-*-summary.json, andresults/<host>/results/matrix-*.json.Confirmed independent packing gains, now in develop via #10843
The ARM-only private-kernel change reduced long array-pair cohort time on Graviton3 as follows. Each cohort contains 32 cases, including partially valid inputs and lengths around 16K.
i64u64f64Baseline
a59294e35e7109fac894a7a38a68f42db0c3c967, candidatef018aaeef739145e1bc50079a441c5d9fd53404a. The cohort uses a geometric mean of case ratios within each block, then the median across blocks. Two 21-block sessions used complementary AB/BA orders, the same full 455-case suite, and 1,000 single-iteration samples per case. The initial fixed-order source comparisons were discarded. The AVX2 builds had identical.textbytes, so no x86 speedup was attributed to this change. See #10843 for the harness and full methodology.These gains required neither this PR nor #10675.
Prior validation at
e843b51408: 963 accumulated scalar-function tests and all-target, all-feature Clippy with warnings denied passed. This rebase was reviewed from source, including the kernel conflict and upstream test coverage. Tests, builds, and benchmarks have not been rerun on the rebased head.