iai_callgrind/
lib_bench.rs

1use std::ffi::OsString;
2
3use derive_more::AsRef;
4use iai_callgrind_macros::IntoInner;
5use iai_callgrind_runner::api::ValgrindTool;
6
7use crate::__internal;
8
9/// The main configuration of a library benchmark.
10///
11/// # Examples
12///
13/// ```rust
14/// # use iai_callgrind::{library_benchmark, library_benchmark_group};
15/// use iai_callgrind::{LibraryBenchmarkConfig, main, Callgrind};
16/// # #[library_benchmark]
17/// # fn some_func() {}
18/// # library_benchmark_group!(name = some_group; benchmarks = some_func);
19/// # fn main() {
20/// main!(
21///     config = LibraryBenchmarkConfig::default()
22///                 .tool(Callgrind::with_args(["toggle-collect=something"]));
23///     library_benchmark_groups = some_group
24/// );
25/// # }
26/// ```
27#[derive(Debug, Default, IntoInner, AsRef, Clone)]
28pub struct LibraryBenchmarkConfig(__internal::InternalLibraryBenchmarkConfig);
29
30impl LibraryBenchmarkConfig {
31    /// Change the default tool to something different than callgrind
32    ///
33    /// Any [`ValgrindTool`] is valid, however using cachegrind also requires to use client requests
34    /// to produce correct metrics. The guide fully describes how to use cachegrind instead of
35    /// callgrind.
36    ///
37    /// # Example for dhat
38    ///
39    /// ```rust
40    /// # mod lib { pub fn some_func(value: u64) -> u64 { value + 2 }}
41    /// use iai_callgrind::{
42    ///     main, LibraryBenchmarkConfig, ValgrindTool, library_benchmark_group, library_benchmark
43    /// };
44    ///
45    /// #[library_benchmark]
46    /// fn bench_me() -> u64 {
47    ///     lib::some_func(10)
48    /// }
49    ///
50    /// library_benchmark_group!(
51    ///    name = my_group;
52    ///    benchmarks = bench_me
53    /// );
54    ///
55    /// # fn main() {
56    /// main!(
57    ///     config = LibraryBenchmarkConfig::default()
58    ///         .default_tool(ValgrindTool::DHAT);
59    ///     library_benchmark_groups = my_group
60    /// );
61    /// # }
62    /// ```
63    ///
64    /// # Example for using cachegrind as default tool on the fly
65    ///
66    /// `--instr-at-start=no` is required to only measure the metrics between the two client
67    /// request calls.
68    ///
69    /// ```rust
70    /// # mod lib { pub fn some_func(value: u64) -> u64 { value + 2 }}
71    /// use iai_callgrind::{
72    ///     main, LibraryBenchmarkConfig, ValgrindTool, library_benchmark_group, library_benchmark,
73    ///     Cachegrind
74    /// };
75    /// use iai_callgrind::client_requests::cachegrind as cr;
76    ///
77    /// #[library_benchmark(
78    ///     config = LibraryBenchmarkConfig::default()
79    ///         .default_tool(ValgrindTool::Cachegrind)
80    ///         .tool(Cachegrind::with_args(["--instr-at-start=no"]))
81    /// )]
82    /// fn bench_me() -> u64 {
83    ///     cr::start_instrumentation();
84    ///     let r = lib::some_func(10);
85    ///     cr::stop_instrumentation();
86    ///     r
87    /// }
88    ///
89    /// library_benchmark_group!(
90    ///    name = my_group;
91    ///    benchmarks = bench_me
92    /// );
93    ///
94    /// # fn main() {
95    /// main!(library_benchmark_groups = my_group);
96    /// # }
97    /// ```
98    pub fn default_tool(&mut self, tool: ValgrindTool) -> &mut Self {
99        self.0.default_tool = Some(tool);
100        self
101    }
102
103    /// Pass valgrind arguments to all tools
104    ///
105    /// Only core [valgrind
106    /// arguments](https://valgrind.org/docs/manual/manual-core.html#manual-core.options) are
107    /// allowed.
108    ///
109    /// These arguments can be overwritten by tool specific arguments for example with
110    /// [`crate::Callgrind::args`]
111    ///
112    /// # Examples
113    ///
114    /// Specify `--trace-children=no` for all configured tools (including callgrind):
115    ///
116    /// ```rust
117    /// # use iai_callgrind::{library_benchmark_group, library_benchmark};
118    /// # #[library_benchmark] fn bench_me() {}
119    /// # library_benchmark_group!(
120    /// #    name = my_group;
121    /// #    benchmarks = bench_me
122    /// # );
123    /// use iai_callgrind::{main, LibraryBenchmarkConfig, Dhat};
124    ///
125    /// # fn main() {
126    /// main!(
127    ///     config = LibraryBenchmarkConfig::default()
128    ///         .valgrind_args(["--trace-children=no"])
129    ///         .tool(Dhat::default());
130    ///     library_benchmark_groups = my_group
131    /// );
132    /// # }
133    /// ```
134    ///
135    /// Overwrite the valgrind argument `--num-callers=25` for `DHAT` with `--num-callers=30`:
136    ///
137    /// ```rust
138    /// # use iai_callgrind::{library_benchmark_group, library_benchmark};
139    /// # #[library_benchmark] fn bench_me() {}
140    /// # library_benchmark_group!(
141    /// #    name = my_group;
142    /// #    benchmarks = bench_me
143    /// # );
144    /// use iai_callgrind::{main, LibraryBenchmarkConfig, Dhat};
145    ///
146    /// # fn main() {
147    /// main!(
148    ///     config = LibraryBenchmarkConfig::default()
149    ///         .valgrind_args(["--num-callers=25"])
150    ///         .tool(Dhat::with_args(["--num-callers=30"]));
151    ///     library_benchmark_groups = my_group
152    /// );
153    /// # }
154    /// ```
155    pub fn valgrind_args<I, T>(&mut self, args: T) -> &mut Self
156    where
157        I: AsRef<str>,
158        T: IntoIterator<Item = I>,
159    {
160        self.0.valgrind_args.extend_ignore_flag(args);
161        self
162    }
163
164    /// Clear the environment variables before running a benchmark (Default: true)
165    ///
166    /// # Examples
167    ///
168    /// ```rust
169    /// # use iai_callgrind::{library_benchmark, library_benchmark_group};
170    /// # #[library_benchmark]
171    /// # fn some_func() {}
172    /// # library_benchmark_group!(name = some_group; benchmarks = some_func);
173    /// use iai_callgrind::{LibraryBenchmarkConfig, main};
174    ///
175    /// # fn main() {
176    /// main!(
177    ///     config = LibraryBenchmarkConfig::default().env_clear(false);
178    ///     library_benchmark_groups = some_group
179    /// );
180    /// # }
181    /// ```
182    pub fn env_clear(&mut self, value: bool) -> &mut Self {
183        self.0.env_clear = Some(value);
184        self
185    }
186
187    /// Add an environment variables which will be available in library benchmarks
188    ///
189    /// These environment variables are available independently of the setting of
190    /// [`LibraryBenchmarkConfig::env_clear`].
191    ///
192    /// # Examples
193    ///
194    /// An example for a custom environment variable, available in all benchmarks:
195    ///
196    /// ```rust
197    /// # use iai_callgrind::{library_benchmark, library_benchmark_group};
198    /// # #[library_benchmark]
199    /// # fn some_func() {}
200    /// # library_benchmark_group!(name = some_group; benchmarks = some_func);
201    /// use iai_callgrind::{LibraryBenchmarkConfig, main};
202    ///
203    /// # fn main() {
204    /// main!(
205    ///     config = LibraryBenchmarkConfig::default().env("FOO", "BAR");
206    ///     library_benchmark_groups = some_group
207    /// );
208    /// # }
209    /// ```
210    pub fn env<K, V>(&mut self, key: K, value: V) -> &mut Self
211    where
212        K: Into<OsString>,
213        V: Into<OsString>,
214    {
215        self.0.envs.push((key.into(), Some(value.into())));
216        self
217    }
218
219    /// Add multiple environment variables which will be available in library benchmarks
220    ///
221    /// See also [`LibraryBenchmarkConfig::env`] for more details.
222    ///
223    /// # Examples
224    ///
225    /// ```rust
226    /// # use iai_callgrind::{library_benchmark, library_benchmark_group};
227    /// # #[library_benchmark]
228    /// # fn some_func() {}
229    /// # library_benchmark_group!(name = some_group; benchmarks = some_func);
230    /// use iai_callgrind::{LibraryBenchmarkConfig, main};
231    ///
232    /// # fn main() {
233    /// main!(
234    ///     config =
235    ///         LibraryBenchmarkConfig::default()
236    ///             .envs([("MY_CUSTOM_VAR", "SOME_VALUE"), ("FOO", "BAR")]);
237    ///     library_benchmark_groups = some_group
238    /// );
239    /// # }
240    /// ```
241    pub fn envs<K, V, T>(&mut self, envs: T) -> &mut Self
242    where
243        K: Into<OsString>,
244        V: Into<OsString>,
245        T: IntoIterator<Item = (K, V)>,
246    {
247        self.0
248            .envs
249            .extend(envs.into_iter().map(|(k, v)| (k.into(), Some(v.into()))));
250        self
251    }
252
253    /// Specify a pass-through environment variable
254    ///
255    /// Usually, the environment variables before running a library benchmark are cleared
256    /// but specifying pass-through variables makes this environment variable available to
257    /// the benchmark as it actually appeared in the root environment.
258    ///
259    /// Pass-through environment variables are ignored if they don't exist in the root
260    /// environment.
261    ///
262    /// # Examples
263    ///
264    /// Here, we chose to pass through the original value of the `HOME` variable:
265    ///
266    /// ```rust
267    /// # use iai_callgrind::{library_benchmark, library_benchmark_group};
268    /// # #[library_benchmark]
269    /// # fn some_func() {}
270    /// # library_benchmark_group!(name = some_group; benchmarks = some_func);
271    /// use iai_callgrind::{LibraryBenchmarkConfig, main};
272    ///
273    /// # fn main() {
274    /// main!(
275    ///     config = LibraryBenchmarkConfig::default().pass_through_env("HOME");
276    ///     library_benchmark_groups = some_group
277    /// );
278    /// # }
279    /// ```
280    pub fn pass_through_env<K>(&mut self, key: K) -> &mut Self
281    where
282        K: Into<OsString>,
283    {
284        self.0.envs.push((key.into(), None));
285        self
286    }
287
288    /// Specify multiple pass-through environment variables
289    ///
290    /// See also [`LibraryBenchmarkConfig::pass_through_env`].
291    ///
292    /// # Examples
293    ///
294    /// ```rust
295    /// # use iai_callgrind::{library_benchmark, library_benchmark_group};
296    /// # #[library_benchmark]
297    /// # fn some_func() {}
298    /// # library_benchmark_group!(name = some_group; benchmarks = some_func);
299    /// use iai_callgrind::{LibraryBenchmarkConfig, main};
300    ///
301    /// # fn main() {
302    /// main!(
303    ///     config = LibraryBenchmarkConfig::default().pass_through_envs(["HOME", "USER"]);
304    ///     library_benchmark_groups = some_group
305    /// );
306    /// # }
307    /// ```
308    pub fn pass_through_envs<K, T>(&mut self, envs: T) -> &mut Self
309    where
310        K: Into<OsString>,
311        T: IntoIterator<Item = K>,
312    {
313        self.0
314            .envs
315            .extend(envs.into_iter().map(|k| (k.into(), None)));
316        self
317    }
318
319    /// Add a configuration for a valgrind tool
320    ///
321    /// Valid configurations are [`crate::Callgrind`], [`crate::Cachegrind`], [`crate::Dhat`],
322    /// [`crate::Memcheck`], [`crate::Helgrind`], [`crate::Drd`], [`crate::Massif`] and
323    /// [`crate::Bbv`].
324    ///
325    /// # Example
326    ///
327    /// Run DHAT in addition to callgrind.
328    ///
329    /// ```rust
330    /// # use iai_callgrind::{library_benchmark, library_benchmark_group};
331    /// # #[library_benchmark]
332    /// # fn some_func() {}
333    /// # library_benchmark_group!(name = some_group; benchmarks = some_func);
334    /// use iai_callgrind::{LibraryBenchmarkConfig, main, Dhat};
335    ///
336    /// # fn main() {
337    /// main!(
338    ///     config = LibraryBenchmarkConfig::default()
339    ///         .tool(Dhat::default());
340    ///     library_benchmark_groups = some_group
341    /// );
342    /// # }
343    /// ```
344    pub fn tool<T>(&mut self, tool: T) -> &mut Self
345    where
346        T: Into<__internal::InternalTool>,
347    {
348        self.0.tools.update(tool.into());
349        self
350    }
351
352    /// Override previously defined configurations of valgrind tools
353    ///
354    /// Usually, if specifying tool configurations with [`LibraryBenchmarkConfig::tool`] these tools
355    /// are appended to the configuration of a [`LibraryBenchmarkConfig`] of higher-levels.
356    /// Specifying a tool with this method overrides previously defined configurations.
357    ///
358    /// # Examples
359    ///
360    /// The following will run `DHAT` and `Massif` (and the default callgrind) for all benchmarks in
361    /// `main!` besides for `some_func` which will just run `Memcheck` (and callgrind).
362    ///
363    /// ```rust
364    /// use iai_callgrind::{
365    ///     main, library_benchmark, library_benchmark_group, LibraryBenchmarkConfig, Memcheck,
366    ///     Massif, Dhat
367    /// };
368    ///
369    /// #[library_benchmark(config = LibraryBenchmarkConfig::default()
370    ///     .tool_override(Memcheck::default())
371    /// )]
372    /// fn some_func() {}
373    ///
374    /// library_benchmark_group!(
375    ///     name = some_group;
376    ///     benchmarks = some_func
377    /// );
378    ///
379    /// # fn main() {
380    /// main!(
381    ///     config = LibraryBenchmarkConfig::default()
382    ///         .tool(Dhat::default())
383    ///         .tool(Massif::default());
384    ///     library_benchmark_groups = some_group
385    /// );
386    /// # }
387    /// ```
388    pub fn tool_override<T>(&mut self, tool: T) -> &mut Self
389    where
390        T: Into<__internal::InternalTool>,
391    {
392        self.0
393            .tools_override
394            .get_or_insert(__internal::InternalTools::default())
395            .update(tool.into());
396        self
397    }
398
399    /// Configure the [`crate::OutputFormat`] of the terminal output of Iai-Callgrind
400    ///
401    /// # Examples
402    ///
403    /// ```rust
404    /// use iai_callgrind::{main, LibraryBenchmarkConfig, OutputFormat};
405    /// # use iai_callgrind::{library_benchmark, library_benchmark_group};
406    /// # #[library_benchmark]
407    /// # fn some_func() {}
408    /// # library_benchmark_group!(
409    /// #    name = some_group;
410    /// #    benchmarks = some_func
411    /// # );
412    /// # fn main() {
413    /// main!(
414    ///     config = LibraryBenchmarkConfig::default()
415    ///         .output_format(OutputFormat::default()
416    ///             .truncate_description(Some(200))
417    ///         );
418    ///     library_benchmark_groups = some_group
419    /// );
420    /// # }
421    pub fn output_format<T>(&mut self, output_format: T) -> &mut Self
422    where
423        T: Into<__internal::InternalOutputFormat>,
424    {
425        self.0.output_format = Some(output_format.into());
426        self
427    }
428}