我了解到这memset(ptr, 0, nbytes)
真的很快,但是有没有更快的方法(至少在 x86 上)?
我假设 memset 使用mov
,但是在将内存归零时,大多数编译器都使用xor
它,因为它更快,对吗?编辑 1:错误,正如 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;
}
结果:
zero_1 是最慢的,但 -O3 除外。zero_sizet 是最快的,在 -O1、-O2 和 -O3 上的性能大致相同。memset 总是比 zero_sizet 慢。(-O3 慢两倍)。有趣的一件事是,在 -O3 zero_1 与 zero_sizet 一样快。然而,反汇编函数的指令数量大约是其四倍(我认为是由循环展开引起的)。此外,我尝试进一步优化 zero_sizet,但编译器总是超过我,但这并不奇怪。
现在 memset 获胜,以前的结果被 CPU 缓存扭曲了。(所有测试均在 Linux 上运行)需要进一步测试。接下来我会尝试汇编程序:)
edit3:修复了测试代码中的bug,测试结果不受影响
编辑 4:在查看反汇编的 VS2010 C 运行时时,我注意到它memset
的 SSE 优化例程为零。这将很难被击败。