codspeed_divan_compat_walltime/lib.rs
1//! [bench_attr]: macro@bench
2//! [bench_attr_examples]: macro@bench#examples
3//! [bench_attr_threads]: macro@bench#threads
4#![doc = include_str!("../README.md")]
5#![warn(missing_docs)]
6#![allow(
7 unknown_lints,
8 unused_unsafe,
9 clippy::needless_doctest_main,
10 clippy::needless_lifetimes,
11 clippy::new_without_default,
12 clippy::type_complexity,
13 clippy::missing_transmute_annotations
14)]
15
16// Used by generated code. Not public API and thus not subject to SemVer.
17#[doc(hidden)]
18#[path = "private.rs"]
19pub mod __private;
20
21mod alloc;
22mod bench;
23mod cli;
24mod compile_fail;
25mod config;
26mod divan;
27mod entry;
28mod stats;
29mod thread_pool;
30mod time;
31mod tree_painter;
32mod util;
33
34pub mod counter;
35
36/// Prevents compiler optimizations on a value.
37///
38/// `black_box` should only be used on [inputs](#benchmark-inputs) and
39/// [outputs](#benchmark-outputs) of benchmarks. Newcomers to benchmarking may
40/// be tempted to also use `black_box` within the implementation, but doing so
41/// will overly pessimize the measured code without any benefit.
42///
43/// ## Benchmark Inputs
44///
45/// When benchmarking, it's good practice to ensure measurements are accurate by
46/// preventing the compiler from optimizing based on assumptions about benchmark
47/// inputs.
48///
49/// The compiler can optimize code for indices it knows about, such as by
50/// removing bounds checks or unrolling loops. If real-world use of your code
51/// would not know indices up front, consider preventing optimizations on them
52/// in benchmarks:
53///
54/// ```
55/// use divan::black_box;
56///
57/// const INDEX: usize = // ...
58/// # 0;
59/// const SLICE: &[u8] = // ...
60/// # &[];
61///
62/// #[divan::bench]
63/// fn bench() {
64/// # fn work<T>(_: T) {}
65/// work(&SLICE[black_box(INDEX)..]);
66/// }
67/// ```
68///
69/// The compiler may also optimize for the data itself, which can also be
70/// avoided with `black_box`:
71///
72/// ```
73/// # use divan::black_box;
74/// # const INDEX: usize = 0;
75/// # const SLICE: &[u8] = &[];
76/// #[divan::bench]
77/// fn bench() {
78/// # fn work<T>(_: T) {}
79/// work(black_box(&SLICE[black_box(INDEX)..]));
80/// }
81/// ```
82///
83/// ## Benchmark Outputs
84///
85/// When benchmarking, it's best to ensure that all of the code is actually
86/// being run. If the compiler knows an output is unused, it may remove the code
87/// that generated the output. This optimization can make benchmarks appear much
88/// faster than they really are.
89///
90/// At the end of a benchmark, we can force the compiler to treat outputs as if
91/// they were actually used:
92///
93/// ```
94/// # use divan::black_box;
95/// #[divan::bench]
96/// fn bench() {
97/// # let value = 1;
98/// black_box(value.to_string());
99/// }
100/// ```
101///
102/// To make the code clearer to readers that the output is discarded, this code
103/// could instead call [`black_box_drop`].
104///
105/// Alternatively, the output can be returned from the benchmark:
106///
107/// ```
108/// #[divan::bench]
109/// fn bench() -> String {
110/// # let value = 1;
111/// value.to_string()
112/// }
113/// ```
114///
115/// Returning the output will `black_box` it and also avoid measuring the time
116/// to [drop](Drop) the output, which in this case is the time to deallocate a
117/// [`String`]. Read more about this in the [`#[divan::bench]`
118/// docs](macro@bench#drop).
119///
120/// ---
121///
122/// <h1>Standard Library Documentation</h1>
123///
124#[doc(inline)]
125pub use std::hint::black_box;
126
127#[doc(inline)]
128pub use crate::{alloc::AllocProfiler, bench::Bencher, divan::Divan};
129
130/// Runs all registered benchmarks.
131///
132/// # Examples
133///
134/// ```
135/// #[divan::bench]
136/// fn add() -> i32 {
137/// // ...
138/// # 0
139/// }
140///
141/// fn main() {
142/// // Run `add` benchmark:
143/// divan::main();
144/// }
145/// ```
146///
147/// See [`#[divan::bench]`](macro@bench) for more examples.
148pub fn main() {
149 Divan::from_args().main();
150}
151
152/// [`black_box`] + [`drop`] convenience function.
153///
154/// # Examples
155///
156/// This is useful when benchmarking a lazy [`Iterator`] to completion with
157/// [`for_each`](Iterator::for_each):
158///
159/// ```
160/// #[divan::bench]
161/// fn parse_iter() {
162/// let input: &str = // ...
163/// # "";
164///
165/// # struct Parser;
166/// # impl Parser {
167/// # fn new(_: &str) -> Parser { Parser }
168/// # fn for_each(self, _: fn(&'static str)) {}
169/// # }
170/// Parser::new(input)
171/// .for_each(divan::black_box_drop);
172/// }
173/// ```
174#[inline]
175pub fn black_box_drop<T>(dummy: T) {
176 _ = black_box(dummy);
177}
178
179/// Registers a benchmarking function.
180///
181/// # Examples
182///
183/// The quickest way to get started is to benchmark the function as-is:
184///
185/// ```
186/// use divan::black_box;
187///
188/// #[divan::bench]
189/// fn add() -> i32 {
190/// black_box(1) + black_box(42)
191/// }
192///
193/// fn main() {
194/// // Run `add` benchmark:
195/// divan::main();
196/// }
197/// ```
198///
199/// If benchmarks need to setup context before running, they can take a
200/// [`Bencher`] and use [`Bencher::bench`]:
201///
202/// ```
203/// use divan::{Bencher, black_box};
204///
205/// #[divan::bench]
206/// fn copy_from_slice(bencher: Bencher) {
207/// let src = (0..100).collect::<Vec<i32>>();
208/// let mut dst = vec![0; src.len()];
209///
210/// bencher.bench_local(move || {
211/// black_box(&mut dst).copy_from_slice(black_box(&src));
212/// });
213/// }
214/// ```
215///
216/// Applying this attribute multiple times to the same item will cause a compile
217/// error:
218///
219/// ```compile_fail
220/// #[divan::bench]
221/// #[divan::bench]
222/// fn bench() {
223/// // ...
224/// }
225/// ```
226///
227/// # Drop
228///
229/// When a benchmarked function returns a value, it will not be [dropped][Drop]
230/// until after the current sample loop is finished. This allows for more
231/// precise timing measurements.
232///
233/// Note that there is an inherent memory cost to defer drop, including
234/// allocations inside not-yet-dropped values. Also, if the benchmark
235/// [panics](macro@std::panic), the values will never be dropped.
236///
237/// The following example benchmarks will only measure [`String`] construction
238/// time, but not deallocation time:
239///
240/// ```
241/// use divan::{Bencher, black_box};
242///
243/// #[divan::bench]
244/// fn freestanding() -> String {
245/// black_box("hello").to_uppercase()
246/// }
247///
248/// #[divan::bench]
249/// fn contextual(bencher: Bencher) {
250/// // Setup:
251/// let s: String = // ...
252/// # String::new();
253///
254/// bencher.bench(|| -> String {
255/// black_box(&s).to_lowercase()
256/// });
257/// }
258/// ```
259///
260/// If the returned value *does not* need to be dropped, there is no memory
261/// cost. Because of this, the following example benchmarks are equivalent:
262///
263/// ```
264/// #[divan::bench]
265/// fn with_return() -> i32 {
266/// let n: i32 = // ...
267/// # 0;
268/// n
269/// }
270///
271/// #[divan::bench]
272/// fn without_return() {
273/// let n: i32 = // ...
274/// # 0;
275/// divan::black_box(n);
276/// }
277/// ```
278///
279/// # Options
280///
281/// - [`name`]
282/// - [`crate`]
283/// - [`args`]
284/// - [`consts`]
285/// - [`types`]
286/// - [`sample_count`]
287/// - [`sample_size`]
288/// - [`threads`]
289/// - [`counters`]
290/// - [`bytes_count`]
291/// - [`chars_count`]
292/// - [`items_count`]
293/// - [`min_time`]
294/// - [`max_time`]
295/// - [`skip_ext_time`]
296/// - [`ignore`]
297///
298/// ## `name`
299/// [`name`]: #name
300///
301/// By default, the benchmark uses the function's name. It can be overridden via
302/// the [`name`] option:
303///
304/// ```
305/// #[divan::bench(name = "my_add")]
306/// fn add() -> i32 {
307/// // Will appear as "crate_name::my_add".
308/// # 0
309/// }
310/// ```
311///
312/// ## `crate`
313/// [`crate`]: #crate
314///
315/// The path to the specific `divan` crate instance used by this macro's
316/// generated code can be specified via the [`crate`] option. This is applicable
317/// when using `divan` via a macro from your own crate.
318///
319/// ```
320/// extern crate divan as sofa;
321///
322/// #[::sofa::bench(crate = ::sofa)]
323/// fn add() -> i32 {
324/// // ...
325/// # 0
326/// }
327/// ```
328///
329/// ## `args`
330/// [`args`]: #args
331///
332/// Function arguments can be provided to benchmark the function over multiple
333/// cases. This is used for comparing across parameters like collection lengths
334/// and [`enum`](https://doc.rust-lang.org/std/keyword.enum.html) variants. If
335/// you are not comparing cases and just need to pass a value into the
336/// benchmark, instead consider passing local values into the [`Bencher::bench`]
337/// closure or use [`Bencher::with_inputs`] for many distinct values.
338///
339/// The following example benchmarks converting a [`Range`](std::ops::Range) to
340/// [`Vec`] over different lengths:
341///
342/// ```
343/// #[divan::bench(args = [1000, LEN, len()])]
344/// fn init_vec(len: usize) -> Vec<usize> {
345/// (0..len).collect()
346/// }
347///
348/// const LEN: usize = // ...
349/// # 0;
350///
351/// fn len() -> usize {
352/// // ...
353/// # 0
354/// }
355/// ```
356///
357/// The list of arguments can be shared across multiple benchmarks through an
358/// external [`Iterator`]:
359///
360/// ```
361/// const LENS: &[usize] = // ...
362/// # &[];
363///
364/// #[divan::bench(args = LENS)]
365/// fn bench_vec1(len: usize) -> Vec<usize> {
366/// // ...
367/// # vec![]
368/// }
369///
370/// #[divan::bench(args = LENS)]
371/// fn bench_vec2(len: usize) -> Vec<usize> {
372/// // ...
373/// # vec![]
374/// }
375/// ```
376///
377/// Unlike the [`consts`] option, any argument type is supported if it
378/// implements [`Any`], [`Copy`], [`Send`], [`Sync`], and [`ToString`] (or
379/// [`Debug`](std::fmt::Debug)):
380///
381/// ```
382/// #[derive(Clone, Copy, Debug)]
383/// enum Arg {
384/// A, B
385/// }
386///
387/// #[divan::bench(args = [Arg::A, Arg::B])]
388/// fn bench_args(arg: Arg) {
389/// // ...
390/// }
391/// ```
392///
393/// The argument type does not need to implement [`Copy`] if it is used through
394/// a reference:
395///
396/// ```
397/// #[derive(Debug)]
398/// enum Arg {
399/// A, B
400/// }
401///
402/// #[divan::bench(args = [Arg::A, Arg::B])]
403/// fn bench_args(arg: &Arg) {
404/// // ...
405/// }
406/// ```
407///
408/// For convenience, common string types are coerced to [`&str`](primitive@str):
409///
410/// ```
411/// fn strings() -> impl Iterator<Item = String> {
412/// // ...
413/// # [].into_iter()
414/// }
415///
416/// #[divan::bench(args = strings())]
417/// fn bench_strings(s: &str) {
418/// // ...
419/// }
420/// ```
421///
422/// Arguments can also be used with [`Bencher`]. This allows for generating
423/// inputs based on [`args`] values or providing throughput information via
424/// [`Counter`s](crate::counter::Counter):
425///
426/// ```
427/// # fn new_value<T>(v: T) -> T { v }
428/// # fn do_work<T>(_: T) {}
429/// use divan::Bencher;
430///
431/// #[divan::bench(args = [1, 2, 3])]
432/// fn bench(bencher: Bencher, len: usize) {
433/// let value = new_value(len);
434///
435/// bencher
436/// .counter(len)
437/// .bench(|| {
438/// do_work(value);
439/// });
440/// }
441/// ```
442///
443/// ## `consts`
444/// [`consts`]: #consts
445///
446/// Divan supports benchmarking functions with [`const`
447/// generics](https://doc.rust-lang.org/reference/items/generics.html#const-generics)
448/// via the [`consts`] option.
449///
450/// The following example benchmarks initialization of [`[i32; N]`](prim@array)
451/// for values of `N` provided by a [literal](https://doc.rust-lang.org/reference/expressions/literal-expr.html),
452/// [`const` item](https://doc.rust-lang.org/reference/items/constant-items.html),
453/// and [`const fn`](https://doc.rust-lang.org/reference/const_eval.html#const-functions):
454///
455/// ```
456/// #[divan::bench(consts = [1000, LEN, len()])]
457/// fn init_array<const N: usize>() -> [i32; N] {
458/// let mut result = [0; N];
459///
460/// for i in 0..N {
461/// result[i] = divan::black_box(i as i32);
462/// }
463///
464/// result
465/// }
466///
467/// const LEN: usize = // ...
468/// # 0;
469///
470/// const fn len() -> usize {
471/// // ...
472/// # 0
473/// }
474/// ```
475///
476/// The list of constants can be shared across multiple benchmarks through an
477/// external [array](prim@array) or [slice](prim@slice):
478///
479/// ```
480/// const SIZES: &[usize] = &[1, 2, 5, 10];
481///
482/// #[divan::bench(consts = SIZES)]
483/// fn bench_array1<const N: usize>() -> [i32; N] {
484/// // ...
485/// # [0; N]
486/// }
487///
488/// #[divan::bench(consts = SIZES)]
489/// fn bench_array2<const N: usize>() -> [i32; N] {
490/// // ...
491/// # [0; N]
492/// }
493/// ```
494///
495/// External constants are limited to lengths 1 through 20, because of
496/// implementation details. This limit does not apply if the list is provided
497/// directly like in the first example.
498///
499/// ```compile_fail
500/// const SIZES: [usize; 21] = [
501/// // ...
502/// # 0; 21
503/// ];
504///
505/// #[divan::bench(consts = SIZES)]
506/// fn bench_array<const N: usize>() -> [i32; N] {
507/// // ...
508/// # [0; N]
509/// }
510/// ```
511///
512/// ## `types`
513/// [`types`]: #types
514///
515/// Divan supports benchmarking generic functions over a list of types via the
516/// [`types`] option.
517///
518/// The following example benchmarks the [`From<&str>`](From) implementations
519/// for [`&str`](prim@str) and [`String`]:
520///
521/// ```
522/// #[divan::bench(types = [&str, String])]
523/// fn from_str<'a, T>() -> T
524/// where
525/// T: From<&'a str>,
526/// {
527/// divan::black_box("hello world").into()
528/// }
529/// ```
530///
531/// The [`types`] and [`args`] options can be combined to benchmark _T_ × _A_
532/// scenarios. The following example benchmarks the [`FromIterator`]
533/// implementations for [`Vec`], [`BTreeSet`], and [`HashSet`]:
534///
535/// ```
536/// use std::collections::{BTreeSet, HashSet};
537///
538/// #[divan::bench(
539/// types = [Vec<i32>, BTreeSet<i32>, HashSet<i32>],
540/// args = [0, 2, 4, 16, 256, 4096],
541/// )]
542/// fn from_range<T>(n: i32) -> T
543/// where
544/// T: FromIterator<i32>,
545/// {
546/// (0..n).collect()
547/// }
548/// ```
549///
550/// [`BTreeSet`]: std::collections::BTreeSet
551/// [`HashSet`]: std::collections::HashSet
552///
553/// ## `sample_count`
554/// [`sample_count`]: #sample_count
555///
556/// The number of statistical sample recordings can be set to a predetermined
557/// [`u32`] value via the [`sample_count`] option. This may be overridden at
558/// runtime using either the `DIVAN_SAMPLE_COUNT` environment variable or
559/// `--sample-count` CLI argument.
560///
561/// ```
562/// #[divan::bench(sample_count = 1000)]
563/// fn add() -> i32 {
564/// // ...
565/// # 0
566/// }
567/// ```
568///
569/// If the [`threads`] option is enabled, sample count becomes a multiple of the
570/// number of threads. This is because each thread operates over the same sample
571/// size to ensure there are always N competing threads doing the same amount of
572/// work.
573///
574/// ## `sample_size`
575/// [`sample_size`]: #sample_size
576///
577/// The number iterations within each statistics sample can be set to a
578/// predetermined [`u32`] value via the [`sample_size`] option. This may be
579/// overridden at runtime using either the `DIVAN_SAMPLE_SIZE` environment
580/// variable or `--sample-size` CLI argument.
581///
582/// ```
583/// #[divan::bench(sample_size = 1000)]
584/// fn add() -> i32 {
585/// // ...
586/// # 0
587/// }
588/// ```
589///
590/// ## `threads`
591/// [`threads`]: #threads
592///
593/// Benchmarked functions can be run across multiple threads via the [`threads`]
594/// option. This enables you to measure contention on [atomics and
595/// locks][std::sync]. The default thread count is the [available parallelism].
596///
597/// ```
598/// use std::sync::Arc;
599///
600/// #[divan::bench(threads)]
601/// fn arc_clone(bencher: divan::Bencher) {
602/// let arc = Arc::new(42);
603///
604/// bencher.bench(|| arc.clone());
605/// }
606/// ```
607///
608/// The [`threads`] option can be set to any of:
609/// - [`bool`] for [available parallelism] (true) or no parallelism.
610/// - [`usize`] for a specific number of threads. 0 means use [available
611/// parallelism] and 1 means no parallelism.
612/// - [`IntoIterator`] over [`usize`] for multiple thread counts, such as:
613/// - [`Range<usize>`](std::ops::Range)
614/// - [`[usize; N]`](prim@array)
615/// - [`&[usize]`](prim@slice)
616///
617/// ```
618/// #[divan::bench(threads = false)]
619/// fn single() {
620/// // ...
621/// }
622///
623/// #[divan::bench(threads = 10)]
624/// fn specific() {
625/// // ...
626/// }
627///
628/// #[divan::bench(threads = 0..=8)]
629/// fn range() {
630/// // Note: Includes 0 for available parallelism.
631/// }
632///
633/// #[divan::bench(threads = [0, 1, 4, 8, 16])]
634/// fn selection() {
635/// // ...
636/// }
637/// ```
638///
639/// ## `counters`
640/// [`counters`]: #counters
641///
642/// The [`Counter`s](crate::counter::Counter) of each iteration can be set via
643/// the [`counters`] option. The following example emits info for the number of
644/// bytes and number of ints processed when benchmarking [slice sorting](slice::sort):
645///
646/// ```
647/// use divan::{Bencher, counter::{BytesCount, ItemsCount}};
648///
649/// const INTS: &[i32] = &[
650/// // ...
651/// ];
652///
653/// #[divan::bench(counters = [
654/// BytesCount::of_slice(INTS),
655/// ItemsCount::new(INTS.len()),
656/// ])]
657/// fn sort(bencher: Bencher) {
658/// bencher
659/// .with_inputs(|| INTS.to_vec())
660/// .bench_refs(|ints| ints.sort());
661/// }
662/// ```
663///
664/// For convenience, singular `counter` allows a single
665/// [`Counter`](crate::counter::Counter) to be set. The following example emits
666/// info for the number of bytes processed when benchmarking
667/// [`char`-counting](std::str::Chars::count):
668///
669/// ```
670/// use divan::counter::BytesCount;
671///
672/// const STR: &str = "...";
673///
674/// #[divan::bench(counter = BytesCount::of_str(STR))]
675/// fn char_count() -> usize {
676/// divan::black_box(STR).chars().count()
677/// }
678/// ```
679///
680/// See:
681/// - [`#[divan::bench_group(counters = ...)]`](macro@bench_group#counters)
682/// - [`Bencher::counter`]
683/// - [`Bencher::input_counter`]
684///
685/// ### `bytes_count`
686/// [`bytes_count`]: #bytes_count
687///
688/// Convenience shorthand for
689/// <code>[counter](#counters) = [BytesCount](counter::BytesCount)::from(n)</code>.
690///
691/// ### `chars_count`
692/// [`chars_count`]: #chars_count
693///
694/// Convenience shorthand for
695/// <code>[counter](#counters) = [CharsCount](counter::CharsCount)::from(n)</code>.
696///
697/// ### `items_count`
698/// [`items_count`]: #items_count
699///
700/// Convenience shorthand for
701/// <code>[counter](#counters) = [ItemsCount](counter::ItemsCount)::from(n)</code>.
702///
703/// ## `min_time`
704/// [`min_time`]: #min_time
705///
706/// The minimum time spent benchmarking each function can be set to a
707/// predetermined [`Duration`] via the [`min_time`] option. This may be
708/// overridden at runtime using either the `DIVAN_MIN_TIME` environment variable
709/// or `--min-time` CLI argument.
710///
711/// Unless [`skip_ext_time`] is set, this includes time external to the
712/// benchmarked function, such as time spent generating inputs and running
713/// [`Drop`].
714///
715/// ```
716/// use std::time::Duration;
717///
718/// #[divan::bench(min_time = Duration::from_secs(3))]
719/// fn add() -> i32 {
720/// // ...
721/// # 0
722/// }
723/// ```
724///
725/// For convenience, [`min_time`] can also be set with seconds as [`u64`] or
726/// [`f64`]. Invalid values will cause a panic at runtime.
727///
728/// ```
729/// #[divan::bench(min_time = 2)]
730/// fn int_secs() -> i32 {
731/// // ...
732/// # 0
733/// }
734///
735/// #[divan::bench(min_time = 1.5)]
736/// fn float_secs() -> i32 {
737/// // ...
738/// # 0
739/// }
740/// ```
741///
742/// ## `max_time`
743/// [`max_time`]: #max_time
744///
745/// The maximum time spent benchmarking each function can be set to a
746/// predetermined [`Duration`] via the [`max_time`] option. This may be
747/// overridden at runtime using either the `DIVAN_MAX_TIME` environment variable
748/// or `--max-time` CLI argument.
749///
750/// Unless [`skip_ext_time`] is set, this includes time external to the
751/// benchmarked function, such as time spent generating inputs and running
752/// [`Drop`].
753///
754/// If `min_time > max_time`, then [`max_time`] has priority and [`min_time`]
755/// will not be reached.
756///
757/// ```
758/// use std::time::Duration;
759///
760/// #[divan::bench(max_time = Duration::from_secs(5))]
761/// fn add() -> i32 {
762/// // ...
763/// # 0
764/// }
765/// ```
766///
767/// For convenience, like [`min_time`], [`max_time`] can also be set with
768/// seconds as [`u64`] or [`f64`]. Invalid values will cause a panic at runtime.
769///
770/// ```
771/// #[divan::bench(max_time = 8)]
772/// fn int_secs() -> i32 {
773/// // ...
774/// # 0
775/// }
776///
777/// #[divan::bench(max_time = 9.5)]
778/// fn float_secs() -> i32 {
779/// // ...
780/// # 0
781/// }
782/// ```
783///
784/// ## `skip_ext_time`
785/// [`skip_ext_time`]: #skip_ext_time
786///
787/// By default, [`min_time`] and [`max_time`] include time external to the
788/// benchmarked function, such as time spent generating inputs and running
789/// [`Drop`]. Enabling the [`skip_ext_time`] option will instead make those
790/// options only consider time spent within the benchmarked function. This may
791/// be overridden at runtime using either the `DIVAN_SKIP_EXT_TIME` environment
792/// variable or `--skip-ext-time` CLI argument.
793///
794/// In the following example, [`max_time`] only considers time spent running
795/// `measured_function`:
796///
797/// ```
798/// # fn generate_input() {}
799/// # fn measured_function(_: ()) {}
800/// #[divan::bench(max_time = 5, skip_ext_time)]
801/// fn bench(bencher: divan::Bencher) {
802/// bencher
803/// .with_inputs(|| generate_input())
804/// .bench_values(|input| measured_function(input));
805/// }
806/// ```
807///
808/// This option can be set to an explicit [`bool`] value to override parent
809/// values:
810///
811/// ```
812/// #[divan::bench(max_time = 5, skip_ext_time = false)]
813/// fn bench(bencher: divan::Bencher) {
814/// // ...
815/// }
816/// ```
817///
818/// ## `ignore`
819/// [`ignore`]: #ignore
820///
821/// Like [`#[test]`](https://doc.rust-lang.org/reference/attributes/testing.html#the-test-attribute),
822/// `#[divan::bench]` functions can use [`#[ignore]`](https://doc.rust-lang.org/reference/attributes/testing.html#the-ignore-attribute):
823///
824/// ```
825/// #[divan::bench]
826/// #[ignore]
827/// fn todo() {
828/// unimplemented!();
829/// }
830/// # divan::main();
831/// ```
832///
833/// This option can also instead be set within the `#[divan::bench]` attribute:
834///
835/// ```
836/// #[divan::bench(ignore)]
837/// fn todo() {
838/// unimplemented!();
839/// }
840/// # divan::main();
841/// ```
842///
843/// Like [`skip_ext_time`], this option can be set to an explicit [`bool`] value
844/// to override parent values:
845///
846/// ```
847/// #[divan::bench(ignore = false)]
848/// fn bench() {
849/// // ...
850/// }
851/// ```
852///
853/// This can be used to ignore benchmarks based on a runtime condition. The
854/// following example benchmark will be ignored if an [environment
855/// variable](std::env::var) is not set to "true":
856///
857/// ```
858/// #[divan::bench(
859/// ignore = std::env::var("BENCH_EXPENSIVE").as_deref() != Ok("true")
860/// )]
861/// fn expensive_bench() {
862/// // ...
863/// }
864/// ```
865///
866/// [`Any`]: std::any::Any
867/// [`Duration`]: std::time::Duration
868/// [available parallelism]: std::thread::available_parallelism
869pub use divan_macros::bench;
870
871/// Registers a benchmarking group.
872///
873/// # Examples
874///
875/// This is used for setting [options] shared across
876/// [`#[divan::bench]`](macro@bench) functions in the same module:
877///
878/// ```
879/// #[divan::bench_group(
880/// sample_count = 100,
881/// sample_size = 500,
882/// )]
883/// mod math {
884/// use divan::black_box;
885///
886/// #[divan::bench]
887/// fn add() -> i32 {
888/// black_box(1) + black_box(42)
889/// }
890///
891/// #[divan::bench]
892/// fn div() -> i32 {
893/// black_box(1) / black_box(42)
894/// }
895/// }
896///
897/// fn main() {
898/// // Run `math::add` and `math::div` benchmarks:
899/// divan::main();
900/// }
901/// ```
902///
903/// Benchmarking [options] set on parent groups cascade into child groups and
904/// their benchmarks:
905///
906/// ```
907/// #[divan::bench_group(
908/// sample_count = 100,
909/// sample_size = 500,
910/// )]
911/// mod parent {
912/// #[divan::bench_group(sample_size = 1)]
913/// mod child1 {
914/// #[divan::bench]
915/// fn bench() {
916/// // Will be sampled 100 times with 1 iteration per sample.
917/// }
918/// }
919///
920/// #[divan::bench_group(sample_count = 42)]
921/// mod child2 {
922/// #[divan::bench]
923/// fn bench() {
924/// // Will be sampled 42 times with 500 iterations per sample.
925/// }
926/// }
927///
928/// mod child3 {
929/// #[divan::bench(sample_count = 1)]
930/// fn bench() {
931/// // Will be sampled 1 time with 500 iterations per sample.
932/// }
933/// }
934/// }
935/// ```
936///
937/// Applying this attribute multiple times to the same item will cause a compile
938/// error:
939///
940/// ```compile_fail
941/// #[divan::bench_group]
942/// #[divan::bench_group]
943/// mod math {
944/// // ...
945/// }
946/// ```
947///
948/// # Options
949/// [options]: #options
950///
951/// - [`name`]
952/// - [`crate`]
953/// - [`sample_count`]
954/// - [`sample_size`]
955/// - [`threads`]
956/// - [`counters`]
957/// - [`bytes_count`]
958/// - [`chars_count`]
959/// - [`items_count`]
960/// - [`min_time`]
961/// - [`max_time`]
962/// - [`skip_ext_time`]
963/// - [`ignore`]
964///
965/// ## `name`
966/// [`name`]: #name
967///
968/// By default, the benchmark group uses the module's name. It can be overridden
969/// via the `name` option:
970///
971/// ```
972/// #[divan::bench_group(name = "my_math")]
973/// mod math {
974/// #[divan::bench(name = "my_add")]
975/// fn add() -> i32 {
976/// // Will appear as "crate_name::my_math::my_add".
977/// # 0
978/// }
979/// }
980/// ```
981///
982/// ## `crate`
983/// [`crate`]: #crate
984///
985/// The path to the specific `divan` crate instance used by this macro's
986/// generated code can be specified via the [`crate`] option. This is applicable
987/// when using `divan` via a macro from your own crate.
988///
989/// ```
990/// extern crate divan as sofa;
991///
992/// #[::sofa::bench_group(crate = ::sofa)]
993/// mod math {
994/// #[::sofa::bench(crate = ::sofa)]
995/// fn add() -> i32 {
996/// // ...
997/// # 0
998/// }
999/// }
1000/// ```
1001///
1002/// ## `sample_count`
1003/// [`sample_count`]: #sample_count
1004///
1005/// The number of statistical sample recordings can be set to a predetermined
1006/// [`u32`] value via the [`sample_count`] option. This may be overridden at
1007/// runtime using either the `DIVAN_SAMPLE_COUNT` environment variable or
1008/// `--sample-count` CLI argument.
1009///
1010/// ```
1011/// #[divan::bench_group(sample_count = 1000)]
1012/// mod math {
1013/// #[divan::bench]
1014/// fn add() -> i32 {
1015/// // ...
1016/// # 0
1017/// }
1018/// }
1019/// ```
1020///
1021/// If the [`threads`] option is enabled, sample count becomes a multiple of the
1022/// number of threads. This is because each thread operates over the same sample
1023/// size to ensure there are always N competing threads doing the same amount of
1024/// work.
1025///
1026/// ## `sample_size`
1027/// [`sample_size`]: #sample_size
1028///
1029/// The number iterations within each statistical sample can be set to a
1030/// predetermined [`u32`] value via the [`sample_size`] option. This may be
1031/// overridden at runtime using either the `DIVAN_SAMPLE_SIZE` environment
1032/// variable or `--sample-size` CLI argument.
1033///
1034/// ```
1035/// #[divan::bench_group(sample_size = 1000)]
1036/// mod math {
1037/// #[divan::bench]
1038/// fn add() -> i32 {
1039/// // ...
1040/// # 0
1041/// }
1042/// }
1043/// ```
1044///
1045/// ## `threads`
1046/// [`threads`]: #threads
1047///
1048/// See [`#[divan::bench(threads = ...)]`](macro@bench#threads).
1049///
1050/// ## `counters`
1051/// [`counters`]: #counters
1052///
1053/// The [`Counter`s](crate::counter::Counter) of each iteration of benchmarked
1054/// functions in a group can be set via the [`counters`] option. The following
1055/// example emits info for the number of bytes and number of ints processed when
1056/// benchmarking [slice sorting](slice::sort):
1057///
1058/// ```
1059/// use divan::{Bencher, counter::{BytesCount, ItemsCount}};
1060///
1061/// const INTS: &[i32] = &[
1062/// // ...
1063/// ];
1064///
1065/// #[divan::bench_group(counters = [
1066/// BytesCount::of_slice(INTS),
1067/// ItemsCount::new(INTS.len()),
1068/// ])]
1069/// mod sort {
1070/// use super::*;
1071///
1072/// #[divan::bench]
1073/// fn default(bencher: Bencher) {
1074/// bencher
1075/// .with_inputs(|| INTS.to_vec())
1076/// .bench_refs(|ints| ints.sort());
1077/// }
1078///
1079/// #[divan::bench]
1080/// fn unstable(bencher: Bencher) {
1081/// bencher
1082/// .with_inputs(|| INTS.to_vec())
1083/// .bench_refs(|ints| ints.sort_unstable());
1084/// }
1085/// }
1086/// # fn main() {}
1087/// ```
1088///
1089/// For convenience, singular `counter` allows a single
1090/// [`Counter`](crate::counter::Counter) to be set. The following example emits
1091/// info for the number of bytes processed when benchmarking
1092/// [`char`-counting](std::str::Chars::count) and
1093/// [`char`-collecting](std::str::Chars::collect):
1094///
1095/// ```
1096/// use divan::counter::BytesCount;
1097///
1098/// const STR: &str = "...";
1099///
1100/// #[divan::bench_group(counter = BytesCount::of_str(STR))]
1101/// mod chars {
1102/// use super::STR;
1103///
1104/// #[divan::bench]
1105/// fn count() -> usize {
1106/// divan::black_box(STR).chars().count()
1107/// }
1108///
1109/// #[divan::bench]
1110/// fn collect() -> String {
1111/// divan::black_box(STR).chars().collect()
1112/// }
1113/// }
1114/// # fn main() {}
1115/// ```
1116///
1117/// See:
1118/// - [`#[divan::bench(counters = ...)]`](macro@bench#counters)
1119/// - [`Bencher::counter`]
1120/// - [`Bencher::input_counter`]
1121///
1122/// ### `bytes_count`
1123/// [`bytes_count`]: #bytes_count
1124///
1125/// Convenience shorthand for
1126/// <code>[counter](#counters) = [BytesCount](counter::BytesCount)::from(n)</code>.
1127///
1128/// ### `chars_count`
1129/// [`chars_count`]: #chars_count
1130///
1131/// Convenience shorthand for
1132/// <code>[counter](#counters) = [CharsCount](counter::CharsCount)::from(n)</code>.
1133///
1134/// ### `cycles_count`
1135/// [`cycles_count`]: #cycles_count
1136///
1137/// Convenience shorthand for
1138/// <code>[counter](#counters) = [CyclesCount](counter::CyclesCount)::from(n)</code>.
1139///
1140/// ### `items_count`
1141/// [`items_count`]: #items_count
1142///
1143/// Convenience shorthand for
1144/// <code>[counter](#counters) = [ItemsCount](counter::ItemsCount)::from(n)</code>.
1145///
1146/// ## `min_time`
1147/// [`min_time`]: #min_time
1148///
1149/// The minimum time spent benchmarking each function can be set to a
1150/// predetermined [`Duration`] via the [`min_time`] option. This may be
1151/// overridden at runtime using either the `DIVAN_MIN_TIME` environment variable
1152/// or `--min-time` CLI argument.
1153///
1154/// Unless [`skip_ext_time`] is set, this includes time external to benchmarked
1155/// functions, such as time spent generating inputs and running [`Drop`].
1156///
1157/// ```
1158/// use std::time::Duration;
1159///
1160/// #[divan::bench_group(min_time = Duration::from_secs(3))]
1161/// mod math {
1162/// #[divan::bench]
1163/// fn add() -> i32 {
1164/// // ...
1165/// # 0
1166/// }
1167/// }
1168/// ```
1169///
1170/// For convenience, [`min_time`] can also be set with seconds as [`u64`] or
1171/// [`f64`]. Invalid values will cause a panic at runtime.
1172///
1173/// ```
1174/// #[divan::bench_group(min_time = 2)]
1175/// mod int_secs {
1176/// // ...
1177/// }
1178///
1179/// #[divan::bench_group(min_time = 1.5)]
1180/// mod float_secs {
1181/// // ...
1182/// }
1183/// ```
1184///
1185/// ## `max_time`
1186/// [`max_time`]: #max_time
1187///
1188/// The maximum time spent benchmarking each function can be set to a
1189/// predetermined [`Duration`] via the [`max_time`] option. This may be
1190/// overridden at runtime using either the `DIVAN_MAX_TIME` environment variable
1191/// or `--max-time` CLI argument.
1192///
1193/// Unless [`skip_ext_time`] is set, this includes time external to benchmarked
1194/// functions, such as time spent generating inputs and running [`Drop`].
1195///
1196/// If `min_time > max_time`, then [`max_time`] has priority and [`min_time`]
1197/// will not be reached.
1198///
1199/// ```
1200/// use std::time::Duration;
1201///
1202/// #[divan::bench_group(max_time = Duration::from_secs(5))]
1203/// mod math {
1204/// #[divan::bench]
1205/// fn add() -> i32 {
1206/// // ...
1207/// # 0
1208/// }
1209/// }
1210/// ```
1211///
1212/// For convenience, like [`min_time`], [`max_time`] can also be set with
1213/// seconds as [`u64`] or [`f64`]. Invalid values will cause a panic at runtime.
1214///
1215/// ```
1216/// #[divan::bench_group(max_time = 8)]
1217/// mod int_secs {
1218/// // ...
1219/// }
1220///
1221/// #[divan::bench_group(max_time = 9.5)]
1222/// mod float_secs {
1223/// // ...
1224/// }
1225/// ```
1226///
1227/// ## `skip_ext_time`
1228/// [`skip_ext_time`]: #skip_ext_time
1229///
1230/// By default, [`min_time`] and [`max_time`] include time external to
1231/// benchmarked functions, such as time spent generating inputs and running
1232/// [`Drop`]. Enabling the [`skip_ext_time`] option will instead make those
1233/// options only consider time spent within benchmarked functions. This may be
1234/// overridden at runtime using either the `DIVAN_SKIP_EXT_TIME` environment
1235/// variable or `--skip-ext-time` CLI argument.
1236///
1237/// In the following example, [`max_time`] only considers time spent running
1238/// `measured_function`:
1239///
1240/// ```
1241/// #[divan::bench_group(skip_ext_time)]
1242/// mod group {
1243/// # fn generate_input() {}
1244/// # fn measured_function(_: ()) {}
1245/// #[divan::bench(max_time = 5)]
1246/// fn bench(bencher: divan::Bencher) {
1247/// bencher
1248/// .with_inputs(|| generate_input())
1249/// .bench_values(|input| measured_function(input));
1250/// }
1251/// }
1252/// ```
1253///
1254/// This option can be set to an explicit [`bool`] value to override parent
1255/// values:
1256///
1257/// ```
1258/// #[divan::bench_group(skip_ext_time = false)]
1259/// mod group {
1260/// // ...
1261/// }
1262/// ```
1263///
1264/// ## `ignore`
1265/// [`ignore`]: #ignore
1266///
1267/// Like [`#[test]`](https://doc.rust-lang.org/reference/attributes/testing.html#the-test-attribute)
1268/// and [`#[divan::bench]`](macro@bench), `#[divan::bench_group]` functions can
1269/// use [`#[ignore]`](https://doc.rust-lang.org/reference/attributes/testing.html#the-ignore-attribute):
1270///
1271/// ```
1272/// #[divan::bench_group]
1273/// #[ignore]
1274/// mod math {
1275/// #[divan::bench]
1276/// fn todo() {
1277/// unimplemented!();
1278/// }
1279/// }
1280/// # divan::main();
1281/// ```
1282///
1283/// This option can also instead be set within the `#[divan::bench_group]`
1284/// attribute:
1285///
1286/// ```
1287/// #[divan::bench_group(ignore)]
1288/// mod math {
1289/// #[divan::bench]
1290/// fn todo() {
1291/// unimplemented!();
1292/// }
1293/// }
1294/// # divan::main();
1295/// ```
1296///
1297/// Like [`skip_ext_time`], this option can be set to an explicit [`bool`] value
1298/// to override parent values:
1299///
1300/// ```
1301/// #[divan::bench_group(ignore = false)]
1302/// mod group {
1303/// // ...
1304/// }
1305/// ```
1306///
1307/// This can be used to ignore benchmarks based on a runtime condition. The
1308/// following example benchmark group will be ignored if an [environment
1309/// variable](std::env::var) is not set to "true":
1310///
1311/// ```
1312/// #[divan::bench_group(
1313/// ignore = std::env::var("BENCH_EXPENSIVE").as_deref() != Ok("true")
1314/// )]
1315/// mod expensive_benches {
1316/// // ...
1317/// }
1318/// ```
1319///
1320/// [`Duration`]: std::time::Duration
1321pub use divan_macros::bench_group;