mirror of
https://github.com/sharkdp/hyperfine.git
synced 2026-10-28 08:08:58 +00:00
Add benchmark session metadata to JSON exports
This commit is contained in:
1 parent
d60eba407d
commit
6d0ae4f87c
4 files changed
+100
-5
No files matched your search
Generated
+18
@@ -369,6 +369,12 @@ version = "0.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15cdd26707701c53297e2fa6afb323d55fbc1d0810c3aec078ae3ef0424c3c15"
|
||||
|
||||
[[package]]
|
||||
name = "hyperfine"
|
||||
version = "1.21.0"
|
||||
@@ -380,12 +386,14 @@ dependencies = [
|
||||
"clap_complete",
|
||||
"colored",
|
||||
"csv",
|
||||
"humantime",
|
||||
"indicatif",
|
||||
"insta",
|
||||
"insta-cmd",
|
||||
"libc",
|
||||
"nix",
|
||||
"once_cell",
|
||||
"platform-info",
|
||||
"predicates",
|
||||
"rand 0.10.3",
|
||||
"rust_decimal",
|
||||
@@ -531,6 +539,16 @@ version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||
|
||||
[[package]]
|
||||
name = "platform-info"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba7c3f5af00d3596a148cc80178ac690152b71c283d15a8bcea0cddfea759a36"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.15.0"
|
||||
|
||||
@@ -29,6 +29,8 @@ shell-words = "1.1"
|
||||
thiserror = "2.0"
|
||||
anyhow = "1.0"
|
||||
uom = { version = "0.36.0", default-features = false, features = ["std", "si", "f64"] }
|
||||
humantime = "2"
|
||||
platform-info = "2.2"
|
||||
|
||||
[target.'cfg(not(windows))'.dependencies]
|
||||
libc = "0.2"
|
||||
|
||||
+17
-5
@@ -8,14 +8,19 @@ use crate::quantity::TimeUnit;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
mod metadata;
|
||||
use metadata::Metadata;
|
||||
|
||||
#[derive(Serialize, Debug)]
|
||||
struct HyperfineSummary<'a> {
|
||||
schema_version: u32,
|
||||
metadata: &'a Metadata,
|
||||
results: &'a [BenchmarkResult],
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct JsonExporter {}
|
||||
pub struct JsonExporter {
|
||||
metadata: Metadata,
|
||||
}
|
||||
|
||||
impl Exporter for JsonExporter {
|
||||
fn serialize(
|
||||
@@ -26,7 +31,7 @@ impl Exporter for JsonExporter {
|
||||
_reference_index: Option<usize>,
|
||||
) -> Result<Vec<u8>> {
|
||||
let mut output = to_vec_pretty(&HyperfineSummary {
|
||||
schema_version: 2,
|
||||
metadata: &self.metadata,
|
||||
results,
|
||||
});
|
||||
if let Ok(ref mut content) = output {
|
||||
@@ -62,12 +67,19 @@ fn test_json_optional_memory() {
|
||||
}]),
|
||||
..BenchmarkResult::default()
|
||||
};
|
||||
let output = JsonExporter::default()
|
||||
let mut exporter = JsonExporter::default();
|
||||
exporter.metadata.start_time = Some("2000-02-29T12:34:56Z".to_owned());
|
||||
let output = exporter
|
||||
.serialize(&[result], None, SortOrder::Command, None)
|
||||
.unwrap();
|
||||
let actual: serde_json::Value = serde_json::from_slice(&output).unwrap();
|
||||
let mut expected = json!({
|
||||
"schema_version": 2,
|
||||
"metadata": {
|
||||
"json_schema_version": metadata::JSON_SCHEMA_VERSION,
|
||||
"hyperfine_version": env!("CARGO_PKG_VERSION"),
|
||||
"start_time": "2000-02-29T12:34:56Z",
|
||||
"platform": exporter.metadata.platform
|
||||
},
|
||||
"results": [{
|
||||
"command": "example",
|
||||
"measurements": [{
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
use serde::Serialize;
|
||||
|
||||
pub(super) const JSON_SCHEMA_VERSION: u32 = 2;
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub(super) struct Metadata {
|
||||
json_schema_version: u32,
|
||||
hyperfine_version: &'static str,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub start_time: Option<String>,
|
||||
pub platform: Platform,
|
||||
}
|
||||
|
||||
impl Default for Metadata {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
json_schema_version: JSON_SCHEMA_VERSION,
|
||||
hyperfine_version: env!("CARGO_PKG_VERSION"),
|
||||
start_time: utc_now(),
|
||||
platform: Platform::detect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn utc_now() -> Option<String> {
|
||||
use std::{fmt::Write, time::SystemTime};
|
||||
|
||||
let now = SystemTime::now();
|
||||
now.duration_since(SystemTime::UNIX_EPOCH).ok()?;
|
||||
let mut timestamp = String::new();
|
||||
write!(&mut timestamp, "{}", humantime::format_rfc3339_seconds(now)).ok()?;
|
||||
Some(timestamp)
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize)]
|
||||
pub(super) struct Platform {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
os: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
architecture: Option<String>,
|
||||
}
|
||||
|
||||
impl Platform {
|
||||
fn detect() -> Self {
|
||||
use platform_info::{PlatformInfo, PlatformInfoAPI, UNameAPI};
|
||||
|
||||
let Ok(info) = PlatformInfo::new() else {
|
||||
return Self::default();
|
||||
};
|
||||
Self {
|
||||
os: Some(info.sysname().to_string_lossy().into_owned()),
|
||||
architecture: Some(info.machine().to_string_lossy().into_owned()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unavailable_platform_fields_are_omitted() {
|
||||
assert_eq!(
|
||||
serde_json::to_value(Platform::default()).unwrap(),
|
||||
serde_json::json!({})
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user