Performance Baseline Harness (perf/)
Automated performance baseline and regression harness for the ytplayer PWA.
The harness drives the real Bun backend server (server/server.js) serving static Brotli-compressed assets, combined with Playwright browser automation on Chromium and WebKit.
1. Architecture
Backend Server (server/server.js)
- Runs as an isolated child process using Bun on an ephemeral port.
- Configured with dedicated scratch directories under
perf/.tmp/(DATA_DIR,DB_PATH,MEDIA_DIR) so no production or developer data is ever touched. - Employs the real static asset delivery stack (
Brotliencoding,ETaggeneration,Cache-Controlimmutable caching for version-stamped assets, andcomputeBuildTag()).
Browser Automation & Network Throttling
- Chromium:
- Network emulation via Chrome DevTools Protocol (
Network.emulateNetworkConditions). - CPU throttling at 4× slowdown (
Emulation.setCPUThrottlingRate). - Unrestricted audio/video playback via
--autoplay-policy=no-user-gesture-required.
- Network emulation via Chrome DevTools Protocol (
- WebKit:
- WebKit on Linux lacks CDP network emulation capabilities.
- Throttling and stalling are handled by a dedicated local proxy (
perf/proxy.mjs) sitting between WebKit and the Bun server. - The proxy shapes traffic by pacing chunk delivery through backpressured streams and injecting round-trip latency and stalls.
- Network Profiles:
lte: 1.6 Mbps (200 KB/s) download, 750 kbps upload, 150 ms round-trip latency.lossy: 1.0 Mbps (125 KB/s) download, 250 ms latency, with intermittent connection stalls (every 7th request delayed by 1,500 ms).
Shell Fixture Extractor (perf/make-shell-fixture.sh)
- Archives the frontend from git commits (
git archive <commit> frontend) intoperf/fixtures/shell-<tag>/. - Computes the build tag using the exact sha256 walk algorithm from
server/server.js computeBuildTag(). - Validates the computed tag against live production (
https://worship.hesed.sbs/api/version).
2. Test Scenarios
cold(Cold First Load):- Fresh browser context with empty cache, no service worker, and clean storage.
- Measures initial page fetch, FCP, LCP, DOMContentLoaded, boot milestone (
#cardsrender), media playback readiness, service worker precaching duration, and origin storage quota.
warm(Warm Reload under SW):- Re-navigates the page with active Service Worker and primed HTTP cache.
- Measures cached asset retrieval efficiency and second-load boot performance.
offline(Offline Reload):- Sets offline state and reloads the application.
- Verifies the app boots entirely from
CacheStorageprecached shell assets without network connectivity.
update-js(Update N → N+1 with 1-line JS comment):- Boots client against Tree N (base frontend), establishing an active Service Worker.
- Swaps server to Tree N+1 (one comment line appended to
app.js, alteringBUILD_TAG). - Triggers
registration.update()and measures total wire bytes and time until the new Service Worker reacheswaitingstate (installed).
update-css(Update N → N+1 with 1-line CSS rule):- Identical to
update-js, but Tree N+1 has one CSS rule appended totheme-glass.css. - Measures the full shell re-download penalty caused by any stylesheet modification.
- Identical to
3. Metrics Collected
Each scenario records the following metrics across 5 independent runs (reporting min, max, and median):
- Request Count: Total HTTP requests made across the wire.
- Wire Bytes: Total compressed bytes transferred over the network.
- Wire Bytes by Type: Categorized byte breakdown (
html,js,css,fonts,images,media,api,other). - FCP (First Contentful Paint): Time from navigation start to first rendered content (ms).
- LCP (Largest Contentful Paint): Time to largest contentful paint via
PerformanceObserver(ms). - DOMContentLoaded: Time to DOMContentLoaded event end (ms).
- Boot Done: Time from navigation start until the first
#cardsview rendering is completed (ms). - Long Tasks Total: Cumulative execution time of main thread tasks exceeding 50 ms (ms, Chromium).
- SW Install Duration: Time from Service Worker registration until precaching completes (ms).
- SW Install Wire Bytes: Network bytes transmitted during Service Worker installation.
- Storage Estimate: Quota and usage reported by
navigator.storage.estimate()(bytes). - Media Ready: Elapsed time for deterministic media fixture (
benchmedia01) to reachreadyState >= 3/ playing state. Notes if autoplay policy blocked playback.
4. How to Run
Prerequisites
Symlink dependencies and ensure server dependencies are installed:
# Worktree root
ln -s ~/development/personal/ytplayer/node_modules node_modules
cd server && bun install && cd ..
Basic Commands
Run the complete baseline suite (5 runs, all browsers, LTE profile):
node perf/baseline.mjs
Run a specific browser or profile:
# Chromium on LTE profile
node perf/baseline.mjs --browser chromium --profile lte
# WebKit on LTE profile
node perf/baseline.mjs --browser webkit --profile lte
# Both browsers on lossy profile
node perf/baseline.mjs --browser all --profile lossy
Run a single scenario:
# Cold load only
node perf/baseline.mjs --scenario cold
# Update scenario with 1-line JS change
node perf/baseline.mjs --scenario update-js
# Update scenario with 1-line CSS change
node perf/baseline.mjs --scenario update-css
Configure run count:
# Quick sanity check (1 iteration)
node perf/baseline.mjs --runs 1
# High precision benchmark (7 iterations)
node perf/baseline.mjs --runs 7
5. Phase 5 Comparison Mode (--compare)
To verify performance gains and detect regressions in later phases:
node perf/baseline.mjs --compare perf/results/baseline-2026-10-07.json
Prints an ASCII/Markdown delta comparison table highlighting percentage changes across wire bytes, boot duration, and update overhead.
6. Hidden Timers Verification (perf/hidden-timers.mjs)
Verifies that non-playback UI intervals (chips, reanchor, rotateChips, flush, checkBuildTag) suspend while the document is hidden and restore upon visibility, while essential background intervals (maybeCheck, 120s resume check) remain active:
node perf/hidden-timers.mjs
Exits with code 0 on success, or code 1 if any interval fails to pause, fails to resume, or if page errors occur.