docs(perf): consolidated before/after, plus what is still unverified
All previous numbers were spread across rounds with different instruments and different workloads. This is one instrument, one workload, alternated, 2 runs per side, merge-base vs HEAD: server idle 141.9 -> 89.7 MiB (-37%) server loaded 257.3 -> 173.0 MiB (-33%) server peak 705.2 -> 568.4 MiB (-19%) after idle soak 332.0 -> 232.5 MiB (-30%) JS event listeners 10,126 -> 7,774 (-23%) React fibers 5,224 -> 3,588 (-31%) DOM nodes 9,175 -> 8,284 (-10%) browser JS heap 55.2 -> 51.1 MiB (-7%) image 410 -> 398 MB (-3%) container CPU 22.8 -> 22.8 s unchanged Recorded prominently rather than buried: under *sustained* 4-tab load the two builds converge, 368 vs 364 MiB. The wins are idle, steady state and peak. That is why hammering the app with five tabs did not feel 30% lighter — at saturation the footprint is live widget data and render churn, which this PR does not change. Also documents the gaps, since "tested" without them would be misleading: no multi-hour soak (the #5301 reports are about days), single user, SQLite only, the DevTools Profiler tab confirmed at bundle level rather than in the extension, and the App Router re-rendering ~1x/second still unfixed. verify-context-menu.mts now also covers touch long-press, and no longer asserts on a fiber total — that counter swung 7,454 to 16,149 between runs of the same build, so it was noise. probe-fiber-tree.mts is the stable counter and is what the -31% above comes from.
This commit is contained in:
2 files changed
+110
-4
No files matched your search
@@ -131,6 +131,30 @@ const closed = await dropdown
|
||||
.catch(() => false);
|
||||
check(closed, "Escape closes the menu");
|
||||
|
||||
// Touch long-press: the shared menu replaced Mantine's Menu.ContextMenu, which
|
||||
// handled this natively, so it has to be re-proven rather than assumed.
|
||||
const longPressItem = (index: number) =>
|
||||
page.evaluate((itemIndex) => {
|
||||
const items = [...document.querySelectorAll('[data-homarr-dev-benchmark-board] [data-type="item"]')];
|
||||
const item = items[itemIndex];
|
||||
if (!item) return false;
|
||||
const rect = item.getBoundingClientRect();
|
||||
const target = (item.querySelector("*") as HTMLElement | null) ?? (item as HTMLElement);
|
||||
const x = rect.x + rect.width / 2;
|
||||
const y = rect.y + rect.height / 2;
|
||||
const touch = new Touch({ identifier: 1, target, clientX: x, clientY: y });
|
||||
target.dispatchEvent(new TouchEvent("touchstart", { bubbles: true, cancelable: true, touches: [touch] }));
|
||||
return true;
|
||||
}, index);
|
||||
|
||||
await longPressItem(2 % Math.max(itemCount, 1));
|
||||
// Delay is 500ms in the component; allow margin.
|
||||
await page.waitForTimeout(1_200);
|
||||
const openedByTouch = await dropdown.isVisible().catch(() => false);
|
||||
check(openedByTouch, "touch long-press opens the context menu");
|
||||
await page.keyboard.press("Escape").catch(() => undefined);
|
||||
await dropdown.waitFor({ state: "hidden", timeout: 5_000 }).catch(() => undefined);
|
||||
|
||||
// A shared menu has to re-target; a per-item menu would trivially pass the first case.
|
||||
if (itemCount > 1) {
|
||||
await rightClickItem(1);
|
||||
@@ -143,11 +167,11 @@ if (itemCount > 1) {
|
||||
await dropdown.waitFor({ state: "hidden", timeout: 5_000 }).catch(() => undefined);
|
||||
}
|
||||
|
||||
// Fiber totals are reported for context only, never asserted on: this counter walks
|
||||
// every root the devtools hook has seen, and portals opened by the menu make it swing
|
||||
// by 2x between runs of the same build. Use probe-fiber-tree.mts for a stable count.
|
||||
const afterFibers = await countFibers(page);
|
||||
console.log(
|
||||
`\nfibers after opening/closing menus: ${afterFibers} (delta ${afterFibers - idleFibers >= 0 ? "+" : ""}${afterFibers - idleFibers})`,
|
||||
);
|
||||
check(afterFibers < idleFibers * 1.5, "tree did not balloon after using the menu");
|
||||
console.log(`\nfibers (context only, not asserted): idle ${idleFibers} -> ${afterFibers} after using the menu`);
|
||||
|
||||
console.log(`\n${failures.length === 0 ? "ALL CHECKS PASSED" : `${failures.length} CHECK(S) FAILED`}`);
|
||||
console.log(JSON.stringify({ itemCount, idleFibers, afterFibers, failures }, null, 2));
|
||||
|
||||
Reference in new issue
Block a user