binggan/
bench_input_group.rs1use std::mem;
2
3use crate::output_value::OutputValue;
4use crate::plugins::{EventListener, PluginManager};
5use crate::{
6 bench::NamedBench, bench_id::BenchId, bench_runner::BenchRunner, parse_args, BenchGroup, Config,
7};
8
9pub struct InputGroup<I: 'static = (), O = ()> {
16 inputs: Vec<OwnedNamedInput<I>>,
17 benches_per_input: Vec<Vec<NamedBench<'static, I, O>>>,
18 runner: BenchRunner,
19}
20
21impl Default for InputGroup<()> {
22 fn default() -> Self {
23 Self::new()
24 }
25}
26
27impl InputGroup<(), ()> {
28 pub fn new() -> Self {
30 Self::new_with_inputs(vec![("", ())])
31 }
32}
33
34pub struct OwnedNamedInput<I> {
36 pub(crate) name: String,
37 pub(crate) data: I,
38 pub(crate) input_size_in_bytes: Option<usize>,
39}
40
41impl<I: 'static, O: OutputValue + 'static> InputGroup<I, O> {
42 pub fn new_with_inputs<S: Into<String>>(inputs: Vec<(S, I)>) -> Self {
45 Self::new_with_inputs_and_options(inputs, parse_args())
46 }
47 pub(crate) fn new_with_inputs_and_options<S: Into<String>>(
50 inputs: Vec<(S, I)>,
51 options: Config,
52 ) -> Self {
53 use yansi::Condition;
54 yansi::whenever(Condition::TTY_AND_COLOR);
55
56 let inputs: Vec<OwnedNamedInput<I>> = inputs
57 .into_iter()
58 .map(|(name, input)| OwnedNamedInput {
59 name: name.into(),
60 data: input,
61 input_size_in_bytes: None,
62 })
63 .collect();
64 let runner = BenchRunner::new_with_options(options);
65 let mut benches_per_input = Vec::new();
66 for _input in &inputs {
68 benches_per_input.push(Vec::new());
69 }
70
71 InputGroup {
72 inputs,
73 runner,
74 benches_per_input,
75 }
76 }
77
78 pub fn throughput<F>(&mut self, f: F)
81 where
82 F: Fn(&I) -> usize + 'static,
83 {
84 for input in &mut self.inputs {
85 input.input_size_in_bytes = Some(f(&input.data));
86 }
87 }
88
89 pub fn register<F, S: Into<String>>(&mut self, name: S, fun: F)
93 where
94 F: Fn(&I) -> O + 'static + Clone,
95 {
96 let name = name.into();
97
98 let num_iter_for_group = self.config().get_num_iter_for_group();
99 for (ord, input) in self.inputs.iter().enumerate() {
100 let bench_id = BenchId::from_bench_name(name.clone())
101 .runner_name(self.runner.name.as_deref())
102 .group_name(Some(input.name.clone()));
103 let named_bench: NamedBench<'static, I, O> =
104 NamedBench::new(bench_id, Box::new(fun.clone()), num_iter_for_group);
105
106 self.benches_per_input[ord].push(named_bench);
107 }
108 }
109
110 pub fn run(&mut self) {
112 let mut benches_per_input = mem::take(&mut self.benches_per_input);
113 for (ord, benches) in benches_per_input.iter_mut().enumerate() {
114 let input = &self.inputs[ord];
115 let mut group = BenchGroup::new(&mut self.runner);
116 group.set_name(&input.name);
117 benches.reverse();
119 while let Some(bench) = benches.pop() {
120 let extended_input = unsafe { transmute_lifetime(&input.data) };
123
124 if let Some(input_size) = input.input_size_in_bytes {
125 group.set_input_size(input_size);
126 }
127 group.register_named_with_input(bench, extended_input);
128 }
129 group.run();
130 }
131 }
132
133 pub fn set_name<S: AsRef<str>>(&mut self, name: S) {
137 self.runner.set_name(name);
138 }
139
140 pub fn config(&mut self) -> &mut Config {
144 &mut self.runner.config
145 }
146
147 pub fn get_plugin_manager(&mut self) -> &mut PluginManager {
150 self.runner.get_plugin_manager()
151 }
152
153 pub fn add_plugin<L: EventListener + 'static>(&mut self, listener: L) -> &mut PluginManager {
155 self.get_plugin_manager().add_plugin(listener)
156 }
157}
158
159unsafe fn transmute_lifetime<I>(input: &I) -> &'static I {
160 mem::transmute(input)
161}