C++/C#/F#/Java/JS/Lua/Python/Ruby渲染比试

512x512像素,每像素10000个采样,intel c++ openmp版本渲染时间为18分36秒。估计ruby版本約需351天。

前篇博文把一个c++全局光照渲染器移植至c#,比较c++和c#之性能。刊出后,园友们不吝指出箇中问题,例如嗷嗷发现c++实现里的随机产生器采用了比较复杂的运行时函数,造成visual

c++和intel c++的巨大差异;赵姐夫发现c#版本用class竟然比struct快等等。修改这些问题后,园友qiaojie亦提出,可同时测试c++/cli,检测其所产生的il代码,在同样的.net平台上运行,看看是否比c#优胜。很多网友也提供了宝贵意见,未能尽录,唯有以努力撰文作为答谢。本人陆续移植了c++代码至java、javascript、lua、python和ruby,赵姐夫亦尝试了f#。本文提供测试源代码、测试结果、简单分析、以及个人体会。

声明

首先,为免误会,再次重申,本测试有其局限,只能测试某一应用、某一实现的结果,并不能反映编程语言及其运行时的综合性能,亦无意尝试这样做。而实验环境也只限于某机器、某操作系统上,并不全面。而且,本测试只提供运行时间的结果,不考虑、不比较语言/平台间的技术性和非技术性优缺点,也没有测试运行期内存。世界上的软件应用林林总总,性能需求也完全不同,本测试只供参考。

由于本人第一次使用python和ruby,若代码有不当之处,敬请告之。当然也非常乐见其他意见。

测试内容

本文测试程序为一个全局光照渲染器,是一个cpu运算密集的控制台应用程序(console application),功能详见前文。在前文刊出后,本人进行了一点profiling、优化,并把代码重新格式化。本渲染器除了有大量数学运算,亦会产生大量临时对象,并进行极多的方法调用(非虚函数)。本测试有别于人工合成的测试(synthetic

tests,例如个别测试运算、字串操作、输入输出等),是一个有实际用途的程序。

移植时尽量维持原代码的逻辑,主要采用面向对象范式。优化方面,不进行人手内联函数(inline function),但优化了一些不必要的重复运算。

测试配置

硬件: intel core i7 920@2.67ghz(4 core, hyperthread), 12gb ram

操作系统: microsoft windows 7 64-bit

测试名称

编译器/解译器

编译/运行选项

vc++

visual c++ 2008 (32-bit)

/ox /ob2 /oi /ot /gl /fd /md /gs- /gy /arch:sse /fp:fast

vc++_openmp

visual c++ 2008 (32-bit)

/ox /ob2 /oi /ot /gl /fd /md /gs- /gy /arch:sse /fp:fast /openmp

ic++

intel c++ compiler (32-bit)

/ox /og /ob2 /oi /ot /qipo /ga /md /gs- /gy /arch:sse2 /fp:fast /zi /qxhost

ic++_openmp

intel c++ compiler (32-bit)

/ox /og /ob2 /oi /ot /qipo /ga /md /gs- /gy /arch:sse2 /fp:fast /zi /qxhost /qopenmp

gcc

gcc 4.3.4 in cygwin (32-bit)

-o3 -march=native -ffast-math

gcc_openmp

gcc 4.3.4 in cygwin (32-bit)

-o3 -march=native -ffast-math -fopenmp

c++/cli

visual c++ 2008 (32-bit), .net framework 3.5

/ox /ob2 /oi /ot /gl /fd /md /gs- /fp:fast /zi /clr /tp

c++/cli_openmp

visual c++ 2008 (32-bit), .net framework 3.5

/ox /ob2 /oi /ot /gl /fd /md /gs- /fp:fast /zi /clr /tp /openmp

c#

visual c# 2008 (32-bit), .net framework 3.5

*c#_outref

visual c# 2008 (32-bit), .net framework 3.5

f#

f# 2.0 (32-bit), .net framework 3.5

java

java se 1.6.0_17

-server

jschrome

chrome 5.0.375.86

jsfirefox

firefox 3.6

luajit

luajit 2.0.0-beta4 (32-bit)

lua

luajit (32-bit)

-joff

python

python 3.1.2 (32-bit)

*ironpython

ironpython 2.6 for .net 4

*jython

jython 2.5.1

ruby

ruby 1.9.1p378

* 见本文最后的"7.更新"一节

渲染的解像度为256x256,每象素作100次采样。

结果及分析

下表中预设的相对时间以最快的单线程测试(ic++)作基准,用鼠标按列可改变基准。由于ruby运行时间太长,只每象素作4次采样,把时间乘上25。另外,因为各测试的渲染时间相差很远,所以用了两个棒形图去显示数据,分别显示时间少于4000秒和少于60秒的测试(ruby是4000秒以外,不予显示)。

c++/.net/java组别

静态语言和动态语言在此测试下的性能不在同一数量级。先比较静态语言。

c++和.net的测试结果和上一篇博文相若,而c#和f#无显著区别。但是,c++/cli虽然同样产生il,于括管的.net平台上执行,其渲染时间却只是c#/f#的55%左右。为什么呢?使用ildasm去反汇编c++/cli和c#的可执行文件后,可以发现,程序的热点函数sphere.intersect()在两个版本中,c++/cli版本的代码大小(code

