2020-09-14 20:28:02 -07:00
|
|
|
use std::borrow::Cow;
|
2018-03-17 18:59:28 -04:00
|
|
|
|
2018-03-20 22:24:57 +01:00
|
|
|
use csv::WriterBuilder;
|
|
|
|
|
|
2021-08-24 21:33:48 +02:00
|
|
|
use super::Exporter;
|
2022-02-20 13:44:34 +01:00
|
|
|
use crate::benchmark::benchmark_result::BenchmarkResult;
|
2023-06-03 21:06:50 +02:00
|
|
|
use crate::options::SortOrder;
|
2022-02-06 20:01:41 +01:00
|
|
|
use crate::util::units::Unit;
|
2021-08-24 21:33:48 +02:00
|
|
|
|
2022-02-06 17:44:28 +01:00
|
|
|
use anyhow::Result;
|
|
|
|
|
|
2018-03-20 17:00:24 -04:00
|
|
|
#[derive(Default)]
|
2018-03-19 17:37:56 -04:00
|
|
|
pub struct CsvExporter {}
|
2018-03-17 18:59:28 -04:00
|
|
|
|
2018-03-20 20:26:28 +01:00
|
|
|
impl Exporter for CsvExporter {
|
2023-06-03 21:06:50 +02:00
|
|
|
fn serialize(
|
|
|
|
|
&self,
|
|
|
|
|
results: &[BenchmarkResult],
|
|
|
|
|
_unit: Option<Unit>,
|
|
|
|
|
_sort_order: SortOrder,
|
|
|
|
|
) -> Result<Vec<u8>> {
|
2018-03-19 17:37:56 -04:00
|
|
|
let mut writer = WriterBuilder::new().from_writer(vec![]);
|
2018-03-20 22:59:43 +01:00
|
|
|
|
2020-09-14 20:28:02 -07:00
|
|
|
{
|
2020-09-17 11:31:27 -07:00
|
|
|
let mut headers: Vec<Cow<[u8]>> = [
|
2021-02-28 10:22:21 +01:00
|
|
|
// The list of times and exit codes cannot be exported to the CSV file - omit them.
|
2020-09-14 20:28:02 -07:00
|
|
|
"command", "mean", "stddev", "median", "user", "system", "min", "max",
|
|
|
|
|
]
|
|
|
|
|
.iter()
|
2020-09-17 11:31:27 -07:00
|
|
|
.map(|x| Cow::Borrowed(x.as_bytes()))
|
2020-09-14 20:28:02 -07:00
|
|
|
.collect();
|
|
|
|
|
if let Some(res) = results.first() {
|
|
|
|
|
for param_name in res.parameters.keys() {
|
2024-05-31 13:26:35 -07:00
|
|
|
headers.push(Cow::Owned(format!("parameter_{param_name}").into_bytes()));
|
2020-09-14 20:28:02 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
writer.write_record(headers)?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for res in results {
|
2021-08-22 16:05:03 +02:00
|
|
|
let mut fields = vec![Cow::Borrowed(res.command.as_bytes())];
|
2020-09-14 20:28:02 -07:00
|
|
|
for f in &[
|
2021-11-14 10:18:28 +01:00
|
|
|
res.mean,
|
|
|
|
|
res.stddev.unwrap_or(0.0),
|
|
|
|
|
res.median,
|
|
|
|
|
res.user,
|
|
|
|
|
res.system,
|
|
|
|
|
res.min,
|
|
|
|
|
res.max,
|
2020-09-14 20:28:02 -07:00
|
|
|
] {
|
|
|
|
|
fields.push(Cow::Owned(f.to_string().into_bytes()))
|
|
|
|
|
}
|
|
|
|
|
for v in res.parameters.values() {
|
|
|
|
|
fields.push(Cow::Borrowed(v.as_bytes()))
|
|
|
|
|
}
|
|
|
|
|
writer.write_record(fields)?;
|
2018-03-17 18:59:28 -04:00
|
|
|
}
|
2018-03-19 17:37:56 -04:00
|
|
|
|
2022-02-06 17:44:28 +01:00
|
|
|
Ok(writer.into_inner()?)
|
2018-03-17 18:59:28 -04:00
|
|
|
}
|
|
|
|
|
}
|
2020-09-14 20:28:02 -07:00
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_csv() {
|
|
|
|
|
use std::collections::BTreeMap;
|
|
|
|
|
let exporter = CsvExporter::default();
|
|
|
|
|
|
|
|
|
|
let results = vec![
|
2022-02-06 13:36:09 +01:00
|
|
|
BenchmarkResult {
|
2024-12-29 13:38:54 +01:00
|
|
|
command: String::from("command_a"),
|
|
|
|
|
command_with_unused_parameters: String::from("command_a"),
|
2022-02-06 13:36:09 +01:00
|
|
|
mean: 1.0,
|
|
|
|
|
stddev: Some(2.0),
|
|
|
|
|
median: 1.0,
|
|
|
|
|
user: 3.0,
|
|
|
|
|
system: 4.0,
|
|
|
|
|
min: 5.0,
|
|
|
|
|
max: 6.0,
|
|
|
|
|
times: Some(vec![7.0, 8.0, 9.0]),
|
2024-06-23 13:29:05 +02:00
|
|
|
memory_usage_byte: None,
|
2022-02-06 13:36:09 +01:00
|
|
|
exit_codes: vec![Some(0), Some(0), Some(0)],
|
|
|
|
|
parameters: {
|
2020-09-14 20:28:02 -07:00
|
|
|
let mut params = BTreeMap::new();
|
|
|
|
|
params.insert("foo".into(), "one".into());
|
|
|
|
|
params.insert("bar".into(), "two".into());
|
|
|
|
|
params
|
|
|
|
|
},
|
2022-02-06 13:36:09 +01:00
|
|
|
},
|
|
|
|
|
BenchmarkResult {
|
2024-12-29 13:38:54 +01:00
|
|
|
command: String::from("command_b"),
|
|
|
|
|
command_with_unused_parameters: String::from("command_b"),
|
2022-02-06 13:36:09 +01:00
|
|
|
mean: 11.0,
|
|
|
|
|
stddev: Some(12.0),
|
|
|
|
|
median: 11.0,
|
|
|
|
|
user: 13.0,
|
|
|
|
|
system: 14.0,
|
|
|
|
|
min: 15.0,
|
|
|
|
|
max: 16.5,
|
|
|
|
|
times: Some(vec![17.0, 18.0, 19.0]),
|
2024-06-23 13:29:05 +02:00
|
|
|
memory_usage_byte: None,
|
2022-02-06 13:36:09 +01:00
|
|
|
exit_codes: vec![Some(0), Some(0), Some(0)],
|
|
|
|
|
parameters: {
|
2020-09-14 20:28:02 -07:00
|
|
|
let mut params = BTreeMap::new();
|
|
|
|
|
params.insert("foo".into(), "one".into());
|
|
|
|
|
params.insert("bar".into(), "seven".into());
|
|
|
|
|
params
|
|
|
|
|
},
|
2022-02-06 13:36:09 +01:00
|
|
|
},
|
2020-09-14 20:28:02 -07:00
|
|
|
];
|
2024-12-29 13:10:50 +01:00
|
|
|
|
|
|
|
|
let actual = String::from_utf8(
|
2023-06-03 21:06:50 +02:00
|
|
|
exporter
|
|
|
|
|
.serialize(&results, Some(Unit::Second), SortOrder::Command)
|
|
|
|
|
.unwrap(),
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
2020-09-14 20:28:02 -07:00
|
|
|
|
2024-12-29 13:10:50 +01:00
|
|
|
insta::assert_snapshot!(actual, @r#"
|
|
|
|
|
command,mean,stddev,median,user,system,min,max,parameter_bar,parameter_foo
|
2024-12-29 13:38:54 +01:00
|
|
|
command_a,1,2,1,3,4,5,6,two,one
|
|
|
|
|
command_b,11,12,11,13,14,15,16.5,seven,one
|
2024-12-29 13:10:50 +01:00
|
|
|
"#);
|
2020-09-14 20:28:02 -07:00
|
|
|
}
|