Skip to content

fix(agentruntime,tui): cut startup section-collector stall; add slow-handler instrumentation - #2538

Merged
topcheer merged 1 commit into
mainfrom
fix/startup-freeze-instrumentation
Sep 18, 2026
Merged

topcheer merged 1 commit into
mainfrom
fix/startup-freeze-instrumentation

Conversation

@topcheer

Copy link
Copy Markdown
Owner

用户报告

启动渲染完成后 TUI freeze 几秒(按键失效/光标静止),过一会恢复。/usage 面板同窗口无响应。

取证

  • macOS sample 采样 600k 行会话 resume:主线程 JSONLStore.loadSession 3.3s 纯 JSON 解析+1.7s GC(Run 前黑屏段实锤)
  • 2026-09-18 debug 日志铁证:250ms 的 input-drain tea.Tick 在启动后 17.4s 才触发=单线程事件循环被堵 17s 且无归因

修复

  1. section_collector firstRefreshBudget 5s→800ms:同步首刷在 Bubble Tea 循环起来之前,慢文件系统用户付多秒黑屏;预算后由后台循环补齐(既有机制),暖缓存机器 <300ms 无感知
  2. slow-handler 仪表:Update handler >100ms 记 debug 日志(type=%T duration)——下次 freeze 复现一行日志直接归因,无需再挂 profiler

验证

internal/tui + internal/agentruntime 两包测试绿。

Co-Authored-By: ggcode noreply@ggcode.dev

…handler instrumentation

User-reported: after startup renders, the TUI freezes for seconds (keys
dead, cursor static) before becoming responsive. Profiling a fresh
instance with macOS 'sample' during the window plus a 600k-line session
resume reproduction (3.3s pure encoding/json parse + 1.7s GC on the
main thread inside REPL.loadSession) confirmed the freeze is real and
startup-path-bound, while the 2026-09-18 debug log pinned the smoking
gun: a 250ms input-drain tea.Tick landing 17.4s after program start -
the single-threaded Bubble Tea loop was blocked for 17s with no
attribution of which handler/frame paid for it.

Two changes:

1. section_collector: firstRefreshBudget 5s -> 800ms. The synchronous
   first refresh sits on the interactive startup path BEFORE the Bubble
   Tea loop starts - past-budget machines paid a multi-second dead
   black screen. The background refresh loop already fills empty
   sections after the budget (designed-in fallback), so dropping the
   wait only trades prompt-section freshness for startup latency on
   slow filesystems. Warm-cache machines finish well under 300ms and
   see no behavior change.

2. tui dispatch: slow-handler instrumentation. Any Update handler over
   100ms logs 'slow update handler: type=%T duration=...' to the debug
   log. This turns the next freeze reproduction into a one-line
   attribution instead of requiring a profiler attach; it is what will
   pinpoint the remaining 17s blockage (suspects: first-frame render
   with uncached multi-KB chat items, startup message storm from LAN
   Chat presence + MCP connects each triggering a full View frame).

No behavior change for fast paths; tests green in both packages.

Co-Authored-By: ggcode <noreply@ggcode.dev>
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