【问题标题】:Compiler optimization: g++ slower than intel编译器优化:g++ 比 intel 慢
【发布时间】:2017-11-06 07:07:00
【问题描述】:

我最近购买了一台具有双启动 C++ 代码的计算机。在 Windows 上,我在 Linux 上使用英特尔 C++ 编译器和 g++。 我的程序主要由计算组成(具有数值积分的定点迭代算法等)。
我以为我可以在我的 linux 上获得接近 windows 的性能,但到目前为止我还没有:对于完全相同的代码,使用 g++ 编译的程序比使用 intel 编译器的程序慢大约 2 倍。从我读到的内容来看,icc 可以更快,甚至可能提高 20-30%,但我没有读到任何关于它快两倍的信息(总的来说,我实际上读到两者应该是等效的)。

起初我使用的标志大致相同:

icl /openmp /I "C:\boost_1_61_0" /fast program.cpp

g++ -o program program.cpp -std=c++11 -fopenmp -O3 -ffast-math

根据其他几个主题的建议,我尝试添加/替换几个其他标志,例如:-funsafe-math-optimizations、-march=native、-fwhole-program、-Ofast 等,但性能只有轻微(或没有)增益。

icc 真的更快还是我错过了什么? 我对 linux 还很陌生,所以我不知道,也许我忘了正确安装一些东西(比如驱动程序),或者在 g++ 中更改了一些选项?我不知道情况是否正常,所以我更愿意问。特别是因为我更喜欢使用 linux 来进行理想的编码,所以我宁愿让它跟上速度。

编辑:我决定在 linux 上安装最后一个 intel 编译器(Intel Compiler C++ 17,update4)来检查。我最终得到了缓解的结果:它并不比 gcc 做得更好(实际上更糟)。 我运行了交叉比较 linux/windows - icc/gcc - 是否并行化,使用前面提到的标志(进行直接比较),这是我的结果(time 运行 1 次迭代测量毫秒):

  1. 普通循环,没有并行化:

    • 视窗:
      gcc = 122074 ; icc = 68799
    • Linux:
      gcc = _91042 ; icc = 92102
  2. 并行化版本:

    • 视窗:
      gcc = 27457 ; icc = 19800
    • Linux:
      gcc = 27000 ; icc = 30000

总结一下:有点乱。 在 linux 上,gcc 似乎总是比 icc 快,尤其是在涉及并行化时(我为更长的程序运行它,差异比这里的要高得多)。
在 Windows 上,情况正好相反,icc 明显优于 gcc,尤其是在没有并行化的情况下(在这种情况下 gcc 需要很长时间才能编译)。

最快的编译是在 windows 上使用并行化和 icc 完成的。我不明白为什么我不能在 linux 上复制它。我需要做些什么(ubuntu 16.04)来帮助加快我的流程吗?
另一个区别是,在 Windows 上,我使用较旧的英特尔作曲家 (Composer XE 2013) 并调用 'ia32' 而不是 intel64(即我应该使用的那个)在Linux上我使用我昨天安装的最后一个版本。在 linux 上,Intel Compiler 17 文件夹在我的第二个硬盘上(而不是我安装 linux 的 ssd)我不知道这是否也会减慢速度。
知道问题可能来自哪里吗?

编辑:确切的硬件: Intel(R) Core(TM) i7-4710HQ CPU @ 2.50GHz,8 CPU,4 核,每核 2 个线程,架构 x86_64 - Linux Ubuntu 16.04 与 gcc 5.4.1 和 Intel 编译器 17 (update4) - Windows 8.1,英特尔 Composer 2013

编辑: 代码很长,这是我正在测试的循环形式(即我的定点迭代的一次迭代)。我想这是非常经典的...不确定它是否可以带来任何话题。

// initialization of all the objects...
// length_grid1 is about 2000
vector< double > V_NEXT(length_grid1), PRICE_NEXT(length_grid1);
double V_min, price_min; 
#pragma omp parallel
{ 
#pragma omp for private(V_min, price_min, i, indexcurrent, alpha, beta)
    for (i = 0; i < length_grid1; i++) {
         indexcurrent = indexsum[i]; 
         V_min = V_compute(&price_min, indexcurrent, ...);
         V_NEXT[indexcurrent] = V_min; PRICE_NEXT[indexcurrent] = price_min;
     }
 }// end parallel

其中 V_compute 函数是一种经典而简单的优化算法(自定义黄金搜索),返回最优值及其参数:

