1use std::process::Child;
2
3use criterion_plot::prelude::*;
4
5use super::*;
6use crate::report::{BenchmarkId, ComparisonData, MeasurementData, ReportContext};
7
8use crate::measurement::ValueFormatter;
9
10fn iteration_times_figure(
11 formatter: &dyn ValueFormatter,
12 measurements: &MeasurementData<'_>,
13 size: Option<Size>,
14) -> Figure {
15 let data = &measurements.avg_times;
16 let max_avg_time = data.max();
17 let mut scaled_y: Vec<_> = data.iter().map(|(f, _)| f).collect();
18 let unit = formatter.scale_values(max_avg_time, &mut scaled_y);
19 let scaled_y = Sample::new(&scaled_y);
20
21 let mut figure = Figure::new();
22 figure
23 .set(Font(DEFAULT_FONT))
24 .set(size.unwrap_or(SIZE))
25 .configure(Axis::BottomX, |a| {
26 a.configure(Grid::Major, |g| g.show()).set(Label("Sample"))
27 })
28 .configure(Axis::LeftY, |a| {
29 a.configure(Grid::Major, |g| g.show())
30 .set(Label(format!("Average Iteration Time ({})", unit)))
31 })
32 .plot(
33 Points {
34 x: 1..(data.len() + 1),
35 y: scaled_y.as_ref(),
36 },
37 |c| {
38 c.set(DARK_BLUE)
39 .set(PointSize(0.5))
40 .set(PointType::FilledCircle)
41 },
42 );
43 figure
44}
45
46pub(crate) fn iteration_times(
47 id: &BenchmarkId,
48 context: &ReportContext,
49 formatter: &dyn ValueFormatter,
50 measurements: &MeasurementData<'_>,
51 size: Option<Size>,
52) -> Child {
53 let mut figure = iteration_times_figure(formatter, measurements, size);
54 figure.set(Title(gnuplot_escape(id.as_title())));
55 figure.configure(Key, |k| {
56 k.set(Justification::Left)
57 .set(Order::SampleText)
58 .set(Position::Inside(Vertical::Top, Horizontal::Left))
59 });
60
61 let path = context.report_path(id, "iteration_times.svg");
62 debug_script(&path, &figure);
63 figure.set(Output(path)).draw().unwrap()
64}
65
66pub(crate) fn iteration_times_small(
67 id: &BenchmarkId,
68 context: &ReportContext,
69 formatter: &dyn ValueFormatter,
70 measurements: &MeasurementData<'_>,
71 size: Option<Size>,
72) -> Child {
73 let mut figure = iteration_times_figure(formatter, measurements, size);
74 figure.configure(Key, |k| k.hide());
75
76 let path = context.report_path(id, "iteration_times_small.svg");
77 debug_script(&path, &figure);
78 figure.set(Output(path)).draw().unwrap()
79}
80
81fn iteration_times_comparison_figure(
82 formatter: &dyn ValueFormatter,
83 measurements: &MeasurementData<'_>,
84 comparison: &ComparisonData,
85 size: Option<Size>,
86) -> Figure {
87 let current_data = &measurements.avg_times;
88 let base_data = &comparison.base_avg_times;
89
90 let mut all_data: Vec<f64> = current_data.iter().map(|(f, _)| f).collect();
91 all_data.extend_from_slice(base_data);
92
93 let typical_value = Sample::new(&all_data).max();
94 let unit = formatter.scale_values(typical_value, &mut all_data);
95
96 let (scaled_current_y, scaled_base_y) = all_data.split_at(current_data.len());
97 let scaled_current_y = Sample::new(scaled_current_y);
98 let scaled_base_y = Sample::new(scaled_base_y);
99
100 let mut figure = Figure::new();
101 figure
102 .set(Font(DEFAULT_FONT))
103 .set(size.unwrap_or(SIZE))
104 .configure(Axis::BottomX, |a| {
105 a.configure(Grid::Major, |g| g.show()).set(Label("Sample"))
106 })
107 .configure(Axis::LeftY, |a| {
108 a.configure(Grid::Major, |g| g.show())
109 .set(Label(format!("Average Iteration Time ({})", unit)))
110 })
111 .configure(Key, |k| {
112 k.set(Justification::Left)
113 .set(Order::SampleText)
114 .set(Position::Inside(Vertical::Top, Horizontal::Left))
115 })
116 .plot(
117 Points {
118 x: 1..(current_data.len() + 1),
119 y: scaled_base_y.as_ref(),
120 },
121 |c| {
122 c.set(DARK_RED)
123 .set(Label("Base"))
124 .set(PointSize(0.5))
125 .set(PointType::FilledCircle)
126 },
127 )
128 .plot(
129 Points {
130 x: 1..(current_data.len() + 1),
131 y: scaled_current_y.as_ref(),
132 },
133 |c| {
134 c.set(DARK_BLUE)
135 .set(Label("Current"))
136 .set(PointSize(0.5))
137 .set(PointType::FilledCircle)
138 },
139 );
140 figure
141}
142
143pub(crate) fn iteration_times_comparison(
144 id: &BenchmarkId,
145 context: &ReportContext,
146 formatter: &dyn ValueFormatter,
147 measurements: &MeasurementData<'_>,
148 comparison: &ComparisonData,
149 size: Option<Size>,
150) -> Child {
151 let mut figure = iteration_times_comparison_figure(formatter, measurements, comparison, size);
152 figure.set(Title(gnuplot_escape(id.as_title())));
153
154 let path = context.report_path(id, "both/iteration_times.svg");
155 debug_script(&path, &figure);
156 figure.set(Output(path)).draw().unwrap()
157}
158
159pub(crate) fn iteration_times_comparison_small(
160 id: &BenchmarkId,
161 context: &ReportContext,
162 formatter: &dyn ValueFormatter,
163 measurements: &MeasurementData<'_>,
164 comparison: &ComparisonData,
165 size: Option<Size>,
166) -> Child {
167 let mut figure = iteration_times_comparison_figure(formatter, measurements, comparison, size);
168 figure.configure(Key, |k| k.hide());
169
170 let path = context.report_path(id, "relative_iteration_times_small.svg");
171 debug_script(&path, &figure);
172 figure.set(Output(path)).draw().unwrap()
173}
174