#[cfg(feature = "flamegraph")]
use pprof::ProfilerGuardBuilder;
fn main() {
let Some(path) = std::env::args_os().nth(1) else {
eprintln!("usage: flamegraph_pipeline <ledger.beancount> [iterations]");
std::process::exit(2);
};
let iterations: usize = std::env::args_os()
.nth(2)
.and_then(|s| s.to_str().and_then(|t| t.parse().ok()))
.unwrap_or(50);
let options = rustledger_loader::LoadOptions {
run_plugins: true,
validate: true,
..Default::default()
};
#[cfg(feature = "flamegraph")]
let guard = match ProfilerGuardBuilder::default()
.frequency(1000)
.blocklist(&["libc", "libgcc", "pthread", "vdso"])
.build()
{
Ok(g) => g,
Err(e) => {
eprintln!("failed to start CPU profiler: {e}");
std::process::exit(1);
}
};
let p = std::path::Path::new(&path);
let mut pipeline_errors = 0usize;
for _ in 0..iterations {
match rustledger_loader::load(p, &options) {
Ok(ledger) => pipeline_errors = ledger.errors.len(),
Err(e) => {
eprintln!("load/process failed: {e}");
std::process::exit(1);
}
}
}
if pipeline_errors > 0 {
eprintln!("note: workload produced {pipeline_errors} pipeline errors");
}
#[cfg(feature = "flamegraph")]
{
let report = match guard.report().build() {
Ok(r) => r,
Err(e) => {
eprintln!("failed to build profile report: {e}");
std::process::exit(1);
}
};
let file = match std::fs::File::create("flamegraph.svg") {
Ok(f) => f,
Err(e) => {
eprintln!("failed to create flamegraph.svg: {e}");
std::process::exit(1);
}
};
if let Err(e) = report.flamegraph(file) {
eprintln!("failed to write flamegraph: {e}");
std::process::exit(1);
}
eprintln!("wrote flamegraph.svg ({iterations} iterations)");
}
#[cfg(not(feature = "flamegraph"))]
eprintln!("ran {iterations} iterations (build with --features flamegraph to profile)");
}