编译器优化:g ++比intel

时间:2017-06-05 13:29:14

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

我最近购买了一台带有双启动的计算机,用C ++编写代码。在Windows上我在linux上使用intel 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 - 并行化与否,使用前面提到的标志(进行直接比较),这里是我的结果(时间运行1次迭代测量 ms ):

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

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

    • 视窗:
      gcc = 27457; icc = 19800
    • Linux操作系统:
      gcc = 27000; icc = 30000
  3. 总结一下:这有点乱。 在linux上,gcc似乎总是比icc更快,特别是当涉及并行化时(我运行它用于更长的程序,差异远远高于此处的那个)。
    在Windows上,它是相反的,icc显然支配gcc,特别是当没有并行化时(在这种情况下gcc需要很长时间才能编译)。

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

    编辑:确切的硬件:  Intel(R)Core(TM)i7-4710HQ CPU @ 2.50GHz,8个CPU,4个内核,每个内核2个线程,架构x86_64 - 带有gcc 5.4.1的Linux Ubuntu 16.04和Intel编译器17(update4) - Windows 8.1,Intel 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),然后涉及大量数值积分等)。

2 个答案:

答案 0 :(得分:20)

看起来你正在使用OpenMP,所以我怀疑OpenMP实现的区别在于,而不仅仅是优化代码的质量。

众所周知,英特尔的OpenMP运行时性能非常高,GCC很好但不是很好。

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

答案 1 :(得分:12)

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

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

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

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

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

此外,gcc正在快速提升。如果您尚未使用7.1,则可能需要尝试更新的版本。也;尝试Clang获得第三个数据点。此外,如果您愿意,可以在Linux上使用icc。