我了解到 memset(ptr, 0, nbytes)
确实很快,但是有没有更快的方法(至少在 x86上) ?
我假设 memset 使用 mov
,但是当归零内存时,大多数编译器使用 xor
,因为它更快,对吗?编者:错误,正如 GregS 指出的那样,只有寄存器才起作用。我到底在想什么?
另外,我请一个比我更了解汇编程序的人查看 stdlib,他告诉我在 x86上 memset 没有充分利用32位宽寄存器。但是当时我很累,所以我不太确定我理解得对不对。
编辑2 : 我重新讨论了这个问题,并做了一些测试:
#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;
}
结果:
0 _ 1是最慢的,除了-O3。Zero _ sizet 是最快的,在-O1、-O2和-O3之间的性能大致相同。Memset 总是比 zero _ sizet 慢。(对于 -O3来说慢了一倍)。有趣的是,at-O30 _ 1的速度和0 _ siz 的速度一样快。然而,反汇编函数的指令数量大约是这个函数的四倍(我认为这是由循环展开引起的)。此外,我尝试进一步优化 zero _ sizet,但编译器总是超过我,但这里并不奇怪。罢工
现在 memset 获胜,以前的结果被 CPU 缓存扭曲。(所有测试都在 Linux 上运行)需要进一步的测试。我接下来试试汇编程序:)
编辑3: 测试代码中的固定错误,测试结果不受影响
编辑4: 在浏览已拆解的 VS2010C 运行时时,我注意到 memset
有一个针对零的 SSE 优化例程。很难战胜它。