编译器优化:g++比intel慢

15
我最近买了一台双系统电脑来编写C ++代码。在Windows上,我使用Intel C ++编译器,在Linux上使用g++。我的程序主要由计算组成(带有数值积分的定点迭代算法等)。我认为我可以在Linux上获得接近Windows的性能,但目前还没有:对于完全相同的代码,使用g ++编译的程序比使用Intel编译器的程序慢约2倍。从我所读的内容来看,icc可能会更快,甚至可以获得20-30%的收益,但我没有读到任何关于它比g ++快两倍(通常情况下,我确实读到它们应该是相等的)的信息。
最初,我使用的标志大致相等:
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 Compiler C ++ 17,update4)进行检查。 我得到了暂时的结果:它并没有比gcc做得更好(实际上更糟)。我使用本文中提到的标志(以进行直接比较)运行了交叉对比linux / windows-icc / gcc-并行化与否,以下是我的结果(测量1次迭代运行时间以ms为单位):
纯循环,无并行化:
Windows:
gcc = 122074 ; icc = 68799
Linux:
gcc = _91042; icc = 92102 并行化版本:
Windows:
gcc = 27457; icc = 19800
Linux:
gcc = 27000; icc = 30000
总而言之:有点混乱。 在Linux上,gcc似乎总是比icc快,特别是当涉及并行化时(我运行了较长的程序,差异要大得多)。在Windows上,情况相反,icc显然占优势,特别是在没有并行化的情况下(在这种情况下,gcc需要很长时间进行编译)。
最快的编译是使用并行化和icc在Windows上完成的。我不明白为什么我无法在Linux上复制此操作。是否有任何我需要执行的操作(ubuntu 16.04)来加速我的进程?另一个区别是,在Windows上,我使用较旧的英特尔作曲家(Composer XE 2013),并调用“ia32”而不是intel64(我应该使用的那个),而在Linux上,我使用了昨天安装的最新版本。在Linux上,Intel Compiler 17文件夹位于我的第二个硬盘驱动器上(而不是安装Linux的SSD上),我不知道这也可能减慢速度。问题可能来自哪里?
编辑:确切的硬件: Intel(
// 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),然后涉及大量的数值积分等)。


1
你可能想尝试在Windows上使用GCC编译你的代码。你可以使用mingw-w64(http://mingw-w64.org/doku.php)。 - Bernard
11
我理解你的意思是,使用g++编译后的程序运行速度较慢,而非编译过程较慢。如果说编译过程较慢,那意味着编译代码所需的时间更长,但我认为这并不是你想表达的。 - Jonathan Wakely
2
你是否在Intel CPU上运行它?如果没有错,ICC可以为英特尔处理器提供比它自己更好的优化,并且可能比其他编译器更快(由于他们自己知道如何以最佳方式利用其CPU指令)。 - Mikhail Churbanov
3
请您提供两个编译器的源代码和汇编程序转储,这将有助于我们更好地理解问题。 - zwol
1
你需要发布一些代码,特别是关键的循环部分。同时要查看汇编代码。否则大家只能猜测。此外,请明确说明你的硬件是什么,编译器的版本是什么,Linux和Windows的版本也要说明。 - Z boson
显示剩余20条评论
2个回答

20

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

英特尔的OpenMP运行时非常高效,GCC的表现也不错,但并不出色。

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


1
我尝试了一下不使用并行化运行程序,结果使用g++编译时时间变长了1.7倍。这是一个相当大的改进,因此看来确实是故事的一部分。 - G. Ander
它可能并没有那么重要的影响,可以参考我在主要问题中添加的交叉比较。 - G. Ander

12
请注意,"fast-math" 会违反一些语言规则,以获得更快的代码,但在某些情况下可能会产生错误结果。
还要注意,"-O3" 并不能保证比 "-O2" 或其他优化级别更快(这取决于您的代码),您应该测试多个版本。
您可能还想启用 "-Wl,-O1" - 连接器也可以进行一些优化。
您可能还想尝试使用 LTO(链接时优化)构建 - 它通常可以产生显着的改进。
我意识到这并没有直接回答您的问题。但是它应该会为您提供一些可操作的东西 :-)
此外,gcc正在快速改进。如果您还没有使用 7.1 版本,请尝试更新版本。另外,尝试使用 Clang 获取第三个数据点。此外,如果需要,您可以在 Linux 上使用 icc。

我尝试了其中大部分,但没有什么明显的改善。至于icc,我想在Linux上使用它,但它需要很多磁盘空间,而我在Linux分区上没有这么多空间,目前还没有找到任何解决方案。 - G. Ander
1
@G. Ander - "至于icc,我想在Linux上使用它,但它需要很多磁盘空间,而我没有" - 看起来这是一个很容易解决的问题。购买更多的磁盘空间就好了;-) - Jesper Juhl
1
@G.Ander,如果您有其他分区,则可以在Linux中映射虚拟磁盘映像文件,然后安装到该磁盘上,没有问题。 - phuclv
我最终将它安装在我的第二个硬盘上。结果并不如预期。(请参见主帖中的编辑比较) - G. Ander

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