Skip to content

DEVICE-SPEED b: Android quickboot from a golden snapshot (same device results, ~25-30 s less per emulator boot) - #157

Merged
thejackshelton merged 79 commits into
masterfrom
device-quickboot
Oct 5, 2026
Merged

thejackshelton merged 79 commits into
masterfrom
device-quickboot

Conversation

@thejackshelton

@thejackshelton thejackshelton commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

What changed (DEVICE-SPEED b, speed-research.md item 7): a matrix AVD now quickboots from a golden snapshot instead of always booting cold with -no-snapshot.

  • How the snapshot is made (device-run.ts):

    • When a matrix AVD has no current golden snapshot, it boots cold as before.
    • Its live checks (liveProblems) and prepareAvd (settings, text scale, stay-awake, keyguard, the settled-launcher wait) run.
    • Then saveGolden uninstalls the host app, removes the vectors dir, saves adb emu avd snapshot save dragon-golden, and only then writes the snapshot's key next to the AVD (dragon-golden.key).
  • How it is used:

    • The next boot loads it with -snapshot dragon-golden -force-snapshot-load -no-snapshot-save, so a run never writes back into it.
    • It is judged exactly as a cold boot: the boot polls, liveProblems, prepareAvd and the focus wait all run again.
    • Every run starts from the same disk state. A cold boot keeps whatever earlier runs left on the data disk.
  • The key is a sha256 over:

    • the emulator version;
    • the system image and its source.properties;
    • the AVD's whole config.ini;
    • the boot flags;
    • the source of prepareAvd, waitForSettledFocus and saveGolden, the text scale and the settle constants.

    Change any of them and the next boot is cold and saves a new snapshot.

  • Failure paths:

    • A snapshot that fails to load (forced, so the emulator exits) is dropped, and the retry is cold.
    • A boot from the snapshot that then fails its checks drops it.
    • A save that fails, or a key that cannot be computed, never fails the boot. It is logged and writes no key, so no snapshot is loaded, and that run goes on with its checked cold boot.
    • failedAttemptStep decides what a failed attempt does next, and is tested on every combination.
    • The floor-probe AVD (provision = false) always boots cold.
  • Unchanged: -gpu swiftshader_indirect (the pixel evidence's renderer), and every other flag. All emulator arguments now come from emulatorArgs.

Proof. Full local device runs through /tmp/device-lease.sh, compared with master's committed records (/tmp/dds/compare.mts): the land driver's deviceRunProblems, byte equality of both device-failures-*.json, and a deep diff of lanes.json with only evidence.laneCode masked.

run boot android boot (spawn to settled) judge failure sets lanes.json diff
base (master) cold -no-snapshot 43 s no problems identical (57 ios, 86 android) 0
base2 (master) cold 47 s no problems identical 0
b1 (this branch, first run) cold, then golden saved in 3–5 s 43–51 s no problems identical 0
b2 (this branch) from the golden snapshot (all 3 AVDs) 19 s no problems identical 0

So results are identical with and without the snapshot. Each emulator boot saves about 25–30 s, and the memory budget admits the next device sooner.

Disk: each golden snapshot is about the AVD's 2 GB of RAM, under ~/.android/avd/<name>.avd/snapshots/dragon-golden.

Tests:

  • device-run.test.ts adds:
    • the cold and quickboot arguments, with the renderer kept;
    • the key changes with each of its six parts;
    • a snapshot is loaded only with its data and current key, and never after it is dropped;
    • every emulator spawn goes through emulatorArgs;
    • one place saves the snapshot;
    • CI neither loads nor saves a snapshot;
    • failedAttemptStep on every combination.
  • vitest run device-run, lanes-concurrent and emulator-log: 65/65 pass (head 0169767).
  • pnpm typecheck: pass.

Device step pending: lanes-records, p6a-promotion and device-failures fail only on the changed laneCode. Regen outputs are not committed for the same reason.

Overlap: #132 edits device-run.ts (androidImage, IOS_RUNTIME, memoryReserve). Those hunks are textually apart from this one. On CI (CI=true, GitHub's runners) quickboot is off (goldenEnabled): a runner is fresh every job, so a saved snapshot would never be loaded, and its boots stay cold and save nothing, as today. No workflow file changes.

Size: about 14 KB of reviewed diff in 2 files.

Review round (precomputed review of 0169767), head 1ae7ac1:

  • Medium, fixed: on the boot that saves the snapshot, the device now settles again after the save (saveGoldenAndSettle: the uninstall, vectors-dir removal and paused VM all come before the second waitForSettledFocus). That function is in the snapshot key.

  • Fixed guest timezone: every boot, cold or snapshot, runs with -timezone Etc/UTC (GUEST_TIMEZONE, part of the flags in the key), so neither depends on the host's zone.

  • Boot mode recorded: an Android device record now carries boot: 'snapshot' | 'cold' | 'running'. iOS records and older records have none.

  • Drop only on load failures: the snapshot is dropped only when the emulator's log says the snapshot failed to load (snapshotLoadFailed), or when a live emulator failed to boot from it. Any other exit (a taken port, a full disk) keeps it and leaves the serial alone, as a cold boot does.

  • Proof on the new head (full local device runs through the device lease, compared with master):

    • r157a: cold boots that save the snapshot and settle again, 497 s;
    • r157b: snapshot boots, 423 s.

    Both: the judge reports no problems, and both failure lists are byte-identical. The only lanes.json differences are the 18 new device.boot fields on Android sets (intended).

  • Tests: device-run, lanes-concurrent, emulator-log, device-lanes and state-lanes: 115/115 pass. pnpm typecheck: pass. CI green on 1ae7ac1.

Review round 2, head d910710: an emulator that exits while booting from the snapshot, with no load-failure line in its log (for example a truncated snapshot that crashes), no longer leaves the AVD stuck. The retry is cold. The snapshot is dropped, and retaken, only if that cold boot succeeds (dropSuspect). If the cold boot fails too (a taken port, a full disk), the snapshot is kept. Tests: device-run, lanes-concurrent, emulator-log, device-lanes and state-lanes, 116/116 pass. pnpm typecheck: pass. CI green. Only failure paths changed, so I did not repeat the device run; the r157a and r157b proof above still covers successful boots.

🤖 Generated with Claude Code

thejackshelton and others added 28 commits October 3, 2026 21:23
…nes-host on xcode-27), regen --skip/--only, ci.yml workflow_dispatch
…ery Chrome round (it is a sink, ~50 min on 3 cores)
…hes are invisible to other branches); never pushes there
…ion, sorted .gitattributes

