- Session::execute is a command span; Model::evaluate and each feature computed (by its type) are spans; io's import, export and design read/write too; the STEP reader's topology, pcurves and solid record. - diagnostics.profile (contract + output schema): report, start/stop, reset, Chrome trace file. - A STEP/IGES import's reply carries its own profile while recording. - Every app compiles the profiler in by default (feature `profile`); SOLIDCRAFT_PROFILE=1 starts it. - solidcraft-cli run/eval/bench-open --profile print the table on stderr, --profile-out writes the trace; run --profile works on designs and STEP files. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
51 lines
2.0 KiB
Rust
51 lines
2.0 KiB
Rust
//! `--profile` and `--profile-out FILE` for `run`, `eval` and `bench-open` (and
|
|
//! `SOLIDCRAFT_PROFILE=1` for any command): record where the time goes, SMLib's calls to the
|
|
//! commands, print the table to stderr when the command ends (stdout stays the command's JSON)
|
|
//! and write the spans as a Chrome trace for chrome://tracing or Perfetto.
|
|
|
|
use solidcraft_engine::profile;
|
|
|
|
/// Rows the table prints.
|
|
const TOP: usize = 30;
|
|
|
|
/// A recording that prints its table when finished.
|
|
pub struct Profiling {
|
|
trace: Option<String>,
|
|
}
|
|
|
|
/// Start recording when `args` (after the command) ask for it, or `SOLIDCRAFT_PROFILE` does.
|
|
pub fn start(args: &[String]) -> Result<Option<Profiling>, String> {
|
|
let trace = match args.iter().position(|a| a == "--profile-out") {
|
|
Some(i) => match args.get(i + 1) {
|
|
Some(f) if !f.starts_with("--") => Some(f.clone()),
|
|
_ => return Err("--profile-out needs a FILE".into()),
|
|
},
|
|
None => None,
|
|
};
|
|
let asked = trace.is_some() || args.iter().any(|a| a == "--profile");
|
|
if !asked && !solidcraft_engine::timing::profile_from_env() {
|
|
return Ok(None);
|
|
}
|
|
if !profile::COMPILED {
|
|
return Err("this solidcraft-cli was built without the profiler (its `profile` feature)".into());
|
|
}
|
|
profile::reset();
|
|
profile::set_enabled(true);
|
|
Ok(Some(Profiling { trace }))
|
|
}
|
|
|
|
impl Profiling {
|
|
/// Stop recording, print the table on stderr and write the trace.
|
|
pub fn finish(self) -> Result<(), String> {
|
|
profile::set_enabled(false);
|
|
eprint!("{}", profile::report().table(TOP));
|
|
if let Some(path) = self.trace {
|
|
let mut bytes = Vec::new();
|
|
profile::write_chrome_trace(&mut bytes).map_err(|e| format!("{path}: {e}"))?;
|
|
std::fs::write(&path, bytes).map_err(|e| format!("{path}: {e}"))?;
|
|
eprintln!("profile: trace written to {path} (open it in chrome://tracing or ui.perfetto.dev)");
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|