From 542d9a333b9570e1a24a3b17bfcebdade77c102f Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Thu, 23 Jul 2026 20:10:40 +0800 Subject: [PATCH] perf, fix: Avoid tight tick loop before page loads https://github.com/lightpanda-io/browser/pull/2999 fixed a spin loop when the page had no i/o but had tasks, something we'd expect to see at page-load end. But it introduced a similar spin loop as what it fixed on page-start, before the page has anything to do. Specifically, 2999 preventing i/o pollings when tasks were waiting. But, the code doesn't run tasks until there's a "runnable" task. On Frame start, we register a background task. Net result is that, for the first 200ms, everything is fine, but then the task is due, so we don't poll, but we also don't run the tasks, repeating a tick(0) loop. The solution is simply to disable the 2999 optimization when there's no runnable page. --- src/browser/Runner.zig | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/browser/Runner.zig b/src/browser/Runner.zig index 7ecc63061..0c4065a4f 100644 --- a/src/browser/Runner.zig +++ b/src/browser/Runner.zig @@ -217,7 +217,9 @@ fn _tick(self: *Runner, comptime is_cdp: bool, timeout_ms: u32, conditions: []Wa return .{ .ok = 0 }; } - if (hasRunnablePage(session)) { + const has_runnable_page = hasRunnablePage(session); + + if (has_runnable_page) { try browser.runMacrotasks(); } @@ -295,12 +297,18 @@ fn _tick(self: *Runner, comptime is_cdp: bool, timeout_ms: u32, conditions: []Wa } if ((comptime is_cdp) or want_http_tick) { - var ms_to_wait = @min(timeout_ms, browser.msToNextTask() orelse 200); - if (browser.hasBackgroundTasks()) { - // background work will queue more to do soon — don't block long - // for a client message; loop back and run macrotasks instead. - ms_to_wait = @min(ms_to_wait, 10); - } + const ms_to_next_task = blk: { + if (has_runnable_page == false) { + break :blk 200; + } + if (browser.hasBackgroundTasks()) { + // msToNextTask could be less than this, but 10ms drift is ok + break :blk 10; + } + break :blk browser.msToNextTask() orelse 200; + }; + const ms_to_wait = @min(timeout_ms, ms_to_next_task); + const waited = try http_client.tick(@intCast(ms_to_wait)); // If the HttpClient didn't wait/poll then it has nothing to do, and we