1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
use crate::error::Result; use crate::measurement::ValueFormatter; use crate::report::{BenchmarkId, MeasurementData, Report, ReportContext}; use crate::Throughput; use csv::Writer; use std::io::Write; use std::path::Path; #[derive(Serialize)] struct CsvRow<'a> { group: &'a str, function: Option<&'a str>, value: Option<&'a str>, throughput_num: Option<&'a str>, throughput_type: Option<&'a str>, sample_measured_value: f64, unit: &'static str, iteration_count: u64, } struct CsvReportWriter<W: Write> { writer: Writer<W>, } impl<W: Write> CsvReportWriter<W> { fn write_data( &mut self, id: &BenchmarkId, data: &MeasurementData<'_>, formatter: &dyn ValueFormatter, ) -> Result<()> { let mut data_scaled: Vec<f64> = data.sample_times().as_ref().into(); let unit = formatter.scale_for_machines(&mut data_scaled); let group = id.group_id.as_str(); let function = id.function_id.as_ref().map(String::as_str); let value = id.value_str.as_ref().map(String::as_str); let (throughput_num, throughput_type) = match id.throughput { Some(Throughput::Bytes(bytes)) => (Some(format!("{}", bytes)), Some("bytes")), Some(Throughput::Elements(elems)) => (Some(format!("{}", elems)), Some("elements")), None => (None, None), }; let throughput_num = throughput_num.as_ref().map(String::as_str); for (count, measured_value) in data.iter_counts().iter().zip(data_scaled.into_iter()) { let row = CsvRow { group, function, value, throughput_num, throughput_type, sample_measured_value: measured_value, unit, iteration_count: (*count) as u64, }; self.writer.serialize(row)?; } Ok(()) } } pub struct FileCsvReport; impl FileCsvReport { fn write_file( &self, path: &Path, id: &BenchmarkId, measurements: &MeasurementData<'_>, formatter: &dyn ValueFormatter, ) -> Result<()> { let writer = Writer::from_path(path)?; let mut writer = CsvReportWriter { writer }; writer.write_data(id, measurements, formatter)?; Ok(()) } } impl Report for FileCsvReport { fn measurement_complete( &self, id: &BenchmarkId, context: &ReportContext, measurements: &MeasurementData<'_>, formatter: &dyn ValueFormatter, ) { let mut path = context.output_directory.clone(); path.push(id.as_directory_name()); path.push("new"); path.push("raw.csv"); log_if_err!(self.write_file(&path, id, measurements, formatter)); } }