我正在观察一些我无法解释的奇怪行为。以下是详细信息: -
#include <sched.h>
#include <sys/resource.h>
#include <time.h>
#include <iostream>
void memcpy_test() {
int size = 32*4;
char* src = new char[size];
char* dest = new char[size];
general_utility::ProcessTimer tmr;
unsigned int num_cpy = 1024*1024*16;
struct timespec start_time__, end_time__;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_time__);
for(unsigned int i=0; i < num_cpy; ++i) {
__builtin_memcpy(dest, src, size);
}
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_time__);
std::cout << "time = " << (double)(end_time__.tv_nsec - start_time__.tv_nsec)/num_cpy << std::endl;
delete [] src;
delete [] dest;
}
当我在编译器选项中指定-march = native时,生成的二进制文件运行速度慢2.7倍。这是为什么 ?如果有的话,我希望-march = native来生成优化的代码。还有其他功能可以显示这种行为吗?
编辑1: 另一个有趣的观点是,如果尺寸> 32 * 4那么这样生成的二进制文件的运行时间没有区别
编辑2: 以下是详细的性能分析(__builtin_memcpy()): -
size = 32 * 4,没有-march = native - 7.5 ns,-march = native - 19.3
size = 32 * 8,没有-march = native - 26.3 ns,-march = native - 26.5
编辑3:
即使我分配了int64_t / int32_t,这个观察也不会改变。
编辑4:
size = 8192,没有-march = native~2750 ns,-march = native~2750(之前报告此数字时出错,错误地写为26.5,现在是正确的)
我已经多次运行,每次运行的数字都是一致的。
答案 0 :(得分:3)
我已经在我的Core 2 Duo上复制了你的发现:g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2
,Linux 2.6.38-10-generic #46-Ubuntu x86_64
。结果可能会因您的编译器版本和CPU而异。我得到~26和~9。
当我在编译器选项中指定-march = native时,生成的二进制文件运行速度慢2.7倍。这是为什么 ?
因为-march =本机版本被编译成(使用objdump -D
找到你也可以使用gcc -S -fverbose-asm
):
rep movsq %ds:(%rsi),%es:(%rdi) ; where rcx = 128 / 8
并且没有编译成16个加载/存储对的版本,如:
mov 0x20(%rbp),%rdx
mov %rdx,0x20(%rbx)
我们的电脑显然速度更快。
如果有的话,我希望-march = native来生成优化代码。
在这种情况下,结果是对rep movsq
的一系列动作感到悲观,但情况可能并非总是如此。第一个版本更短,在某些(大多数?)情况下可能更好。或者它可能是优化器中的错误。
是否有其他功能可以显示此类行为?
指定-march=native
时生成的代码不同的任何函数,可疑包括在头中实现为宏或静态的函数,其名称以__builtin
开头。也可能是(浮点)数学函数。
另一个有趣的观点是,如果尺寸&gt; 32 * 4那么这样生成的二进制文件的运行时间没有区别
这是因为它们都编译为rep movsq
,128可能是GCC将生成一系列加载/存储的最大大小(看看这是否也适用于其他平台会很有趣)。 BTW当编译器在编译时不知道大小(例如int size=atoi(argv[1]);
)时,它只是在有或没有开关的情况下变成对memcpy
的调用。
答案 1 :(得分:0)
这是众所周知的问题(而且很老)。
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43052
查看错误报告中的一些底部评论:
“仅供参考:mesa现在默认为-fno-builtin-memcmp来解决这个问题 问题“
看起来glibc的memcpy远比内置更好......