9.4 KiB
Performance Baseline Report (Phase 0 / UNCHANGED code)
Date: 2026-10-07
Commit: b77938a
Dataset: perf/results/baseline-2026-10-07.json
1. Executive Summary & Headline Baseline Numbers
This baseline captures the performance metrics of the unoptimized ytplayer codebase (commit b77938a, matching production tag 1175f1a1d2c1) across 5 scenarios on both Chromium and WebKit under simulated LTE and Lossy network profiles (median of 5 runs).
Headline Baseline Numbers
-
Cold First-Load Wire Transfer:
- Chromium: 164 requests, 1,015.0 KB compressed wire bytes (boot-done median: 10,163 ms under 4× CPU throttle + LTE).
- WebKit: 162 requests, 1,152.0 KB (1.12 MB) wire bytes (boot-done median: 3,201 ms under proxy LTE).
- Breakdown: ~477 KB JavaScript, ~397 KB Web Fonts, ~131 KB CSS, ~27 KB HTML.
-
Warm Reload (under Service Worker):
- Chromium: 4 requests, 5.2 KB wire bytes (periodic API version poll), boot-done median: 675 ms (LTE) / 651 ms (Lossy).
- WebKit: 0 requests, 0 KB wire bytes, boot-done median: 131 ms (LTE) / 131 ms (Lossy).
-
Offline Reload (under Service Worker):
- Chromium: 0 requests, 0 B wire bytes, reload median: 240 ms, boot-done median: 219 ms.
- WebKit: 0 requests, 0 B wire bytes, reload median: 135 ms, boot-done median: 128 ms.
-
Update N -> N+1 Wire Cost (The Invalidation Penalty):
- 1-line
app.jschange:- Chromium: 88 requests, 596.6 KB wire bytes (~611 KB uncompressed/brotli), duration: 2,013 ms (LTE) / 2,031 ms (Lossy).
- WebKit: 86 requests, 664.3 KB wire bytes (~680 KB wire), duration: 4,457 ms (LTE) / 8,135 ms (Lossy).
- 1-line
theme-glass.csschange:- Chromium: 88 requests, 596.7 KB wire bytes, duration: 1,970 ms (LTE) / 2,004 ms (Lossy).
- WebKit: 86-87 requests, 664.3 KB wire bytes, duration: 4,510 ms (LTE) / 8,269 ms (Lossy).
- 1-line
Core Invalidation Finding: A single 1-line change to any static file (
app.jsortheme-glass.css) mutatesBUILD_TAGcalculated bycomputeBuildTag(). This causessw.jsto re-fetch and re-cache all 86-88 shell assets (~600-664 KB wire payload) rather than just the mutated resource.
2. Benchmark Harness Execution
The benchmark harness is located in perf/baseline.mjs and driven by Playwright with an isolated ephemeral Bun server and a custom pacing proxy (perf/proxy.mjs).
Quick Start / Exact Commands
# Ensure node_modules is symlinked to root
ln -s ~/development/personal/ytplayer/node_modules node_modules
# Run full baseline suite (all scenarios, both browsers, both profiles, 5 runs)
node perf/baseline.mjs --runs 5 --browser all --profile all --scenario all --out perf/results/baseline-2026-10-07.json
# Run individual browser or scenario
node perf/baseline.mjs --runs 5 --browser chromium --profile lte --scenario cold
node perf/baseline.mjs --runs 5 --browser webkit --profile lte --scenario update-js
# Run comparison against baseline after optimizations
node perf/baseline.mjs --runs 5 --browser all --profile all --scenario all --compare perf/results/baseline-2026-10-07.json
3. Results by Browser and Profile (Median of 5 Runs)
Chromium — LTE (1.6 Mbps down, 750 kbps up, 150 ms RTT, 4× CPU throttle)
| Scenario | Reqs (med) | Wire Bytes (med) | FCP (ms) | LCP (ms) | Boot Done (ms) | SW Ready / Reload (ms) | Long Task Total (ms) |
|---|---|---|---|---|---|---|---|
| Cold First Load | 164 | 1,015.0 KB | 1,540 | 1,896 | 10,163 | 38,446 | 397 |
| Warm Reload (SW) | 4 | 5.2 KB | 180 | 684 | 675 | - | 156 |
| Offline Reload | 0 | 0.0 KB | 72 | 108 | 219 | 240 | - |
| Update N->N+1 (JS) | 88 | 596.6 KB | - | - | - | 2,013 | - |
| Update N->N+1 (CSS) | 88 | 596.7 KB | - | - | - | 1,970 | - |
- Storage Estimate: Quota = 4,298,447,325 B (~4.0 GB), Usage = 3,480,029 B (~3.31 MB).
- Cold Wire Bytes by Type: JS 477.2 KB, Fonts 397.1 KB, CSS 130.7 KB, HTML 27.1 KB, Images 6.3 KB, API/Other 1.0 KB.
Chromium — Lossy (1.0 Mbps down, 500 kbps up, 250 ms RTT, 4× CPU throttle)
| Scenario | Reqs (med) | Wire Bytes (med) | FCP (ms) | LCP (ms) | Boot Done (ms) | SW Ready / Reload (ms) | Long Task Total (ms) |
|---|---|---|---|---|---|---|---|
| Cold First Load | 164 | 1,015.0 KB | 2,344 | 2,912 | 16,015 | 42,518 | 432 |
| Warm Reload (SW) | 4 | 5.2 KB | 184 | 644 | 651 | - | 155 |
| Offline Reload | 0 | 0.0 KB | 80 | 92 | 237 | 253 | - |
| Update N->N+1 (JS) | 88 | 596.6 KB | - | - | - | 2,031 | - |
| Update N->N+1 (CSS) | 88 | 596.7 KB | - | - | - | 2,004 | - |
WebKit — LTE (1.6 Mbps down, 150 ms RTT via proxy)
| Scenario | Reqs (med) | Wire Bytes (med) | FCP (ms) | LCP (ms) | Boot Done (ms) | SW Ready / Reload (ms) | Long Task Total (ms) |
|---|---|---|---|---|---|---|---|
| Cold First Load | 162 | 1.12 MB | 1,088 | 1,287 | 3,201 | 30,508 | 0* |
| Warm Reload (SW) | 0 | 0.0 KB | 110 | 110 | 131 | - | 0* |
| Offline Reload | 0 | 0.0 KB | 107 | 107 | 128 | 135 | - |
| Update N->N+1 (JS) | 86 | 664.3 KB | - | - | - | 4,457 | - |
| Update N->N+1 (CSS) | 86 | 664.3 KB | - | - | - | 4,510 | - |
WebKit — Lossy (1.0 Mbps down, 250 ms RTT + 1,500 ms stalls via proxy)
| Scenario | Reqs (med) | Wire Bytes (med) | FCP (ms) | LCP (ms) | Boot Done (ms) | SW Ready / Reload (ms) | Long Task Total (ms) |
|---|---|---|---|---|---|---|---|
| Cold First Load | 162 | 1.12 MB | 3,557 | 3,735 | 7,303 | 35,449 | 0* |
| Warm Reload (SW) | 0 | 0.0 KB | 111 | 112 | 131 | - | 0* |
| Offline Reload | 0 | 0.0 KB | 109 | 119 | 129 | 141 | - |
| Update N->N+1 (JS) | 86 | 664.3 KB | - | - | - | 8,135 | - |
| Update N->N+1 (CSS) | 87 | 664.4 KB | - | - | - | 8,269 | - |
*Note: WebKit does not expose PerformanceLongTaskTiming (longtask entries), so long task total evaluates to 0 ms.
4. Variance & Noise Observed
Over the 5 runs per configuration, measurements demonstrated high stability:
- Wire Bytes & Request Counts: Deterministic (0% variance across identical runs).
- Cold Boot-Done:
- Chromium LTE: Min 10,129 ms, Max 10,798 ms (<6% variance).
- Chromium Lossy: Min 15,871 ms, Max 16,031 ms (<1% variance).
- WebKit LTE: Min 3,138 ms, Max 3,245 ms (<3% variance).
- WebKit Lossy: Min 6,963 ms, Max 8,710 ms (~20% variance due to proxy random stalls).
- Warm & Offline Reload:
- Chromium Offline Reload: Min 238 ms, Max 257 ms (<8% variance).
- WebKit Offline Reload: Min 131 ms, Max 141 ms (<7% variance).
- Update Duration:
- Chromium: Runs cluster around ~2,000 ms (2,013 ms median). Occasional outlier runs (~45–200 ms) occur if the browser resolves
reg.update()immediately before network completion reporting. - WebKit: Steady scaling between LTE (~4.5 s) and Lossy (~8.2 s) pacing.
- Chromium: Runs cluster around ~2,000 ms (2,013 ms median). Occasional outlier runs (~45–200 ms) occur if the browser resolves
5. Limitations & Caveats
- WebKit Network Throttling:
WebKit lacks Chrome DevTools Protocol (CDP) support for hardware network emulation and CPU throttling. We paced throughput (1.6 Mbps) and injected latency/stalls using a custom local reverse proxy (
perf/proxy.mjs). This throttles HTTP response chunks truthfully but cannot simulate OS-level socket buffer delays or 4× CPU throttling. - Autoplay Policy in WebKit:
Playwright WebKit on Linux rejects
--autoplay-policy=no-user-gesture-requiredand enforces Safari-style gesture requirements on unmuted audio elements. The media playback benchmark detects this and correctly reportsautoplayBlocked: truewithout failing the test run. - WebKit SetOffline Incompatibility:
Calling Playwright's
context.setOffline(true)on Linux WebKit causes an unrecoverable engine crash (WebKit encountered an internal error). Offline mode for WebKit is simulated by terminating the proxy upstream connection (proxy.setOffline(true)).
6. Manual iPhone Testing Protocol (Phase 0 / iOS Safari PWA)
Because automated headless WebKit cannot fully replicate iOS Safari's mobile background constraints and battery telemetry, the following manual protocol is required:
Protocol Steps
-
Install PWA:
- Open Safari on iPhone and navigate to
https://worship.hesed.sbs. - Tap the Share button -> "Add to Home Screen".
- Launch ytplayer directly from the Home Screen icon.
- Open Safari on iPhone and navigate to
-
Verify Version & Cache:
- Verify the footer / version string matches
1175f1a1d2c1(or current production build tag). - Turn on Airplane Mode and force-reload to confirm offline readiness. Turn Airplane Mode back off.
- Verify the footer / version string matches
-
30-Minute Screen-Off Battery Test:
- Note baseline battery percentage (e.g., 85%).
- Select a pre-cached playlist or track and tap Play. Ensure continuous audio is heard.
- Lock the screen (display off) and let playback run uninterrupted for 30 minutes.
- Note battery percentage at 30 minutes (calculate drain %/hr).
- Listen for any audio dropouts, stuttering, or premature process suspension.
-
Interruption & Resumption Test:
- Trigger an interruption while locked (e.g., initiate an incoming phone call or start Siri).
- End the interruption and observe if playback automatically resumes via
MediaSessionhandlers. - Test Lock Screen Controls (Play/Pause, Next Track, scrubber).
-
Log Findings:
- Record iPhone Model, iOS Version, Battery Drain (% per 30m), Dropouts Count (0 = pass), and Resumption Status (Pass/Fail).