24コアCPUですが、カーソルを移動できません

私の車が減速し始めたときによく起こるように、それはすべて始まりました。 24コアプロセッサ(48スレッド)を備えた稼働中のWindows 10コンピューターで、50%アイドル状態でした。 64 GBのメモリのうち、半分以下が使用されました。 高速SSDも特に使用されませんでした。 それでも、マウスを動かしても、カーソルはすぐに反応しませんでした-時には数秒の遅延がありました。



そこで、私はいつもやったことをしました-ETWを使用してイベントトレースを記録および分析しました。 その結果、プロセス終了のパフォーマンスに深刻な影響を与えるWindows 10のバグを発見しました。



ETWトレースは、多くのプログラムでUIがフリーズすることを示しています。 タスクマネージャーで1,125秒のフリーズを調査することにしました。







以下のスクリーンショットでは、プロセス名ごとにグループ化された、フリーズ中のシステムのCPU使用率を確認できます-CPU使用率が50%を超えることはめったにありません。







CPU Usage(Precise)テーブルは、タスクマネージャーUIのスレッドが、 SendMessageWなどの関数呼び出しによって常にブロックされていることを示しています。明らかにカーネルのクリティカル領域(これはカーネルモードのクリティカルセクションのバージョン)で待機しており、win32kbase.sys!EnterCritのコールスタックの奥深くにあります!ここ):







UIのリソースを取得したユーザーを見つけるために、6つのプロセスを介して手動で待機チェーンを実行しました。 分析の結果、私のメモは次のようになります。



Taskmgr.exe(72392)は、スレッド69.196で1.125秒間(MsgCheckDelay)フリーズします。 最大の遅延は、win32kbase.sys!EnterCritで115.6ミリ秒でしたが、EnterCritはconhost.exeプロセス(16264)、3.273101862のスレッド2560による実行のために準備されました。 conhost.exe(16264)、2560はプロセスmstsc.exe(79392)、71272で115.640.966ミリ秒待機した後、3.273077782で準備されました。mstsc.exeはTabTip.exe(8284)、8348で準備されました(同じ時間、同じ遅延)。 UIforETW.exeプロセス(78120)、79584、conhost.exeプロセス(16264)、58696、gomacc.exeプロセス(93668)、59948、gomacc.exeプロセス( 95164)、76844。


ほとんどのプロセスが数マイクロ秒後にロックを解除したため、続行する必要がありました。 しかし、最終的に、数マイクロ秒の間ロックを保持しているように見えるいくつかのプロセス(gomacc.exeプロセス)が見つかりました。 または、少なくとも、ロックを保持している誰かによって準備され、数マイクロ秒後に、他の誰かがそれを削除する準備をしました。 これらのプロセスはすべて、 NtGdiCloseProcess内でロック解除されています



これらの待機チェーンに沿って手動で歩くのにうんざりしていたので、同じコールスタックに遭遇する頻度を確認することにしました。 これを行うには、 Ready Thread Stack列を左にドラッグし、そこでNtGdiCloseProcessを探します。 次に、WPAの[呼び出し元表示]-> [関数別 ]オプションを使用して、 この機能に一致するすべてのレディスレッドスタックを表示します。このウィンドウでは、以下の親スタックです。







NtGdiCloseProcessReady Thread Stackにある場合、5768のコンテキストスイッチがあり、それぞれがクリティカルセクションが解放された瞬間を意味します。 これらの呼び出しスタックのスレッドは合計63.3秒待機しました-1.125秒の遅延に対しては悪くありません! また、フローが200マイクロ秒だけロックを保持した後にこれらの各イベントが発生した場合、5768個のイベントで1.125秒間フリーズが発生します。



私はWindowsのこの部分に精通していませんが、 PspExitThreadNtGdiCloseProcessの組み合わせは、この動作がプロセスの最後に観察されることを明確に示しています。



これはChromeのビルド中に起こり、Chromeのビルドは多くのプロセスを生み出します。 分散ビルドシステムを使用しました。つまり、プロセスは非常に迅速に作成され、完了しました。



次のステップは、 NtGdiCloseProcess内で費やされた時間を見つけることでした 。 そこで、 CPU Usage(Sampled)テーブルをWPAに移動し、バタフライグラフを取得しました。今回はNtGdiCloseProcessを呼び出します 。 以下のスクリーンショットは、合計時間のうち、約1085ミリ秒の1,125がNtGdiCloseProcessプロセス内で費やされたこと、つまり合計時間の96%を示しています。







1つの関数が95%の時間ロックを保持している場合、特にGetMessage呼び出しまたはカーソル位置の更新に同じロックを取得する必要がある場合は非常に悪いです。 実験のために、最大速度で1000個のプロセスを作成し、0.5秒待機してから、すべてのプロセスに同時に完了するように命令するテストプログラムを作成しました。 スクリーンショットは、4コア(8スレッド)ホームラップトップでのこのプログラムによるCPUの使用を示しています。







だから私たちが見るもの。 プロセスの作成は、必要に応じてCPUに制限されます。 ただし、プロセスの終了はCPUによって開始時と終了時のみに制限されており、中間では、システムで使用可能な8つのスレッドのうちの1つだけを使用して、 NtGdiCloseProcess内で1つのロックを奪い合うため、長時間(約1秒)連続して実行されます。 これは深刻な問題です。 このギャップは、プログラムがフリーズし、カーソルが遅れて移動する時間を表します。このギャップは数秒間引き伸ばされることもあります。



コンピューターがしばらく動作していたときに問題が悪化しているように思えたので、ラップトップを再起動し、ロード後に再度テストを実行しました。 プロセス完了シーケンスはそれほど重くはありませんでしたが、新しくロードされたマシンでも問題は明らかに存在していました。







古いWindows 7コンピューター(Intel Core 2 Q8200、サンプル2008)で同じテストを実行すると、結果は次のようになります。







ここでのプロセス作成は、はるかに弱いCPUで予想されるように遅くなりますが、プロセスの完了は私の新しいラップトップと同じくらい速く、完全に並列化されています。



これは、プロセス終了のシリアル化が、Windows 7とWindows 10の間にある新しい問題であることを示しています。



48スレッド、そのうち47がアイドル状態



アムダールの法則では、十分な数のコアにタスクを分散すると、合計実行時間は最長フラグメントの実行時間と等しくなり、並列化できなくなります。 作業中のコンピューターを数日間集中的に使用した場合、プロセスの完了が分散アセンブリ時間の重要な部分であったときに、このシリアル化の問題が明らかになりました。 可能な限りアセンブリを高速化するため(および実装中にカーソルが動き始めるように)、数日ごとにコンピューター再起動する必要がありました。 そして、それでも、ビルド速度は本来あるべきほど高速ではなかったため、Windows 7はより魅力的に見えました。



実際、システムにカーネルを追加すると、UIの反応速度が低下しました。 これは、Chromeビルドシステムが非常にスマートであり、コアが多いとより多くのプロセスが生成されるため、さらに多くの終了プロセスがグローバルブロッキングのために戦っているからです。 したがって、ここでは「24コアCPUであるが、カーソルを移動できない」だけでなく、「24コアCPUであるため 、カーソルを移動できない」と表示されます。



問題はマイクロソフトに報告され、調査中です。



そしてもう一つ...



24コアマシンでプロセスを作成および完了するためのテストプログラムを次に示します。







右下にあるこの小さな水平の赤い線をご覧ください。 これはアムダールの法則の図解であり、マシンのリソースの98%がほぼ2秒間アイドル状態にあり、プロセスの完了手順がカーソルを移動するために必要なロックを取得しました。



素材



ProcessCreateTestsコードはこちらから入手できます



この記事が気に入ったら、他の調査が好きかもしれません:



あなたのブラウザが私のコンパイラに入った!

Windowsのシャットダウン:調査と識別 」(および続き

PowerPointのパフォーマンスの低下の問題

検索機能によるVisual Studio DoS攻撃



All Articles