Commit Graph

2 Commits

Author SHA1 Message Date
a68c8996c6 perf tooling: jank_capture.py (end-to-end capture+report) + stress-test fixes in jank_eval
jank_capture.py: one command owns the whole pipeline so provenance can
never be wrong (the failure mode this replaces: append-only logs spanning
processes, hand byte-offsets, tail-guessing, wrong-build data):
  1. record build identity (versionName + apk sha256 + tag)
  2. force-stop + DELETE it.log  (file can then contain exactly ONE process)
  3. cold launch, verify ResumedActivity (before and after)
  4. scripted drags ('4,2,4' = 4s drag, 2s settle, 4s drag)
  5. pull the complete log
  6. report: PROVENANCE + jank_eval verdict + MISS forensics
  verdicts: PASS(0) / FAIL(1) / SUSPECT(fitted grid) / INVALID(multi-process)
MISS forensics: groups consecutive misses into episodes, classifies each
  (CHAIN-STALL / LOOP-STUCK / GUARD-REJECT / NO-WAKE-ITER) with a +-33 ms
  all-thread context window (IT poll/ev/rd/dec/pc/rc/vsw/nvol, VSYNC
  latency, PRES, FR, SLOWEV, DECODE, OTHR, INVK).
  self-test: synthetic 120Hz log with a 30 ms stuck-poll episode.

jank_eval.py fixes found under emulator stress:
  - auto-windows active threshold was circular: 0.75x the refresh rate
    meant a JANKY app (low present rate) is never detected as active.
    Now 0.4x rate / 250 ms buckets. (Emulated 60 Hz scroll at 30-40 Hz
    present was invisible to the old threshold.)
  - BUCK 500->250 ms required the density multiplier *2 -> *4 (forgot,
    caught by stress: only the fastest spans were windowed).
  - fallback period (no VSYNC lines) was a telescoping mean (spans idle
    gaps: 391 presents over 23 s fit '59.6 ms'). Now median-of-deltas
    snapped to standard rates. A fitted grid cannot prove drops/doubles:
    verdict on it excludes them (stalls+lates+spread remain) and the
    verdict is marked SUSPECT (exit 3) instead of PASS/FAIL.
  - run_file now returns (ok, suspect); small-log early exit fixed.

Stress matrix on emulator (x86_64, 60 Hz SF) — all pass:
  capture pipeline x3 (standard 4,2,4 / fast 1,1,1 / slow 6,2,6)
  pause/resume mid-drag (teardown -> occluded -> resume burst)
  determinism (identical report twice), multi-process -> INVALID,
  explicit --windows, --period-ms override, no-VSYNC -> SUSPECT path,
  small log -> exit 1, synthetic perfect 120 Hz -> PASS exit 0.
2026-10-30 14:45:52 -04:00
915e04c2c3 120Hz: jank_eval referee + slot-based wake guard + MISS ledger
tools/jank_eval.py: strict PASS/FAIL jank evaluator (the referee).
- slot grid from VSYNC ftn edges (hardware truth); anchor fallback only
- PASS iff per active window: no dropped slot, no same-slot double, no
  present past the SF latch, no >20ms present gap, phase spread <=0.5ms
- self-test: 7 synthetic log files through the same main() path, all
  classified correctly; validated on the emulator (60 Hz emu display
  detected, active windows found)
- re-judges slt4 honestly: my 'clean' drag-1 window is FAIL (30.6ms +
  21ms stalls, 20 past-latch presents, 1.1ms spread) — the user saw it

lib.rs/stg.rs: slot-based wake guard replaces the interval freshness
guard (0.2ms false-reject margin). A wake renders iff its edge-grid slot
is strictly after the last rendered slot; a gap of >=2 slots emits
MISS {mon, slots, nowake} — the missing evidence for stall slots
(wakes lost vs loop blocked vs guard).

sltest: log drain batch-flush (64 lines) — per-line FUSE flush stalled
the drain thread for minutes (file frozen, process alive).
gallery: MISS lines added to the perf-log allowlist.
2026-10-30 13:29:50 -04:00