Add anyhow for better errors

This commit is contained in:
David Venhoff 2025-09-12 11:54:10 +02:00
parent 9a08103872
commit d7cf79a092
6 changed files with 99 additions and 27 deletions

70
Cargo.lock generated
View File

@ -2,6 +2,21 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "addr2line"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
dependencies = [
"gimli",
]
[[package]]
name = "adler2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]]
name = "aho-corasick"
version = "1.1.3"
@ -61,12 +76,36 @@ dependencies = [
"windows-sys 0.60.2",
]
[[package]]
name = "anyhow"
version = "1.0.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
dependencies = [
"backtrace",
]
[[package]]
name = "autocfg"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "backtrace"
version = "0.3.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
dependencies = [
"addr2line",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
"windows-targets 0.52.6",
]
[[package]]
name = "base-x"
version = "0.2.11"
@ -421,6 +460,12 @@ dependencies = [
"wasi 0.14.5+wasi-0.2.4",
]
[[package]]
name = "gimli"
version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]]
name = "glob"
version = "0.3.3"
@ -573,6 +618,15 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniz_oxide"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
dependencies = [
"adler2",
]
[[package]]
name = "nix"
version = "0.26.4"
@ -618,6 +672,15 @@ dependencies = [
"syn 2.0.106",
]
[[package]]
name = "object"
version = "0.36.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
version = "1.21.3"
@ -692,6 +755,7 @@ dependencies = [
name = "qemu-nyx-runner"
version = "0.1.0"
dependencies = [
"anyhow",
"clap",
"csv",
"libnyx",
@ -809,6 +873,12 @@ dependencies = [
"serde",
]
[[package]]
name = "rustc-demangle"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
[[package]]
name = "rustc-hash"
version = "2.1.1"

View File

@ -12,6 +12,7 @@ libnyx = { git = "https://git.cs.tu-dortmund.de/david.venhoff/libnyx-fork" }
pt-dump-decoder = { path = "pt-dump-decoder" }
csv = "1.3.1"
clap.workspace = true
anyhow = { version = "1.0.99", features = ["backtrace"] }
[workspace.dependencies]
clap = { version = "4.5.47", features = ["derive"] }
clap = { version = "4.5.47", features = ["derive"] }

View File

@ -1,13 +1,12 @@
use crate::benchmark::Benchmark;
use crate::nyx::{NyxRunner, TraceMode};
use std::error::Error;
use std::path::Path;
use std::time::Duration;
pub struct BenchmarkNyxNoPt(NyxRunner);
impl BenchmarkNyxNoPt {
pub fn new(client_path: &Path) -> Result<Self, Box<dyn Error>> {
pub fn new(client_path: &Path) -> anyhow::Result<Self> {
Ok(BenchmarkNyxNoPt(NyxRunner::setup(
client_path,
TraceMode::Disabled,

View File

@ -2,14 +2,13 @@ use crate::benchmark::{Benchmark, ToCsv};
use crate::nyx::{NyxRunner, TraceMode};
use csv::Writer;
use pt_dump_decoder::{AnalyzeData, analyze_dump};
use std::error::Error;
use std::io::Write;
use std::path::Path;
pub struct BenchmarkNyx(NyxRunner);
impl BenchmarkNyx {
pub fn new(client_bin: &Path) -> Result<Self, Box<dyn Error>> {
pub fn new(client_bin: &Path) -> anyhow::Result<Self> {
Ok(BenchmarkNyx(NyxRunner::setup(
client_bin,
TraceMode::Enabled,

View File

@ -11,7 +11,6 @@ use crate::benchmark_baseline::Baseline;
use crate::benchmark_nyx_no_pt::BenchmarkNyxNoPt;
use crate::benchmark_nyx_pt::BenchmarkNyx;
use clap::Parser;
use std::error::Error;
use std::fmt::Debug;
use std::fs;
use std::path::{Path, PathBuf};
@ -30,7 +29,7 @@ struct Args {
debug: bool,
}
fn main() -> Result<(), Box<dyn Error>> {
fn main() -> anyhow::Result<()> {
let args = Args::parse();
if args.debug {
@ -56,7 +55,7 @@ fn benchmark<B: Benchmark>(
binary_name: &str,
output_dir: &Path,
mut benchmark: B,
) -> Result<(), Box<dyn Error>> {
) -> anyhow::Result<()> {
warmup(&mut benchmark);
let results = benchmark_loop(&mut benchmark);
write_results::<B>(binary_name, output_dir, &results)?;
@ -89,10 +88,10 @@ fn write_results<B: Benchmark>(
binary_name: &str,
output_dir: &Path,
results: &[B::BenchmarkResult],
) -> Result<(), Box<dyn Error>> {
) -> anyhow::Result<()> {
fs::create_dir_all(output_dir)?;
let filename = format!("benchmark_{binary_name}_{}", B::TITLE);
let file = std::fs::File::create(output_dir.join(filename))?;
let file = fs::File::create(output_dir.join(filename))?;
let mut writer = csv::WriterBuilder::new().from_writer(file);
writer.write_record(B::BenchmarkResult::HEADERS)?;
for result in results {

View File

@ -1,8 +1,8 @@
//! This module contains functionality to download and setup nyx,
//! so that it can be used to execute a binary.
use anyhow::{Context, anyhow, bail};
use libnyx::{NyxConfig, NyxProcess, NyxProcessRole, NyxReturnValue};
use std::error::Error;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::time::Duration;
@ -19,7 +19,7 @@ pub enum TraceMode {
pub struct NyxRunner(NyxProcess);
impl NyxRunner {
pub fn setup(client_bin: &Path, trace_mode: TraceMode) -> Result<Self, Box<dyn Error>> {
pub fn setup(client_bin: &Path, trace_mode: TraceMode) -> anyhow::Result<Self> {
if let Err(e) = fs::remove_dir_all(WORKDIR_PATH)
&& !matches!(e.kind(), io::ErrorKind::NotFound)
{
@ -28,7 +28,9 @@ impl NyxRunner {
let sharedir = setup_nyx(&PathBuf::from("nyx_data"), client_bin)?;
let sharedir = sharedir.to_str().expect("Expected unicode path");
let mut nyx_config = NyxConfig::load(sharedir)?;
let mut nyx_config = NyxConfig::load(sharedir)
.map_err(|err| anyhow!(err))
.with_context(|| "Creating nyx config")?;
nyx_config.set_workdir_path(WORKDIR_PATH.to_string());
nyx_config.set_input_buffer_size(0x2000);
nyx_config.set_nyx_debug_log_path("qemu_nyx.log".to_string());
@ -37,7 +39,9 @@ impl NyxRunner {
nyx_config.set_process_role(NyxProcessRole::StandAlone);
nyx_config.print();
let mut nyx_runner = NyxProcess::new(&mut nyx_config, 0)?;
let mut nyx_runner = NyxProcess::new(&mut nyx_config, 0)
.map_err(|err| anyhow!(err))
.with_context(|| "Creating Nyx Process")?;
nyx_runner.option_set_trace_mode(true);
nyx_runner.option_set_reload_mode(false);
@ -79,30 +83,31 @@ impl Drop for NyxRunner {
/// [client] Is the path to the client binary.
///
/// Returns the path to the working directory
pub fn setup_nyx(out_dir: &Path, client: &Path) -> Result<PathBuf, io::Error> {
fn inner(out_dir: &Path, client: &Path) -> Result<PathBuf, io::Error> {
pub fn setup_nyx(out_dir: &Path, client: &Path) -> anyhow::Result<PathBuf> {
fn inner(out_dir: &Path, client: &Path) -> anyhow::Result<PathBuf> {
if !out_dir.exists() {
fs::create_dir(out_dir)?;
}
println!("Installing nyx...");
setup_nyx_tools(out_dir)?;
setup_nyx_tools(out_dir).with_context(|| "Setting up nyx tools")?;
create_nyx_workdir(out_dir, client)
create_nyx_workdir(out_dir, client).with_context(|| "Creating the nyx working directory")
}
// Clean up the out directory if something went wrong
match inner(out_dir, client) {
Ok(path) => Ok(path),
Err(err) => {
fs::remove_dir_all(out_dir)?;
fs::remove_dir_all(out_dir)
.with_context(|| format!("Error while handling error: {err}"))?;
Err(err)
}
}
}
#[track_caller]
fn shell(cwd: impl AsRef<Path>, command_string: &str) -> Result<(), io::Error> {
fn shell(cwd: impl AsRef<Path>, command_string: &str) -> anyhow::Result<()> {
println!("Running ({}) {command_string}", cwd.as_ref().display());
let cwd = cwd.as_ref();
@ -118,9 +123,7 @@ fn shell(cwd: impl AsRef<Path>, command_string: &str) -> Result<(), io::Error> {
let mut process = command.spawn()?;
let exit_status = process.wait()?;
if !exit_status.success() {
return Err(io::Error::other(format!(
"Command ({command_string}) failed with {exit_status}"
)));
bail!("Command ({command_string}) failed with {exit_status}");
}
Ok(())
@ -128,7 +131,7 @@ fn shell(cwd: impl AsRef<Path>, command_string: &str) -> Result<(), io::Error> {
/// Downloads and compiles qemu-nyx and packer and compiles them for the current architecture
/// This means that cross-compilation is not supported
fn setup_nyx_tools(out_dir: &Path) -> Result<(), io::Error> {
fn setup_nyx_tools(out_dir: &Path) -> anyhow::Result<()> {
let packer_path = out_dir.join("packer");
let qemu_path = out_dir.join("QEMU-Nyx");
if !packer_path.exists() {
@ -142,7 +145,7 @@ fn setup_nyx_tools(out_dir: &Path) -> Result<(), io::Error> {
)?;
// Compile with maximum optimizations
let qemu_compile_mode = "lto";
let qemu_compile_mode = "debug_static";
shell(
qemu_path,
&format!("bash compile_qemu_nyx.sh {qemu_compile_mode}"),
@ -152,8 +155,9 @@ fn setup_nyx_tools(out_dir: &Path) -> Result<(), io::Error> {
Ok(())
}
fn create_nyx_workdir(out_dir: &Path, client_bin: &Path) -> Result<PathBuf, io::Error> {
let client_bin = fs::canonicalize(client_bin)?;
fn create_nyx_workdir(out_dir: &Path, client_bin: &Path) -> anyhow::Result<PathBuf> {
let client_bin =
fs::canonicalize(client_bin).with_context(|| format!("canonicalizing {client_bin:?}"))?;
let client_bin = client_bin.to_str().expect("Expected unicode path");
// Create the directory and move required binaries to it
shell(