概要:
memcpyは、実際のアプリケーションまたはテストアプリケーションのシステムで2GB/秒を超えて転送できないようです。メモリ間のコピーを高速化するにはどうすればよいですか?
全詳細:
データキャプチャアプリケーションの一部として(いくつかの特殊なハードウェアを使用)、一時バッファからメインメモリに約3GB/秒をコピーする必要があります。データを取得するために、ハードウェアドライバーに一連のバッファー(各2MB)を提供します。ハードウェアはデータを各バッファにDMAし、各バッファがいっぱいになるとプログラムに通知します。私のプログラムはバッファを空にし(memcpyを別のより大きなRAMブロックに)、処理されたバッファをカードに再ポストして再度埋めます。memcpyがデータを十分に速く移動することに問題があります。メモリからメモリへのコピーは、実行しているハードウェアで3GB/秒をサポートするのに十分な速度である必要があるようです。Lavalys EVERESTは、9337MB /秒のメモリコピーベンチマーク結果を提供しますが、単純なテストプログラムであっても、memcpyではこれらの速度に近づくことはできません。
バッファ処理コード内のmemcpy呼び出しを追加/削除することで、パフォーマンスの問題を切り分けました。memcpyがなくても、約3GB/秒のフルデータレートで実行できます。memcpyを有効にすると、約550Mb /秒に制限されます(現在のコンパイラを使用)。
私のシステムでmemcpyのベンチマークを行うために、データのいくつかのブロックでmemcpyを呼び出すだけの別のテストプログラムを作成しました。(以下のコードを投稿しました)これは、使用しているコンパイラ/ IDE(National Instruments CVI)とVisual Studio2010の両方で実行しました。現在VisualStudioを使用していませんが、喜んで使用します。必要なパフォーマンスが得られる場合は、切り替えを行います。しかし、やみくもに移動する前に、それが私のmemcpyパフォーマンスの問題を解決することを確認したかったのです。
Visual C ++ 2010:1900MB/秒
NI CVI 2009:550MB/秒
CVIがVisualStudioよりも大幅に遅いことに驚いていませんが、memcpyのパフォーマンスがこれほど低いことに驚いています。これが直接比較できるかどうかはわかりませんが、これはEVERESTベンチマーク帯域幅よりもはるかに低くなっています。そのレベルのパフォーマンスは必要ありませんが、最低3GB/秒が必要です。確かに、標準ライブラリの実装は、エベレストが使用しているものよりもはるかに悪くなることはありません!
この状況でmemcpyを高速化するために、もしあれば、何ができますか?
ハードウェアの詳細:AMDMagnyCours-4xオクタルコア128GBDDR3 Windows Server 2003 Enterprise X64
テストプログラム:
#include <windows.h>
#include <stdio.h>
const size_t NUM_ELEMENTS = 2*1024 * 1024;
const size_t ITERATIONS = 10000;
int main (int argc, char *argv[])
{
LARGE_INTEGER start, stop, frequency;
QueryPerformanceFrequency(&frequency);
unsigned short * src = (unsigned short *) malloc(sizeof(unsigned short) * NUM_ELEMENTS);
unsigned short * dest = (unsigned short *) malloc(sizeof(unsigned short) * NUM_ELEMENTS);
for(int ctr = 0; ctr < NUM_ELEMENTS; ctr++)
{
src[ctr] = rand();
}
QueryPerformanceCounter(&start);
for(int iter = 0; iter < ITERATIONS; iter++)
memcpy(dest, src, NUM_ELEMENTS * sizeof(unsigned short));
QueryPerformanceCounter(&stop);
__int64 duration = stop.QuadPart - start.QuadPart;
double duration_d = (double)duration / (double) frequency.QuadPart;
double bytes_sec = (ITERATIONS * (NUM_ELEMENTS/1024/1024) * sizeof(unsigned short)) / duration_d;
printf("Duration: %.5lfs for %d iterations, %.3lfMB/sec\n", duration_d, ITERATIONS, bytes_sec);
free(src);
free(dest);
getchar();
return 0;
}
編集:余分な5分があり、貢献したい場合は、上記のコードをマシンで実行して、コメントとして時間を投稿できますか?