我观察到一些我无法解释的奇怪行为。以下是详细信息:-
#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:
另一个有趣的一点是,如果 size > 32*4 那么由此生成的二进制文件的运行时间之间没有区别
编辑2:
以下是详细的性能分析(__builtin_memcpy()):-
大小 = 32 * 4,没有 -march=native - 7.5 ns,有 -march=native - 19.3
大小 = 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,现在是正确的)
我已经跑了很多次,每次运行的数字都是一致的。
最佳答案
我已将您的发现复制到:g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2
, Linux 2.6.38-10-generic #46-Ubuntu x86_64
在我的 Core 2 Duo 上。结果可能会因您的编译器版本和 CPU 而异。我得到 ~26 和 ~9。
When I specify -march=native in compiler options, generated binary runs 2.7 times slower. Why is that ?
因为 -march=native 版本被编译成(使用
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)
这在我们的计算机上显然更快。
If anything, I would expect -march=native to produce optimized code.
在这种情况下,结果证明是悲观的支持
rep movsq
在一系列 Action 中,但情况可能并非总是如此。第一个版本较短,在某些(大多数?)情况下可能会更好。或者它可能是优化器中的错误。Is there other functions which could show this type of behavior ?
指定
-march=native
时生成的代码不同的任何函数, 嫌疑人包括在头文件中实现为宏或静态的函数,其名称以 __builtin
开头.可能还有(浮点)数学函数。Another interesting point is that if size > 32*4 then there is no difference between the run time of the binaries thus generated
这是因为它们都编译为
rep movsq
, 128 可能是 GCC 将生成一系列加载/存储的最大大小(看看这是否也适用于其他平台会很有趣)。顺便说一句,当编译器在编译时不知道大小(例如 int size=atoi(argv[1]);
)时,它只会变成对 memcpy
的调用。带或不带开关。
关于64-bit - memcpy() 性能 - Ubuntu x86_64,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6801440/