C+的巨大性能差异+;Mac和Linux下的程序(用GCC编译) 最近我在C++中编写了一个小程序(很诚实,它是C类的),并在MAC和Linux机器上测试了性能。
即使硬件是可比的,性能是如此不同,我真的有一些奇怪的事情发生 首先是一些细节: 输入:约200MB压缩数据 程序的操作:它解压缩数据,然后将其加载到内存中,并执行许多数据访问以执行数据之间的连接。程序是连续的(没有额外的线程或进程) 输出:屏幕上显示的一些字符串 该代码在Linux机器上使用GCC4.8.1编译,在Mac机器上使用GCC4.8.2编译。在这两种情况下,都会使用以下参数调用编译器:C+的巨大性能差异+;Mac和Linux下的程序(用GCC编译) 最近我在C++中编写了一个小程序(很诚实,它是C类的),并在MAC和Linux机器上测试了性能。,c++,performance,macos,gcc,operating-system,C++,Performance,Macos,Gcc,Operating System,即使硬件是可比的,性能是如此不同,我真的有一些奇怪的事情发生 首先是一些细节: 输入:约200MB压缩数据 程序的操作:它解压缩数据,然后将其加载到内存中,并执行许多数据访问以执行数据之间的连接。程序是连续的(没有额外的线程或进程) 输出:屏幕上显示的一些字符串 该代码在Linux机器上使用GCC4.8.1编译,在Mac机器上使用GCC4.8.2编译。在这两种情况下,都会使用以下参数调用编译器: gcc -c -O3 -fPIC -MD -MF $(patsubst %.o,%.d,$@) //
gcc -c -O3 -fPIC -MD -MF $(patsubst %.o,%.d,$@) //The last three arguments are to create the dependencies between the files
Mac(OS=Mac mavericks 10.9)是一款macbook pro,配备2,3 GHz Intel core I7(四核)256KB二级缓存、6MB三级缓存、8GB DDR3 1600Mhz和256 GB SSD磁盘
Linux机器(内核2.6.32-358)具有Intel E5-2620 2.0 GHz(六核)16MB缓存、64GB DDR3 1600Mhz和256 GB SSD磁盘。这两台机器都应该使用Sandy Bridge架构(也许Mac是ivy Bridge,但无论如何这不会有太大区别)
现在,如果我在linux机器上启动程序,那么需要217毫秒才能完成,而如果我在Mac机器上启动它,则需要132毫秒:这使linux代码的速度慢了1.6倍
现在,我知道这两台机器有不同的操作系统和硬件,但我发现这样的减速太大了,不能用这些因素来解释,我觉得这背后一定有其他原因
请注意,此计时是在所有数据加载到内存后进行的,我确信在此期间程序不会交换到磁盘。因此,我可以排除SSD磁盘的问题
现在,我真的不知道是什么导致了这种减速?内存基本上是等效的,而CPU只是稍微慢一点
难道GCC在linux上产生的代码比mac上产生的代码更糟糕吗
难道Linux操作系统比Mac更糟糕吗
这两件事我都很难相信。有什么帮助吗
编辑:
我意识到我没有提到我是如何计时的:我使用boost chrono库,只测量调用主函数所需的时间。比如:
time = now();
function();
duration = now() - time;
print(duration);
EDIT2:
经过一些测试,我们用一个更简单(而且愚蠢)的程序再现了性能的差异:
在linux机器上,它是:
Joins 10000000 Cycles total 838198832
显然,linux版本需要更多的CPU周期,这可能是访问内存所需要的。现在的问题是:为什么内存访问速度较慢
一个原因可能是in1和in2不适合CPU缓存,这需要一些RAM访问。正如Roy Longboattom所指出的,linux中的内存实际上是ECC,这可能是性能降低的原因。如果我们将这一点与CPU速度稍低(sandy和ivy bridge之间的差异)结合起来,那么我们可能对这种差异有一个很好的解释
无论如何,谢谢大家的提示 从另一个角度看,运行时的差异只有85毫秒,这很小 你到底在测量什么?如果是整个程序运行时,包括启动和拆卸(例如,使用Unix
time
命令),那么差异可能很容易归因于所涉及的动态链接器:至少在Linux上,您的程序将在实际执行之前链接到系统libstdc++
。如果MacOS动态链接器的速度稍微快一点(或者程序在Mac上静态链接?),这很容易解释差异
或者甚至可能是写入终端所需的时间。例如,在Linux上,
gnome终端
由于使用抗锯齿字体和完全的Unicode支持,通常被视为“缓慢”。如果改用xterm
,程序是否运行得更快?如果将输出重定向到/dev/null
,会发生什么情况?两个系统都遵循System V AMD64 ABI,因此gcc不应该在这方面产生影响。不幸的是,如今系统性能中的随机效应相当普遍,因此有时通过重新排序链接顺序这样愚蠢的事情,您可能会获得显著的性能差异(参见Mytkowicz等人,“在不做任何明显错误的事情的情况下生成错误数据”。)
以下是一些关于如何分析这一点的建议:
perf'工具。检查是否存在
major faults',这表明您存在需要转到磁盘的页面错误(当然,在多次运行时不太可能)。只有这样,您才能排除磁盘在这方面的影响。不幸的是,据我所知,OSX没有那么简单的方法来收集性能计数器祝你好运 实际上,如果您考虑到不同的频率(如果您的程序是CPU限制的而不是内存限制的,这可能很关键,您没有告诉我们您的代码是做什么的),那么差异将减少到~1.43 但是,如果其中一个CPU是IvyBridge
Joins 10000000 Cycles total 589015641
Joins 10000000 Cycles total 838198832
for(j = 0; j < 10000000; ++j) {
int el = in1[j];
for(m = 0; m < 10000000; m++) {
count = count + 1;
if (in2[m] == el)
{
joins++;
break;
}
}
}
.L6:
movzbl in1(%ecx), %edx
xorl %eax, %eax
jmp .L5
.p2align 4,,7
.p2align 3
.L3:
addl $1, %eax
cmpl $10000000, %eax
je .L4
.L5:
cmpb in2(%eax), %dl
fadd %st, %st(1)
jne .L3
addl $1, %ebx
.L4:
addl $1, %ecx
cmpl $10000000, %ecx
jne .L6
Result 2400 MHz
Count 320000000 Joins 10000000 0.4920310 seconds 20.32M joins per second
Result 1600 MHz
Count 320000000 Joins 10000000 0.7400470 seconds 13.51M joins per second