perf: 使い捨て SessionStore init の副作用排除と refresh デバウンスで常時 CPU を削減#79
Draft
sasagar wants to merge 2 commits into
Draft
perf: 使い捨て SessionStore init の副作用排除と refresh デバウンスで常時 CPU を削減#79sasagar wants to merge 2 commits into
sasagar wants to merge 2 commits into
Conversation
- ContentView の @State 初期値式は View 再 init のたびに評価され、使い捨ての SessionStore が restore()(セッション毎に git status / gh pr view / ソケット bind / hooks 注入 / 常駐スレッド起動)まで実行していた。復元と常駐監視を start() に分離して表示側から 1 回だけ呼ぶ(実測でバススレッド 48 本 → 3 本、 総スレッド 68 本 → 15 本) - WorkPaneModel: FSEvents からの refresh を 0.5 秒デバウンス+in-flight 合流に 変更。1 回の refresh は repo 数 × 4 + 3 個の git を起動するため、エージェント 作業中のバーストでの多重実行が定常 CPU(実測 ~30%)の主因だった。start() も 冪等化 - 非アクティブセッションの FileWatcher/refresh を停止(ZStack 常駐は維持しつつ 可視セッションだけ監視。アクティブ化時に 1 回再取得) - AgentStatusBus.start() を冪等化(二重 start による runServer 並走・fd 漏れを防止)
- FileWatcher が FSEvents の変更パス群をコールバックへ渡すように拡張 - WorkPaneModel.refresh を部分リフレッシュ対応に: 変更パスに紐づく repo だけ git(status/numstat/listFiles)を回し、残りは repo 単位キャッシュから合成。 履歴(commitGraph 300 件)とブランチバーも対象 repo が変わったときだけ再取得。 パスがどの repo にも紐づかない場合は discoverRepos の上で全量へフォールバック (シンボリックリンク差異・新規 clone への安全弁) - SessionStore の conflict watch を 5 秒ポーリングからイベント駆動へ: セッション毎の 軽量 FSEvents 監視で dirty マークだけ付け、2 秒デバウンスで対象セッション (同一 repo に複数セッションがあるもの)だけ git status を回す。無変更時の 定常 git 起動がゼロになる - CLAUDE.md に常用向け Release ビルド手順を追記(Debug は最適化なしでパースが 数倍遅い)。Release 構成でのビルドが通ることを確認済み
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
症状
エージェント作業中にアプリの CPU が常時 30% 前後に張り付き、消費電力が高い。
実測で特定した原因
ContentViewの@State private var store = SessionStore()の初期値式は View 再 init のたびに評価され、そのつど使い捨ての SessionStore がrestore()を実行していた。restore はセッション毎に git status / gh pr view / AF_UNIX ソケット bind / hooks 注入 / 常駐スレッド起動まで行う。実測: DB 上のセッション 3 個に対し accept 待ちスレッドが 48 本(バスのスレッドが自身を retain するため掃除もされない)。refresh()が走り、1 回の refresh は repo 数 × 4 + 3 個の git を起動。プロセスサンプルでは__posix_spawnと文字列パースが CPU の大半を占め、任意の瞬間に 1〜10 個の git が生存していた。修正(コミット順)
1 コミット目(構造の止血)
start()に分離し.taskから 1 回だけ呼ぶWorkPaneModel.scheduleRefresh(): 0.5 秒デバウンス+in-flight 合流。start()冪等化SessionDetailViewにisActiveを渡し、非アクティブ時は watcher 停止(pty 常駐は維持)AgentStatusBus.start()冪等化(二重 start の runServer 並走・fd 漏れ防止)2 コミット目(さらなる削減)
FileWatcherが変更パス群をコールバックへ渡すように拡張WorkPaneModel.refreshを部分リフレッシュ化: 変更パスに紐づく repo だけ git を回し、残りは repo 単位キャッシュから合成。履歴(commitGraph 300 件)・ブランチバーも対象 repo 変更時のみ再取得。紐づかないパスは全量へフォールバック(安全弁)実測(1 コミット目適用時点)
テスト / 検証
swift test全 98 テスト成功、アプリ Debug/Release 両構成でビルド成功