Skip to content

feat(divan): placeholder implementation of counter #115

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
4 changes: 4 additions & 0 deletions crates/divan_compat/examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,7 @@ harness = false
[[bench]]
name = "the_algorithms"
harness = false

[[bench]]
name = "counters"
harness = false
160 changes: 160 additions & 0 deletions crates/divan_compat/examples/benches/counters.rs
Original file line number Diff line number Diff line change
@@ -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<i32> { 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<i32> { 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<i32> { divan::black_box(data).iter().map(|x| x * 2).collect() });
}

#[divan::bench]
fn filter_items_with_counter(bencher: Bencher) {
let data = (1..=100).collect::<Vec<_>>();
let items = ItemsCount::new(data.len());

bencher.counter(items).bench(|| -> Vec<i32> {
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<i32> {
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<char> { divan::black_box(text).chars().collect() });
}
}
7 changes: 7 additions & 0 deletions crates/divan_compat/macros/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ impl AttrOptions {
// These arguments are ignored for codspeed runs
meta.value()?.parse::<Expr>()?; // 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::<Expr>()?; // Discard the value
}
_ => {
let path = meta.path.clone();
let parsed_meta = if meta.input.is_empty() {
Expand Down
41 changes: 41 additions & 0 deletions crates/divan_compat/src/compat/bench/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<C>(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<C, F>(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> {
Expand All @@ -73,6 +94,26 @@ impl<'a, 'b, I, GenI> Bencher<'a, 'b, BencherConfig<GenI>>
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<C>(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<C, F>(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<O, B>(self, benched: B)
where
B: Fn(I) -> O + Sync,
Expand Down
6 changes: 6 additions & 0 deletions crates/divan_compat/src/compat/bench/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<bool>,

/// 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<Vec<String>>,
}
135 changes: 135 additions & 0 deletions crates/divan_compat/src/compat/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<N>(count: N) -> Self
where
N: TryInto<u64>,
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<T>() -> Self {
eprintln!("Warning: Counter feature is not yet supported by codspeed-divan-compat");
Self {
count: std::mem::size_of::<T>() as u64,
}
}

/// Counts the size of multiple instances of a type with [`size_of`].
#[inline]
pub fn of_many<T>(n: usize) -> Self {
eprintln!("Warning: Counter feature is not yet supported by codspeed-divan-compat");
Self {
count: (std::mem::size_of::<T>() * n) as u64,
}
}

/// Counts the size of a value with [`size_of_val`].
#[inline]
pub fn of_val<T: ?Sized>(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: ?Sized + AsRef<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<T, S: ?Sized + AsRef<[T]>>(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<N>(count: N) -> Self
where
N: TryInto<u64>,
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: ?Sized + AsRef<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<N>(count: N) -> Self
where
N: TryInto<u64>,
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<N>(count: N) -> Self
where
N: TryInto<u64>,
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;

Expand Down
Loading