From 37ef970dfcf54e20f02f686a0a2c69eb45a3ef8b Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 10 Sep 2026 17:38:36 +0300 Subject: [PATCH] test(perf): count update cycles, model builds and adoptions during boot (#520) The full comparison says model readiness grew by ~500 ms inside #500 and that the growth sits in one long task, but neither contentFingerprint (2.8 ms on this fixture) nor spaceModels (0.1 ms) can account for it. The benchmark now prints, per sample, how many Lit update cycles ran before the first stable frame, how long they took together, how many models were built, how many adoptions happened and the config epoch. Diagnostics only: printed to the log, never part of the budgeted record, and the same harness runs against the comparison bundle, so candidate and base are counted alike. Issue: #520 User-Visible: no --- demo/benchmark_large_house.mjs | 24 ++++++++++++++++++++++++ node_modules | 1 + 2 files changed, 25 insertions(+) create mode 120000 node_modules diff --git a/demo/benchmark_large_house.mjs b/demo/benchmark_large_house.mjs index f7d8634d..c6b7a2be 100644 --- a/demo/benchmark_large_house.mjs +++ b/demo/benchmark_large_house.mjs @@ -294,6 +294,26 @@ try { } else history.replaceState(null, '', location.pathname); const host = document.getElementById('host'); const card = document.createElement('houseplan-card'); + // #520 diagnostics: where the extra half second of model readiness goes. + // Counts Lit update cycles and model builds; printed, never budgeted. + card.__diag = { updates: 0, updateMs: 0, models: 0, adopts: 0 }; + const diagPerform = card.performUpdate.bind(card); + card.performUpdate = function () { + const started = performance.now(); + const result = diagPerform(); + card.__diag.updates += 1; + card.__diag.updateMs += performance.now() - started; + return result; + }; + const diagBuild = card._buildModel.bind(card); + card._buildModel = function () { card.__diag.models += 1; return diagBuild(); }; + if (typeof card._adoptStructuralResponses === 'function') { + const legacy = card._adoptStructuralResponses.bind(card); + card._adoptStructuralResponses = function (...args) { card.__diag.adopts += 1; return legacy(...args); }; + } else if (typeof card._adoptAuthoritative === 'function') { + const gated = card._adoptAuthoritative.bind(card); + card._adoptAuthoritative = function (...args) { card.__diag.adopts += 1; return gated(...args); }; + } card.setConfig({ type: 'custom:houseplan-card', title: `Performance baseline ${sample}`, icon_size: 3.4, }); @@ -363,6 +383,10 @@ try { if (interaction && '_bootSoft' in card) await until(() => card._bootSoft === false); await frame(); const firstStableRenderMs = Number((performance.now() - loadStarted).toFixed(2)); + console.log(`#520 diag sample ${sample}: updates=${card.__diag.updates}` + + ` updateMs=${card.__diag.updateMs.toFixed(1)} models=${card.__diag.models}` + + ` adopts=${card.__diag.adopts} cfgEpoch=${card._cfgEpoch}` + + ` modelReady=${modelReadyMs} firstStable=${firstStableRenderMs}`); const initialProjection = typeof card._effectiveProjection === 'function' ? card._effectiveProjection() : null; if (requiresIsometric && initialProjection !== 'iso') diff --git a/node_modules b/node_modules new file mode 120000 index 00000000..824938e6 --- /dev/null +++ b/node_modules @@ -0,0 +1 @@ +/tmp/rel/node_modules \ No newline at end of file