From 7981718d83d88bb7d755b946ffc88c1c9b6b5cd9 Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Sun, 30 Aug 2026 17:38:11 +0200 Subject: [PATCH] Time the phases of a launch, because the tablet has no profiler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two things are now off the launch path and the rest of it is unmeasured. There is no way to attach a profiler to an Android launch, and the window that matters — from `android_main` to the first `poll_events` — is over before anything on the device can be asked a question about it. So a line in the log file is the only measurement anybody gets. Three of them: the GPU open, the window build, and the total to the event loop. The last is the one that matters, because it is the figure the input dispatcher is counting against — anything approaching five seconds there is the next ANR whatever the phases above it say. The GPU open is timed rather than moved. It is a Vulkan instance, an adapter enumeration and a device request, and on the desktop it cannot be deferred at all: it selects the Slint backend, and creating a window selects one for us. On Android it could be, because nothing shares that device with the compositor (TD-1) — but "could be deferred" is not "costs enough to be worth deferring", and there is no number yet that says which. This is the line that will produce one. Co-Authored-By: Claude Opus 5 (1M context) --- ui/dr-ui/src/lib.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/ui/dr-ui/src/lib.rs b/ui/dr-ui/src/lib.rs index 3ef9090..ba2da58 100644 --- a/ui/dr-ui/src/lib.rs +++ b/ui/dr-ui/src/lib.rs @@ -975,13 +975,36 @@ pub fn run(paths: Vec) -> Result<()> { log::debug!("could not set the xdg app id: {e}"); } + // Everything between here and `window.run()` at the bottom happens before + // the event loop exists, and on Android that is not merely a slow start: + // `android_main` calls this, and nothing drains the activity's input + // channel until Slint reaches its first `poll_events` inside `run()`. Five + // seconds of it is an ANR, over a window that has never painted. + // + // So the two phases that touch a driver or a disk are timed, and so is the + // whole of it. There is no profiler on the tablet and no way to attach one + // to a launch: a line in the log file is the only measurement anybody gets, + // and without it the next regression here is guesswork about which of half + // a dozen candidates it was. + let launch_began = std::time::Instant::now(); + // Before the window, and it has to be: this selects the Slint backend, and // creating a window selects one for us. See `shared_gpu`. The device is // shared by demosaic, the adjust pass and the compositor; without one the // app still browses through the preview path, just without develop. + // + // Timed rather than moved: this is a Vulkan instance, an adapter + // enumeration and a device request, none of which can be deferred on the + // desktop because the backend must be chosen before a window exists. On + // Android it could be — nothing shares that device with the compositor + // (TD-1) — but "could be" is not "costs enough to be worth it", and this + // line is what will say which. let gpu = shared_gpu(); + log::info!("gpu opened in {} ms", launch_began.elapsed().as_millis()); + let before_window = std::time::Instant::now(); let window = AppWindow::new()?; + log::info!("window built in {} ms", before_window.elapsed().as_millis()); // The version the About page shows. Taken from the crate rather than // passed in, so it is the version of the code that is running and cannot // be set to something else by a caller. @@ -3152,6 +3175,15 @@ pub fn run(paths: Vec) -> Result<()> { show(&window); } + // The figure that matters, because it is the one the input dispatcher is + // counting against. Anything approaching five seconds here is an ANR on the + // next Android launch whatever the phases above say, and anything that + // pushes it up belongs on a worker. + log::info!( + "startup: {} ms to the event loop", + launch_began.elapsed().as_millis() + ); + window.run()?; Ok(()) }