次の非常に単純なコンピュータープログラムを検討してください。
for i = 1 to n:
y[i] = x[p[i]]
ここで、とは要素のバイト配列であり、は要素の単語配列です。ここで、は大きく、たとえば(したがって、データのごく一部のみがあらゆる種類のキャッシュメモリに収まります)。y n p n n n = 2 31
がから間に一様に分布した乱数で構成されていると仮定します。1 n
最新のハードウェアの観点から見ると、これは次のことを意味するはずです。
- 読書安い(シーケンシャルリード)であります
- 読ん非常に高価である(ランダム読み取り、ほぼすべてのあるキャッシュミスを読み込みます。私たちは、メインメモリから個々のバイトを取得する必要があります)
- 書き込み安い(シーケンシャル書き込み)です。
そして、これはまさに私が観察していることです。このプログラムは、シーケンシャルな読み取りと書き込みのみを行うプログラムと比較して非常に遅いです。すごい。
ここで疑問が生じます。このプログラムは、最新のマルチコアプラットフォームでどの程度並列化されますか?
私の仮説では、このプログラムはうまく並列化されません。結局のところ、ボトルネックはメインメモリです。単一のコアは、メインメモリからのデータを待機するだけで、すでにほとんどの時間を無駄にしています。
ただし、これは、この種の操作がボトルネックとなっているいくつかのアルゴリズムを試し始めたときに観察したものではありませんでした!
単純なforループをOpenMP並列forループに置き換えました(本質的に、範囲を小さな部分に分割し、これらの部分を異なるCPUコアで並列に実行します)。
ローエンドのコンピューターでは、スピードアップは確かに軽微でした。しかし、ハイエンドプラットフォームでは、優れた線形に近い高速化が得られたことに驚きました。いくつかの具体的な例(正確なタイミングは少しずれている可能性があり、多くのランダムな変動があります;これらは単なる簡単な実験でした):
2 x 4コアXeon(合計8コア):シングルスレッドバージョンと比較して、5〜8倍高速化。
2 x 6コアXeon(合計12コア):シングルスレッドバージョンと比較して8〜14倍高速化。
今、これは全く予想外でした。質問:
正確になぜプログラムの並列化のこの種のは、とてもよくありませんか?ハードウェアで何が起こりますか?(私の現在の推測は、これらの線に沿ったものです:異なるスレッドからのランダムな読み取りは「パイプライン化」されており、これらに対する回答を取得する平均レートは、単一のスレッドの場合よりもはるかに高くなります。)
速度を上げるには、複数のスレッドと複数のコアを使用する必要がありますか?メインメモリとCPUの間のインターフェイスで何らかのパイプライン処理が実際に行われる場合、シングルスレッドアプリケーションでは、メインメモリに、、...、コンピュータはメインメモリから関連するキャッシュラインのフェッチを開始できますか?これが原則的に可能である場合、実際にどのように達成しますか?x [ p [ i + 1 ] ]
この種のプログラムの分析(およびパフォーマンスの正しい予測)に使用できる正しい理論モデルは何ですか?
編集:https : //github.com/suomela/parallel-random-readからソースコードとベンチマーク結果を入手できます。
球場の数字の例():
- 約 単一スレッドで反復あたり42 ns(ランダム読み取り)
- 約 12コアで反復あたり5 ns(ランダム読み取り)。