1 | use std::process::Child; |
2 | |
3 | use criterion_plot::prelude::*; |
4 | |
5 | use super::*; |
6 | use crate::report::{BenchmarkId, ComparisonData, MeasurementData, ReportContext}; |
7 | |
8 | use crate::measurement::ValueFormatter; |
9 | |
10 | fn 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 | |
46 | pub(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 | |
66 | pub(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 | |
81 | fn 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 | |
143 | pub(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 | |
159 | pub(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 | |