Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
18 changes: 14 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ license.workspace = true
homepage.workspace = true
repository.workspace = true

[lib]
bench = false

[package.metadata.docs.rs]
all-features = true
rustdoc-args = [
Expand Down Expand Up @@ -101,7 +98,6 @@ ruint = { path = ".", features = ["arbitrary", "proptest"] }
ark-bn254-03 = { version = "0.3.0", package = "ark-bn254" }
ark-bn254-04 = { version = "0.4.0", package = "ark-bn254" }

criterion = { version = "2.10", package = "codspeed-criterion-compat" }
rand-09 = { version = "0.9", package = "rand" }

approx = "0.5"
Expand All @@ -115,6 +111,10 @@ serde_json = "1.0"
# borsh
borsh = { version = "1.5", features = ["derive"] }

# benches only; we still need to include these here to make rust-analyzer work
arrayvec = "0.7"
criterion = { version = "3", package = "codspeed-criterion-compat" }

[features]
default = ["std"]
std = [
Expand Down Expand Up @@ -202,3 +202,13 @@ strip = false

[profile.bench]
inherits = "profiling"

# Looks like there is no way to completely disable cargo's automatic bench/test/etc. finding.
[lib]
bench = false

[[bench]]
name = "bench"
harness = false
path = "benches/bench.rs"
# required-features = ["run_with_-p_ruint-bench"]
69 changes: 69 additions & 0 deletions benches/benches/base_convert.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use crate::prelude::*;
use std::collections::BTreeSet;

#[allow(clippy::single_element_loop)]
pub fn group(criterion: &mut Criterion) {
const_for!(BITS in BENCH {
const LIMBS: usize = nlimbs(BITS);
for input_bits in BTreeSet::from([BITS]) {
for base in [10] {
bench_from_base::<BITS, LIMBS>(criterion, input_bits, base, false, |digits| {
Uint::<BITS, LIMBS>::from_base_le(base, digits.iter().copied()).unwrap()
});
bench_from_base::<BITS, LIMBS>(criterion, input_bits, base, true, |digits| {
Uint::<BITS, LIMBS>::from_base_be(base, digits.iter().copied()).unwrap()
});

bench_to_base::<BITS, LIMBS>(criterion, input_bits, base, false, |n, f| {
n.to_base_le(base).for_each(f);
});
bench_to_base::<BITS, LIMBS>(criterion, input_bits, base, true, |n, f| {
n.to_base_be(base).for_each(f);
});
}
}
});
}

fn bench_from_base<const BITS: usize, const LIMBS: usize>(
criterion: &mut Criterion,
input_bits: usize,
base: u64,
is_be: bool,
mut f: impl FnMut(&[u64]) -> Uint<BITS, LIMBS>,
) {
let endian = if is_be { "be" } else { "le" };
bench_arbitrary_with(
criterion,
&format!("base_convert/{BITS}/{input_bits}/{base}/{endian}"),
Uint::<BITS, LIMBS>::arbitrary().prop_map(|mut n| {
n >>= BITS - input_bits;
let digits: Vec<u64> = if is_be {
n.to_base_be(base).collect()
} else {
n.to_base_le(base).collect()
};
arrayvec::ArrayVec::<u64, BITS>::from_iter(digits)
}),
|n| f(black_box(n.as_slice())),
);
}

fn bench_to_base<const BITS: usize, const LIMBS: usize>(
criterion: &mut Criterion,
input_bits: usize,
base: u64,
is_be: bool,
mut f: impl FnMut(Uint<BITS, LIMBS>, fn(u64)),
) {
fn noop(_: u64) {}
let noop = black_box(noop);

let endian = if is_be { "be" } else { "le" };
bench_arbitrary_with(
criterion,
&format!("base_convert/{BITS}/{input_bits}/{base}/{endian}"),
Uint::<BITS, LIMBS>::arbitrary().prop_map(|n| n >> (BITS - input_bits)),
|n| f(n, noop),
);
}
33 changes: 33 additions & 0 deletions benches/benches/fmt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use crate::prelude::*;
use std::fmt::Write;

pub fn group(criterion: &mut Criterion) {
const_for!(BITS in BENCH {
const LIMBS: usize = nlimbs(BITS);

bench_fmt::<BITS, LIMBS, _>(criterion, "fmt/binary", |n, buf| {
write!(buf, "{n:b}").unwrap()
});
bench_fmt::<BITS, LIMBS, _>(criterion, "fmt/octal", |n, buf| {
write!(buf, "{n:o}").unwrap()
});
bench_fmt::<BITS, LIMBS, _>(criterion, "fmt/decimal", |n, buf| {
write!(buf, "{n}").unwrap()
});
bench_fmt::<BITS, LIMBS, _>(criterion, "fmt/hex", |n, buf| {
write!(buf, "{n:x}").unwrap()
});
});
}

fn bench_fmt<const BITS: usize, const LIMBS: usize, T>(
criterion: &mut Criterion,
name: &str,
mut f: impl FnMut(Uint<BITS, LIMBS>, &mut String) -> T,
) {
let mut buf = String::with_capacity(BITS);
bench_unop(criterion, name, |n| {
buf.clear();
f(n, black_box(&mut buf))
});
}
10 changes: 9 additions & 1 deletion benches/benches/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
mod add;
mod algorithms;
mod base_convert;
mod bits;
mod cmp;
mod div;
mod fmt;
mod log;
mod modular;
mod mul;
Expand All @@ -12,14 +14,20 @@ mod root;
pub(crate) mod prelude;

pub fn group(c: &mut criterion::Criterion) {
cmp::group(c);
bits::group(c);

add::group(c);
mul::group(c);
div::group(c);
pow::group(c);
log::group(c);
root::group(c);
modular::group(c);

cmp::group(c);

base_convert::group(c);
fmt::group(c);

algorithms::group(c);
}
15 changes: 13 additions & 2 deletions benches/benches/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,12 @@ fn manual_batch<T, U>(
name: &str,
) -> impl FnMut(T) {
assert!(
!std::mem::needs_drop::<T>(),
!needs_drop::<T>(),
"cannot batch inputs that need to be dropped: {}",
std::any::type_name::<T>(),
);
assert!(
!std::mem::needs_drop::<U>(),
!needs_drop::<U>(),
"cannot batch outputs that need to be dropped: {}",
std::any::type_name::<U>(),
);
Expand All @@ -108,6 +108,17 @@ fn manual_batch<T, U>(
}
}

#[cfg(codspeed)]
fn needs_drop<T>() -> bool {
// SAFETY: `ArrayVec` doesn't implement `Copy` when `T: Copy` even though it
// can.
if std::any::type_name::<T>().contains("ArrayVec<u64") {
false
} else {
std::mem::needs_drop::<T>()
}
}

#[cfg(not(codspeed))]
fn manual_batch<T, U>(
_setup: impl FnMut() -> T,
Expand Down
3 changes: 2 additions & 1 deletion ruint-bench/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ harness = false
[dev-dependencies]
ruint = { path = "..", features = ["std", "proptest"] }

criterion = { version = "2.10", package = "codspeed-criterion-compat" }
arrayvec = "0.7"
criterion = { version = "3", package = "codspeed-criterion-compat" }
proptest = "1"

[[bench]]
Expand Down