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}