特定のシステムのシミュレーションを実行するプログラムを C++ で作成しています。タイムステップごとに、実行の大部分は 1 つのループで占められています。幸いなことに、これは非常に並列であるため、Boost Threads を使用して並列化することにしました (2 コアのマシンで実行しています)。ロックがないため、シリアル バージョンの 2 倍近くの高速化が期待できます。ただし、スピードアップはまったくないことがわかりました。
ループの並列バージョンを次のように実装しました。
- 2 つのスレッドを起動します (バリアでブロックされています)。
その後、各スレッドは以下を実行します。
- グローバル カウンターをアトミックにフェッチしてインクリメントします。
- そのインデックスでパーティクルを取得します。
- その粒子で計算を実行し、結果を別の配列に格納します
- ジョブ終了バリアで待機
メイン スレッドはジョブ終了バリアで待機します。
このアプローチを使用したのは、適切な負荷分散を提供する必要があるためです (各計算にかかる時間が異なる場合があるため)。この速度低下の原因は何なのか、非常に興味があります。アトミック変数は高速であるといつも読んでいますが、今ではパフォーマンス コストがあるのかどうか疑問に思い始めています。
何を探すべきか、またはヒントがあれば、本当に感謝します。私は 1 週間頭を悩ませてきましたが、プロファイリングではあまり明らかになりませんでした。
編集:問題は解決しました! この問題をどのように解決したかを詳しく説明します。再度 gprof を使用しましたが、今回は最適化フラグ (-O3) なしでコンパイルしました。すぐに、プロファイラーは、個々の粒子の計算を実行する関数に信じられないほどの時間を費やしていることを示しました。これは、シリアル バージョンよりもはるかに長い時間です。
この関数は仮想であり、多態的にアクセスされます。vtable を介してではなく直接アクセスするようにコードを変更したところ、ほら、並列バージョンではほぼ 2 倍のスピードアップが実現しました。シリアル版での同じ変更はほとんど効果がありませんでした。
なぜそうなのかはよくわかりませんが、誰かが知っていれば興味があります!
ポスターの皆様ありがとうございました。皆さんはある程度助けてくれました。1 つの答えを受け入れるのは非常に難しいでしょう。