Skip to content
Open
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
196 changes: 184 additions & 12 deletions src/uu/factor/benches/factor_bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,195 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore funcs
// spell-checker:ignore funcs semiprimes

use divan::{Bencher, black_box};
use num_bigint::BigUint;
use num_prime::nt_funcs::{factorize64, factorize128, factors};
use std::collections::BTreeMap;
use uu_factor::uumain;
use uucore::benchmark::run_util_function;

/// Benchmark multiple u64 digits
#[divan::bench(args = [(2)])]
fn factor_multiple_u64s(bencher: Bencher, start_num: u64) {
bencher
// this is a range of 5000 different u128 integers
.with_inputs(|| (start_num, start_num + 2500))
.bench_values(|(start_u64, end_u64)| {
for u64_digit in start_u64..=end_u64 {
black_box(run_util_function(uumain, &[&u64_digit.to_string()]));
}
});
// Internal algorithm benchmarks avoid CLI parsing and stdout overhead.

fn factorize(n: &BigUint) -> (BTreeMap<BigUint, usize>, Option<Vec<BigUint>>) {
match n.bits() {
0..=64 => {
let n_u64 = n
.try_into()
.expect("value with at most 64 bits fits in u64");
let factors = factorize64(n_u64)
.into_iter()
.map(|(factor, count)| (BigUint::from(factor), count))
.collect();
(factors, None)
}
65..=128 => {
let n_u128 = n
.try_into()
.expect("value with at most 128 bits fits in u128");
let factors = factorize128(n_u128)
.into_iter()
.map(|(factor, count)| (BigUint::from(factor), count))
.collect();
(factors, None)
}
_ => factors(n.clone(), None),
}
}

#[divan::bench]
fn factorize_small_u64(bencher: Bencher) {
bencher.bench(|| {
for n in 2u64..=100 {
black_box(factorize(&BigUint::from(n)));
}
});
}

#[divan::bench]
fn factorize_32bit_semiprime(bencher: Bencher) {
let n = BigUint::from(4_295_098_369_u64);

bencher.bench(|| {
black_box(factorize(&n));
});
}

#[divan::bench]
fn factorize_64bit_semiprime(bencher: Bencher) {
let n = BigUint::from(18_446_743_979_220_271_189_u64);

bencher.bench(|| {
black_box(factorize(&n));
});
}

#[divan::bench]
fn factorize_large_prime(bencher: Bencher) {
let n = BigUint::from(18_446_744_073_709_551_557_u64);

bencher.bench(|| {
black_box(factorize(&n));
});
}

#[divan::bench]
fn factorize_close_factors(bencher: Bencher) {
let n = BigUint::from(4_294_049_777_u64);

bencher.bench(|| {
black_box(factorize(&n));
});
}

#[divan::bench]
fn factorize_96bit_composite(bencher: Bencher) {
let n = BigUint::parse_bytes(b"19807040619342712411247977", 10).unwrap();

bencher.bench(|| {
black_box(factorize(&n));
});
}

#[divan::bench]
fn factorize_120bit_mixed(bencher: Bencher) {
let n = BigUint::parse_bytes(b"1329227995784915872903807060280344217", 10).unwrap();

bencher.bench(|| {
black_box(factorize(&n));
});
}

// End-to-end benchmarks include CLI parsing and output formatting.

/// Benchmark small u64 numbers via CLI.
#[divan::bench(args = [(2, 502)])]
fn factor_small_u64(bencher: Bencher, (start, end): (u64, u64)) {
bencher.bench(|| {
for n in start..=end {
black_box(run_util_function(uumain, &[&n.to_string()]));
}
});
}

/// Benchmark a longer sequential u64 workload.
#[divan::bench(args = [(2, 2502)])]
fn factor_multiple_u64s(bencher: Bencher, (start, end): (u64, u64)) {
bencher.bench(|| {
for n in start..=end {
black_box(run_util_function(uumain, &[&n.to_string()]));
}
});
}

/// Benchmark medium u64 values including 32-bit semiprimes.
#[divan::bench(args = ["4295098369", "3215031751", "2147483647"])]
fn factor_medium_u64(bencher: Bencher, number: &str) {
bencher.bench(|| {
black_box(run_util_function(uumain, &[number]));
});
}

/// Benchmark large u64 primes.
#[divan::bench(args = ["18446744073709551557", "9223372036854775783"])]
fn factor_large_u64_prime(bencher: Bencher, number: &str) {
bencher.bench(|| {
black_box(run_util_function(uumain, &[number]));
});
}

/// Benchmark the PR timing cases as end-to-end utility runs.
#[divan::bench(args = [
"18446744073709551557", // 64-bit prime near 2^64
"9999999999999999999", // large u64 composite
"123456789012345678901234567890", // 97-bit u128 composite
"18446743979220271189", // 64-bit semiprime
])]
fn factor_pr_timing_cases(bencher: Bencher, number: &str) {
bencher.bench(|| {
black_box(run_util_function(uumain, &[number]));
});
}

/// Benchmark a 64-bit semiprime made from two 32-bit primes.
#[divan::bench]
fn factor_64bit_semiprime(bencher: Bencher) {
bencher.bench(|| {
black_box(run_util_function(uumain, &["18446743979220271189"]));
});
}

/// Benchmark a 96-bit composite.
#[divan::bench]
fn factor_96bit_composite(bencher: Bencher) {
let n = "19807040619342712411247977";

bencher.bench(|| {
black_box(run_util_function(uumain, &[n]));
});
}

/// Benchmark a 120-bit composite with mixed factor sizes.
#[divan::bench]
fn factor_120bit_mixed(bencher: Bencher) {
let n = "1329227995784915872903807060280344217";

bencher.bench(|| {
black_box(run_util_function(uumain, &[n]));
});
}

/// Benchmark multiple numbers in sequence.
#[divan::bench]
fn factor_batch_mixed(bencher: Bencher) {
let test_numbers = ["2", "1000000007", "4295098369", "18446743979220271189"];

bencher.bench(|| {
for n in test_numbers {
black_box(run_util_function(uumain, &[n]));
}
});
}

fn main() {
Expand Down
Loading