fixtures.ts registers each group on one line of GROUPS, sorted by id, and runs the legacy groups in their frozen order, then
every later group by id. scripts/regen.ts keeps the legacy steps and MANUAL entries and gathers each feature's steps (placed
after the step they name), extra outputs and MANUAL entries from scripts/regen-steps/<feature>.ts, one sorted line per feature.
.gitattributes is sorted (same patterns, same attribute). STEPS, MANUAL, FIXTURE_GROUPS and FIXTURES are unchanged;
registry-claims.test fails when two features claim one group, fixture id, step name, output or command.
…itattributes keeps master's animator line in sorted order
…lap, and registry-claims checks no tracked file has two writers; fixtures.ts documents the run order of later groups
…ules, so ua:capture's regen inputs leave out the compiler
….ts; the compiler and the internal entry no longer import it, and regen keys a workspace package on the entry Node picks under the step's conditions
…ault)

planted-swift.test.ts and planted-kotlin.test.ts compiled and ran a planted harness for each of the 7 FAULTS in one test
(planted-swift took 734 s on the CI runner, planted-kotlin 329 s). Each (target, fault) pair is now its own test file
(planted.ts holds the shared test), so vitest schedules them across workers and shards. planted-union.test.ts proves the
files cover FAULTS on both targets exactly once.
The determinism describe of parity.test.ts (356 tests, 290 s of its 548 s on the CI runner) runs from
parity-determinism-<k>.test.ts, one chunk of FIXTURES per file under the same describe titles, each with its own Chrome and
its own coverage check. parity.test.ts keeps a coverage test proving the chunk files together check every fixture once.
… with any NaN; corpus inputs, results and digests write every NaN as 7ff8000000000000 (x86-64 makes some fff8...)
… are not serialized through Playwright's value serializer
…s run; only the vectors verdict waits for its host run
…cold boot and prepareAvd, keyed by emulator, image, AVD config, flags and provisioning code
HOTSPOT-SPLIT 2/2: per-feature fixture groups and regen steps; sorted .gitattributes
CI-OFFLOAD step 2: regen-on-ci (pnpm regen on GitHub runners, pushed back to the branch)
…napshot and retries cold; a failed save or key read never fails the boot
thejackshelton and others added 17 commits October 5, 2026 01:08
translate: a stale harness cache entry (artifact deleted, directory kept) is replaced, never returned; root cause of the land-147 'Unable to access jarfile' failures
land: keep the translate harness build caches when cleaning ignored outputs
land: an idle machine is quiet even with a heavy slot held
SLOW-SPLIT 2: parity determinism shards in 4 chunk files
NaN-any: a NaN matches any NaN in the bit-exact corpus comparison (PM ruling)
thejackshelton and others added 9 commits October 5, 2026 01:42
tw-sweep: compile on every core; Chrome checks on 8 pages, each capture one JSON string (same snapshot)
Chrome captures: pixel, DPR and break captures take 8 cases at once (same bytes)
Lanes verdict at the edge: lanes.json no longer invalidates every regen step
Commands: pnpm regen; pnpm run parity:devices; pnpm regen
Commands: pnpm regen; pnpm run parity:devices; pnpm regen
@thejackshelton
thejackshelton merged commit ee6e321 into master Oct 5, 2026
5 checks passed
@thejackshelton
thejackshelton deleted the device-quickboot branch October 5, 2026 07:45
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