deb: record per-phase build timings, shown by pkh deb profile
Time every Phase the build flow announces through enter_phase — the chroot bootstrap (tarball download, extraction, finalization), the apt phases, patch application, the build and binary steps and the artifact retrieval — and land the ordered profile in the record's manifest of every run, failed builds included: their profile ends at the phase the error propagated out of. Timing rides the enter_phase choke point instead of new measurement sites, so a phase added later profiles itself. The manifest field is additive (serde default, skipped when absent), so older manifests keep loading without a schema bump. The coarse timings stay the source of the deb list columns: they measure the apt transactions themselves, where the profile measures whole phases. pkh deb profile renders a record's profile through the same read-only record discovery as pkh deb log — the newest record of the tree, or an id prefix as shown by pkh deb list — so record_for_log becomes the neutral find_record. Phase keys are storage names, distinct from the display labels; Phase::from_key turns them back and a test keeps both in sync.
This commit is contained in:
+28
-2
@@ -392,6 +392,12 @@ fn main() {
|
||||
.arg(arg!([id] "Record id (default: the newest record of this tree)").required(false))
|
||||
.arg(arg!(-f --follow "Keep reading the log as the build writes it")),
|
||||
)
|
||||
.subcommand(
|
||||
Command::new("profile")
|
||||
.about("Print a recorded build's per-phase timing profile")
|
||||
.long_about("Print the timing profile of a recorded build: how long every phase took, from the chroot bootstrap (tarball download, extraction, finalization) through the apt phases (package lists, essential packages, injected packages, build dependencies) and patch application to the build and binary steps and the artifact retrieval, each with its share of the total.\nWithout an ID, the newest record of this tree; with an ID (as shown by 'pkh deb list'), that exact record. A failed build's profile ends at the phase the error surfaced from.")
|
||||
.arg(arg!([id] "Record id (default: the newest record of this tree)").required(false)),
|
||||
)
|
||||
)
|
||||
.subcommand(
|
||||
Command::new("test")
|
||||
@@ -910,10 +916,10 @@ fn main() {
|
||||
// `pkh deb log`: print a recorded build's log (optionally
|
||||
// following a live build); read-only too.
|
||||
if let Some(("log", log_matches)) = sub_matches.subcommand() {
|
||||
let tree = cwd.canonicalize().unwrap_or(cwd.clone());
|
||||
let tree = cwd.canonicalize().unwrap_or_else(|_| cwd.clone());
|
||||
let id = log_matches.get_one::<String>("id").map(String::as_str);
|
||||
let follow = log_matches.get_flag("follow");
|
||||
let record = match pkh::deb::session::record_for_log(
|
||||
let record = match pkh::deb::session::find_record(
|
||||
&pkh::deb::session::sessions_root(),
|
||||
&tree,
|
||||
id,
|
||||
@@ -935,6 +941,26 @@ fn main() {
|
||||
return;
|
||||
}
|
||||
|
||||
// `pkh deb profile`: print a recorded build's per-phase
|
||||
// timing profile; read-only too.
|
||||
if let Some(("profile", profile_matches)) = sub_matches.subcommand() {
|
||||
let tree = cwd.canonicalize().unwrap_or_else(|_| cwd.clone());
|
||||
let id = profile_matches.get_one::<String>("id").map(String::as_str);
|
||||
let record = match pkh::deb::session::find_record(
|
||||
&pkh::deb::session::sessions_root(),
|
||||
&tree,
|
||||
id,
|
||||
) {
|
||||
Ok(record) => record,
|
||||
Err(e) => {
|
||||
error!("{e}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
print!("{}", pkh::deb::session::render_record_profile(&record));
|
||||
return;
|
||||
}
|
||||
|
||||
// Ctrl+C during the build must say what happened and release the
|
||||
// ephemeral chroot instead of dying on the default disposition.
|
||||
// The live view (when enabled) registers its own reporter on top
|
||||
|
||||
Reference in New Issue
Block a user