size)为201字节, c#则为125字节! c++/cli版本在编译时,已把函数内所有vec类的方法调用全部内联,而c#版本则使用callvirt调用vec的方法。估计jit没有把这函数进行内联,做成这个性能差异。另外,c++/cli版本使用了值类型,并使用指针(代码中为引用)作参数传送。若把c#的版本的vec方法改写为:

//class vec

//{

//public static vec operator +(vec a, vec b)

//}

struct vec

{

void add(ref vec a, ref vec b, out vec c);

}

那么,struct不用gc,同时ref/out不用复制,其性能会比较高。但是代码会变得很难看:

// 原来用运算符重载(operator overloading):

a = b * c + d;

// 改用ref/out

vec e;

vec.mul(ref b, ref, c, out e);

vec.add(ref e, ref d, out a);

为了维持让语言"正常"的使用方法,本实验不采用这种api风格(更新:加入了c#_outref测试,詳見文末)。

然而,托管代码(c++/cli)的渲染时间,仅为原生非括管代码(ic++)的1.91倍,个人觉得.net的jit已经非常不错。

另一方面,java的性能表现非常突出,只比c++/cli稍慢一点,java版本的渲染时间为c#/f#的65%左右。以前一直认为,c#不少设计会使其性能高于java,例如c#的方法预设为非虚,java则预设为虚;又例如c#支持struct作值类型(value

type),java则只有class引用类型(reference type),后者必须使用gc。但是,这个测试显示,java vm应该在jit中做了大量优化,估计也应用了内联,才能使其性能逼近c++/cli。

纯c++方面,intel c++编译器最快,visual c++慢一点点(1.19x),gcc再慢一点点(1.32x)。这结果符合本人预期。 intel c++的openmp版本和单线程比较,达5.16加速比(speedup),对于4核hyper

threading来说算是不错的结果。读者若有兴趣,也可以自行测试c# 4.0的并行新特性。

动态语言组别

首先,要说一句,google太强了,难以想像jschome的渲染时间仅是ic++的16.12倍,c#的4.94倍。我有信心用javascript继续写图形、物理方面的博文了。

以下比较各动态语言的相对时间,以jschrome为基准。 chrome的v8 javascript引擎(1.00x)大幅抛离firefox的spidermonkey引擎(15.09x)。而luajit(3.49x)和lua(5.16x)则排第二和第三名。

lua的jit版本是没有jit的68%,并没有想像中的快,但是也比python(16.48x)快得多。曾听说过ruby有效能问题,没想到问题竟然如此严重(327.31x),其渲染时间差不多是python的20倍。

我认为,本实验中,不同语言的性能差异,并非在于数值运算,而是对象生成及函数调用。我使用python内建的profiling功能:

python -m profile smallpt.py

从结果发现,vec类共产生约15亿个实例,vec的方法调用约17.5亿次,intersect()共调用5.7亿次,产生随机数5.7亿个,radiance()调用(即追踪的路径线段)6.5百万次。这些庞大数字,放大了对象生成和函数调用的常数开销(overhead)。

结语

也许本博文的意义不大(yet-another-unfair-biased-performance-comparison-among-programming-languages),但对本人而言,此次实验加深了对各种语言性能的了解,或应该是消除了一些误解。简单总括运行性能方面的体验和感想:

c++和vm类静态语言可以大约只差2~4倍,jvm和clr差异不大。

c++和动态语言之比,则可以是15~5000倍,不同动态语言的差异很大。

一直以为lua(jit)会是最快的通用脚本语言,没想到此测试中败给javascript(v8),或许应该多点研究嵌入v8引擎(swig能支持就最理想了)。

以为python和ruby的性能相差不远,但测试结果两者大相径庭。暂时不太了解ruby的特长,或许之后再研究其优点是否能盖过其性能问题。

最后建议读者,若要为某应用挑选语言,又要顾及性能,那么应该自己做实验去比较。不要盲目相信一些流言或评测(包括本文)。

附录: javascript版本测试

警告: 建议使用chrome。firefox可能会慢得无法响应。

run

stop

更新

2010/7/7: 新增的c#_outref测试,按noremorse建议,把vec和ray变作struct,所有函数传送这两种对象改为ref/ out。 源代码

2010/7/8: 新增ironpython和jython。

2010/7/8: 园友猫粮撰文《as3的光线跟踪极限测试》。
       看来as3性能不太好。

2010/7/10: 园友domslab撰文《对《c++/c#/f#/java /js/lua/python/ruby渲染比试》一文的补充——增加mono测试》,比较了gcc/mono c#/java在windows/linux的性能。

2010/7/11: 园友noremorse撰文《swifter c#之inline还是不inline。
       这是个问题》
,以本例研究.net runtime的内联机制。


======================================================
在最后,我邀请大家参加新浪APP,就是新浪免费送大家的一个空间,支持PHP+MySql,免费二级域名,免费域名绑定 这个是我邀请的地址,您通过这个链接注册即为我的好友,并获赠云豆500个,价值5元哦!短网址是http://t.cn/SXOiLh我创建的小站每天访客已经达到2000+了,每天挂广告赚50+元哦,呵呵,饭钱不愁了,\(^o^)/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值