私はそれが本当に速いことを学びましたmemset(ptr, 0, nbytes)
が、もっと速い方法はありますか (少なくとも x86 では)?
memset は を使用していると思いますがmov
、メモリをゼロにするとき、ほとんどのコンパイラはxor
より高速であるため、正しいですか? edit1: GregSが指摘したように、レジスタでのみ機能するのは間違っています。私が考えていたことは何でしょう?
また、私よりもアセンブラーに詳しい人に stdlib を見てもらうように依頼したところ、x86 では memset が 32 ビット幅のレジスターを十分に活用していないとのことでした。しかし、その時はとても疲れていたので、それを正しく理解できたかどうか自信がありません。
edit2 : この問題を再検討し、少しテストを行いました。これが私がテストしたものです:
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <sys/time.h>
#define TIME(body) do { \
struct timeval t1, t2; double elapsed; \
gettimeofday(&t1, NULL); \
body \
gettimeofday(&t2, NULL); \
elapsed = (t2.tv_sec - t1.tv_sec) * 1000.0 + (t2.tv_usec - t1.tv_usec) / 1000.0; \
printf("%s\n --- %f ---\n", #body, elapsed); } while(0) \
#define SIZE 0x1000000
void zero_1(void* buff, size_t size)
{
size_t i;
char* foo = buff;
for (i = 0; i < size; i++)
foo[i] = 0;
}
/* I foolishly assume size_t has register width */
void zero_sizet(void* buff, size_t size)
{
size_t i;
char* bar;
size_t* foo = buff;
for (i = 0; i < size / sizeof(size_t); i++)
foo[i] = 0;
// fixes bug pointed out by tristopia
bar = (char*)buff + size - size % sizeof(size_t);
for (i = 0; i < size % sizeof(size_t); i++)
bar[i] = 0;
}
int main()
{
char* buffer = malloc(SIZE);
TIME(
memset(buffer, 0, SIZE);
);
TIME(
zero_1(buffer, SIZE);
);
TIME(
zero_sizet(buffer, SIZE);
);
return 0;
}
結果:
-O3 を除いて、zero_1 が最も遅いです。zero_sizet は、-O1、-O2、および -O3 でほぼ同等のパフォーマンスで最速です。memset は常に zero_sizet よりも低速でした。(-O3 の場合は 2 倍遅くなります)。興味深い点の 1 つは、-O3 で zero_1 が zero_sizet と同等に高速だったことです。ただし、逆アセンブルされた関数には、約 4 倍の命令がありました (ループの展開が原因だと思います)。また、zero_sizet をさらに最適化しようとしましたが、コンパイラは常に私よりも優れていましたが、ここで驚くことではありません。
今のところ memset が勝っていますが、以前の結果は CPU キャッシュによって歪められていました。(すべてのテストは Linux で実行されました) さらなるテストが必要です。次はアセンブラを試してみます:)
edit3:テスト コードのバグを修正しました。テスト結果は影響を受けません
edit4:逆アセンブルされた VS2010 C ランタイムを調べてmemset
いると、SSE に最適化されたゼロのルーチンがあることに気付きました。これを倒すのは難しいでしょう。