From e4612ca128951a0b89c9d0d570a15930168c460b Mon Sep 17 00:00:00 2001 From: Valentin Haudiquet Date: Fri, 2 Oct 2026 20:39:24 +0200 Subject: [PATCH] deb: give the build-user setup and resume cleanup their own phases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The profile's build-dependency phase spanned everything between the apt passes and the build step, and for a kernel incremental build that hid ~13 minutes of housekeeping: the recursive chown handing the staged tree to the build user, and the resume_clear quirk dropping the previous attempt's stamp caches. Both now enter the profiler (ClearingResumeCaches only when the quirk has paths and a tree is carried, PreparingBuildUser only for rootless builds), so the status bar and pkh deb profile show where the time actually goes — on a large carried tree the chown dominates, which is the honest answer to a 6m30s DEPS column next to a 19m19s phase. --- README.md | 8 ++++---- src/deb/local.rs | 13 ++++++++++--- src/deb/mod.rs | 17 +++++++++++++++++ 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index bc7a22c..fdf9ae3 100644 --- a/README.md +++ b/README.md @@ -175,10 +175,10 @@ pkh deb list # the records of this tree: id, outcome, pkh deb log [-f] [] # print a record's build log; -f follows a # live build pkh deb profile [] # a record's per-phase timing profile: how - # long the chroot bootstrap, each apt phase, - # patch application, the build and binary - # steps and the artifact retrieval took, with - # their shares of the total + # long every step took (chroot bootstrap, + # apt phases, patch application, build-user + # setup, build and binary steps, artifact + # retrieval), with their shares of the total pkh deb --no-ccache # build without the shared compile cache ``` diff --git a/src/deb/local.rs b/src/deb/local.rs index 5c5d055..da688ec 100644 --- a/src/deb/local.rs +++ b/src/deb/local.rs @@ -639,8 +639,10 @@ pub async fn build( // with no config prerequisite) would build from the previous // attempt's configuration: drop the listed caches so the wrapper // steps re-run over the incremental inner builds. - if build_resume { - for rel in crate::quirks::get_resume_clear_paths(package, series) { + let resume_clear_paths = crate::quirks::get_resume_clear_paths(package, series); + if build_resume && !resume_clear_paths.is_empty() { + enter_phase(view, Phase::ClearingResumeCaches, profiler); + for rel in resume_clear_paths { let path = Path::new(package_dir_str).join(&rel); if !ctx.exists(&path).unwrap_or(false) { continue; @@ -689,7 +691,12 @@ pub async fn build( // LTO/make -j process flood), and a rules chown that fails for the // build user is cosmetic — the .deb is assembled in the binary step's // own fakeroot session, where files unknown to its database are - // recorded as root-owned anyway. + // recorded as root-owned anyway. Handing the tree over is a recursive + // chown that can take minutes on a large carried tree, so it is a + // phase of its own in the status bar and the profile. + if build_user.is_some() { + enter_phase(view, Phase::PreparingBuildUser, profiler); + } let rule_ids = match build_user { Some(_) => { let workroot = Path::new(package_dir_str) diff --git a/src/deb/mod.rs b/src/deb/mod.rs index 0a9869b..5e4bf18 100644 --- a/src/deb/mod.rs +++ b/src/deb/mod.rs @@ -43,6 +43,12 @@ pub enum Phase { InjectingPackages, /// apt-get build-dep InstallingBuildDeps, + /// Drop the resumed tree's input-untracked stamp caches (quirk: + /// `resume_clear`) + ClearingResumeCaches, + /// Create the unprivileged build user and hand the staged tree to + /// it (rootless builds) + PreparingBuildUser, /// debian/rules build Building, /// fakeroot debian/rules binary @@ -63,6 +69,8 @@ impl Phase { Phase::ApplyingPatches => "Applying patches", Phase::InjectingPackages => "Injecting packages", Phase::InstallingBuildDeps => "Installing build dependencies", + Phase::ClearingResumeCaches => "Clearing resumed build caches", + Phase::PreparingBuildUser => "Preparing the build user", Phase::Building => "Building package", Phase::ProducingBinaries => "Producing binary packages", Phase::RetrievingArtifacts => "Retrieving artifacts", @@ -82,6 +90,8 @@ impl Phase { Phase::ApplyingPatches => "applying_patches", Phase::InjectingPackages => "injecting_packages", Phase::InstallingBuildDeps => "installing_build_deps", + Phase::ClearingResumeCaches => "clearing_resume_caches", + Phase::PreparingBuildUser => "preparing_build_user", Phase::Building => "building", Phase::ProducingBinaries => "producing_binaries", Phase::RetrievingArtifacts => "retrieving_artifacts", @@ -101,6 +111,8 @@ impl Phase { "applying_patches" => Phase::ApplyingPatches, "injecting_packages" => Phase::InjectingPackages, "installing_build_deps" => Phase::InstallingBuildDeps, + "clearing_resume_caches" => Phase::ClearingResumeCaches, + "preparing_build_user" => Phase::PreparingBuildUser, "building" => Phase::Building, "producing_binaries" => Phase::ProducingBinaries, "retrieving_artifacts" => Phase::RetrievingArtifacts, @@ -122,6 +134,9 @@ fn default_classifier(phase: Phase) -> Box { Phase::InstallingBuildDeps => { Box::new(AptInstallClassifier::new("Installing build dependencies")) } + Phase::ClearingResumeCaches | Phase::PreparingBuildUser => { + Box::new(GenericClassifier::new()) + } Phase::Building | Phase::ProducingBinaries => Box::new(MakeClassifier::new()), Phase::RetrievingArtifacts => Box::new(GenericClassifier::new()), } @@ -1147,6 +1162,8 @@ mod tests { Phase::ApplyingPatches, Phase::InjectingPackages, Phase::InstallingBuildDeps, + Phase::ClearingResumeCaches, + Phase::PreparingBuildUser, Phase::Building, Phase::ProducingBinaries, Phase::RetrievingArtifacts,