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