Parse JSON output from `cargo build --timings`

finchie
Apr 18, 2024, 8:12 AM
LOR3KOXGQ2VYGDHXQ6MG22ZME5TMPFTUW7A5OG36IAVQANOCXBRAC

Dependencies

  • [2] ZPFD3275 Switch from `cargo_metadata`+`petgraph` to `guppy`
  • [3] JVYWRCPT Add basic chart visualisation
  • [4] Q3Z6XMP5 Migrate dependency tree to `petgraph::Graph`
  • [5] 7CVIL7UJ Create simple metadata parser

Change contents

  • file addition: timings.rs (----------)
    [3.15]
    use std::io::{BufRead, BufReader};
    use std::process::{Command, Stdio};
    use cargo_metadata::{PackageId, Target};
    use serde::{Deserialize, Serialize};
    // Use an alternative profile so clean-building is "sandboxed" to this tool
    const CARGO_CUSOTM_PROFILE: [&str; 2] = ["--config", r#"profile.depwiz.inherits="dev""#];
    /// See https://docs.rs/cargo/latest/cargo/core/compiler/enum.CompileMode.html
    /// These are the only two cases we are interested in
    #[derive(Clone, Debug, Serialize, Deserialize)]
    #[serde(rename_all = "kebab-case")]
    enum Mode {
    Build,
    RunCustomBuild,
    }
    /// See https://docs.rs/cargo/latest/cargo/util/machine_message/struct.TimingInfo.html
    #[derive(Clone, Debug, Serialize, Deserialize)]
    pub struct Message {
    reason: String,
    package_id: PackageId,
    target: Target,
    mode: Mode,
    duration: f64,
    rmeta_time: Option<f64>,
    }
    pub fn generate() -> Vec<Message> {
    // TODO: `cargo build --timings=json` seems to only work on a clean build
    Command::new("cargo")
    .arg("clean")
    .args(CARGO_CUSOTM_PROFILE)
    .args(&["--profile", "depwiz"])
    .stdout(Stdio::inherit())
    .stderr(Stdio::inherit())
    .output()
    .unwrap();
    let timings_ouput = Command::new("cargo")
    .arg("build")
    .args(CARGO_CUSOTM_PROFILE)
    .args(&[
    "--profile",
    "depwiz",
    "-Zunstable-options",
    "--timings=json",
    ])
    .stderr(Stdio::inherit())
    .output()
    .unwrap();
    let mut timings = Vec::new();
    let mut timings_buffer = BufReader::new(timings_ouput.stdout.as_slice());
    let mut message_buffer = Vec::new();
    loop {
    timings_buffer
    .read_until(b'\n', &mut message_buffer)
    .unwrap();
    let json_message: Message = match serde_json::from_slice(&message_buffer) {
    Ok(message) => message,
    Err(err) => {
    use serde_json::error::Category;
    match err.classify() {
    Category::Eof => break,
    Category::Data => todo!(
    "JSON object not properly handled, got `{err:?}` for message: `{}`",
    String::from_utf8(message_buffer.clone()).unwrap()
    ),
    _ => {
    panic!("Unexpected error while parsing: {err:?}");
    }
    }
    }
    };
    // Make sure it's actually a timings message
    assert_eq!(json_message.reason, "timing-info");
    timings.push(json_message);
    message_buffer.clear();
    }
    timings
    }
  • edit in src/main.rs at line 6
    [3.126]
    [3.265]
    mod timings;
  • replacement in src/main.rs at line 50
    [3.718][2.1175:1288]()
    let mut cmd = MetadataCommand::new();
    let package_graph = PackageGraph::from_command(&mut cmd).unwrap();
    [3.718]
    [3.896]
    dbg!(timings::generate());
    let mut metadata_cmd = MetadataCommand::new();
    let package_graph = PackageGraph::from_command(&mut metadata_cmd).unwrap();
  • edit in Cargo.toml at line 7
    [3.1040]
    [3.1637]
    cargo_metadata = "0.18.1"
  • edit in Cargo.toml at line 10
    [2.1354]
    serde = { version = "1.0.198", features = ["serde_derive"] }
    serde_json = "1.0.116"
  • edit in Cargo.lock at line 115
    [3.2014]
    [3.2804]
    "cargo_metadata",
  • edit in Cargo.lock at line 118
    [2.2087]
    [3.2817]
    "serde",
    "serde_json",
  • replacement in Cargo.lock at line 378
    [3.3118][3.3118:3138]()
    version = "1.0.197"
    [3.3118]
    [3.3138]
    version = "1.0.198"
  • replacement in Cargo.lock at line 380
    [3.3203][3.3203:3281]()
    checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
    [3.3203]
    [3.3281]
    checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc"
  • replacement in Cargo.lock at line 387
    [3.3352][3.3352:3372]()
    version = "1.0.197"
    [3.3352]
    [3.3372]
    version = "1.0.198"
  • replacement in Cargo.lock at line 389
    [3.3437][3.3437:3515]()
    checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
    [3.3437]
    [3.3515]
    checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9"
  • replacement in Cargo.lock at line 398
    [3.3601][3.3601:3621]()
    version = "1.0.115"
    [3.3601]
    [3.3621]
    version = "1.0.116"
  • replacement in Cargo.lock at line 400
    [3.3686][3.3686:3764]()
    checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd"
    [3.3686]
    [3.3764]
    checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"