【问题标题】:Why Clang allocate std::complex so fast?为什么 Clang 分配 std::complex 这么快?
【发布时间】:2020-03-11 02:13:47
【问题描述】:

我已经使用 GCC、Clang 和 Intel C++ 编译器测试了 std::complex<double> 数组的内存分配性能。我发现这些编译器之间存在巨大的性能差异。 Clang 比其他编译器快几个数量级。

谁能找出原因?非常感谢!下面附上测试代码、测试环境、测试结果详情。

附件

这是性能测试代码:

#include <iostream>
#include <complex>

#include <sys/time.h>
#include <stdlib.h>


double GetWallTime(void) {
  struct timeval time;
  if (gettimeofday(&time, NULL)) { return 0; }
  return (double)time.tv_sec + (double)time.tv_usec * .000001;
}


int main(int argc, char *argv[]) {
  auto size = atol(argv[1]);

  auto time_now = GetWallTime();
  auto double_array = new double [size];
  std::cout << "allocate double[" << size << "]: use "
            << GetWallTime() - time_now   << " sec" << std::endl;
  delete[] double_array;

  time_now = GetWallTime();
  auto c99cplx_array = new double _Complex [size];
  std::cout << "allocate double _Complex[" << size << "]: use "
            << GetWallTime() - time_now  << " sec" << std::endl;
  delete[] c99cplx_array;

  time_now = GetWallTime();
  auto stdcplx_array = new std::complex<double> [size];
  std::cout << "allocate std::complex<double>[" << size << "]: use "
            << GetWallTime() - time_now         << " sec" << std::endl;
  delete[] stdcplx_array;
  return 0;
}

在具有 Xeon E5-2680 v2 *2 CPU 和 64G DDR3 内存的 Linux 机器上,我使用这三个编译器编译此代码并运行测试。我得到以下结果:

使用g++ 7.5.0 和--std=c++11 -O3 标志:

allocate double[10000000]: use 5.6982e-05 sec
allocate double _Complex[10000000]: use 1.71661e-05 sec
allocate std::complex<double>[10000000]: use 0.0911679 sec

使用icpc 19.1.0.166 和--std=c++11 -O3 标志:

allocate double[10000000]: use 7.41482e-05 sec
allocate double _Complex[10000000]: use 1.69277e-05 sec
allocate std::complex<double>[10000000]: use 0.087034 sec

在版本中使用clang++

> clang++ --version
Intel(R) oneAPI DPC++ Compiler 2021.1-beta03 (2019.10.0.1121)
Target: x86_64-unknown-linux-gnu
Thread model: posix

带有--std=c++11 -O3 标志:

allocate double[10000000]: use 4.19617e-05 sec
allocate double _Complex[10000000]: use 9.53674e-07 sec
allocate std::complex<double>[10000000]: use 1.19209e-06 sec

【问题讨论】:

  • 让我们看看:0.0000171661 秒与 0.000000953674 秒,如果我做对了。我认为,这些微小的时间间隔正在拉伸系统时钟的粒度,因此几乎没有意义。
  • clang 正在优化所有分配。想知道他是否被允许这样做。如果我们将volatile 添加到变量中,得到的结果非常相似。 std::complex&lt;double&gt; 需要更长的时间,因为它已被初始化。
  • @SamVarshavchik 感谢评论,请看第三行。 9.11679e-02 与 1.19209e-06。
  • 代码太容易分析和优化了。添加一些无法优化的逻辑,例如使用结果设置全局变量。此外,它应该在一个循环(如一百万或十亿)内重复,以使其处于计时器分辨率和精度的范围内。
  • 回滚编辑 - 本网站使用问答格式,您不应在问题框中发布答案。相反,您可以接受已发布的答案,如果您想做出额外的贡献来回答问题,您可以发布自己的答案

标签: c++ performance clang compiler-optimization dynamic-memory-allocation


【解决方案1】:

因为你的测试很糟糕。 Clang 只是完全删除了 new/delete,因为它毫无意义。你正在有效地分析这个:

#include <complex>
int main() {

    auto ptr = new std::complex<double>[1000];
    delete [] ptr;
    return 0;
}

哪个 clang 正确地简化为:

main:                                   # @main
        xor     eax, eax
        ret

https://godbolt.org/z/4JjXfh

另一方面,gcc 分配和释放内存。您不是在测试分配速度,而是在测试一个空无一物的汉堡。不要像这样进行微基准测试,而是在实际代码上使用分析器。

如果您想对此进行分析,请执行以下操作:

volatile auto stdcplx_array = new std::complex<double> [size];

这将为每个编译器提供准确的基准(并不是说你的基准值得做——它只会减少到一个新的 + memset + 删除)

【讨论】:

  • volatile 会阻止重用之前释放的内存吗? (iirc 他们没有,所以它仍然可能会导致差异)
猜你喜欢
  • 2014-02-05
  • 1970-01-01
  • 2020-10-16
  • 1970-01-01
  • 2016-10-08
  • 2021-06-10
  • 2015-01-07
  • 1970-01-01
  • 2014-11-23
相关资源
最近更新 更多