C++的clang数组比clang向量和gcc向量、数组都快很多。

3

以下代码展示了我的测试用例。我使用clang++ --std=c++11 -O2和g++ --std=c++11 -O2编译了两者。


long long *ary = new long long[100000000]();
for (long long i = 0; i < 100000000; ++i)
    ary[i] = i;

std::vector<long long> vec(100000000, 0);
for (long long i = 0; i < 100000000; ++i)
    vec[i] = i;

对于这两种情况,我只进行了初始化测试,然后进行了初始化和for循环的测试。结果如下:

GCC:

  • 仅数组初始化:0.182秒
  • 数组初始化和for循环:0.250秒
  • 仅向量初始化:0.169秒
  • 向量初始化和for循环:0.252秒

Clang:

  • 仅数组初始化:0.004秒
  • 数组初始化和for循环:0.004秒
  • 仅向量初始化:0.150秒
  • 向量初始化和for循环:0.240秒

gcc的结果符合向量与数组一样快的普遍观点。此外,clang和gcc在向量方面的结果基本一致。然而,clang的结果非常荒谬,数组表现出明显更快的速度。有人知道为什么吗?


也许与clang vs gcc - 优化包括operator new有关。 - Shafik Yaghmour
2
没有办法,Clang实际上执行了那段代码。主要怀疑是由于没有任何可观察的效果而被优化掉了。 - Lightness Races in Orbit
2个回答

8
一个25倍的加速比告诉你,你的代码已经被优化掉了。由于你的代码没有产生任何可见效果,因此可以将其删除。你的基准测试无效。

你说得对。我加了std::cout << arr[50000000] << std::endl,时间变得可比了。谢谢。 - JamesLens
@JamesLens,也许将来有时这可能不够用。整个数组/向量是一个常量,优化器最终可能会看透它。我会用不同的方法来做。将整个向量初始化为外部值,例如从当前时间派生的值。然后,对其求和并打印出总和。由于总和是动态的,即使使用神仙编译器也无法删除它。 - usr

2
这里的区别在于 clanggcc 如何优化调用 new。以下代码:
long long *ary = new long long[100000000]();
for (long long i = 0; i < 100000000; ++i)
    ary[i] = i;

在-O2优化级别下,clang将对其进行全部优化(请看实况):
xorl    %eax, %eax
retq

gcc无法实时查看时:
 movl   $800000000, %edi
 call   operator new[](unsigned long)
 leaq   800000000(%rax), %rcx
 movq   %rax, %rdx
.L2:
 movq   $0, (%rdx)
 addq   $8, %rdx
 cmpq   %rcx, %rdx
 jne    .L2
 xorl   %edx, %edx

问题是这个优化是否有效?有人可能会争辩说,根据如同规则,这不是一个有效的优化,因为new可能导致可观察行为
在C++14中,通过提案N3664:澄清内存分配,这被视为一种有效的优化,但是clang在此期间之前就已经包含了这种优化,请参见这个答案

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接