double V_compute(double *xmin, int row_index, ... ) {
double x1, x2, f1, f2, fxmin;
// golden_ratio=0.61803399; 
x1 = upper_bound - golden_ratio*(upper_bound - lower_bound);
x2 = lower_bound + golden_ratio*(upper_bound - lower_bound);

// Evaluate the function at the test points
f1 = intra_value(x1, row_index, ...);
f2 = intra_value(x2, row_index, ...);

while (fabs(upper_bound - lower_bound) > tolerance) {
    if (f2 > f1){
        upper_bound = x2; x2 = x1; f2 = f1;
        x1 = upper_bound - golden_ratio*(upper_bound - lower_bound);
        f1 = intra_value(x1, row_index, ...);
    } else {
        lower_bound = x1; x1 = x2; f1 = f2;
        x2 = lower_bound + golden_ratio*(upper_bound - lower_bound);
        f2 = intra_value(x2, row_index, ...);
    }
}
// Estimated minimizer = (lower bound + upper bound) / 2
*xmin = (lower_bound + upper_bound)/2;
fxmin = intra_value(*xmin, row_index, ...);
return - fxmin; }       

优化的函数(intra_value)在计算方面相当复杂(从预编译的网格中选择一个网格点(row_index),然后涉及大量的数值积分等)。

【问题讨论】:

  • 您可能想尝试在 Windows 上的 GCC 中编译您的代码。你可以使用mingw-w64
  • “使用 g++ 编译大约慢 2 倍” 我假设您的意思是编译的程序更慢,而不是编译更慢。说编译较慢意味着编译代码需要更长的时间,但我认为这不是你在说的
  • 你在 Intel CPU 上运行它吗?如果没有记错的话,ICC 可以为英特尔处理器提供更好的优化(与它自己相比),并且可能比其他编译器更快(由于他们自己知道如何以最佳方式利用其 CPU 指令)。
  • 您是否尝试使用-fprofile-generate then -fprofile-use 进行配置文件引导优化?你也应该试试-march=native
  • 如果您愿意发布两个编译器的源代码和程序集转储,这将有所帮助。

标签: c++ performance g++ intel compiler-optimization


【解决方案1】:

看起来您使用的是 OpenMP,因此我怀疑差异在于 OpenMP 实现,而不仅仅是优化代码的质量。

众所周知,英特尔的 OpenMP 运行时性能相当高,而 GCC 的性能不错但不是很好。

OpenMP 程序具有非常不同的性能特征,它们不仅仅取决于编译器对循环或内联函数调用的优化程度。 OpenMP 运行时的实现很重要,线程和同步原语的操作系统实现也很重要,这在 Windows 和 GNU/Linux 之间是完全不同的。

【讨论】:

  • 我试图在没有并行化的情况下运行一个程序,它最终使用 g++ 的时间延长了 1.7 倍。这是一个相当大的改进,所以它似乎确实是这里故事的一部分。
  • 它可能没有那么重要的影响,参见我在主要问题中添加的交叉比较
【解决方案2】:

请注意,“快速数学”打破了一些语言规则以获得快速代码,并且在某些情况下可能会产生不正确的结果。

另请注意,-O3保证-O2 或任何其他优化级别(取决于您的代码)更快 - 您应该测试多个版本。

您可能还想启用-Wl,-O1 - 链接器也可以进行一些优化。

您可能还想尝试使用 LTO(链接时间优化)进行构建 - 它通常可以产生显着的改进。

我意识到这并不能回答您的问题。但它应该给你一些可以玩的东西:-)

此外,gcc 的改进速度非常快。如果您尚未使用 7.1,您可能想尝试更新版本。还;尝试 Clang 获取第三个数据点。此外,如果您愿意,可以在 Linux 上使用 icc。

【讨论】:

  • 我尝试了其中的大部分,但没有任何明显的改进。至于 icc,我想在 linux 上使用它,但它需要很多我在 linux 分区上没有的磁盘空间,我还没有找到任何解决方案。
  • @G。 Ander——“至于 icc,我想在 linux 上使用它,但它需要很多我没有的磁盘空间”——听起来是一个很容易解决的问题。购买更多磁盘空间;-)
  • @G.Ander 如果您有其他分区,您可以毫无问题地在 Linux 中映射虚拟磁盘映像文件,然后安装到该磁盘
  • 我终于把它安装在我的第二个硬盘上了。结果并不像预期的那么好。 (参见主帖中的编辑比较)
猜你喜欢
  • 1970-01-01
  • 2012-02-12
  • 2012-08-05
  • 2012-09-05
  • 1970-01-01
  • 2011-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多