Skip to content

perf: defer + cache cross-package index resolution off the first frame#5

Merged
pchmn merged 3 commits into
mainfrom
chore/improve-perf
Jun 4, 2026
Merged

perf: defer + cache cross-package index resolution off the first frame#5
pchmn merged 3 commits into
mainfrom
chore/improve-perf

Conversation

@pchmn

@pchmn pchmn commented Jun 4, 2026

Copy link
Copy Markdown
Owner

Summary

  • Defer phase-B resolution off the first frame. The three feature indexes (AppIndex, ShortcutIndex, SettingsPageIndex) resolved other packages' labels/resources via PackageManager from Application.onCreate, contending with the first-frame composition on ART locks (ResourcesManager#getResources was the sole slow_start_reason). That work now runs from MainActivity after the first content draw, via a ViewTreeObserver.OnDrawListener + decorView.post (a Choreographer vsync count fired off-by-one — see ADR-0009).
  • Disk-cache all three indexes (Option 2). ShortcutIndex + SettingsPageIndex now persist their entries (*IndexCacheRepository), like AppIndex. Cold start hydrates (phase A) before the first frame with zero getResources, so typed results and the blank-state recents render immediately — this fixes recent shortcuts/settings popping in late (they stale-filter against the live index; see ADR-0008).
  • Pre-warm the GoogleSans device font (warmUpGoogleSans) so the first text layout doesn't pay the DeviceFontFamilyName lookup during the heavy post-first-frame composition (which queues WINDOW_FOCUS_CHANGED and delays the IME).
  • Trustworthy benchmark. BootReceiver self-skips on the .benchmark build — macrobenchmark's StartupMode.COLD re-delivers BOOT_COMPLETED every iteration, which otherwise ran AppIndex.refresh during the first frame and inflated TTID uniformly.
  • Result (Pixel 9, clean run): time_get_resources 376 → 111 ms, no-AOT cold-start floor 240.7 → 178.5 ms; Baseline ≈ None (~177 ms) — the path is now light enough that AOT barely matters. Docs updated (AGENTS.md, ADR-0008/0009, docs/performance-analysis.md).

Test plan

  • ./gradlew compileDebugKotlin
  • ./gradlew :benchmark:connectedBenchmarkReleaseAndroidTest — clean run, no BOOT_COMPLETED/phaseB.enumerate before TTID
  • Recent shortcuts/settings render on the first frame (warm cache) on a real device
  • First-ever launch (empty caches) still usable within the typing lead time

🤖 Generated with Claude Code

pchmn and others added 3 commits June 3, 2026 14:56
…path

- Pre-warm the GoogleSans device font (`warmUpGoogleSans`, dispatched from
  `Application.onCreate`) so the first text layout doesn't pay the
  `DeviceFontFamilyName` lookup during the heavy post-first-frame composition
  (which otherwise queues `WINDOW_FOCUS_CHANGED` and delays the IME).
- `BootReceiver` self-skips on the `.benchmark` applicationId: macrobenchmark's
  StartupMode.COLD re-delivers BOOT_COMPLETED every iteration, which would run
  AppIndex.refresh (phase B) during the first frame and contaminate TTID.
- Regenerate the baseline profile; record the clean benchmark results and
  update AGENTS.md, ADR-0008/0009 and docs/performance-analysis.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@pchmn pchmn merged commit f0550b9 into main Jun 4, 2026
@pchmn pchmn deleted the chore/improve-perf branch June 4, 2026 17:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant