認識されない機能により、プログラムが5倍遅くなります

Windowsの速度を下げる、パート3:プロセスの終了







著者はGoogleでのChromeのパフォーマンスの最適化に取り組んでいます-約 あたり



2017年の夏、Windowsのパフォーマンスの問題に苦労しました。 プロセスの終了が遅く、シリアル化され、システム入力キューがブロックされたため、Chromeのアセンブリ中にマウスカーソルが何度もフリーズしました。 主な理由は、プロセスの最後に、WindowsがGDIオブジェクトの検索に多くの時間を費やし、システムグローバルユーザー32の重要なセクションを押さえることでした。 これについては「24コアプロセッサですが、カーソルを移動できません」という記事で説明しました。



マイクロソフトはバグを修正し、ビジネスに戻りましたが、バグが戻ったことが判明しました。 入力が頻繁にフリーズする、LLVMテストの遅い動作について苦情がありました。



しかし、実際には、バグは再発しませんでした。 その理由は、コードの変更です。



2017年号



各Windowsプロセスには、いくつかの標準GDIオブジェクト記述子が含まれています。 グラフィックスで何もしないプロセスの場合、これらの記述子は通常NULLです。 プロセスの最後に、Windowsはこれらの記述子がNULLであっても、これらの記述子に対していくつかの関数を呼び出します。 Windows 10 Anniversary Editionがリリースされるまで、 セキュリティの変更によりこれらの機能が遅くなるまで、機能は高速で動作していました 。 操作中、入力イベントに使用されたのと同じロックを保持していました。 多数のプロセスが同時に終了すると、各プロセスはこの重要なロックを保持する低速関数を複数回呼び出し、最終的にユーザー入力がブロックされ、カーソルがフリーズします。



Microsoftのパッチは、GDIオブジェクトのないプロセスでこれらの関数を呼び出さないことでした。 詳細はわかりませんが、Microsoftのパッチは次のようなものだったと思います。



+ if (IsGUIProcess())

+ NtGdiCloseProcess();

– NtGdiCloseProcess();








つまり、プロセスがGUI / GDIプロセスでない場合は、GDIクリーンアップをスキップします。



すぐに作成および終了するコンパイラおよびその他のプロセスはGDIオブジェクトを使用しなかったため、このパッチはUIのフリーズを修正するのに十分であることが判明しました。



2018年号



プロセスには、いくつかの標準GDIオブジェクトが実際に非常に簡単に割り当てられることが判明しました。 プロセスがgdi32.dllをロードすると、必要かどうかにかかわらず、GDIオブジェクト(DC、サーフェス、リージョン、ブラシ、フォントなど)を自動的に受け取ります(これらの標準GDIオブジェクトはタスクマネージャーに表示されないことに注意してください)プロセスのGDIオブジェクト間)。



しかし、それは問題ではないはずです。 つまり、コンパイラはなぜgdi32.dllをロードするのでしょうか? さて、user32.dll、shell32.dll、ole32.dll、または他の多くのDLLをロードすると、gdi32.dll(前述の標準GDIオブジェクト)が自動的に追加されることがわかりました。 また、これらのライブラリのいずれかを誤ってダウンロードすることは非常に簡単です。



LLVMは、 CommandLineToArgvW (shell32.dll)と呼ばれる各プロセス、およびSHGetKnownFolderPath (shell32.dll)と呼ばれることもある各プロセスをロードするときにテストします。 LLVMテストスイートは非常に多くのプロセスを生成するため 、最終的にプロセスの完了時にシリアル化され、2017年の場合よりも大幅に遅延して入力がフリーズします。



しかし、今回はブロッキングの主な問題について知っていたので、すぐに何をすべきかがわかりました。



まず、コマンドラインを手動で解析して CommandLineToArgvW呼び出しを削除しました 。 その後、LLVMテストスイートは、問題のあるDLLから関数を呼び出すことはほとんどありませんでした。 ただし、これがパフォーマンスに影響を与えないことは事前にわかっていました。 その理由は、残りの条件付き呼び出しでさえ常にshell32.dllをプルするのに十分であり、それが標準のGDIオブジェクトを作成するgdi32.dllをプルするためでした。



