Nothing fancy, like the others needs a bit more styling but should do for now.
ZEN3WUPDVQWI7LPTEG3WQA5QSEHU74CUXVFJJFIJNSIFC7N2CMEAC
Style::Histogram => Bar::new()
// TODO: charming does not support relative bar widths, but echarts does.
// This is an exact value, NOT a percentage, and is wrong - each bar overlaps
// itself. This is "fine" for a histogram, so leaving for now,
// but should change eventually.
.bar_width(100)
.data(histogram::data(timings))
.into(),
use crate::timings;
use charming::{component::Axis, datatype::DataPoint, element::AxisType};
const BUCKET_COUNT: usize = 10;
fn find_min_max_duration(pkg_durations: &[f64]) -> (f64, f64) {
assert!(!pkg_durations.is_empty());
let mut min = f64::MAX;
let mut max = f64::MIN;
for duration in pkg_durations {
min = duration.min(min);
max = duration.max(max);
}
assert_ne!(min, f64::MAX);
assert_ne!(max, f64::MIN);
assert!(min.is_sign_positive());
assert!(max.is_sign_positive());
(min, max)
}
pub fn axes(timings: &timings::Output) -> (Axis, Axis) {
let pkg_durations: Vec<f64> = timings.pkg_times().collect();
let (min_duration, max_duration) = find_min_max_duration(&pkg_durations);
let bucket_width = (max_duration - min_duration) / (BUCKET_COUNT as f64);
let mut x_labels = Vec::with_capacity(BUCKET_COUNT);
for bucket_index in 0..BUCKET_COUNT {
// The start time is offset, first bucket starts at min_duration
let start_time = min_duration + (bucket_width * (bucket_index as f64));
// The label is the start time rounded to 2 decimal places
x_labels.push(format!("{start_time:.2}"));
}
let x_axis = Axis::new().type_(AxisType::Category).data(x_labels);
let y_axis = Axis::new().type_(AxisType::Value);
(x_axis, y_axis)
}
pub fn data(timings: &timings::Output) -> Vec<DataPoint> {
let pkg_durations: Vec<f64> = timings.pkg_times().collect();
let (min_duration, max_duration) = find_min_max_duration(&pkg_durations);
// Make sure to start the buckets at min, not 0
let bucket_width = (max_duration - min_duration) / (BUCKET_COUNT as f64);
let mut buckets = [0_u64; BUCKET_COUNT];
for duration in pkg_durations {
let relative_duration = duration - min_duration;
let remainder = relative_duration % bucket_width;
// Calculate the nearest multiple of bucket_size
let next_multiple = (relative_duration - remainder) / bucket_width;
// Make sure we have an integer before casting
assert_eq!(next_multiple, next_multiple.floor());
let bucket_index = next_multiple as usize;
// Increment the frequency of the relevant bucket
buckets[bucket_index] += 1;
}
// Convert the buckets into `charming::datatype::DataPoint`s
buckets
.into_iter()
.map(|bucket| (bucket as i64).into())
.collect()
}
}
// TODO: this returns each total package time, but it would be interesting to filter by
// crate type (lib, binary, proc_macro), target, build script runs etc
pub fn pkg_times<'s>(&'s self) -> impl Iterator<Item = f64> + 's {
self.repr
.values()
.map(|messages| messages.iter().map(|msg| msg.duration).sum())