Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
20aea67
Add precomputed divisors for 32-bit and 64-bit integers
mbutrovich Oct 8, 2026
7d3e750
update docs
mbutrovich Oct 8, 2026
63ae153
Return an enum of branch-free divisors and use figure 5.2 for signed …
mbutrovich Oct 9, 2026
dc3425f
Merge branch 'main' into divisor-types
mbutrovich Oct 9, 2026
fbc312d
Merge branch 'main' into divisor-types
mbutrovich Oct 12, 2026
a92947e
Merge branch 'main' into divisor-types
mbutrovich Oct 14, 2026
aa95d2f
Merge branch 'main' into divisor-types
mbutrovich Oct 15, 2026
eb6edf7
Merge branch 'main' into divisor-types
mbutrovich Oct 19, 2026
12f4eee
Merge branch 'main' into divisor-types
mbutrovich Oct 23, 2026
5b30dbb
Merge branch 'main' into divisor-types
mbutrovich Oct 23, 2026
5acae0c
Merge branch 'main' into divisor-types
mbutrovich Oct 23, 2026
6f639a3
cite figure 5.1 and Hacker's Delight for the divisor algorithms
mbutrovich Oct 23, 2026
7ef5ad9
Experiment: N-bit, round-down and magnitude divisor variants for the …
mbutrovich Oct 26, 2026
51f0ebf
Experiment: N-bit, round-down and magnitude divisor variants for the …
mbutrovich Oct 26, 2026
b78c2b4
Compute the figure 4.1 multiplier without a second wide division, and…
mbutrovich Oct 26, 2026
cc1a8f2
Merge branch 'main' into divisor-types
mbutrovich Oct 26, 2026
2fb77f1
Merge branch 'main' into divisor-types
mbutrovich Oct 27, 2026
46ab603
Correct reference citations in divisor comments and test values for d…
mbutrovich Oct 27, 2026
4641eda
perf(arrow-buffer): use unsigned high products for signed divisors
sdf-jkl Oct 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions arrow-buffer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ rand = { version = "0.10", default-features = false, features = ["std", "std_rng
name = "bit_mask"
harness = false

[[bench]]
name = "divisor"
harness = false

[[bench]]
name = "i256"
harness = false
Expand Down
81 changes: 81 additions & 0 deletions arrow-buffer/benches/divisor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

use arrow_buffer::{DivisorI32, DivisorI64, DivisorU32, DivisorU64};
use criterion::*;
use rand::rngs::StdRng;
use rand::{RngExt, SeedableRng};
use std::hint;

const SIZE: usize = 8192;

/// Matches on the variant of `$divisor` once, outside the loop, and moves it into the
/// closure, as a kernel would. The last arm covers variants the enum may add later
macro_rules! div_rem_all {
($values:expr, $divisor:expr, $enum:ident, $field:tt, [$($variant:ident),+]) => {
match $divisor {
$($enum::$variant(d) => $values
.iter()
.map(move |x| d.wrapping_div_rem(*x).$field)
.collect::<Vec<_>>(),)+
d => $values
.iter()
.map(move |x| d.wrapping_div_rem(*x).$field)
.collect::<Vec<_>>(),
}
};
}

/// Divides `SIZE` random values by 7, 13 and 16 with `/` and `%`, and with the divisor type.
/// 13 uses `Up` where the type has it, 16 uses `PowerOfTwo`, and 7 uses `Down` for `u32` on
/// targets with cheap saturation and `AddIndicator` otherwise
macro_rules! bench_divisor {
($c:expr, $divisor:ident, $t:ty, $variants:tt) => {{
let mut rng = StdRng::seed_from_u64(42);
let values: Vec<$t> = (0..SIZE).map(|_| rng.random()).collect();
let mut group = $c.benchmark_group(concat!("divisor_", stringify!($t)));
group.throughput(Throughput::Elements(SIZE as u64));
for d in [7, 13, 16] {
// Hide the divisor from the compiler, as it is when it comes from a `Scalar`
let d: $t = hint::black_box(d);
let divisor = $divisor::new(d).unwrap();
group.bench_function(format!("div {d}/operator"), |b| {
b.iter(|| values.iter().map(move |x| x / d).collect::<Vec<_>>())
});
group.bench_function(format!("div {d}/divisor"), |b| {
b.iter(|| div_rem_all!(values, divisor, $divisor, 0, $variants))
});
group.bench_function(format!("rem {d}/operator"), |b| {
b.iter(|| values.iter().map(move |x| x % d).collect::<Vec<_>>())
});
group.bench_function(format!("rem {d}/divisor"), |b| {
b.iter(|| div_rem_all!(values, divisor, $divisor, 1, $variants))
});
}
group.finish();
}};
}

fn criterion_benchmark(c: &mut Criterion) {
bench_divisor!(c, DivisorU32, u32, [PowerOfTwo, Up, Down, AddIndicator]);
bench_divisor!(c, DivisorI32, i32, [PowerOfTwo, AddIndicator]);
bench_divisor!(c, DivisorU64, u64, [PowerOfTwo, Up, AddIndicator]);
bench_divisor!(c, DivisorI64, i64, [PowerOfTwo, AddIndicator]);
}

criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);
Loading