2番目の修正は、 shell32.dll遅延ロードでした 。 遅延ロードとは、プロセスの開始時にロードする代わりに、関数が呼び出されたときに、ライブラリがオンデマンドでロードされることを意味します。 これは、shell32.dllとgdi32.dllがほとんど読み込まれないことを意味しますが、常にではありません。



その後、LLVMテストスイートは5倍ではなく1分間で5倍の速度で実行を開始しました。 また、開発マシンでマウスがフリーズすることはないため、テストの実行中に従業員は通常どおり作業できます。 これは、このようなささいな変更に対する非常識な加速であり、パッチの作成者は私の調査にとても感謝していたので、彼は私に企業ボーナスを提案しました。



時々、小さな変更が最大の結果をもたらすことがあります。 「ゼロ」をダイヤルする場所知る必要があります



実行パスは受け入れられません



実行さなかったコードに注意を払ったことを繰り返す価値があります-これは重要な変更でした。 gdi32.dllにアクセスしないコマンドラインツールを使用している場合、 条件付き関数呼び出しでコードを追加すると、gdi32.dllがロードされているとプロセスが何度も遅くなります。 以下の例では、 CommandLineToArgvWが呼び出されることはありませんが、コード内に単純に存在するだけで(呼び出し遅延なし)、パフォーマンスに悪影響を及ぼします。



 int main(int argc, char* argv[]) { if (argc < 0) { CommandLineToArgvW(nullptr, nullptr); // shell32.dll, pulls in gdi32.dll } }
      
      





そのため、コードが実行されない場合でも、関数呼び出しを削除するだけで、場合によってはパフォーマンスを大幅に改善できます。



病理学の再現



最初のエラーを調査したとき、1000個のプロセスを作成し、それらをすべて並行して強制終了するプログラム( ProcessCreateTests )を作成しました。 これによりフリーズが再現され、Microsoftがエラーを修正したとき、テストプログラムを使用してパッチを確認しました。 ビデオを参照してください。 バグが生まれ変わった後、 -user32オプションを追加してプログラムを変更しました。このオプションは、数千のテストプロセスのそれぞれに対してuser32.dllをロードします。 予想どおり、このオプションを使用すると、すべてのテストプロセスの完了時間が劇的に長くなり、マウスカーソルのフリーズを簡単に検出できます。 -user32オプションを使用すると、プロセスの作成時間も長くなりますが、プロセスの作成中にカーソルが一時停止することはありません。 このプログラムを使用して、問題がどれほどひどいものであるかを確認できます。 1週間の稼働時間後の4コア/ 8スレッドノートブックの典型的な結果を次に示します。 -user32オプションはすべての時間を増やしますが、プロセス終了時のUserCritロックは特に劇的です。



> ProcessCreatetests.exe

Process creation took 2.448 s (2.448 ms per process).

Lock blocked for 0.008 s total, maximum was 0.001 s.



Process destruction took 0.801 s (0.801 ms per process).

Lock blocked for 0.004 s total, maximum was 0.001 s.



> ProcessCreatetests.exe -user32

Testing with 1000 descendant processes with user32.dll loaded.

Process creation took 3.154 s (3.154 ms per process).

Lock blocked for 0.032 s total, maximum was 0.007 s.



Process destruction took 2.240 s (2.240 ms per process).

Lock blocked for 1.991 s total, maximum was 0.864 s.








楽しみのために深く掘り下げる



問題をより詳細に研究するために使用できるいくつかのETWメソッドについて考え、すでにそれらを書き始めました。 しかし、私はそのような不可解な振る舞いに出くわしたので、別の記事を書くことにしました。 この場合、Windowsの動作はさらに奇妙になります。



シリーズの他の記事:





文学






All Articles