From 8f346946b4d4dc7d030eba0be211b9ef1588e01b Mon Sep 17 00:00:00 2001 From: Arthur Pastel Date: Thu, 31 Jul 2025 11:17:23 +0200 Subject: [PATCH] feat(divan): placeholder implementation of counter --- crates/divan_compat/examples/Cargo.toml | 4 + .../divan_compat/examples/benches/counters.rs | 160 ++++++++++++++++++ crates/divan_compat/macros/src/args.rs | 7 + crates/divan_compat/src/compat/bench/mod.rs | 41 +++++ .../divan_compat/src/compat/bench/options.rs | 6 + crates/divan_compat/src/compat/mod.rs | 135 +++++++++++++++ 6 files changed, 353 insertions(+) create mode 100644 crates/divan_compat/examples/benches/counters.rs diff --git a/crates/divan_compat/examples/Cargo.toml b/crates/divan_compat/examples/Cargo.toml index 188a5c0c..1e9ea793 100644 --- a/crates/divan_compat/examples/Cargo.toml +++ b/crates/divan_compat/examples/Cargo.toml @@ -40,3 +40,7 @@ harness = false [[bench]] name = "the_algorithms" harness = false + +[[bench]] +name = "counters" +harness = false diff --git a/crates/divan_compat/examples/benches/counters.rs b/crates/divan_compat/examples/benches/counters.rs new file mode 100644 index 00000000..ffddfe7c --- /dev/null +++ b/crates/divan_compat/examples/benches/counters.rs @@ -0,0 +1,160 @@ +//! Example benchmarks demonstrating divan counter usage +//! +//! This file shows how to use different types of counters with divan: +//! - BytesCount: for measuring throughput in bytes +//! - ItemsCount: for counting processed items +//! - CharsCount: for counting processed characters +//! - CyclesCount: for counting processing cycles + +use divan::{counter::*, AllocProfiler, Bencher}; + +#[global_allocator] +static ALLOC: AllocProfiler = AllocProfiler::system(); + +fn main() { + divan::main(); +} + +/// Example data for benchmarks +const SAMPLE_DATA: &[i32] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; +const SAMPLE_TEXT: &str = "Hello, world! This is a sample string for benchmarking."; + +mod bytes_counter_examples { + use super::*; + + #[divan::bench] + fn vec_copy_with_bytes_counter(bencher: Bencher) { + let data = SAMPLE_DATA; + let bytes = BytesCount::of_slice(data); + + bencher + .counter(bytes) + .bench(|| -> Vec { divan::black_box(data).to_vec() }); + } + + #[divan::bench] + fn string_copy_with_bytes_counter(bencher: Bencher) { + let text = SAMPLE_TEXT; + let bytes = BytesCount::of_str(text); + + bencher + .counter(bytes) + .bench(|| -> String { divan::black_box(text).to_owned() }); + } + + #[divan::bench] + fn slice_into_vec_with_bytes(bencher: Bencher) { + let ints = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let bytes = BytesCount::of_slice(ints); + + bencher + .counter(bytes) + .bench(|| -> Vec { divan::black_box(ints).into() }); + } +} + +mod items_counter_examples { + use super::*; + + #[divan::bench] + fn process_items_with_counter(bencher: Bencher) { + let data = SAMPLE_DATA; + let items = ItemsCount::new(data.len()); + + bencher + .counter(items) + .bench(|| -> Vec { divan::black_box(data).iter().map(|x| x * 2).collect() }); + } + + #[divan::bench] + fn filter_items_with_counter(bencher: Bencher) { + let data = (1..=100).collect::>(); + let items = ItemsCount::new(data.len()); + + bencher.counter(items).bench(|| -> Vec { + divan::black_box(&data) + .iter() + .filter(|&&x| x % 2 == 0) + .copied() + .collect() + }); + } +} + +mod chars_counter_examples { + use super::*; + + #[divan::bench] + fn count_chars_in_string(bencher: Bencher) { + let text = SAMPLE_TEXT; + let chars = CharsCount::of_str(text); + + bencher + .counter(chars) + .bench(|| -> usize { divan::black_box(text).chars().count() }); + } + + #[divan::bench] + fn uppercase_chars_with_counter(bencher: Bencher) { + let text = "hello world with unicode: café naïve résumé"; + let chars = CharsCount::of_str(text); + + bencher + .counter(chars) + .bench(|| -> String { divan::black_box(text).to_uppercase() }); + } +} + +mod cycles_counter_examples { + use super::*; + + #[divan::bench] + fn simulated_processing_cycles(bencher: Bencher) { + // Simulate processing 1000 "cycles" of work + let cycles = CyclesCount::new(1000); + + bencher.counter(cycles).bench(|| { + // Simulate some work that processes 1000 cycles + let mut sum = 0u64; + for i in 0..1000 { + sum = sum.wrapping_add(divan::black_box(i)); + } + sum + }); + } + + #[divan::bench] + fn hash_computation_cycles(bencher: Bencher) { + let data = SAMPLE_DATA; + // Treat each hash operation as processing N cycles where N = data length + let cycles = CyclesCount::new(data.len()); + + bencher.counter(cycles).bench(|| -> u64 { + use std::collections::hash_map::DefaultHasher; + use std::hash::{Hash, Hasher}; + + let mut hasher = DefaultHasher::new(); + divan::black_box(data).hash(&mut hasher); + hasher.finish() + }); + } +} + +mod multiple_counters_examples { + use super::*; + + #[divan::bench(counters = [BytesCount::of_slice(SAMPLE_DATA), ItemsCount::new(SAMPLE_DATA.len())])] + fn process_with_multiple_counters() -> Vec { + SAMPLE_DATA.iter().map(|x| x * x).collect() + } + + #[divan::bench] + fn string_processing_multi_counter(bencher: Bencher) { + let text = "Processing this text with multiple counters"; + + bencher + .counter(BytesCount::of_str(text)) + .counter(CharsCount::of_str(text)) + .bench(|| -> Vec { divan::black_box(text).chars().collect() }); + } +} diff --git a/crates/divan_compat/macros/src/args.rs b/crates/divan_compat/macros/src/args.rs index da32978c..4a854358 100644 --- a/crates/divan_compat/macros/src/args.rs +++ b/crates/divan_compat/macros/src/args.rs @@ -45,6 +45,13 @@ impl AttrOptions { // These arguments are ignored for codspeed runs meta.value()?.parse::()?; // Discard the value } + "counters" => { + // Counters are not yet supported, but we parse them to avoid errors + eprintln!( + "Warning: Counter feature is not yet supported by codspeed-divan-compat" + ); + meta.value()?.parse::()?; // Discard the value + } _ => { let path = meta.path.clone(); let parsed_meta = if meta.input.is_empty() { diff --git a/crates/divan_compat/src/compat/bench/mod.rs b/crates/divan_compat/src/compat/bench/mod.rs index 5ffd3fd3..5ec824b9 100644 --- a/crates/divan_compat/src/compat/bench/mod.rs +++ b/crates/divan_compat/src/compat/bench/mod.rs @@ -51,6 +51,27 @@ impl<'a, 'b> Bencher<'a, 'b> { _marker: self._marker, } } + + /// Add a counter to this benchmark (placeholder implementation). + /// + /// Note: Counters are not yet supported by codspeed-divan-compat. + /// This method is provided for API compatibility but does not affect benchmarking. + pub fn counter(self, _counter: C) -> Self { + eprintln!("Warning: Counter feature is not yet supported by codspeed-divan-compat"); + self + } + + /// Add a counter based on input to this benchmark (placeholder implementation). + /// + /// Note: Counters are not yet supported by codspeed-divan-compat. + /// This method is provided for API compatibility but does not affect benchmarking. + pub fn input_counter(self, _counter_fn: F) -> Self + where + F: Fn() -> C, + { + eprintln!("Warning: Counter feature is not yet supported by codspeed-divan-compat"); + self + } } impl<'a, 'b> Bencher<'a, 'b> { @@ -73,6 +94,26 @@ impl<'a, 'b, I, GenI> Bencher<'a, 'b, BencherConfig> where GenI: FnMut() -> I, { + /// Add a counter to this benchmark (placeholder implementation). + /// + /// Note: Counters are not yet supported by codspeed-divan-compat. + /// This method is provided for API compatibility but does not affect benchmarking. + pub fn counter(self, _counter: C) -> Self { + eprintln!("Warning: Counter feature is not yet supported by codspeed-divan-compat"); + self + } + + /// Add a counter based on input to this benchmark (placeholder implementation). + /// + /// Note: Counters are not yet supported by codspeed-divan-compat. + /// This method is provided for API compatibility but does not affect benchmarking. + pub fn input_counter(self, _counter_fn: F) -> Self + where + F: Fn(&I) -> C, + { + eprintln!("Warning: Counter feature is not yet supported by codspeed-divan-compat"); + self + } pub fn bench_values(self, benched: B) where B: Fn(I) -> O + Sync, diff --git a/crates/divan_compat/src/compat/bench/options.rs b/crates/divan_compat/src/compat/bench/options.rs index c55e0fd6..3b596c8e 100644 --- a/crates/divan_compat/src/compat/bench/options.rs +++ b/crates/divan_compat/src/compat/bench/options.rs @@ -10,4 +10,10 @@ pub struct BenchOptions { /// This may be set within the attribute or with a separate /// [`#[ignore]`](https://doc.rust-lang.org/reference/attributes/testing.html#the-ignore-attribute). pub ignore: Option, + + /// Counters to be used with this benchmark. + /// + /// Note: Counters are not yet supported by codspeed-divan-compat. + /// This field is provided for API compatibility but does not affect benchmarking. + pub counters: Option>, } diff --git a/crates/divan_compat/src/compat/mod.rs b/crates/divan_compat/src/compat/mod.rs index 479bc59b..e5aba00c 100644 --- a/crates/divan_compat/src/compat/mod.rs +++ b/crates/divan_compat/src/compat/mod.rs @@ -20,6 +20,141 @@ mod util; use std::{cell::RefCell, rc::Rc}; pub use bench::*; + +// Counter types (placeholder implementations) +pub mod counter { + /// Process N bytes. + #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] + pub struct BytesCount { + count: u64, + } + + /// Process N [`char`s](char). + #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] + pub struct CharsCount { + count: u64, + } + + /// Process N cycles, displayed as Hertz. + #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] + pub struct CyclesCount { + count: u64, + } + + /// Process N items. + #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] + pub struct ItemsCount { + count: u64, + } + + impl BytesCount { + /// Count N bytes. + #[inline] + pub fn new(count: N) -> Self + where + N: TryInto, + N::Error: std::fmt::Debug, + { + eprintln!("Warning: Counter feature is not yet supported by codspeed-divan-compat"); + Self { + count: count.try_into().unwrap(), + } + } + + /// Counts the size of a type with [`size_of`]. + #[inline] + pub fn of() -> Self { + eprintln!("Warning: Counter feature is not yet supported by codspeed-divan-compat"); + Self { + count: std::mem::size_of::() as u64, + } + } + + /// Counts the size of multiple instances of a type with [`size_of`]. + #[inline] + pub fn of_many(n: usize) -> Self { + eprintln!("Warning: Counter feature is not yet supported by codspeed-divan-compat"); + Self { + count: (std::mem::size_of::() * n) as u64, + } + } + + /// Counts the size of a value with [`size_of_val`]. + #[inline] + pub fn of_val(val: &T) -> Self { + eprintln!("Warning: Counter feature is not yet supported by codspeed-divan-compat"); + Self { + count: std::mem::size_of_val(val) as u64, + } + } + + /// Counts the bytes of a [`&str`]. + #[inline] + pub fn of_str>(s: &S) -> Self { + eprintln!("Warning: Counter feature is not yet supported by codspeed-divan-compat"); + Self::of_val(s.as_ref()) + } + + /// Counts the bytes of a [slice](prim@slice). + #[inline] + pub fn of_slice>(s: &S) -> Self { + eprintln!("Warning: Counter feature is not yet supported by codspeed-divan-compat"); + Self::of_val(s.as_ref()) + } + } + + impl CharsCount { + /// Count N [`char`s](char). + #[inline] + pub fn new(count: N) -> Self + where + N: TryInto, + N::Error: std::fmt::Debug, + { + eprintln!("Warning: Counter feature is not yet supported by codspeed-divan-compat"); + Self { + count: count.try_into().unwrap(), + } + } + + /// Counts the [`char`s](prim@char) of a [`&str`](prim@str). + #[inline] + pub fn of_str>(s: &S) -> Self { + eprintln!("Warning: Counter feature is not yet supported by codspeed-divan-compat"); + Self::new(s.as_ref().chars().count() as u64) + } + } + + impl CyclesCount { + /// Count N cycles. + #[inline] + pub fn new(count: N) -> Self + where + N: TryInto, + N::Error: std::fmt::Debug, + { + eprintln!("Warning: Counter feature is not yet supported by codspeed-divan-compat"); + Self { + count: count.try_into().unwrap(), + } + } + } + + impl ItemsCount { + /// Count N items. + #[inline] + pub fn new(count: N) -> Self + where + N: TryInto, + N::Error: std::fmt::Debug, + { + eprintln!("Warning: Counter feature is not yet supported by codspeed-divan-compat"); + Self { + count: count.try_into().unwrap(), + } + } + } +} use codspeed::codspeed::CodSpeed; use entry::AnyBenchEntry;