use std::{collections::HashMap, path::Path};
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct TracesConfig {
pub traces_db: TracesDb,
pub traces: Vec<TraceEntry>,
}
impl TracesConfig {
pub fn load(path: &Path) -> Result<TracesConfig> {
let contents = std::fs::read_to_string(path)
.with_context(|| format!("reading config file {}", path.display()))?;
toml::from_str(&contents).with_context(|| format!("parsing TOML config {}", path.display()))
}
}
#[derive(Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct TracesDb {
pub download_url: String,
}
#[derive(Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct TraceEntry {
pub path: String,
#[serde(default)]
pub nonloopable: bool,
#[serde(default)]
pub replay_args: Vec<String>,
#[serde(default)]
pub devices: HashMap<String, DeviceEntry>,
}
impl TraceEntry {
pub fn device(&self, name: &str) -> Option<&DeviceEntry> {
self.devices.get(name)
}
}
#[derive(Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct DeviceEntry {
pub checksum: String,
#[serde(default)]
pub singlethread: bool,
#[serde(default)]
pub skip: bool,
#[serde(default)]
pub replay_args: Vec<String>,
}
#[cfg(test)]
mod tests {
use super::*;
const MINIMAL_TOML: &str = r#"
[traces_db]
download_url = "https://s3.freedesktop.org/mesa-tracie-public/"
[[traces]]
path = "valve/half-life-2-v2.trace"
devices = {
freedreno-a306 = {
checksum = "8f5929c82e7d990e8c3d2bea14688224aabbccdd8f5929c82e7d990e8c3d2bea",
skip = true,
},
freedreno-a530 = {
checksum = "c7b816feafeae42eef3ccd5357db4cd7c7b816feafeae42eef3ccd5357db4cd7",
},
}
[[traces]]
path = "valve/portal-2-v2.trace"
devices = {
freedreno-a530 = {
checksum = "102a09ce76092436173fd09a6a2bd941102a09ce76092436173fd09a6a2bd941"
},
}
"#;
#[test]
fn parse_minimal_toml() {
let config: TracesConfig = toml::from_str(MINIMAL_TOML).expect("parsing TOML");
assert_eq!(
config.traces_db.download_url,
"https://s3.freedesktop.org/mesa-tracie-public/"
);
assert_eq!(config.traces.len(), 2);
let hl2 = &config.traces[0];
assert_eq!(hl2.path, "valve/half-life-2-v2.trace");
assert_eq!(hl2.devices.len(), 2);
let a306 = &hl2.device("freedreno-a306").unwrap();
assert_eq!(
a306.checksum,
"8f5929c82e7d990e8c3d2bea14688224aabbccdd8f5929c82e7d990e8c3d2bea"
);
assert!(a306.skip);
let a530 = &hl2.device("freedreno-a530").unwrap();
assert!(!a530.skip);
}
#[test]
fn device_lookup() {
let config: TracesConfig = toml::from_str(MINIMAL_TOML).expect("parsing TOML");
let hl2 = &config.traces[0];
assert!(hl2.device("freedreno-a306").is_some());
assert!(hl2.device("freedreno-a530").is_some());
assert!(hl2.device("unknown-device").is_none());
}
#[test]
fn skip_detection() {
let config: TracesConfig = toml::from_str(MINIMAL_TOML).expect("parsing TOML");
let hl2 = &config.traces[0];
let a306 = hl2.device("freedreno-a306").unwrap();
assert!(a306.skip);
let a530 = hl2.device("freedreno-a530").unwrap();
assert!(!a530.skip);
}
#[test]
fn trace_with_no_device_entry() {
let config: TracesConfig = toml::from_str(MINIMAL_TOML).expect("parsing TOML");
let portal2 = &config.traces[1];
assert_eq!(portal2.path, "valve/portal-2-v2.trace");
assert!(portal2.device("freedreno-a306").is_none());
assert!(portal2.device("freedreno-a530").is_some());
}
}