From b531c89f821ec1bfb2463bdd23dad084036932ee Mon Sep 17 00:00:00 2001 From: Local Dev Date: Sat, 3 Oct 2026 14:14:46 +0200 Subject: [PATCH] Theseus boot tracer: measure a working launch, and say when it did not MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With a script as the Electron entry, the app path is the script's folder; main.js loads chrome.html, home.html and every overlay by relative name, so all of them failed with ERR_FILE_NOT_FOUND and every traced run measured a broken launch (it also left a window showing the error page). The tracer now sets app.setAppPath to TheseusNavigator, records failed main-frame loads, and run.mjs marks such a run INVALID. Re-measured (warm runs, fresh profile): the per-overlay lazy loading in e524c12 saves 5 processes and ~100 MB private memory at 15 s — not ~30 MB with an unchanged process count as its message says; that figure came from the broken runs. The BNS indexer utilityProcess costs ~60-75 MB. --- scripts/boot-trace/run.mjs | 6 ++++-- scripts/boot-trace/trace-main.js | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/scripts/boot-trace/run.mjs b/scripts/boot-trace/run.mjs index 976055ec..557e02a6 100644 --- a/scripts/boot-trace/run.mjs +++ b/scripts/boot-trace/run.mjs @@ -60,6 +60,7 @@ function summarise(file) { fetches6s: ev.filter((e) => e.kind === "fetch" && e.start < 6000).length, proc15: metric("15s").processes ?? null, mem15: metric("15s").privateMB ?? null, + failed: ev.filter((e) => e.kind === "fail").map((e) => e.label), }; } @@ -68,9 +69,10 @@ for (let i = 1; i <= RUNS; i++) { process.stdout.write(`run ${i}/${RUNS}… `); const file = await runOnce(i); if (!existsSync(file)) { console.log("no trace written (see " + file.replace(/json$/, "log") + ")"); continue; } - const r = summarise(file); rows.push(r); console.log("done"); + const r = summarise(file); rows.push(r); + console.log(r.failed.length ? `INVALID — ${r.failed.length} page load(s) failed: ${r.failed[0]}` : "done"); } const cols = [["ready", "ready"], ["toolbar", "toolbar"], ["firstPage", "1st page"], ["blocks6s", "blocked<6s"], ["addons", "addons"], ["overlaysLoaded", "overlays"], ["fetches6s", "fetch<6s"], ["proc15", "procs@15s"], ["mem15", "MB@15s"]]; console.log("\n" + ["run", ...cols.map((c) => c[1])].map((h) => h.padStart(11)).join("")); -rows.forEach((r, i) => console.log([String(i + 1), ...cols.map(([k]) => String(r[k] ?? "—"))].map((v) => v.padStart(11)).join(""))); +rows.forEach((r, i) => console.log((r.failed.length ? "!" : " ") + [String(i + 1), ...cols.map(([k]) => String(r[k] ?? "—"))].map((v) => v.padStart(11)).join(""))); console.log(`\ntimes in ms since process start; MB = private memory of all Theseus processes. Traces: ${traceDir}`); diff --git a/scripts/boot-trace/trace-main.js b/scripts/boot-trace/trace-main.js index 5ab3a833..904e9a45 100644 --- a/scripts/boot-trace/trace-main.js +++ b/scripts/boot-trace/trace-main.js @@ -43,6 +43,10 @@ for (const k of ["log", "warn", "error"]) { } const { app } = require("electron"); +// With a script as the entry, Electron takes the script's folder as the app +// path, and main.js loads its pages by relative name (loadFile("chrome.html")) +// — every UI page then fails with ERR_FILE_NOT_FOUND. Point it at the app. +app.setAppPath(APP); app.setPath("userData", process.env.THESEUS_USER_DATA); // With a script as the entry, package.json isn't read: keep the real name and // version so profile paths and version checks behave as in a normal run. @@ -54,6 +58,8 @@ app.on("ready", () => mark("app", "ready")); app.on("web-contents-created", (_e, wc) => { const id = wc.id; mark("wc", "created #" + id); wc.once("did-finish-load", () => { let u = ""; try { u = wc.getURL(); } catch {} mark("wc", `loaded #${id} ${u.replace(/^file:\/\/\/.*\//, "file:").slice(0, 90)}`); }); + // A failed main-frame load means the run did not measure a working launch. + wc.on("did-fail-load", (_e, code, desc, url, isMainFrame) => { if (isMainFrame && code !== -3) mark("fail", `#${id} ${code} ${desc} ${String(url).slice(0, 90)}`); }); }); const metrics = (label) => { try {