diff --git a/CHANGELOG.md b/CHANGELOG.md index 58269a9..ab4f363 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [0.8.2](https://github.com/criterion-rs/criterion.rs/compare/criterion-v0.8.1...criterion-v0.8.2) - 2026-02-04 +### Changed + +- Added support for plots with logarithmic axis with base other than 10 (e.g. log2) + ### Fixed - don't build alloca on unsupported targets diff --git a/book/src/user_guide/advanced_configuration.md b/book/src/user_guide/advanced_configuration.md index b24223e..417fc3e 100644 --- a/book/src/user_guide/advanced_configuration.md +++ b/book/src/user_guide/advanced_configuration.md @@ -138,7 +138,7 @@ fn do_a_thing(x: u64) { fn bench(c: &mut Criterion) { let plot_config = PlotConfiguration::default() - .summary_scale(AxisScale::Logarithmic); + .summary_scale(AxisScale::Logarithmic(10.0)); let mut group = c.benchmark_group("log_scale_example"); group.plot_config(plot_config); diff --git a/plot/src/axis.rs b/plot/src/axis.rs index 80e2451..5beda30 100644 --- a/plot/src/axis.rs +++ b/plot/src/axis.rs @@ -14,7 +14,7 @@ pub struct Properties { grids: map::grid::Map, hidden: bool, label: Option>, - logarithmic: bool, + scale: Scale, range: Option<(f64, f64)>, scale_factor: f64, tics: Option, @@ -26,7 +26,7 @@ impl Default for Properties { grids: map::grid::Map::new(), hidden: false, label: None, - logarithmic: false, + scale: Scale::Linear, range: None, scale_factor: 1., tics: None, @@ -103,10 +103,7 @@ impl Set for Properties { fn set(&mut self, scale: Scale) -> &mut Properties { self.hidden = false; - match scale { - Scale::Linear => self.logarithmic = false, - Scale::Logarithmic => self.logarithmic = true, - } + self.scale = scale; self } @@ -178,8 +175,8 @@ impl Script for (Axis, &Properties) { script.push_str(&format!("set {}range [{}:{}]\n", axis_, low, high)) } - if properties.logarithmic { - script.push_str(&format!("set logscale {}\n", axis_)); + if let Scale::Logarithmic(base) = properties.scale { + script.push_str(&format!("set logscale {} {}\n", axis_, base)) } for (grid, properties) in properties.grids.iter() { diff --git a/plot/src/lib.rs b/plot/src/lib.rs index 9dbc2da..281368f 100644 --- a/plot/src/lib.rs +++ b/plot/src/lib.rs @@ -853,7 +853,7 @@ pub enum PointType { #[derive(Clone, Copy)] pub enum Scale { Linear, - Logarithmic, + Logarithmic(f64), } /// Axis scale factor diff --git a/src/connection.rs b/src/connection.rs index b18a773..dfbb570 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -308,13 +308,13 @@ impl From<&InternalBenchmarkId> for RawBenchmarkId { #[derive(Debug, Serialize)] pub enum AxisScale { Linear, - Logarithmic, + LogarithmicWithBase(f64), } impl From for AxisScale { fn from(other: crate::AxisScale) -> Self { match other { crate::AxisScale::Linear => AxisScale::Linear, - crate::AxisScale::Logarithmic => AxisScale::Logarithmic, + crate::AxisScale::Logarithmic(base) => AxisScale::LogarithmicWithBase(base), } } } diff --git a/src/lib.rs b/src/lib.rs index e0c6610..2a8c5e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1323,8 +1323,8 @@ pub enum AxisScale { #[default] Linear, - /// Axes scale logarithmically - Logarithmic, + /// Axes scale logarithmically, with specified base + Logarithmic(f64), } /// Contains the configuration options for the plots generated by a particular benchmark @@ -1334,7 +1334,7 @@ pub enum AxisScale { /// use self::criterion::{Bencher, Criterion, PlotConfiguration, AxisScale}; /// /// let plot_config = PlotConfiguration::default() -/// .summary_scale(AxisScale::Logarithmic); +/// .summary_scale(AxisScale::Logarithmic(10.0)); /// /// // Using Criterion::default() for simplicity; normally you'd use the macros. /// let mut criterion = Criterion::default(); diff --git a/src/plot/gnuplot_backend/summary.rs b/src/plot/gnuplot_backend/summary.rs index 4e42eae..3fc3706 100644 --- a/src/plot/gnuplot_backend/summary.rs +++ b/src/plot/gnuplot_backend/summary.rs @@ -32,15 +32,6 @@ static COMPARISON_COLORS: [Color; NUM_COLORS] = [ Color::Rgb(0, 255, 127), ]; -impl AxisScale { - fn to_gnuplot(self) -> Scale { - match self { - AxisScale::Linear => Scale::Linear, - AxisScale::Logarithmic => Scale::Logarithmic, - } - } -} - #[allow(clippy::explicit_counter_loop)] pub(crate) fn line_comparison( line_cfg: LinePlotConfig, @@ -71,7 +62,7 @@ pub(crate) fn line_comparison( .set(Title(format!("{}: Comparison", gnuplot_escape(title)))) .configure(Axis::BottomX, |a| { a.set(Label(format!("Input{}", input_suffix))) - .set(axis_scale.to_gnuplot()) + .set(Scale::from(axis_scale)) }); let mut i = 0; @@ -92,7 +83,7 @@ pub(crate) fn line_comparison( a.configure(Grid::Major, |g| g.show()) .configure(Grid::Minor, |g| g.hide()) .set(Label(format!("Average {} ({})", line_cfg.label, unit))) - .set(axis_scale.to_gnuplot()) + .set(Scale::from(axis_scale)) }); // This assumes the curves are sorted. It also assumes that the benchmark IDs all have numeric @@ -189,7 +180,7 @@ pub fn violin( .configure(Grid::Minor, |g| g.hide()) .set(Range::Limits(0., max * one[0])) .set(Label(format!("Average time ({})", unit))) - .set(axis_scale.to_gnuplot()) + .set(Scale::from(axis_scale)) }) .configure(Axis::LeftY, |a| { a.set(Label("Input")) diff --git a/src/plot/mod.rs b/src/plot/mod.rs index 7bdf5d7..b5a51fd 100644 --- a/src/plot/mod.rs +++ b/src/plot/mod.rs @@ -2,10 +2,13 @@ mod gnuplot_backend; #[cfg(feature = "plotters")] mod plotters_backend; +use criterion_plot::Scale; pub(crate) use gnuplot_backend::Gnuplot; #[cfg(feature = "plotters")] pub(crate) use plotters_backend::PlottersBackend; +use crate::AxisScale; + use { crate::{ estimate::Statistic, @@ -34,6 +37,15 @@ pub(crate) struct PlotContext<'a> { pub(crate) is_thumbnail: bool, } +impl From for Scale { + fn from(value: AxisScale) -> Self { + match value { + AxisScale::Linear => Scale::Linear, + AxisScale::Logarithmic(base) => Scale::Logarithmic(base), + } + } +} + impl<'a> PlotContext<'a> { pub fn size(mut self, s: Option) -> PlotContext<'a> { if let Some(s) = s { diff --git a/src/plot/plotters_backend/summary.rs b/src/plot/plotters_backend/summary.rs index bf8d6f1..b504e7e 100644 --- a/src/plot/plotters_backend/summary.rs +++ b/src/plot/plotters_backend/summary.rs @@ -1,6 +1,7 @@ use { super::*, crate::AxisScale, + criterion_plot::Scale, itertools::Itertools, plotters::coord::{ ranged1d::{AsRangedCoord, ValueFormatter as PlottersValueFormatter}, @@ -41,8 +42,8 @@ pub(crate) fn line_comparison( .titled(&format!("{}: Comparison", title), (DEFAULT_FONT, 20)) .unwrap(); - match axis_scale { - AxisScale::Linear => draw_line_comparison_figure( + match Scale::from(axis_scale) { + Scale::Linear => draw_line_comparison_figure( line_cfg, root_area, unit, @@ -51,12 +52,12 @@ pub(crate) fn line_comparison( value_type, series_data, ), - AxisScale::Logarithmic => draw_line_comparison_figure( + Scale::Logarithmic(base) => draw_line_comparison_figure( line_cfg, root_area, unit, - x_range.log_scale(), - y_range.log_scale(), + x_range.log_scale().base(base), + y_range.log_scale().base(base), value_type, series_data, ), @@ -223,10 +224,16 @@ pub fn violin( .titled(&format!("{}: Violin plot", title), (DEFAULT_FONT, 20)) .unwrap(); - match axis_scale { - AxisScale::Linear => draw_violin_figure(root_area, unit, x_range, y_range, kdes), - AxisScale::Logarithmic => { - draw_violin_figure(root_area, unit, x_range.log_scale(), y_range, kdes); + match Scale::from(axis_scale) { + Scale::Linear => draw_violin_figure(root_area, unit, x_range, y_range, kdes), + Scale::Logarithmic(base) => { + draw_violin_figure( + root_area, + unit, + x_range.log_scale().base(base), + y_range, + kdes, + ); } } }