これは実際にはコーディングの問題です。
Linuxで実行されている4 * 4GB DDR3 1600Mhzコンピューターを搭載したi7-3820があります。Intel の仕様によると、メモリを 51.2GB/s (GiB/s ではない) でスキャンできると思います。残念ながら、40GB/秒しか得られません。
まず、メモリから xmm へのロード手順をアセンブリでコーディングしました。次のように宣言されているとします。
extern "C" {
void load_mem_256b(int *start, int *end, int step, int *p_sum);
}
戻り値は、最適化を避けるために、読み込まれたすべての整数の最初の int の合計です。
start が指すメモリ アドレスから 256 ビットをロードし、start をステップ * 8 (8 * sizeof(int) = 256 ビット) ずつ進めます。
メモリを読み取る 2 つの方法を試しました。最初の方法は、4 つのスレッドを開き、メモリを 4 つのセグメントに分割することです。もう 1 つの方法は、4 つのスレッドを開き、各スレッドに 1024b の i 番目の 256b 部分をロードさせ、4 つのスレッドを適切に同期させることです。
前に述べたように、最初の方法は 40GB/s を達成しました。2 番目の方法は低速です。
最初の方法では、メモリがギャング モードで動作している場合、別の行でメモリへのアクセスが大量に発生します。DIMM * 4 DIMM あたり 2 ランクあるため、パフォーマンスが低下せずに正常に動作するかどうかはわかりません。2 番目の方法では、メモリ ロードを同じ行にのみ発生させ、異なるメモリ チャネルから別のスレッドをロードさせるとします。
最初の方法は次のようになります。
for (int i = 0; i < number_of_threads; ++i)
threads[i] = std::thread(std::bind(
load_mem_256b, start + i * 8, end, number_of_threads, &(sums[i])));
2 番目の方法は次のようになります。
size_t amount = 32768;
my::spin_barrier barrier(number_of_threads + 1);
for (int i = 0; i < number_of_threads; ++i)
threads[i] = std::thread(std::bind(load_mem_256b_barrier,
start + i * 8, end,
number_of_threads,
&barrier, amount, &(sums[i])));
threads[number_of_threads] = std::thread(std::bind(
prefetch, start, end, amount, &barrier));
いくつかの追加データは、最初の方法で、1 つまたは 2 つまたは 3 つのスレッドのみを開くと、17GB/s、32GB/s、39GB/s でメモリをロードできることです。これらすべての数字に奇妙に感じます。メモリが非連結モードで動作している場合、1 つのスレッドが 17GB/s でメモリをロードできるのはなぜですか? (1 つのチャネルは 12.8GB/秒しか送信できません) しかし、ギャング モードで動作している場合、2 番目の方法が最初の方法よりも大幅に遅いのはなぜですか?
そして最後に、理論上の速度で実際にメモリをロードする方法は?