私は軽量プロセスを試してきました。デフォルトでは、複製機能が呼び出され、複製されたLWPに新しいPIDが割り当てられます。これは素晴らしい動作します。これにより、そのLWPのすべてのサブスレッドを識別できます。私が持っている小さな問題はパフォーマンスです。パフォーマンスが大幅に低下しました(処理速度が30%遅くなりました)。今私はLWPを予約し、優先順位を割り当てることが可能であることを読んでいます(私もそれを試みませんでした)。これはパフォーマンスに役立ちますか?
straceを実行したときに私が感じたことの1つは、Futexの使用量が8〜10倍爆発的に増加したことです。 LWPがこれの主な理由になるのでしょうか?理解できる部分はコンテキスト切り替えが爆発的に増加したものですが、LWPは同じメモリ空間を共有するため、Futexの使用によって爆発が起こらないと思います。
LWPを使用または使用することを決定する際に従うべきヒントやベストプラクティスはありますか?
パフォーマンスの観点からフォークする方が良いオプションですか、それとも悪いオプションですか?
答え1
straceを実行したときに私が感じたことの1つは、Futexの使用量が8〜10倍爆発的に増加したことです。 LWPがこれの主な理由になるのでしょうか? [...]、しかしLWPは同じメモリ空間を共有するので、Futexの使用量は爆発的に増やすべきではありません。
はい、LWPを使用すると、おそらくFutexesの使用量が増えます。これは、実際には同じメモリを共有する異なるスレッドの同期という正確なケースを意味するためです。
Futexesは、共有メモリがあるときにすべてのロック操作の遅いパスに使用され、LWPまたはスレッドは、ロックがロック解除されたことを知らせるまでカーネルにブロックします。
クイックパスはアトミック操作を使用します(CPUはカウンタをアトミックに増加または減少させ、最初にロックされたか最後にロック解除されたかを検出できます)。したがって、高速パスでシステムコールを実行する必要はありません。
ロック競合が増加するということは、より多くのFutex操作が発生することを意味します。これは、システム呼び出し自体が原因であるだけでなく、Futexが呼び出されたときに一部のLWPまたはスレッドがリソースを待ち、スリープ状態にあることを意味するため、パフォーマンスに影響します。狂うことができます。
glibc のコードはマルチスレッドまたは LWP の使用を認識するため、コードに明示的なロックがない場合でもシステムライブラリにロックがあるため、ロック競合が発生し、次のようにプログラムが遅くなる可能性があります。 。
パフォーマンスが大幅に低下しました(処理速度が30%遅くなりました)。
メモリを共有するスレッドが多い場合のもう1つの要因は、おおよそのロックがあるいくつかのカーネルメモリ構造があり、ロック競合もある可能性があることです。
特にmmap_sem
、より多くのメモリ領域をプロセスにマッピングするたびに、書き込みのためにその領域をロックする必要があります。 (特にmalloc()
友達とより多くのメモリを割り当てる可能これをトリガーします。 )
今私はLWPを予約し、優先順位を割り当てることが可能であることを読んでいます(私もそれを試みませんでした)。これはパフォーマンスに役立ちますか?
たぶん...言うのは難しいです。ベンチマークする必要があります。
表示されているものがロック競合であり、コードパスを介して一般化(単一またはいくつかのLWPにローカライズされていない)されている場合、これは役に立ちません。
あなたはそれを使用することができますperf
ツールLinuxで一連のプロセスパフォーマンスを理解するのに役立ちます。ホットスポットを表示し、カーネルホットスポットが存在するかどうかを表示することもできます。
LWPを使用または使用することを決定する際に従うべきヒントやベストプラクティスはありますか?
LWPやスレッドの場合、多数を使用すると、malloc()
カーネルに関連する問題(メモリマップの拡張により潜在的な競合が発生するmmap_sem
)とユーザー空間の問題(単一スタジアムを使用するという意味)があるため、実装が非常に重要になります。スレッド(スペースを保存するにはロックする必要があります)。
多数のスレッドを使用する場合のパフォーマンスを向上させるために、いくつかの malloc ライブラリが作成されました。例えば、tcmallocまたはジャマルロック。これを採用するのは一般的に簡単であり(追加のライブラリにリンクするだけです)、実際にボトルネックが発生した場合にパフォーマンスが大幅に向上する可能性があります。いつものように、ベンチマークでこれが役立つことを確認してください。
パフォーマンスの観点からフォークする方が良いオプションですか、それとも悪いオプションですか?
おそらくより良いでしょう。話すのは難しいです。特定のケースでより良いことを確認するには、ベンチマークが必要です。
LWPと同様に、ベンチマークで実際に価値があることを確認する必要があります。
前述のように、LWPまたはスレッド間で共有メモリを使用すると(または同じメモリを共有するより多くのLWPまたはスレッドがある場合)、ロック競合の可能性が高くなります(直接明示的なロックがない場合でも、glibcとカーネルはこれを行います。 ) LWP 実際に速度が遅くなる可能性が高い。
私はマルチスレッドアプリケーションが遅すぎる状況を直接目撃しました。開発者は40スレッドの代わりに単一スレッドを使用するように変更しました。アプリケーションの速度が突然1,000%速くなりました。 90%の時間がロック競合に費やされることがわかりました!
答え2
数日間のテストの最後に、次の事実が見つかりました。
Futexesはスレッド間でメモリバッファを共有するために発生し(残念ながら回避できません)、スレッドはかなり高い頻度で数学モデルを実行します。 futexは実行遅延に直接影響しますが、線形的には影響を与えず、データの頻度が高いほど影響が大きくなります。
ほとんどのデータサイズがわかっているため、一部の割り当てではメモリプールや同様の使用を回避できます。これは実行とCPUの負荷にプラスの影響を与えます。
LWPは、親PIDとは異なるPIDを使用して複製します。これはLinuxでは問題ありませんが、pThreadでは機能しません。パフォーマンスの面では、LWPによるパフォーマンスの低下がいくつかありますが、大幅に低下しません。共有メモリリソースは、より大きな問題を引き起こす。
jeMalloc、tcMalloc、およびlocklessMallocを使用してアプリケーションを構築した場合、これらのライブラリのどれも私に競争上の優位性を提供できませんでした。コア数が4つ以上の場合はTcMallocが良く、キャッシュが大きい場合はjeMallocが良いです。しかし、私の場合、複数の実行シナリオの結果はベースラインと+/- 1%異なりました。
より多くのメモリ領域をプロセスにマッピングすると、実行全体に大きな違いが生じる可能性があります。 FillBradenの言葉は正しいです。実行が開始されたとき、またはデータフローによってデータ量が増加したときに私たちに大きな打撃を与えます。私たちはメモリプールを使用して動作をアップグレードしました。
実行速度も向上させるSCHED_RRを使用してアプリケーションを実行するテストシリーズが含まれています。問題は、優先順位の点でスレッドのスコアが高いため、これが影響を与えることです。利点は、ハイパースレッディングなしで非常に安定してコアを実行できることです。その理由は、アプリケーションとモデルの動作によるものです。未知の理由で、ハイパースレッディングは状況をかなり混乱させます。
個々のモデルを分岐すると、どのスレッドがどのモデルに属しているかを識別するのに役立ちますが、実行速度には何の利点もありません。これは間違いなく正常に動作しないモデルスレッドを識別して修正するための取引およびソリューションです。