タスクは非常に単純で、一連の整数変数をメモリに書き込みます。
元のコード:
for (size_t i=0; i<1000*1000*1000; ++i)
{
data[i]=i;
};
並列化されたコード:
size_t stepsize=len/N;
#pragma omp parallel num_threads(N)
{
int threadIdx=omp_get_thread_num();
size_t istart=stepsize*threadIdx;
size_t iend=threadIdx==N-1?len:istart+stepsize;
#pragma simd
for (size_t i=istart; i<iend; ++i)
x[i]=i;
};
パフォーマンスは最悪です。1Gの変数 (1 秒あたり 5GB に相当)を書き込むのに1.6 秒かかります。上記のコードの単純な並列化 ( ) によって、速度は少し向上しますが、パフォーマンスは依然として最悪です。4 スレッドで1.4 秒、1.35 秒かかりますi7 3970 で 6 スレッド。uint64
open mp parallel
私のリグ ( i7 3970/64G DDR3-1600 ) の理論上のメモリ帯域幅は51.2 GB/secです。上記の例では、達成されたメモリ帯域幅は理論上の帯域幅の約1/10にすぎません。 -帯域幅制限。
コードを改善する方法を知っている人はいますか?
私は GPU で多くのメモリ バウンド コードを書きました。GPU が GPU のデバイス メモリ帯域幅 (理論帯域幅の 85%+ など) を最大限に活用するのは非常に簡単です。
編集:
コードは Intel ICC 13.1 によって 64 ビット バイナリにコンパイルされ、最大最適化 (O3) と AVX コード パス、および自動ベクトル化がオンになっています。
アップデート:
以下のすべてのコードを試しました (Paul R に感謝します)。特別なことは何も起こりません。コンパイラーは simd/ベクトル化の最適化を完全に行うことができると思います。
なぜそこに数字を入力したいのかというと、簡単に言えば:
高性能ヘテロジニアス コンピューティング アルゴリズムの一部であり、デバイス側では、マルチ GPU セットが非常に高速であるため、CPU が複数のシーケンスを書き込もうとするとパフォーマンスのボトルネックがたまたま発生することがわかったほど、アルゴリズムは非常に効率的です。メモリへの数字の。
当然のことながら、CPU は数値を埋めるのが苦手であることを知っています (対照的に、GPU は非常に近い速度で数のシーケンスを埋めることができます ( GK110 では 288GB/秒から238GB/秒に対して、GK110 では51.2GB/秒から5GB/秒) CPU) を GPU のグローバル メモリの理論上の帯域幅に変更する必要があるため、アルゴリズムを少し変更することもできますが、なぜ CPU がここで数列を埋めるのが苦手なのか不思議に思います。
私のリグのメモリ帯域幅に関しては、帯域幅 (51.2GB) はほぼ正しいと思います。私のmemcpy()
テストに基づいて、達成された帯域幅は理論上の帯域幅 ( >40GB/秒) の約80%+です。