最近モニタの接続や接続解除を行うとWindowsのエクスプローラが暫く操作できなくなって困っていた。職業柄HDMIデバイスの抜き差しがかなり多くてクッソ不便なので真面目に追ってみた。
tl;dr
- デスクトップに大量に画像・動画を置いてると、モニタのつけはずし操作が遅くなる
- → デスクトップを綺麗にしよう (デスクトップアイコンを非表示にしていても)
1000 個くらいあったファイルを一掃したら相当に高速になった。Windowsデスクトップのアイコンは普通のエクスプローラWindowの一種として実装されているが、デスクトップ全体を占める巨大なWindowをリサイズすることになるので、そのリサイズに時間が掛かっていたのではないかと予想している。
データの採取
WindowsにはEvent Tracing for Windows(ETW)という、macで言うところのDTraceのようなカーネルトレース機構があり、これをいわゆるサンプリングプロファイラとして使って 応答するまでに実行していたプログラムとその実行箇所 を調べる。
ツールのインストール
プロファイラ等のツールはWindows ADK( https://docs.microsoft.com/ja-jp/windows-hardware/get-started/adk-install )の一部として提供されているので、一式インストールする。
次に、GoogleUIforETW( https://github.com/google/UIforETW/releases )がWrapperとして著名なので、これを展開して bin/UIforETW.exe
を実行する。UIforETWは、Windows Performace Analyzerで便利な分析手法をいくつか自動的にセットアップしてくれる。
プロファイルの採取
Windows Performance Recorder を立ち上げて、適当にプロファイルを採取する。
Start をクリックしたら、重そうな操作を実行し、トレースを取得する。
解析
... 解析については、数をこなして慣れるしかない面がある。
前処理
トレース( *.etl
)を取得したら、Windows Performance Analyzerを開いて、Window → Load Symbols でシンボルをロードする。
次に、"Randomascii wait analysis"(UIforETW が自動的にセットアップする)から、重い処理であろう箇所を探し、範囲選択する。
今回は、このエクスプローラのアクティビティが怪しいので、この部分を選択し、ズームする。
重い処理の特定
"Randomascii inclusive stack" から、 Count
の大きいところを次々と開けていく。
すると、 windows.storage.dll!FireOnCollectionChanged<CEventSinkContainer>
→ shell32.dll!CCollectionSink::OnCollectionChanged
→ shell32.dll!CListViewHost::OnCollectionChanged
... の呼び出しで大半の時間を消費していることがわかる。
推理
関数名から、おそらくWindowsエクスプローラ(shell32)の表示ロジックとみられる
↓
エクスプローラのWindowを全て閉じた状態でも再現する
↓
常に表示されているのはデスクトップなのでデスクトップが怪しい
↓
普段デスクトップは非表示で使っているけど、内部的には表示 & リサイズしているのではないか?
↓
とりあえずデスクトップを掃除してみる → 当たり 。モニタを抜き差ししても、すぐ操作できるようになった
かんそう
デスクトップアイコンを非表示にしてもデスクトップフォルダの内容が性能に影響するのはマジで釈然としない。