1use std::{borrow::Cow, time::Duration};
2
3use crate::{counter::CounterSet, time::FineDuration};
4
5/// Benchmarking options set directly by the user in `#[divan::bench]` and
6/// `#[divan::bench_group]`.
7///
8/// Changes to fields must be reflected in the "Options" sections of the docs
9/// for `#[divan::bench]` and `#[divan::bench_group]`.
10#[derive(Clone, Default)]
11pub struct BenchOptions<'a> {
12 /// The number of sample recordings.
13 pub sample_count: Option<u32>,
14
15 /// The number of iterations inside a single sample.
16 pub sample_size: Option<u32>,
17
18 /// The number of threads to benchmark the sample. This is 1 by default.
19 ///
20 /// If set to 0, this will use [`std::thread::available_parallelism`].
21 ///
22 /// We use `&'static [usize]` by leaking the input because `BenchOptions` is
23 /// cached on first retrieval.
24 pub threads: Option<Cow<'a, [usize]>>,
25
26 /// Counts the number of values processed each iteration of a benchmarked
27 /// function.
28 pub counters: CounterSet,
29
30 /// The time floor for benchmarking a function.
31 pub min_time: Option<Duration>,
32
33 /// The time ceiling for benchmarking a function.
34 pub max_time: Option<Duration>,
35
36 /// When accounting for `min_time` or `max_time`, skip time external to
37 /// benchmarked functions, such as time spent generating inputs and running
38 /// [`Drop`].
39 pub skip_ext_time: Option<bool>,
40
41 /// Whether the benchmark should be ignored.
42 ///
43 /// This may be set within the attribute or with a separate
44 /// [`#[ignore]`](https://doc.rust-lang.org/reference/attributes/testing.html#the-ignore-attribute).
45 pub ignore: Option<bool>,
46}
47
48impl<'a> BenchOptions<'a> {
49 /// Overwrites `other` with values set in `self`.
50 #[must_use]
51 pub(crate) fn overwrite<'b>(&'b self, other: &'b Self) -> Self
52 where
53 'b: 'a,
54 {
55 Self {
56 // `Copy` values:
57 sample_count: self.sample_count.or(other.sample_count),
58 sample_size: self.sample_size.or(other.sample_size),
59 threads: self.threads.as_deref().or(other.threads.as_deref()).map(Cow::Borrowed),
60 min_time: self.min_time.or(other.min_time),
61 max_time: self.max_time.or(other.max_time),
62 skip_ext_time: self.skip_ext_time.or(other.skip_ext_time),
63 ignore: self.ignore.or(other.ignore),
64
65 // `Clone` values:
66 counters: self.counters.overwrite(&other.counters),
67 }
68 }
69
70 /// Returns `true` if non-zero samples are specified.
71 #[inline]
72 pub(crate) fn has_samples(&self) -> bool {
73 self.sample_count != Some(0) && self.sample_size != Some(0)
74 }
75
76 #[inline]
77 pub(crate) fn min_time(&self) -> FineDuration {
78 self.min_time.map(FineDuration::from).unwrap_or_default()
79 }
80
81 #[inline]
82 pub(crate) fn max_time(&self) -> FineDuration {
83 self.max_time.map(FineDuration::from).unwrap_or(FineDuration::MAX)
84 }
85}
86