【发布时间】:2016-02-07 08:07:49
【问题描述】:
体验过 C++,我试图了解 sizeof 和 strlen 对于字符串文字的性能差异。
这是我的小基准代码:
#include <iostream>
#include <cstring>
#define LOOP_COUNT 1000000000
unsigned long long rdtscl(void)
{
unsigned int lo, hi;
__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
}
int main()
{
unsigned long long before = rdtscl();
size_t ret;
for (int i = 0; i < LOOP_COUNT; i++)
ret = strlen("abcd");
unsigned long long after = rdtscl();
std::cout << "Strlen " << (after - before) << " ret=" << ret << std::endl;
before = rdtscl();
for (int i = 0; i < LOOP_COUNT; i++)
ret = sizeof("abcd");
after = rdtscl();
std::cout << "Sizeof " << (after - before) << " ret=" << ret << std::endl;
}
用clang++编译,得到如下结果:
clang++ -O3 -Wall -o sizeof_vs_strlen sizeof_vs_strlen.cpp
./sizeof_vs_strlen
Strlen 36 ret=4
Sizeof 62092396 ret=5
与g++:
g++ -O3 -Wall -o sizeof_vs_strlen sizeof_vs_strlen.cpp
./sizeof_vs_strlen
Strlen 30 ret=4
Sizeof 30 ret=5
我强烈怀疑g++ 确实使用sizeof 优化了循环,而clang++ 没有。
这个结果是一个已知问题吗?
编辑:
clang++ 为带有sizeof 的循环生成的程序集:
rdtsc
mov %edx,%r14d
shl $0x20,%r14
mov $0x3b9aca01,%ecx
xchg %ax,%ax
add $0xffffffed,%ecx // 0x400ad0
jne 0x400ad0 <main+192>
mov %eax,%eax
or %rax,%r14
rdtsc
还有g++:
rdtsc
mov %edx,%esi
mov %eax,%ecx
rdtsc
我不明白为什么 clang++ 做 {add, jne} 循环,它似乎没用。它是一个错误吗?
有关信息:
g++ (GCC) 5.1.0
clang version 3.6.2 (tags/RELEASE_362/final)
编辑2:
它可能是clang 中的一个错误。
我开了一个bug report。
【问题讨论】:
-
要做的第一件事是检查您正在测试的每个语句的程序集......我希望任何编译器都将这两个优化为硬编码值
-
1/ 读取程序集(或提供它) 2/ 如果您尝试测量
strlen的性能,您做错了,因为您的基准测试允许编译器进行计算以进行编译-时间。 -
您可以自己查看优化是否发生,将 -S 标志添加到 clang 或 gcc,您可以查看程序集输出并比较 clang 与 gcc。奇怪的是,如果你省略 1. 循环,clang 也会优化 2. 你的循环。
-
感谢您的 cmets。我添加了生成的汇编代码。 Pascal Cuoq > 我知道,我从
O0开始,但后来发现O3这个奇怪的结果。 -
顺便说一句:你使用
unsigned long long,这在c++11之前的标准中是没有的,但是你的编译命令缺少std=c++11
标签: c++ gcc clang compiler-optimization