| use super::*; | |
| use kde; | |
| use report::{BenchmarkId, ComparisonData, MeasurementData, ReportContext}; | |
| use std::process::Child; | |
| pub(crate) fn pdf( | |
| id: &BenchmarkId, | |
| context: &ReportContext, | |
| measurements: &MeasurementData, | |
| size: Option<Size>, | |
| ) -> Child { | |
| let avg_times = &measurements.avg_times; | |
| let mean = avg_times.mean(); | |
| let iter_counts = measurements.iter_counts(); | |
| let &max_iters = iter_counts | |
| .iter() | |
| .max_by_key(|&&iters| iters as u64) | |
| .unwrap(); | |
| let exponent = (max_iters.log10() / 3.).floor() as i32 * 3; | |
| let y_scale = 10f64.powi(-exponent); | |
| let y_label = if exponent == 0 { | |
| "Iterations".to_owned() | |
| } else { | |
| format!("Iterations (x 10^{})", exponent) | |
| }; | |
| let (xs, ys) = kde::sweep(&avg_times, KDE_POINTS, None); | |
| let (lost, lomt, himt, hist) = avg_times.fences(); | |
| let vertical = &[0., max_iters]; | |
| let zeros = iter::repeat(0); | |
| let mut figure = Figure::new(); | |
| figure | |
| .set(Font(DEFAULT_FONT)) | |
| .set(size.unwrap_or(SIZE)) | |
| .configure(Axis::BottomX, |a| { | |
| let (x_scale, prefix) = scale_time(avg_times.max()); | |
| let xs_ = Sample::new(&xs); | |
| a.set(Label(format!("Average time ({}s)", prefix))) | |
| .set(Range::Limits(xs_.min() * x_scale, xs_.max() * x_scale)) | |
| .set(ScaleFactor(x_scale)) | |
| }) | |
| .configure(Axis::LeftY, |a| { | |
| a.set(Label(y_label)) | |
| .set(Range::Limits(0., max_iters * y_scale)) | |
| .set(ScaleFactor(y_scale)) | |
| }) | |
| .configure(Axis::RightY, |a| a.set(Label("Density (a.u.)"))) | |
| .configure(Key, |k| { | |
| k.set(Justification::Left) | |
| .set(Order::SampleText) | |
| .set(Position::Outside(Vertical::Top, Horizontal::Right)) | |
| }) | |
| .plot( | |
| FilledCurve { | |
| x: &*xs, | |
| y1: &*ys, | |
| y2: zeros, | |
| }, | |
| |c| { | |
| c.set(Axes::BottomXRightY) | |
| .set(DARK_BLUE) | |
| .set(Label("PDF")) | |
| .set(Opacity(0.25)) | |
| }, | |
| ) | |
| .plot( | |
| Lines { | |
| x: &[mean, mean], | |
| y: vertical, | |
| }, | |
| |c| { | |
| c.set(DARK_BLUE) | |
| .set(LINEWIDTH) | |
| .set(LineType::Dash) | |
| .set(Label("Mean")) | |
| }, | |
| ) | |
| .plot( | |
| Points { | |
| x: avg_times.iter().filter_map( | |
| |(t, label)| { | |
| if label.is_outlier() { | |
| None | |
| } else { | |
| Some(t) | |
| } | |
| }, | |
| ), | |
| y: avg_times | |
| .iter() | |
| .zip(iter_counts.iter()) | |
| .filter_map( | |
| |((_, label), i)| { | |
| if label.is_outlier() { | |
| None | |
| } else { | |
| Some(i) | |
| } | |
| }, | |
| ), | |
| }, | |
| |c| { | |
| c.set(DARK_BLUE) | |
| .set(Label("\"Clean\" sample")) | |
| .set(PointType::FilledCircle) | |
| .set(POINT_SIZE) | |
| }, | |
| ) | |
| .plot( | |
| Points { | |
| x: avg_times.iter().filter_map( | |
| |(x, label)| { | |
| if label.is_mild() { | |
| Some(x) | |
| } else { | |
| None | |
| } | |
| }, | |
| ), | |
| y: avg_times | |
| .iter() | |
| .zip(iter_counts.iter()) | |
| .filter_map( | |
| |((_, label), i)| { | |
| if label.is_mild() { | |
| Some(i) | |
| } else { | |
| None | |
| } | |
| }, | |
| ), | |
| }, | |
| |c| { | |
| c.set(DARK_ORANGE) | |
| .set(Label("Mild outliers")) | |
| .set(POINT_SIZE) | |
| .set(PointType::FilledCircle) | |
| }, | |
| ) | |
| .plot( | |
| Points { | |
| x: avg_times.iter().filter_map( | |
| |(x, label)| { | |
| if label.is_severe() { | |
| Some(x) | |
| } else { | |
| None | |
| } | |
| }, | |
| ), | |
| y: avg_times | |
| .iter() | |
| .zip(iter_counts.iter()) | |
| .filter_map( | |
| |((_, label), i)| { | |
| if label.is_severe() { | |
| Some(i) | |
| } else { | |
| None | |
| } | |
| }, | |
| ), | |
| }, | |
| |c| { | |
| c.set(DARK_RED) | |
| .set(Label("Severe outliers")) | |
| .set(POINT_SIZE) | |
| .set(PointType::FilledCircle) | |
| }, | |
| ) | |
| .plot( | |
| Lines { | |
| x: &[lomt, lomt], | |
| y: vertical, | |
| }, | |
| |c| c.set(DARK_ORANGE).set(LINEWIDTH).set(LineType::Dash), | |
| ) | |
| .plot( | |
| Lines { | |
| x: &[himt, himt], | |
| y: vertical, | |
| }, | |
| |c| c.set(DARK_ORANGE).set(LINEWIDTH).set(LineType::Dash), | |
| ) | |
| .plot( | |
| Lines { | |
| x: &[lost, lost], | |
| y: vertical, | |
| }, | |
| |c| c.set(DARK_RED).set(LINEWIDTH).set(LineType::Dash), | |
| ) | |
| .plot( | |
| Lines { | |
| x: &[hist, hist], | |
| y: vertical, | |
| }, | |
| |c| c.set(DARK_RED).set(LINEWIDTH).set(LineType::Dash), | |
| ); | |
| figure.set(Title(escape_underscores(id.as_title()))); | |
| let path = context.report_path(id, "pdf.svg"); | |
| debug_script(&path, &figure); | |
| figure.set(Output(path)).draw().unwrap() | |
| } | |
| pub(crate) fn pdf_small( | |
| id: &BenchmarkId, | |
| context: &ReportContext, | |
| measurements: &MeasurementData, | |
| size: Option<Size>, | |
| ) -> Child { | |
| let avg_times = &*measurements.avg_times; | |
| let mean = avg_times.mean(); | |
| let (xs, ys, mean_y) = kde::sweep_and_estimate(avg_times, KDE_POINTS, None, mean); | |
| let xs_ = Sample::new(&xs); | |
| let ys_ = Sample::new(&ys); | |
| let y_limit = ys_.max() * 1.1; | |
| let zeros = iter::repeat(0); | |
| let mut figure = Figure::new(); | |
| figure | |
| .set(Font(DEFAULT_FONT)) | |
| .set(size.unwrap_or(SIZE)) | |
| .configure(Axis::BottomX, |a| { | |
| let (x_scale, prefix) = scale_time(avg_times.max()); | |
| a.set(Label(format!("Average time ({}s)", prefix))) | |
| .set(Range::Limits(xs_.min() * x_scale, xs_.max() * x_scale)) | |
| .set(ScaleFactor(x_scale)) | |
| }) | |
| .configure(Axis::LeftY, |a| { | |
| a.set(Label("Density (a.u.)")) | |
| .set(Range::Limits(0., y_limit)) | |
| }) | |
| .configure(Axis::RightY, |a| a.hide()) | |
| .configure(Key, |k| k.hide()) | |
| .plot( | |
| FilledCurve { | |
| x: &*xs, | |
| y1: &*ys, | |
| y2: zeros, | |
| }, | |
| |c| { | |
| c.set(Axes::BottomXRightY) | |
| .set(DARK_BLUE) | |
| .set(Label("PDF")) | |
| .set(Opacity(0.25)) | |
| }, | |
| ) | |
| .plot( | |
| Lines { | |
| x: &[mean, mean], | |
| y: &[0., mean_y], | |
| }, | |
| |c| c.set(DARK_BLUE).set(LINEWIDTH).set(Label("Mean")), | |
| ); | |
| let path = context.report_path(id, "pdf_small.svg"); | |
| debug_script(&path, &figure); | |
| figure.set(Output(path)).draw().unwrap() | |
| } | |
| fn pdf_comparison_figure( | |
| measurements: &MeasurementData, | |
| comparison: &ComparisonData, | |
| size: Option<Size>, | |
| ) -> Figure { | |
| let base_avg_times = Sample::new(&comparison.base_avg_times); | |
| let base_mean = base_avg_times.mean(); | |
| let new_mean = measurements.avg_times.mean(); | |
| let (base_xs, base_ys, base_y_mean) = | |
| kde::sweep_and_estimate(base_avg_times, KDE_POINTS, None, base_mean); | |
| let (xs, ys, y_mean) = | |
| kde::sweep_and_estimate(&measurements.avg_times, KDE_POINTS, None, new_mean); | |
| let base_xs_ = Sample::new(&base_xs); | |
| let xs_ = Sample::new(&xs); | |
| let (x_scale, prefix) = scale_time(base_xs_.max().max(xs_.max())); | |
| let zeros = iter::repeat(0); | |
| let mut figure = Figure::new(); | |
| figure | |
| .set(Font(DEFAULT_FONT)) | |
| .set(size.unwrap_or(SIZE)) | |
| .configure(Axis::BottomX, |a| { | |
| a.set(Label(format!("Average time ({}s)", prefix))) | |
| .set(ScaleFactor(x_scale)) | |
| }) | |
| .configure(Axis::LeftY, |a| a.set(Label("Density (a.u.)"))) | |
| .configure(Axis::RightY, |a| a.hide()) | |
| .configure(Key, |k| { | |
| k.set(Justification::Left) | |
| .set(Order::SampleText) | |
| .set(Position::Outside(Vertical::Top, Horizontal::Right)) | |
| }) | |
| .plot( | |
| FilledCurve { | |
| x: &*base_xs, | |
| y1: &*base_ys, | |
| y2: zeros.clone(), | |
| }, | |
| |c| c.set(DARK_RED).set(Label("Base PDF")).set(Opacity(0.5)), | |
| ) | |
| .plot( | |
| Lines { | |
| x: &[base_mean, base_mean], | |
| y: &[0., base_y_mean], | |
| }, | |
| |c| c.set(DARK_RED).set(Label("Base Mean")).set(LINEWIDTH), | |
| ) | |
| .plot( | |
| FilledCurve { | |
| x: &*xs, | |
| y1: &*ys, | |
| y2: zeros, | |
| }, | |
| |c| c.set(DARK_BLUE).set(Label("New PDF")).set(Opacity(0.5)), | |
| ) | |
| .plot( | |
| Lines { | |
| x: &[new_mean, new_mean], | |
| y: &[0., y_mean], | |
| }, | |
| |c| c.set(DARK_BLUE).set(Label("New Mean")).set(LINEWIDTH), | |
| ); | |
| figure | |
| } | |
| pub(crate) fn pdf_comparison( | |
| id: &BenchmarkId, | |
| context: &ReportContext, | |
| measurements: &MeasurementData, | |
| comparison: &ComparisonData, | |
| size: Option<Size>, | |
| ) -> Child { | |
| let mut figure = pdf_comparison_figure(measurements, comparison, size); | |
| figure.set(Title(escape_underscores(id.as_title()))); | |
| let path = context.report_path(id, "both/pdf.svg"); | |
| debug_script(&path, &figure); | |
| figure.set(Output(path)).draw().unwrap() | |
| } | |
| pub(crate) fn pdf_comparison_small( | |
| id: &BenchmarkId, | |
| context: &ReportContext, | |
| measurements: &MeasurementData, | |
| comparison: &ComparisonData, | |
| size: Option<Size>, | |
| ) -> Child { | |
| let mut figure = pdf_comparison_figure(measurements, comparison, size); | |
| figure.configure(Key, |k| k.hide()); | |
| let path = context.report_path(id, "relative_pdf_small.svg"); | |
| debug_script(&path, &figure); | |
| figure.set(Output(path)).draw().unwrap() | |
| } |