• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use super::*;
2 use crate::kde;
3 use crate::measurement::ValueFormatter;
4 use crate::report::{BenchmarkId, ComparisonData, MeasurementData, ReportContext};
5 use std::process::Child;
6 
pdf( id: &BenchmarkId, context: &ReportContext, formatter: &dyn ValueFormatter, measurements: &MeasurementData<'_>, size: Option<Size>, ) -> Child7 pub(crate) fn pdf(
8     id: &BenchmarkId,
9     context: &ReportContext,
10     formatter: &dyn ValueFormatter,
11     measurements: &MeasurementData<'_>,
12     size: Option<Size>,
13 ) -> Child {
14     let avg_times = &measurements.avg_times;
15     let typical = avg_times.max();
16     let mut scaled_avg_times: Vec<f64> = (avg_times as &Sample<f64>).iter().cloned().collect();
17     let unit = formatter.scale_values(typical, &mut scaled_avg_times);
18     let scaled_avg_times = Sample::new(&scaled_avg_times);
19 
20     let mean = scaled_avg_times.mean();
21 
22     let iter_counts = measurements.iter_counts();
23     let &max_iters = iter_counts
24         .iter()
25         .max_by_key(|&&iters| iters as u64)
26         .unwrap();
27     let exponent = (max_iters.log10() / 3.).floor() as i32 * 3;
28     let y_scale = 10f64.powi(-exponent);
29 
30     let y_label = if exponent == 0 {
31         "Iterations".to_owned()
32     } else {
33         format!("Iterations (x 10^{})", exponent)
34     };
35 
36     let (xs, ys) = kde::sweep(scaled_avg_times, KDE_POINTS, None);
37     let (lost, lomt, himt, hist) = avg_times.fences();
38     let mut fences = [lost, lomt, himt, hist];
39     let _ = formatter.scale_values(typical, &mut fences);
40     let [lost, lomt, himt, hist] = fences;
41 
42     let vertical = &[0., max_iters];
43     let zeros = iter::repeat(0);
44 
45     let mut figure = Figure::new();
46     figure
47         .set(Font(DEFAULT_FONT))
48         .set(size.unwrap_or(SIZE))
49         .configure(Axis::BottomX, |a| {
50             let xs_ = Sample::new(&xs);
51             a.set(Label(format!("Average time ({})", unit)))
52                 .set(Range::Limits(xs_.min(), xs_.max()))
53         })
54         .configure(Axis::LeftY, |a| {
55             a.set(Label(y_label))
56                 .set(Range::Limits(0., max_iters * y_scale))
57                 .set(ScaleFactor(y_scale))
58         })
59         .configure(Axis::RightY, |a| a.set(Label("Density (a.u.)")))
60         .configure(Key, |k| {
61             k.set(Justification::Left)
62                 .set(Order::SampleText)
63                 .set(Position::Outside(Vertical::Top, Horizontal::Right))
64         })
65         .plot(
66             FilledCurve {
67                 x: &*xs,
68                 y1: &*ys,
69                 y2: zeros,
70             },
71             |c| {
72                 c.set(Axes::BottomXRightY)
73                     .set(DARK_BLUE)
74                     .set(Label("PDF"))
75                     .set(Opacity(0.25))
76             },
77         )
78         .plot(
79             Lines {
80                 x: &[mean, mean],
81                 y: vertical,
82             },
83             |c| {
84                 c.set(DARK_BLUE)
85                     .set(LINEWIDTH)
86                     .set(LineType::Dash)
87                     .set(Label("Mean"))
88             },
89         )
90         .plot(
91             Points {
92                 x: avg_times
93                     .iter()
94                     .zip(scaled_avg_times.iter())
95                     .filter_map(
96                         |((_, label), t)| {
97                             if label.is_outlier() {
98                                 None
99                             } else {
100                                 Some(t)
101                             }
102                         },
103                     ),
104                 y: avg_times
105                     .iter()
106                     .zip(iter_counts.iter())
107                     .filter_map(
108                         |((_, label), i)| {
109                             if label.is_outlier() {
110                                 None
111                             } else {
112                                 Some(i)
113                             }
114                         },
115                     ),
116             },
117             |c| {
118                 c.set(DARK_BLUE)
119                     .set(Label("\"Clean\" sample"))
120                     .set(PointType::FilledCircle)
121                     .set(POINT_SIZE)
122             },
123         )
124         .plot(
125             Points {
126                 x: avg_times
127                     .iter()
128                     .zip(scaled_avg_times.iter())
129                     .filter_map(
130                         |((_, label), t)| {
131                             if label.is_mild() {
132                                 Some(t)
133                             } else {
134                                 None
135                             }
136                         },
137                     ),
138                 y: avg_times
139                     .iter()
140                     .zip(iter_counts.iter())
141                     .filter_map(
142                         |((_, label), i)| {
143                             if label.is_mild() {
144                                 Some(i)
145                             } else {
146                                 None
147                             }
148                         },
149                     ),
150             },
151             |c| {
152                 c.set(DARK_ORANGE)
153                     .set(Label("Mild outliers"))
154                     .set(POINT_SIZE)
155                     .set(PointType::FilledCircle)
156             },
157         )
158         .plot(
159             Points {
160                 x: avg_times
161                     .iter()
162                     .zip(scaled_avg_times.iter())
163                     .filter_map(
164                         |((_, label), t)| {
165                             if label.is_severe() {
166                                 Some(t)
167                             } else {
168                                 None
169                             }
170                         },
171                     ),
172                 y: avg_times
173                     .iter()
174                     .zip(iter_counts.iter())
175                     .filter_map(
176                         |((_, label), i)| {
177                             if label.is_severe() {
178                                 Some(i)
179                             } else {
180                                 None
181                             }
182                         },
183                     ),
184             },
185             |c| {
186                 c.set(DARK_RED)
187                     .set(Label("Severe outliers"))
188                     .set(POINT_SIZE)
189                     .set(PointType::FilledCircle)
190             },
191         )
192         .plot(
193             Lines {
194                 x: &[lomt, lomt],
195                 y: vertical,
196             },
197             |c| c.set(DARK_ORANGE).set(LINEWIDTH).set(LineType::Dash),
198         )
199         .plot(
200             Lines {
201                 x: &[himt, himt],
202                 y: vertical,
203             },
204             |c| c.set(DARK_ORANGE).set(LINEWIDTH).set(LineType::Dash),
205         )
206         .plot(
207             Lines {
208                 x: &[lost, lost],
209                 y: vertical,
210             },
211             |c| c.set(DARK_RED).set(LINEWIDTH).set(LineType::Dash),
212         )
213         .plot(
214             Lines {
215                 x: &[hist, hist],
216                 y: vertical,
217             },
218             |c| c.set(DARK_RED).set(LINEWIDTH).set(LineType::Dash),
219         );
220     figure.set(Title(gnuplot_escape(id.as_title())));
221 
222     let path = context.report_path(id, "pdf.svg");
223     debug_script(&path, &figure);
224     figure.set(Output(path)).draw().unwrap()
225 }
226 
pdf_small( id: &BenchmarkId, context: &ReportContext, formatter: &dyn ValueFormatter, measurements: &MeasurementData<'_>, size: Option<Size>, ) -> Child227 pub(crate) fn pdf_small(
228     id: &BenchmarkId,
229     context: &ReportContext,
230     formatter: &dyn ValueFormatter,
231     measurements: &MeasurementData<'_>,
232     size: Option<Size>,
233 ) -> Child {
234     let avg_times = &*measurements.avg_times;
235     let typical = avg_times.max();
236     let mut scaled_avg_times: Vec<f64> = (avg_times as &Sample<f64>).iter().cloned().collect();
237     let unit = formatter.scale_values(typical, &mut scaled_avg_times);
238     let scaled_avg_times = Sample::new(&scaled_avg_times);
239     let mean = scaled_avg_times.mean();
240 
241     let (xs, ys, mean_y) = kde::sweep_and_estimate(scaled_avg_times, KDE_POINTS, None, mean);
242     let xs_ = Sample::new(&xs);
243     let ys_ = Sample::new(&ys);
244 
245     let y_limit = ys_.max() * 1.1;
246     let zeros = iter::repeat(0);
247 
248     let mut figure = Figure::new();
249     figure
250         .set(Font(DEFAULT_FONT))
251         .set(size.unwrap_or(SIZE))
252         .configure(Axis::BottomX, |a| {
253             a.set(Label(format!("Average time ({})", unit)))
254                 .set(Range::Limits(xs_.min(), xs_.max()))
255         })
256         .configure(Axis::LeftY, |a| {
257             a.set(Label("Density (a.u.)"))
258                 .set(Range::Limits(0., y_limit))
259         })
260         .configure(Axis::RightY, |a| a.hide())
261         .configure(Key, |k| k.hide())
262         .plot(
263             FilledCurve {
264                 x: &*xs,
265                 y1: &*ys,
266                 y2: zeros,
267             },
268             |c| {
269                 c.set(Axes::BottomXRightY)
270                     .set(DARK_BLUE)
271                     .set(Label("PDF"))
272                     .set(Opacity(0.25))
273             },
274         )
275         .plot(
276             Lines {
277                 x: &[mean, mean],
278                 y: &[0., mean_y],
279             },
280             |c| c.set(DARK_BLUE).set(LINEWIDTH).set(Label("Mean")),
281         );
282 
283     let path = context.report_path(id, "pdf_small.svg");
284     debug_script(&path, &figure);
285     figure.set(Output(path)).draw().unwrap()
286 }
287 
pdf_comparison_figure( formatter: &dyn ValueFormatter, measurements: &MeasurementData<'_>, comparison: &ComparisonData, size: Option<Size>, ) -> Figure288 fn pdf_comparison_figure(
289     formatter: &dyn ValueFormatter,
290     measurements: &MeasurementData<'_>,
291     comparison: &ComparisonData,
292     size: Option<Size>,
293 ) -> Figure {
294     let base_avg_times = Sample::new(&comparison.base_avg_times);
295     let typical = base_avg_times.max().max(measurements.avg_times.max());
296     let mut scaled_base_avg_times: Vec<f64> = comparison.base_avg_times.clone();
297     let unit = formatter.scale_values(typical, &mut scaled_base_avg_times);
298     let scaled_base_avg_times = Sample::new(&scaled_base_avg_times);
299 
300     let mut scaled_new_avg_times: Vec<f64> = (&measurements.avg_times as &Sample<f64>)
301         .iter()
302         .cloned()
303         .collect();
304     let _ = formatter.scale_values(typical, &mut scaled_new_avg_times);
305     let scaled_new_avg_times = Sample::new(&scaled_new_avg_times);
306 
307     let base_mean = scaled_base_avg_times.mean();
308     let new_mean = scaled_new_avg_times.mean();
309 
310     let (base_xs, base_ys, base_y_mean) =
311         kde::sweep_and_estimate(scaled_base_avg_times, KDE_POINTS, None, base_mean);
312     let (xs, ys, y_mean) =
313         kde::sweep_and_estimate(scaled_new_avg_times, KDE_POINTS, None, new_mean);
314 
315     let zeros = iter::repeat(0);
316 
317     let mut figure = Figure::new();
318     figure
319         .set(Font(DEFAULT_FONT))
320         .set(size.unwrap_or(SIZE))
321         .configure(Axis::BottomX, |a| {
322             a.set(Label(format!("Average time ({})", unit)))
323         })
324         .configure(Axis::LeftY, |a| a.set(Label("Density (a.u.)")))
325         .configure(Axis::RightY, |a| a.hide())
326         .configure(Key, |k| {
327             k.set(Justification::Left)
328                 .set(Order::SampleText)
329                 .set(Position::Outside(Vertical::Top, Horizontal::Right))
330         })
331         .plot(
332             FilledCurve {
333                 x: &*base_xs,
334                 y1: &*base_ys,
335                 y2: zeros.clone(),
336             },
337             |c| c.set(DARK_RED).set(Label("Base PDF")).set(Opacity(0.5)),
338         )
339         .plot(
340             Lines {
341                 x: &[base_mean, base_mean],
342                 y: &[0., base_y_mean],
343             },
344             |c| c.set(DARK_RED).set(Label("Base Mean")).set(LINEWIDTH),
345         )
346         .plot(
347             FilledCurve {
348                 x: &*xs,
349                 y1: &*ys,
350                 y2: zeros,
351             },
352             |c| c.set(DARK_BLUE).set(Label("New PDF")).set(Opacity(0.5)),
353         )
354         .plot(
355             Lines {
356                 x: &[new_mean, new_mean],
357                 y: &[0., y_mean],
358             },
359             |c| c.set(DARK_BLUE).set(Label("New Mean")).set(LINEWIDTH),
360         );
361     figure
362 }
363 
pdf_comparison( id: &BenchmarkId, context: &ReportContext, formatter: &dyn ValueFormatter, measurements: &MeasurementData<'_>, comparison: &ComparisonData, size: Option<Size>, ) -> Child364 pub(crate) fn pdf_comparison(
365     id: &BenchmarkId,
366     context: &ReportContext,
367     formatter: &dyn ValueFormatter,
368     measurements: &MeasurementData<'_>,
369     comparison: &ComparisonData,
370     size: Option<Size>,
371 ) -> Child {
372     let mut figure = pdf_comparison_figure(formatter, measurements, comparison, size);
373     figure.set(Title(gnuplot_escape(id.as_title())));
374     let path = context.report_path(id, "both/pdf.svg");
375     debug_script(&path, &figure);
376     figure.set(Output(path)).draw().unwrap()
377 }
378 
pdf_comparison_small( id: &BenchmarkId, context: &ReportContext, formatter: &dyn ValueFormatter, measurements: &MeasurementData<'_>, comparison: &ComparisonData, size: Option<Size>, ) -> Child379 pub(crate) fn pdf_comparison_small(
380     id: &BenchmarkId,
381     context: &ReportContext,
382     formatter: &dyn ValueFormatter,
383     measurements: &MeasurementData<'_>,
384     comparison: &ComparisonData,
385     size: Option<Size>,
386 ) -> Child {
387     let mut figure = pdf_comparison_figure(formatter, measurements, comparison, size);
388     figure.configure(Key, |k| k.hide());
389     let path = context.report_path(id, "relative_pdf_small.svg");
390     debug_script(&path, &figure);
391     figure.set(Output(path)).draw().unwrap()
392 }
393