diff --git a/src/uu/factor/benches/factor_bench.rs b/src/uu/factor/benches/factor_bench.rs index 952ea09a616..f2f4c331221 100644 --- a/src/uu/factor/benches/factor_bench.rs +++ b/src/uu/factor/benches/factor_bench.rs @@ -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, Option>) { + 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() {