| 1 | use super::{PlotContext, PlotData, Plotter}; |
| 2 | use crate::measurement::ValueFormatter; |
| 3 | use crate::report::{BenchmarkId, ComparisonData, MeasurementData, ValueType}; |
| 4 | use plotters::data::float::pretty_print_float; |
| 5 | use plotters::prelude::*; |
| 6 | |
| 7 | use crate::kde; |
| 8 | use crate::stats::bivariate::Data; |
| 9 | use crate::stats::univariate::Sample; |
| 10 | |
| 11 | static DEFAULT_FONT: FontFamily = FontFamily::SansSerif; |
| 12 | static KDE_POINTS: usize = 500; |
| 13 | static SIZE: (u32, u32) = (960, 540); |
| 14 | static POINT_SIZE: u32 = 3; |
| 15 | |
| 16 | const DARK_BLUE: RGBColor = RGBColor(31, 120, 180); |
| 17 | const DARK_ORANGE: RGBColor = RGBColor(255, 127, 0); |
| 18 | const DARK_RED: RGBColor = RGBColor(227, 26, 28); |
| 19 | |
| 20 | mod distributions; |
| 21 | mod iteration_times; |
| 22 | mod pdf; |
| 23 | mod regression; |
| 24 | mod summary; |
| 25 | mod t_test; |
| 26 | |
| 27 | fn convert_size(size: Option<(usize, usize)>) -> Option<(u32, u32)> { |
| 28 | if let Some((w, h)) = size { |
| 29 | return Some((w as u32, h as u32)); |
| 30 | } |
| 31 | None |
| 32 | } |
| 33 | #[derive(Default)] |
| 34 | pub struct PlottersBackend; |
| 35 | |
| 36 | #[allow (unused_variables)] |
| 37 | impl Plotter for PlottersBackend { |
| 38 | fn pdf(&mut self, ctx: PlotContext<'_>, data: PlotData<'_>) { |
| 39 | if let Some(cmp) = data.comparison { |
| 40 | let (path, title) = if ctx.is_thumbnail { |
| 41 | ( |
| 42 | ctx.context.report_path(ctx.id, "relative_pdf_small.svg" ), |
| 43 | None, |
| 44 | ) |
| 45 | } else { |
| 46 | ( |
| 47 | ctx.context.report_path(ctx.id, "both/pdf.svg" ), |
| 48 | Some(ctx.id.as_title()), |
| 49 | ) |
| 50 | }; |
| 51 | pdf::pdf_comparison_figure( |
| 52 | path.as_ref(), |
| 53 | title, |
| 54 | data.formatter, |
| 55 | data.measurements, |
| 56 | cmp, |
| 57 | convert_size(ctx.size), |
| 58 | ); |
| 59 | return; |
| 60 | } |
| 61 | if ctx.is_thumbnail { |
| 62 | pdf::pdf_small( |
| 63 | ctx.id, |
| 64 | ctx.context, |
| 65 | data.formatter, |
| 66 | data.measurements, |
| 67 | convert_size(ctx.size), |
| 68 | ); |
| 69 | } else { |
| 70 | pdf::pdf( |
| 71 | ctx.id, |
| 72 | ctx.context, |
| 73 | data.formatter, |
| 74 | data.measurements, |
| 75 | convert_size(ctx.size), |
| 76 | ); |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | fn regression(&mut self, ctx: PlotContext<'_>, data: PlotData<'_>) { |
| 81 | let (title, path) = match (data.comparison.is_some(), ctx.is_thumbnail) { |
| 82 | (true, true) => ( |
| 83 | None, |
| 84 | ctx.context |
| 85 | .report_path(ctx.id, "relative_regression_small.svg" ), |
| 86 | ), |
| 87 | (true, false) => ( |
| 88 | Some(ctx.id.as_title()), |
| 89 | ctx.context.report_path(ctx.id, "both/regression.svg" ), |
| 90 | ), |
| 91 | (false, true) => ( |
| 92 | None, |
| 93 | ctx.context.report_path(ctx.id, "regression_small.svg" ), |
| 94 | ), |
| 95 | (false, false) => ( |
| 96 | Some(ctx.id.as_title()), |
| 97 | ctx.context.report_path(ctx.id, "regression.svg" ), |
| 98 | ), |
| 99 | }; |
| 100 | |
| 101 | if let Some(cmp) = data.comparison { |
| 102 | let base_data = Data::new(&cmp.base_iter_counts, &cmp.base_sample_times); |
| 103 | regression::regression_comparison_figure( |
| 104 | title, |
| 105 | path.as_path(), |
| 106 | data.formatter, |
| 107 | data.measurements, |
| 108 | cmp, |
| 109 | &base_data, |
| 110 | convert_size(ctx.size), |
| 111 | ); |
| 112 | } else { |
| 113 | regression::regression_figure( |
| 114 | title, |
| 115 | path.as_path(), |
| 116 | data.formatter, |
| 117 | data.measurements, |
| 118 | convert_size(ctx.size), |
| 119 | ); |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | fn iteration_times(&mut self, ctx: PlotContext<'_>, data: PlotData<'_>) { |
| 124 | let (title, path) = match (data.comparison.is_some(), ctx.is_thumbnail) { |
| 125 | (true, true) => ( |
| 126 | None, |
| 127 | ctx.context |
| 128 | .report_path(ctx.id, "relative_iteration_times_small.svg" ), |
| 129 | ), |
| 130 | (true, false) => ( |
| 131 | Some(ctx.id.as_title()), |
| 132 | ctx.context.report_path(ctx.id, "both/iteration_times.svg" ), |
| 133 | ), |
| 134 | (false, true) => ( |
| 135 | None, |
| 136 | ctx.context.report_path(ctx.id, "iteration_times_small.svg" ), |
| 137 | ), |
| 138 | (false, false) => ( |
| 139 | Some(ctx.id.as_title()), |
| 140 | ctx.context.report_path(ctx.id, "iteration_times.svg" ), |
| 141 | ), |
| 142 | }; |
| 143 | |
| 144 | if let Some(cmp) = data.comparison { |
| 145 | let base_data = Data::new(&cmp.base_iter_counts, &cmp.base_sample_times); |
| 146 | iteration_times::iteration_times_comparison_figure( |
| 147 | title, |
| 148 | path.as_path(), |
| 149 | data.formatter, |
| 150 | data.measurements, |
| 151 | cmp, |
| 152 | convert_size(ctx.size), |
| 153 | ); |
| 154 | } else { |
| 155 | iteration_times::iteration_times_figure( |
| 156 | title, |
| 157 | path.as_path(), |
| 158 | data.formatter, |
| 159 | data.measurements, |
| 160 | convert_size(ctx.size), |
| 161 | ); |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | fn abs_distributions(&mut self, ctx: PlotContext<'_>, data: PlotData<'_>) { |
| 166 | distributions::abs_distributions( |
| 167 | ctx.id, |
| 168 | ctx.context, |
| 169 | data.formatter, |
| 170 | data.measurements, |
| 171 | convert_size(ctx.size), |
| 172 | ); |
| 173 | } |
| 174 | |
| 175 | fn rel_distributions(&mut self, ctx: PlotContext<'_>, data: PlotData<'_>) { |
| 176 | distributions::rel_distributions( |
| 177 | ctx.id, |
| 178 | ctx.context, |
| 179 | data.measurements, |
| 180 | data.comparison.unwrap(), |
| 181 | convert_size(ctx.size), |
| 182 | ); |
| 183 | } |
| 184 | |
| 185 | fn line_comparison( |
| 186 | &mut self, |
| 187 | ctx: PlotContext<'_>, |
| 188 | formatter: &dyn ValueFormatter, |
| 189 | all_curves: &[&(&BenchmarkId, Vec<f64>)], |
| 190 | value_type: ValueType, |
| 191 | ) { |
| 192 | let path = ctx.line_comparison_path(); |
| 193 | summary::line_comparison( |
| 194 | formatter, |
| 195 | ctx.id.as_title(), |
| 196 | all_curves, |
| 197 | &path, |
| 198 | value_type, |
| 199 | ctx.context.plot_config.summary_scale, |
| 200 | ); |
| 201 | } |
| 202 | |
| 203 | fn violin( |
| 204 | &mut self, |
| 205 | ctx: PlotContext<'_>, |
| 206 | formatter: &dyn ValueFormatter, |
| 207 | all_curves: &[&(&BenchmarkId, Vec<f64>)], |
| 208 | ) { |
| 209 | let violin_path = ctx.violin_path(); |
| 210 | |
| 211 | summary::violin( |
| 212 | formatter, |
| 213 | ctx.id.as_title(), |
| 214 | all_curves, |
| 215 | &violin_path, |
| 216 | ctx.context.plot_config.summary_scale, |
| 217 | ); |
| 218 | } |
| 219 | |
| 220 | fn t_test(&mut self, ctx: PlotContext<'_>, data: PlotData<'_>) { |
| 221 | let title = ctx.id.as_title(); |
| 222 | let path = ctx.context.report_path(ctx.id, "change/t-test.svg" ); |
| 223 | t_test::t_test( |
| 224 | path.as_path(), |
| 225 | title, |
| 226 | data.comparison.unwrap(), |
| 227 | convert_size(ctx.size), |
| 228 | ); |
| 229 | } |
| 230 | |
| 231 | fn wait(&mut self) {} |
| 232 | } |
| 233 | |