掺和比试
Milo老师搞了一个语言大比试——《C++/C#/F#/Java/JS/Lua/Python/Ruby渲染比试》。我觉得挺好玩的,本来早就想掺和,只是最近比较忙,现在真是来晚了。
不过也没什么能掺和的,因为Milo老师的比试已经很全面了,我也就是提供一点自己的测试数据罢了。
硬件:Intel Q8200 2.33G/4G RAM
软件:Windows 2003 Server
说明:为便于与Milo老师的结论作参照,我这里以GCC版本为基准计算对比系数,其中括号内为換算到Milo老师环境中的相对比值。
语言 | 编译器 | 编译运行参数 | 耗时 | 对比 | 内存 |
C++(OpenMP) | GCC 4.3.4 in Cygwin (32-bit) | -O3 -march=native -ffast-math -fopenmp | 5.647 | 0.27x(0.36x) | 4M+ |
C++ | Intel C/C++ Compiler 11.1 (IA32) in Ubuntu 10.04 (32-bit) (VirtualBox 3.2.4, 1CPU, 1GRAM) | 默认编译参数 | 17.08 | 0.83x(1.09x) | 2M+ |
C++ | GCC 4.4.3 in Ubuntu 10.04 (32-bit) (VirtualBox 3.2.4, 1CPU, 1GRAM) | -O3 -march=native -ffast-math | 18.71 | 0.91x(1.19x) | 2M+ |
C++ | GCC 4.3.4 in Cygwin (32-bit) | -O3 -march=native -ffast-math | 20.64 | 1.00x(1.32x) | 4M+ |
C++ | Microsoft Visual C++ 2010 学习版 | /Ox /Ob2 /Oi /Ot /Oy- /GL /Gm- /GS- /Gy /arch:SSE /fp:fast /Gd (不含部分默认参数) | 22.59 | 1.09x(1.44x) | 2M+ |
C++ | GCC 3.4.5 in MinGW (32-bit) | -O3 -march=pentium4 -ffast-math | 51.19 | 2.48x(3.27x) | 2M+ |
Java | Java SE 1.6.0_10 | -server | 55.63 | 2.69x(3.56x) | 70M+ |
C++ | Embarcadero C++ Builder 2010 | -P -6 -pr -ff -Vx -Ve -r | 55.77 | 2.70x(3.57x) | 3M+ |
C++ | Borland Turbo C++ Explorer | -O2 -Hc -Vx -Ve -x- -RT- -ff -X- -pr -a8 -6 -b- -k- -vi -tWC -tWM- -c | 60.00 | 2.90x(3.84x) | 3M+ |
C++ | Borland C++ Builder 6.0 | -Hc -P -Vx -Ve -x- -RT- -ff -X- -pr -a8 -6 -b- -k- -vi -tWC -tWM- -c | 60.14 | 2.91x(3.85x) | 3M+ |
Delphi | Embarcadero Delphi 2010 | 默认编译参数 | 173.77 | 8.42x(11.1x) | 5M+ |
Delphi | FreePascal 2.2.4(Lazarus 0.9.28.2b) | 默认编译参数 | 241.25 | 11.7x(15.4x) | 5M+ |
Delphi | FreePascal 2.4(Lazarus 0.9.28.2b) in Ubuntu 10.04 (32-bit) (VirtualBox 3.2.4, 1CPU, 1GRAM) | 默认编译参数 | 329,19 | 15.5x(20.5x) | 2M+ |
Delphi | Borland Delphi 7 | 自己实现的对象管理 | 429.52 | 20.8x(27.5x) | 5M+ |
Delphi | Borland Delphi 7 | 默认编译参数 | 553.91 | 26.8x(35.4x) | 4M+ |
VC学习版不提供OpenMP支持,GCC 4.2以前的版本也不支持,BCC更不用说,故OpenMP只试了Cygwin。
增 加了一列内存使用情况。基本上C++都差不多,Java则明显多得多。因为这个程序中涉及大量(数以十亿计)的小object的创建和删 除,JAVA的GC回收内存有一定的滞后性,所以运行时内存占用得会多一点,当然这也有个好处就是节约了不断回收小内存所花费的时间,对速度有一定的帮 助。
从结果上看新版本的C++编译器对于代码的优化还是很明显的,同样是GCC,Cygwin的4.3.4就比MinGW的3.4.5好得多——当然BCC是个例外,最新版本的速度也没有超过JAVA。
在研究过这个程序的代码以后发现,这个程序对内存管理的要求还是挺高的,对于有GC的VM语言或动态语言来说,实现起来会比较方便,C++的栈对象用起来也还不错(运算符重载更是方便),不过要是用C或DELPHI之类内存需要自己管理的语言就杯具了——如表上所示。
关于DELPHI版的说明:
因 为这个程序在运行时累计需要创建释放的对象多达15亿,而DELPHI的内存管理有个问题就是缺少自动释放的机制。虽然通过接口的引用计数机制是可以实现 类似的功能,但是需要增加很多不必要的函数调用,这样一来速度反而会大幅下降。现在采用的方式是手工即时释放。可能是因为DELPHI7的堆管理机制不是 很适合这种大量小对象的反复创建释放,运行一会以后速度就慢下来,以致于最后耗时很长。
后来我试着自己做了一个对象管理,以POOL的方式 进行管理,速度上略有提高,不过还是不明显。而FreePascal Compiler(FPC)显然有一些额外的优化,速度比我自己管理要快近一倍。但是Delphi 2010的优化更多,比FPC还要快约50%。不过从目标代码上看,D7只有100K,FPC是150K,D2010则是300K,看来后二者可能使用了 大量的INLINE优化——这种优化对这个应用来说很重要。
根据POOL反馈的数据显示,Vec对象累计创建:1565329629个,但实际峰值使用量(递归最深的时候)仅:1770个。
另外,可以注意到的是,我这里有两个版本是与Milo老师的相同:一个是Cygwin版,一个是JAVA版。其中非OpenMP的Cygwin版比Milo老师慢得很少,但是JAVA版却慢了很多。可见硬件性能的提升对于JAVA程序的帮助比较明显。