Files
virtual-controller/remote-client-android/BISECT_LOG.md
T
Paul Lipscomb 60c8255c2d Android perf: fix fader stutter (appendLog), drawText feedback widget, bisect docs
Bisect session with per-suspect kill switches (see BISECT_LOG.md):
- appendLog was the confirmed stutter culprit — ran per-message (~110/sec)
  on the main thread even with the log panel hidden; A/B verified. Disabled
  via DEBUG_DISABLE_APPEND_LOG; shippable visible-only fix still TODO.
- Per-message Log.d also disabled (freebie, no felt difference).
- Glow, gradient fill, network flash, feedback setText all exonerated and
  restored; switches left in place at false.
- FocusFeedbackWidgetView rewritten: TextView -> bare View + canvas.drawText.
  60hz updates are now field-assign + invalidate, no per-update text Layout.
- ContextMenuViewLogic: explicit color-picker branch for the new view type.
- Timecode chunkiness root cause was REAPER audio buffer size (source-side
  burst cadence), documented in PERF_SESSION_2026-07-31.md; stutter bug
  report stamped RESOLVED.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-31 17:46:07 -05:00

5.5 KiB

Focus Fader Stutter — Bisect Log

Companion to FEEDBACK_STUTTER_BUG.md. One kill-switch per suspect; flip one, rebuild, drag a Focus Fader while 60hz feedback streams, record the result here, then either keep it off or restore it and move to the next.

Ranked suspect list

# Suspect Where Switch
1 appendLog per message (even when panel hidden) ArrangeFunctionsWebSocket.appendLog DEBUG_DISABLE_APPEND_LOG
2 logScrollView.post(fullScroll) per message inside appendLog covered by #1
3 Runnable flood (~3 posts/msg, 300+/sec) appendLog + dispatch handlers mostly covered by #1
4 flashCard per message at 60hz ArrangeFunctionsWebSocket.flashCard → ArrangeCardView.flashActivity DEBUG_DISABLE_NETWORK_FLASH
5 setText at 60hz on feedback TextView FocusFeedbackWidgetView.setTextFromNetwork DEBUG_DISABLE_FEEDBACK_SETTEXT
6 LAYER_TYPE_SOFTWARE + blur glow on fader FocusFaderWidgetView ctor (also FaderWidgetView) DEBUG_DISABLE_GLOW (one per class)
7 new LinearGradient every onDraw FocusFaderWidgetView.onDraw (also FaderWidgetView) DEBUG_DISABLE_GRADIENT_FILL (one per class)
8 Log.d full-JSON concat per message ArrangeFunctionsWebSocket.onMessage DEBUG_DISABLE_RECEIVE_LOGCAT
9 Echo stream (sent values come back, run appendLog+flashCard mid-drag) handleWidgetUpdateF partially covered by #1
10 vibrator.vibrate at value edges FocusFaderWidgetView.checkEdgeHaptic not yet added

Verdict (2026-07-31)

appendLog was the stutter. A/B confirmed: re-enabling it brings the stutter back immediately. Receive-logcat kept off as a freebie (no felt difference). Everything else exonerated and restored to original behavior — including the glow/software-layer rendering, which Paul tested and cleared.

Final switch states: DEBUG_DISABLE_APPEND_LOG = true, DEBUG_DISABLE_RECEIVE_LOGCAT = true, all others false (original behavior).

Timecode fluidity root cause (found by Paul, same day): REAPER's audio buffer size. REAPER emits OSC feedback per audio block, so a large buffer makes updates arrive in chunky bursts — uneven cadence no client-side rendering can smooth. Lowering the buffer restored fluid feedback. The drawText rewrite of FocusFeedbackWidgetView (done just before this discovery) stays: it's the cheapest render path and collapses same-frame updates to one draw regardless of source pacing.

Test runs

Run 1 — DEBUG_DISABLE_APPEND_LOG = true (suspects 1+2, most of 3)

  • Date: 2026-07-31
  • Switches off: appendLog (all in/out log lines + auto-scroll posts)
  • Side effect while off: debug log panel shows nothing new when opened
  • Result: CONFIRMED CULPRIT — "way smoother" with appendLog disabled.
  • A/B re-test same day: re-enabled appendLog, stutter came back immediately; disabled again. Not a placebo — appendLog is definitively implicated. Left OFF for now; permanent fix TBD.

Run 2 — DEBUG_DISABLE_RECEIVE_LOGCAT = true (suspect 8)

  • Date: 2026-07-31
  • Switches off: appendLog (kept off from Run 1) + per-message Log.d in onMessage
  • Side effect while off: incoming messages no longer visible in logcat
  • Result: No perceptible difference. Kept off anyway (free optimization, nobody reads logcat during performance).

Run 3 — DEBUG_DISABLE_GLOW = true (suspect 6)

  • Date: 2026-07-31
  • Switches off: appendLog + receive-logcat (from Runs 1-2) + shadow-layer glow and software rendering in FocusFaderWidgetView AND FaderWidgetView
  • Side effect while off: faders lose their glow — plain value line + dot
  • Result: Exonerated. Still smooth with glow off, but no felt difference attributable to it — Paul: "the glow wasn't an issue." Turned back ON (original software-layer glow restored) at end of bisect.

Run 4 — DEBUG_DISABLE_NETWORK_FLASH = true (suspect 4)

  • Date: 2026-07-31
  • Switches off: appendLog + receive-logcat + glow (Runs 1-3) + network-triggered activity-ring flashes (local touch flashes still work)
  • Side effect while off: cards don't blink green on desktop-driven updates
  • Result: SKIPPED — suspect was already inert. The tablet's "Activity: ON/OFF" button (default OFF) was off during all stutter tests, and flashActivity() early-returns on that flag before any timer work. Kill switch left in place (harmless, skips a registry lookup) but this suspect is exonerated for the observed stutter.

Run 5 — DEBUG_DISABLE_FEEDBACK_SETTEXT = true (suspect 5, plus its share of 3)

  • Date: 2026-07-31
  • Switches off: appendLog + receive-logcat + glow (Runs 1-3) + the ENTIRE widget_feedback UI path: the runOnUiThread post, registry lookup, and setText all skipped (placed before the post, so this also removes 60/sec of the runnable flood)
  • Side effect while off: feedback readouts (timecode etc.) freeze at last text
  • Result: Nothing earth-shaking — no clear felt difference. Switch turned back OFF (readouts are needed regardless). 60hz setText is tolerable now that appendLog is gone; candidate for once-per-frame conflation later, not a primary culprit.

Run 6 — DEBUG_DISABLE_GRADIENT_FILL = true (suspect 7)

  • Date: 2026-07-31
  • Switches off: appendLog + receive-logcat + glow (kept from earlier runs); gradient fill replaced with flat translucent fill in both fader classes
  • Side effect while off: fader fill is flat color, no fade-to-transparent
  • Result: No felt difference — gradient turned back ON (look kept). Create-once gradient (setLocalMatrix) stays on the permanent-fix list as hygiene, not a culprit.