harness_cli/configs/
run_info.rs

1//! The evaluation summary specification.
2//!
3//! A evaluation summary contains the metadata of the evaluation run, including the crate info, the current system info at the time of the evaluation, and the enabled evaluation profile.
4//!
5//! Each `cargo harness run` will start an evaluation, and generate a unique `RUNID` for this evaluation.
6//! The evaluation summary will be dumped to `target/harness/logs/<RUNID>/config.toml`.
7//!
8//! By having the repo and the evaluation summary, you can reproduce the evaluation by running:
9//!
10//! ```bash
11//! cargo harness run --config <RUNID>
12//! ```
13//!
14//! OR
15//!
16//! ```bash
17//! cargo harness run --config /path/to/config.toml
18//! ```
19
20use std::{collections::HashMap, ops::Deref, path::PathBuf};
21
22use cargo_metadata::MetadataCommand;
23use chrono::{DateTime, Local};
24use serde::{Deserialize, Serialize};
25
26use crate::utils::{self, lockfile::load_lockfiles};
27
28use super::harness::{CargoConfig, Profile};
29
30#[derive(Debug, Serialize, Deserialize)]
31pub struct ProfileWithName {
32    pub name: String,
33    #[serde(flatten)]
34    pub profile: Profile,
35}
36
37impl Deref for ProfileWithName {
38    type Target = Profile;
39
40    fn deref(&self) -> &Self::Target {
41        &self.profile
42    }
43}
44
45/// The evaluation run metadata. This will be collected before each evaluation and dumped to the log directory.
46#[derive(Debug, Serialize, Deserialize)]
47pub struct RunInfo {
48    /// Version
49    pub version: i32,
50    /// Benchmark run id
51    pub runid: String,
52    /// Profile name (default to the crate name)
53    pub project: String,
54    /// Benchmark start time
55    #[serde(rename = "start-time-utc")]
56    pub start_timestamp_utc: i64,
57    /// Benchmark finish time
58    #[serde(rename = "finish-time-utc")]
59    pub finish_timestamp_utc: Option<i64>,
60    /// The commit that the profile is loaded from. This is also used as the default build commit
61    pub commit: String,
62    /// The crate info
63    #[serde(rename = "crate")]
64    pub crate_info: CrateInfo,
65    /// The enabled evaluation profile
66    pub profile: ProfileWithName,
67    /// Current system information
68    pub system: SystemInfo,
69    /// Cargo.lock files for each used git commit, for deterministic builds
70    pub lockfiles: Lockfiles,
71}
72
73impl RunInfo {
74    pub(crate) fn new_v0(
75        crate_info: CrateInfo,
76        profile: Profile,
77        runid: String,
78        profile_name: String,
79        project: Option<String>,
80        start_time: DateTime<Local>,
81    ) -> anyhow::Result<Self> {
82        let lockfiles = load_lockfiles(&crate_info, &profile)?;
83        let project = project.unwrap_or_else(|| crate_info.name.clone());
84        Ok(Self {
85            version: 0,
86            crate_info,
87            project,
88            system: utils::sys::get_current_system_info(),
89            profile: ProfileWithName {
90                name: profile_name,
91                profile,
92            },
93            runid,
94            commit: utils::git::get_git_hash()?,
95            start_timestamp_utc: start_time.to_utc().timestamp(),
96            finish_timestamp_utc: None,
97            lockfiles,
98        })
99    }
100
101    pub(crate) fn load(path: &PathBuf) -> anyhow::Result<Self> {
102        let content = std::fs::read_to_string(path)?;
103        Ok(toml::from_str(&content)?)
104    }
105}
106
107/// Crate metadata
108#[derive(Debug, Serialize, Deserialize, Clone)]
109pub struct CrateInfo {
110    /// Crate name
111    pub name: String,
112    /// Path to the target directory
113    pub target_dir: PathBuf,
114    /// All benchmark names used in the evaluation
115    pub benches: Vec<String>,
116    /// Workspace root
117    pub workspace_root: PathBuf,
118}
119
120impl CrateInfo {
121    pub(crate) fn get_target_path() -> anyhow::Result<PathBuf> {
122        let Ok(meta) = MetadataCommand::new().manifest_path("./Cargo.toml").exec() else {
123            anyhow::bail!("Failed to get metadata from ./Cargo.toml");
124        };
125        let target_dir = meta.target_directory.as_std_path();
126        Ok(target_dir.to_owned())
127    }
128
129    pub(crate) fn load() -> anyhow::Result<Self> {
130        let Ok(meta) = MetadataCommand::new().manifest_path("./Cargo.toml").exec() else {
131            anyhow::bail!("Failed to get metadata from ./Cargo.toml");
132        };
133        let target_dir = meta.target_directory.as_std_path();
134        let Some(pkg) = meta.root_package() else {
135            anyhow::bail!("No root package found");
136        };
137        let benches = CargoConfig::load_benches()?;
138        Ok(CrateInfo {
139            name: pkg.name.clone(),
140            target_dir: target_dir.to_owned(),
141            benches,
142            workspace_root: meta.workspace_root.as_std_path().to_owned(),
143        })
144    }
145}
146
147/// The system information, including the hardware specs, the OS info, and the environment variables.
148#[derive(Debug, Serialize, Deserialize, Clone)]
149pub struct SystemInfo {
150    /// Host name
151    pub host: String,
152    /// Operating system name and version
153    pub os: String,
154    /// CPU architecture
155    pub arch: String,
156    /// Kernel version
157    #[serde(rename = "kernel-version")]
158    pub kernel: String,
159    /// CPU model
160    #[serde(rename = "cpu-model")]
161    pub cpu_model: String,
162    /// CPU frequency
163    #[serde(rename = "cpu-frequency")]
164    pub cpu_frequency: Vec<usize>,
165    /// Total memory size in bytes
166    pub memory_size: usize,
167    /// Total swap size in bytes
168    pub swap_size: usize,
169    /// (*Linux only*) All logged in users
170    #[cfg(target_os = "linux")]
171    pub users: Vec<String>,
172    /// Total number of running processes
173    pub processes: usize,
174    /// All current environment variables
175    pub env: HashMap<String, String>,
176    /// The PID of the current process
177    pub pid: usize,
178    /// The rustc version
179    pub rustc: String,
180    /// (*Linux only*) The scaling governor of each CPU core
181    #[cfg(target_os = "linux")]
182    #[serde(rename = "scaling-governor")]
183    pub scaling_governor: Vec<String>,
184}
185
186/// Cargo.lock files for each used git commit, for deterministic builds
187#[derive(Debug, Serialize, Deserialize)]
188pub struct Lockfiles {
189    #[serde(flatten)]
190    pub lockfiles: HashMap<String, toml::Value>,
191}