次のコードのパフォーマンスについてサポートが必要です。これは、動的に割り当てられた任意のサイズの2つの配列に対してmemcpyを実行します。
int main()
{
double *a, *b;
unsigned n = 10000000, i;
a = malloc(n*sizeof(double));
b = malloc(n*sizeof(double));
for(i=0; i<n; i++) {
a[i] = 1.0;
/* b[i] = 0.0; */
}
tic();
bzero(b, n*sizeof(double));
toc("bzero1");
tic();
bzero(b, n*sizeof(double));
toc("bzero2");
tic();
memcpy(b, a, n*sizeof(double));
toc("memcpy");
}
tic/tocは実行時間を測定します。
私のコンピューターでは、memcpy(Linux、gccバージョン4.4.6)に0.035秒かかります。ここで、宛先配列bを初期化する行のコメントを解除すると、コードは3倍速くなります(!)-0.011秒。
memcpyの代わりにループを使用した場合にも同様の動作が見られます。使用する前にメモリを「初期化」するだけで十分なので、通常はこれを気にしません。ただし、単純なメモリコピーを実行し、可能な限り高速に実行する必要があります。データを初期化するには、たとえばメモリに0を書き込む必要がありますが、これは不要で時間がかかります。そして、使用可能なすべてのメモリ帯域幅でメモリコピーを実行したいと思います。
この問題の解決策はありますか?それとも、Linuxが動的メモリを処理する方法(ある種の怠惰なページ割り当て?)に接続されており、回避できませんか?他のシステムではどうですか?
編集: gcc4.6でも同じ結果が得られます。-O3を使用してコンパイルしました。
編集: コメントありがとうございます。メモリマッピングには時間がかかることを理解しています。実際のメモリアクセスよりもはるかに長い時間がかかることを受け入れるのに苦労していると思います。コードが変更され、後続の2つのbzero呼び出しを使用した配列bの初期化のベンチマークが含まれるようになりました。タイミングが表示されます
bzero1 0.273981
bzero2 0.056803
memcpy 0.117934
明らかに、最初のbzero呼び出しは、ゼロをメモリにストリーミングするだけではありません。つまり、メモリマッピングとメモリゼロ化です。一方、2番目のbzero呼び出しは、memcpyを実行するのに必要な時間の半分を要します。これは、正確に予想どおりです。書き込みのみの時間と読み取りおよび書き込み時間です。OSのセキュリティ上の理由から、2番目のbzero呼び出しのオーバーヘッドが存在する必要があることを理解しています。残りはどうですか?どういうわけかそれを減らすことはできませんか?例えば、より大きなメモリページを使用しますか?異なるカーネル設定?
私はこれをUbuntu喘鳴で実行していることに言及する必要があります。