Spiga

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

2010-07-07 00:20 by Milo Yip, 26555 visits, 收藏, 编辑


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),但对本人而言,此次实验加深了对各种语言性能的了解,或应该是消除了一些误解。简单总括运行性能方面的体验和感想:
  1. C++和VM类静态语言可以大约只差2~4倍,JVM和CLR差异不大。
  2. C++和动态语言之比,则可以是15~5000倍,不同动态语言的差异很大。
  3. 一直以为Lua(JIT)会是最快的通用脚本语言,没想到此测试中败给JavaScript(V8),或许应该多点研究嵌入V8引擎(SWIG能支持就最理想了)。
  4. 以为Python和Ruby的性能相差不远,但测试结果两者大相径庭。暂时不太了解Ruby的特长,或许之后再研究其优点是否能盖过其性能问题。

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

附录: JavaScript版本测试

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


更新

Add your comment

96 条回复

  1. #1楼 RednaxelaFX      2010-07-07 00:57
    沙发?
    想问一下,LuaJIT采用的是1还是2?
    源码只能明天再看了,今晚得困觉鸟 T T
     回复 引用 查看   
  2. #2楼[楼主] Milo Yip      2010-07-07 01:02
    @RednaxelaFX
    恭喜沙發。
    忘了寫,已補上。所用的LuaJIT版本為2.0.0-beta4。
     回复 引用 查看   
  3. #3楼 张三~      2010-07-07 01:09
    先回帖在看
     回复 引用 查看   
  4. #4楼 张三~      2010-07-07 01:30
    唯一的疑问,ruby不是让楼主等了20个小时??有毅力啊```~
     回复 引用 查看   
  5. #5楼 Wuya      2010-07-07 01:36
    太强大了。
     回复 引用 查看   
  6. #6楼[楼主] Milo Yip      2010-07-07 01:56
    @张三~
    引用张三~:唯一的疑问,ruby不是让楼主等了20个小时??有毅力啊```~

    文中提及,因為太慢,原來每象素100次採樣,改為4次,最後把時間乘以25。
     回复 引用 查看   
  7. #7楼 Snake@Net      2010-07-07 03:41
    深夜路过,原来js+chrome竟然这么强大!
    另外C#和JAVA性能差距给我感觉有点大.
    希望微软继续努力!
     回复 引用 查看   
  8. #8楼 Pandaimp      2010-07-07 08:13
    mark
     回复 引用 查看   
  9. #9楼 assiwe      2010-07-07 08:27
    java比.net快这么多...看看一天总说Java垃圾的人这回怎么说
     回复 引用 查看   
  10. #10楼 MagicAngle      2010-07-07 08:43
    12G的RAM,楼主电脑够强大,呵呵~
     回复 引用 查看   
  11. #11楼 银河      2010-07-07 08:48
    好文,推荐 +1。
    楼主有没有考虑使用 .NET Framework 4 和 Visual Stduio 2010 来做这个比试?
    特别是 F#,可能在 CLR 4.0 下的性能会比在 CLR 2.0 下的性能更好。
     回复 引用 查看   
  12. #12楼 阿水      2010-07-07 08:52
    直接做个结果的数据表,看起来比较直观哈
     回复 引用 查看   
  13. #13楼 轩辕法王      2010-07-07 08:57
    引用银河:
    好文,推荐 +1。
    楼主有没有考虑使用 .NET Framework 4 和 Visual Stduio 2010 来做这个比试?
    特别是 F#,可能在 CLR 4.0 下的性能会比在 CLR 2.0 下的性能更好。


    是的,建议用.net4来测,性能会有改善,3.x全是基于2.0的,而4是独立的平台
     回复 引用 查看   
  14. #14楼 技术,趋势      2010-07-07 09:25
    哈哈,看完整篇文章,原来是大力推荐Chrome浏览器的软文啊。

    开个玩笑,Google能把JS做得这么流畅,说明这些大公司只要稍微用用功,性能是可以大幅提升的,希望微软学习下Google的这种科研精神。继续走做出来功能就抛给用户这种路,会越走越死。

    用Chrome快半年了,感觉不是一般的爽,大部分情况下都不愿用IE了。希望IE9能真正的有所进步。
     回复 引用 查看   
  15. #15楼 天天不在      2010-07-07 09:30
    引用技术,趋势:
    哈哈,看完整篇文章,原来是大力推荐Chrome浏览器的软文啊。

    开个玩笑,Google能把JS做得这么流畅,说明这些大公司只要稍微用用功,性能是可以大幅提升的,希望微软学习下Google的这种科研精神。继续走做出来功能就抛给用户这种路,会越走越死。

    用Chrome快半年了,感觉不是一般的爽,大部分情况下都不愿用IE了。希望IE9能真正的有所进步。

    我用Chrome也不算新人了,感觉简洁大方,几乎不会卡着,但是有一点,就是有时任务管理器一看,几个Chrome占用都是20M(我都是打开的卡片,不是新开的窗口),加起来少的时候也有50M,有点郁闷啊,公司的机器太烂了。
     回复 引用 查看   
  16. #16楼 技术,趋势      2010-07-07 10:05
    引用天天不在:
    引用技术,趋势:
    哈哈,看完整篇文章,原来是大力推荐Chrome浏览器的软文啊。

    开个玩笑,Google能把JS做得这么流畅,说明这些大公司只要稍微用用功,性能是可以大幅提升的,希望微软学习下Google的这种科研精神。继续走做出来功能就抛给用户这种路,会越走越死。

    用Chrome快半年了,感觉不是一般的爽,大部分情况下都不愿用IE了。希望IE9能真正的有所进步。

    我用Chrome也不算新人了,感觉简洁大方,几乎不会卡着,但是有一点,就是有时任务管理器一看,几个Chrome占用都是20M(我都是打开的卡片,不是新开的窗口),加起来少的时候也有50M,有点郁闷啊,公司的机器太烂了。


    那你的确是需要加点内存,我同时打开IE8和Chrome5,IE8的内存需求比Chrome5稍大一点,都在60到70M之间一个进程。

    从操作的流畅性看,Chrome非常明显,用IE8打开页面,上下滚动是有视觉上能感受到的滞后的,Chrome肉眼就很难分辨。
     回复 引用 查看   
  17. #17楼 麒麟.NET      2010-07-07 10:08
    @天天不在
    Chrome里每个标签页都会占用一个chrome.exe进程,这也是很正常的,占用的总内存量跟IE也差不多。
     回复 引用 查看   
  18. #18楼 sujiantao      2010-07-07 10:20
    java这么快呀~
     回复 引用 查看   
  19. #19楼[楼主] Milo Yip      2010-07-07 10:37
    @轩辕法王
    @银河
    其實之前也測試過用.Net SDK(未裝VS2010),差別不大。稍後再補上。
     回复 引用 查看   
  20. #20楼 默公子      2010-07-07 11:09
    楼主强力党啊!

    其实我很期待,楼主有没有CUDA版本和OpenCL的测试~~~~
     回复 引用 查看   
  21. #21楼 Galactica      2010-07-07 11:28
    .net 4.0有个求PI的例程.你应该使用全值类型.

    如果你new来new去,我劝你还是先测试各平台下new的性能.
     回复 引用 查看   
  22. #22楼[楼主] Milo Yip      2010-07-07 11:30
    @Galactica
    引用Galactica:
    .net 4.0有个求PI的例程.你应该使用全值类型.

    如果你new来new去,我劝你还是先测试各平台下new的性能.

    不用ref/out的話,在這實現中已測試過class比struct快。
     回复 引用 查看   
  23. #23楼 Greatest      2010-07-07 11:45
    我优化了一下python。
    首先,原始的程序,我改成了16*16 16spp是10.1秒,
    把所有的类改成new style class也就是从object继承,变成7.4秒,
    每个类加上__slots__成员,变成7.4秒,
    再使用psyco这个jit模块,变成4.69秒。
    最后,原始的程序使用psyco模块后,时间略微有些上升。
     回复 引用 查看   
  24. #24楼 Greatest      2010-07-07 11:46
    上面写错了:
    改成: 每个类加上__slots__成员,变成7.2秒不到一点
     回复 引用 查看   
  25. #25楼 汝熹      2010-07-07 11:47
    很喜欢楼主的文章,支持
     回复 引用 查看   
  26. #26楼 mikeandmore      2010-07-07 12:03
    gcc的ffast-math有时候会更慢。相反还是打开sse比较靠谱。我看你vc和icc都打开了sse。

    gcc似乎可以用-march=native来自动检测最优的SIMD指令。
     回复 引用 查看   
  27. #27楼 noremorse      2010-07-07 12:10
    不可多的的关于计算密集的性能比较文章。光线跟踪是典型计算密集的高并行性的应用。

    但是在C++C#/Java的比较中,我觉得没用out ref的方法对C#是不公平的,虽然这样尽量保持了代码的一致性,但是失去了运行模型的一致性,C++是传的引用,Java用的是class,唯有C#是实际复制结构的,而这个隐含消耗是很大的,在实际计算密集场景中很少有人会这么做,故此XNA等数学库也都提供了两个版本。我觉得既然是测试高性能应用的场景应该选用语言中性能高的实现方案而不是写起来更优雅的方案,要不为什么C++要多写个&呢。我用Milo老师的代码改成void Add(ref Vec a, ref Vec b, out Vec c);的形式测试了一下。

    笔记本U是Pentium(R) Dual-Core CPU T4200 @ 2.00GHz 2.00GHz,.NET运行环境是.NET4 CP 结果如下:

    不用out ref的原版代码:120s
    使用out ref的传引用版: 59s

    所用程序
    http://files.cnblogs.com/noremorse/smallptref.rar
     回复 引用 查看   
  28. #28楼[楼主] Milo Yip      2010-07-07 12:25
    @mikeandmore
    引用mikeandmore:
    gcc的ffast-math有时候会更慢。相反还是打开sse比较靠谱。我看你vc和icc都打开了sse。

    gcc似乎可以用-march=native来自动检测最优的SIMD指令。


    我寫了部份文章後,再調過參數,但忘了更新內文,我是有用到-march=native的。謝謝指正。
     回复 引用 查看   
  29. #29楼 knight_stalker      2010-07-07 12:26
    你用写 C++ 的方法去写 ruby …… 当然杯具了 ……
    本来内建的 vector, matrix 和 rand 速度都很快的
     回复 引用 查看   
  30. #30楼[楼主] Milo Yip      2010-07-07 12:30
    @noremorse
    謝謝你的源碼,我會考慮是否加入這個測試中。

    但這個測試中,C#的Vec也是用class,Java的版本也是用class。所以沒有C# struct複製的問題。
     回复 引用 查看   
  31. #31楼[楼主] Milo Yip      2010-07-07 12:32
    @knight_stalker
    引用knight_stalker:
    你用写 C++ 的方法去写 ruby …… 当然杯具了 ……
    本来内建的 vector, matrix 和 rand 速度都很快的

    但其他語言(JS, Lua, Python)也是這樣啊。所以個人認為這是恰當的。
     回复 引用 查看   
  32. #32楼 技术,趋势      2010-07-07 12:40
    引用Milo Yip:
    @knight_stalker
    引用knight_stalker:
    你用写 C++ 的方法去写 ruby …… 当然杯具了 ……
    本来内建的 vector, matrix 和 rand 速度都很快的

    但其他語言(JS, Lua, Python)也是這樣啊。所以個人認為這是恰當的。


    同意Milo Yip的比较方式,不同的语言,就得用不同的语言的普遍或是默认特性去比较,这样才有意义。比如说C#的Out ref,如果再写成unsafe再嵌入汇编代码,那还有什么好比较的。反正最后的运算都会转成CPU的指令集。
     回复 引用 查看   
  33. #33楼 王克伟      2010-07-07 13:00
    支持,好像声明部分的HTML代码有点问题
     回复 引用 查看   
  34. #34楼 knight_stalker      2010-07-07 13:05
    什么是普遍默认特性太难界定了吧
    #define 和 inline 不就是 C/C++ 专有特性么 …… 而且 C++ 不用这些特性也能写出来。

    ps: gcc 有时不用 inline 反而更快。。
     回复 引用 查看   
  35. #35楼 mtlung      2010-07-07 13:16
    嘗試開啟 Intel/VC C++ 的反饋式優化,看看會有什麼驚起。
     回复 引用 查看   
  36. #36楼 轩辕法王      2010-07-07 13:37
    引用技术,趋势:
    引用Milo Yip:
    @knight_stalker
    引用knight_stalker:
    你用写 C++ 的方法去写 ruby …… 当然杯具了 ……
    本来内建的 vector, matrix 和 rand 速度都很快的

    但其他語言(JS, Lua, Python)也是這樣啊。所以個人認為這是恰當的。


    同意Milo Yip的比较方式,不同的语言,就得用不同的语言的普遍或是默认特性去比较,这样才有意义。比如说C#的Out ref,如果再写成unsafe再嵌入汇编代码,那还有什么好比较的。反正最后的运算都会转成CPU的指令集。


    支持,.net上的语言ansafe后,基本就变成了c/c++了,还比个P啊
     回复 引用 查看   
  37. #37楼 chenkai      2010-07-07 14:38
    Ruby 性能时间楼主是如何得出的. 利用什么工具?
    F#的并行计算能力表现还尚可. 等"赵姐夫"F # 测试出来 在比对一下.
     回复 引用 查看   
  38. #38楼 Jimixu      2010-07-07 14:44
    一看标题就知道是Milo大神的帖子~~
     回复 引用 查看   
  39. #39楼 Nick Wang (懒人王)      2010-07-07 14:52
    V8是编译javascript后再执行的(据说)
    Ruby在Windows下有性能问题,python不清楚,你可以换linux试试。
     回复 引用 查看   
  40. #40楼 Jeffrey Zhao      2010-07-07 16:18
    引用chenkai:
    Ruby 性能时间楼主是如何得出的. 利用什么工具?
    F#的并行计算能力表现还尚可. 等"赵姐夫"F # 测试出来 在比对一下.

    F#并行和C#并行都是利用库了,应该没什么区别的说。
     回复 引用 查看   
  41. #41楼 Sword-Breaker      2010-07-07 16:40
    其实可以考虑加入IronPython试试?
     回复 引用 查看   
  42. #42楼 Sumtec      2010-07-07 18:49
    @Milo
    Chrome输出的质量不是一般的差,估计运算精度有问题。
    401.618 sec
     回复 引用 查看   
  43. #43楼[楼主] Milo Yip      2010-07-07 19:39
    @阿水
    看不到第4節的那個數據表麼? 瀏覽器問題?
     回复 引用 查看   
  44. #44楼[楼主] Milo Yip      2010-07-07 19:40
    @王克伟
    謝謝,已經修好。
     回复 引用 查看   
  45. #45楼[楼主] Milo Yip      2010-07-07 20:10
    @Sumtec
    引用Sumtec:
    @Milo
    Chrome输出的质量不是一般的差,估计运算精度有问题。
    401.618 sec


    不,所有測試都是每象素100採樣,是有很多noise的。最頂的那個圖是10000採樣。
     回复 引用 查看   
  46. #46楼 noremorse      2010-07-07 20:20
    @Milo Yip
    引用Milo Yip:
    @noremorse
    謝謝你的源碼,我會考慮是否加入這個測試中。

    但這個測試中,C#的Vec也是用class,Java的版本也是用class。所以沒有C# struct複製的問題。



    恩 我下的是前一篇的代码 呵呵 :)
     回复 引用 查看   
  47. #47楼 搏击的小船      2010-07-07 21:58
    实践才是真理,支持楼主
     回复 引用 查看   
  48. #48楼 露磬弢      2010-07-07 22:00
    使用 TargetedPatchingOptOutAttribute
    然后使用本机镜像生成器试试
     回复 引用 查看   
  49. #49楼 devil0153      2010-07-07 22:03
    牛人,围观
     回复 引用 查看   
  50. #50楼       2010-07-07 23:44
    老子用chrome,一样假死。。。
     回复 引用 查看   
  51. #51楼[楼主] Milo Yip      2010-07-08 00:03
    @noremorse
    我按你的做法,把最新的代碼修改一次,更新了本文。

    我發現你的代碼裡有bug,渲染結果不對,使時間變短了:
    Vec.add(out d, ref d, ref ta);
    Vec.add(out d, ref d, ref ta);
    

    第二個應該是tb :)

    測試結果是快了,但在我的機器上只快4秒左右。
     回复 引用 查看   
  52. #52楼[楼主] Milo Yip      2010-07-08 00:17
    @Sword-Breaker
    好,已經加入IronPython和Jython。
     回复 引用 查看   
  53. #53楼[楼主] Milo Yip      2010-07-08 01:54
    @Greatest
    我試改了用new style class和__slot__,結果是3983.139秒,比原來的3920.556還慢一點。你也是用Python 3.1.2麼?
     回复 引用 查看   
  54. #54楼 noremorse      2010-07-08 08:06
    引用Milo Yip:
    @noremorse
    我按你的做法,把最新的代碼修改一次,更新了本文。

    我發現你的代碼裡有bug,渲染結果不對,使時間變短了:
    Vec.add(out d, ref d, ref ta);
    Vec.add(out d, ref d, ref ta);
    

    第二個應該是tb :)

    測試結果是快了,但在我的機器上只快4秒左右。


    哈哈,谢谢Milo老师指正,的确写错了。我改成tb后的确代码确实慢了几秒,但是在我的机器仍然与struct和class方法有较大优势:
    A: smallpt struct 120x s
    B: smallpt class 110x s
    C: smallpt ref 70x s

    两个问题比较疑惑:
    1.为什么改了个变量对计算时间有显著影响,我猜想是值变化了影响了radiance计算的时间,因为sin、cos、sqrt的计算时间是根值相关的,不知道对不对。
    2.为什么AB方案和C方案在你机器性能接近而在我机器性能差异很大,A比C多结构复制,B比C多内存分配回收,那么是否表示是cache、内存性能的差异的原因?

     回复 引用 查看   
  55. #55楼[楼主] Milo Yip      2010-07-08 10:31
    @noremorse
    引用noremorse:
    两个问题比较疑惑:
    1.为什么改了个变量对计算时间有显著影响,我猜想是值变化了影响了radiance计算的时间,因为sin、cos、sqrt的计算时间是根值相关的,不知道对不对。
    2.为什么AB方案和C方案在你机器性能接近而在我机器性能差异很大,A比C多结构复制,B比C多内存分配回收,那么是否表示是cache、内存性能的差异的原因?

    1. 因為d本是半球體內的隨機方向,錯了之後都指向接近某個角度了,以渲染結果來看,地面完全接受不到光,應該是第一層radiance()調用之後就射向攝像機的方向(沒有牆),第二層就沒繼續進行recursive call了。
    2. 很有可能。因為本測試是一直做recursive call,內存pattern是stack,如果需要的內存能放進cache,速度差異很大。C盡量減少新對象的產生,所需內存最少。我測試用的機器有8MB L2 cache,你的應該是1MB。所以分別比較明顯。
     回复 引用 查看   
  56. #56楼 猫粮      2010-07-08 11:51
    http://bbs.9ria.com/thread-58209-1-1.html
    根据作者的java源代码稍微移植了一下成了AS3版的,发现执行效率实在是太差,差到匪夷所思…跑255*255 100个sample要3小时以上…
    和chrome v8相差那么远实在是很不甘心啊…
     回复 引用 查看   
  57. #57楼 noremorse      2010-07-08 12:09
    @Milo Yip
    恩 的确是递归次数有差异,测试了下,正确版本是64百万次调用,我写错的是55百万次。急躁懒惰的毛病总改不了。拜Milo为师了,收个徒弟吧。
     回复 引用 查看   
  58. #58楼[楼主] Milo Yip      2010-07-08 12:56
    @Galactica
    昨天加入了用ref/out struct的測試。
     回复 引用 查看   
  59. #59楼 轩辕法王      2010-07-08 13:07
    这里有个贴:c#的绘图方法竟然比c++的快,求解~~
    http://topic.csdn.net/u/20100707/09/A1B59C89-6DBA-43B0-80EE-E3B62A7D1B46.html
     回复 引用 查看   
  60. #60楼 飞天老鼠      2010-07-08 20:58
    博主能贴一下C#的编译参数吗?还是用默认方式(不带参数)来编译的?
     回复 引用 查看   
  61. #61楼[楼主] Milo Yip      2010-07-08 21:51
    @飞天老鼠
    引用飞天老鼠:博主能贴一下C#的编译参数吗?还是用默认方式(不带参数)来编译的?

    因為不知道在VS裡怎麼看C#的參數。用默認 release x86
     回复 引用 查看   
  62. #62楼[楼主] Milo Yip      2010-07-08 21:52
    @轩辕法王
    引用轩辕法王:
    这里有个贴:c#的绘图方法竟然比c++的快,求解~~
    http://topic.csdn.net/u/20100707/09/A1B59C89-6DBA-43B0-80EE-E3B62A7D1B46.html

    信息不足,無法研究。
     回复 引用 查看   
  63. #63楼 轩辕法王      2010-07-13 10:12
    .NET、Mono与Java、C++性能测试大PK(1)

    http://developer.51cto.com/art/201007/211089.htm
     回复 引用 查看   
  64. #64楼 cuishengli      2010-07-13 13:45
    文章不错,提个建议时间用"#,##0.00"格式。
     回复 引用 查看   
  65. #65楼 infinte      2010-07-16 14:45
    补个数据,用IE9的pp3預覽版跑分的結果是 670.753 秒,不及Chrome 5但還是超過了LuaJIT和火狐。

    硬件配置、系統和樓主相同(i7 920 2.63,開了動態降頻節能和動態單核提頻。關閉的話可能時間會更短)

    Chakra引擎前途無量啊………………微軟這次爆發了
    (建議樓主下載安裝后進行測試。需Windows 7環境。)

    (要在Ie9下跑測試需要把Run按鈕的onclick事件上追加“;return false”;否則按鈕一點頁面就刷新。使用button標籤是更好的方法。)
     回复 引用 查看   
  66. #66楼 ShaPherD      2010-07-16 16:52
    测试要选择每个语言最好的渲染办法
    而且有些语言本身就不适合渲染吧
     回复 引用 查看   
  67. #67楼 GhostHeaven      2010-07-18 09:49
    用HTML5的Web Worker的话至少还能让JS快N倍(N = CPU核心数量)
     回复 引用 查看   
  68. #68楼[楼主] Milo Yip      2010-07-18 11:39
    @ShaPherD
    引用ShaPherD:
    测试要选择每个语言最好的渲染办法
    而且有些语言本身就不适合渲染吧

    請問有那種更好的渲染辦法?
    若認為某些語言本身不適合用此方法渲染,本文的實驗或許就可作為佐証。
     回复 引用 查看   
  69. #69楼[楼主] Milo Yip      2010-07-18 11:39
    @cuishengli
    引用cuishengli:文章不错,提个建议时间用"#,##0.00"格式。

    非常好的建議,已改用3位小數數字。
     回复 引用 查看   
  70. #70楼[楼主] Milo Yip      2010-07-18 11:42
    @GhostHeaven
    引用GhostHeaven:用HTML5的Web Worker的话至少还能让JS快N倍(N = CPU核心数量)

    是的,本測試除了C++的OpenMP版本,其他語言都沒有測試多綫程的情況。在4核i7使用了OpenMP可以快5.16x,因為還有hyperthread。
     回复 引用 查看   
  71. #71楼[楼主] Milo Yip      2010-07-18 11:45
    @猫粮
    引用猫粮:
    http://bbs.9ria.com/thread-58209-1-1.html
    根据作者的java源代码稍微移植了一下成了AS3版的,发现执行效率实在是太差,差到匪夷所思…跑255*255 100个sample要3小时以上…
    和chrome v8相差那么远实在是很不甘心啊…

    忘了回覆。也許應該是V8匪夷所思地快。
    已把你的連結加進本文更新部分。
     回复 引用 查看   
  72. #72楼 wuxqing      2010-07-20 23:32
    gcc 应该在linux下跑,cygwin还是差很多的
    要是有时间的话,可以测一下,linux下java、ruby、pyton等跨平台语言的速度。
     回复 引用 查看   
  73. #73楼 wuxqing      2010-07-21 08:54
    看到了“2010/7/10: 园友Domslab撰文 .... 比较了gcc/mono C#/Java在Windows/Linux的性能”,不过链接是错误的
     回复 引用 查看   
  74. #74楼 ylxf      2010-07-24 08:14
    java比C#快,这个比较意外啊。
     回复 引用 查看   
  75. #75楼 飞天老鼠      2010-07-30 21:16
    我找了台虚拟机,出现奇怪的问题,C#的ref方式居然比C#的普通方式慢了近两成。.net 2.0与4.0下都是这样。这会不会与是在虚拟机里面有关系?
     回复 引用 查看   
  76. #76楼 Shitty      2010-08-08 15:23
    楼主你测试性能有没有试过gcc的dw2和SJLJ的区别?

    我的测试结果
    Core2 E6300 OC 2.8GHz 4G ddr2 800 Win7 32bit mingw32 gcc 4.5.0
    g++ -O3 -ffast-math -march=native -fopenmp 12.3s
    g++ -O3 -ffast-math -fopemp 13.1s
    g++ -O3 -march=native -fopenmp 14.5s
     回复 引用 查看   
  77. #77楼 JunyiSun      2010-08-11 11:19
    http://code.google.com/p/shedskin/

    能否测试一下用shedskin把py转化为cpp后的性能?

    不过这个库对于一些动态特性有限制,比如覆盖__call__就不行。
     回复 引用 查看   
  78. #78楼 riverzhou      2010-08-16 22:18
    非常感谢博主的精彩文章。
    有关python,版本选择上不够合理。
    3系现在很少在生产环境中使用,
    大量使用的都是2系的,比如2.6/2.7。建议加上2.6或者2.7的python测试。
    另外,python也有很严重的GC的问题,可以做一次把gc关闭的测试。
    import gc
    gc.disable()
    重型计算结束后,
    是可以用gc.enable()再打开自动gc的。

    动态语言里,少了一个重量级的兄弟,perl。这个应该是第一个大规模流行的动态语言了。

    google彻底改变了js,V8是一个极度优秀的jit引擎,可以生成非常高质量的原生机器码。

    期待此文能继续更新。
     回复 引用 查看   
  79. #79楼 riverzhou      2010-08-16 22:24
    另外,除了python的版本选择不够合理或者全面的话,
    GCC也有些问题。

    cygwin是通过一个模拟转换层来实现posix到win32的兼容的。cygwin最大的优势是可以不改或者基本不改linux等posix上的代码而编译成win32上可运行的程序。
    但是,在windows上用gcc的,现在基本都是mingw为主,cygwin通常都是临时方案,最后都会用mingw用win32原生的函数和win32的原生现成来编译。cygwin是基于pthread的。
    现在比较流行和方便的,是TDM打包的mingw,可以选择4.4或者4.5的GCC。
    另外,楼上也有人提到,gcc的异常模型,SJLJ和DW-2。据说sjlj的性能要比dw2差很多。

    python是慢,但是似乎不应该慢这么多。
    而gcc,比不过icc是正常的,比vc慢这么多,似乎也不应该。
     回复 引用 查看   
  80. #80楼 riverzhou      2010-08-16 22:28
    引用wuxqing:
    gcc 应该在linux下跑,cygwin还是差很多的
    要是有时间的话,可以测一下,linux下java、ruby、pyton等跨平台语言的速度。

    不这么认为。
    以我的经验看,mingw的性能并不差,特别是4.4/4.5。
    cygwin编译的是posix程序,有个posix到win32的转换,慢是正常的。
    apache移植windows,开始用的就是cygwin,应为方便,但是性能很差,
    后来也改用mingw来编译了,就好多了。

    至于.net,最好能有个mono来对比。
     回复 引用 查看   
  81. #81楼 riverzhou      2010-08-16 22:37
    引用Shitty:
    楼主你测试性能有没有试过gcc的dw2和SJLJ的区别?

    我的测试结果
    Core2 E6300 OC 2.8GHz 4G ddr2 800 Win7 32bit mingw32 gcc 4.5.0
    g++ -O3 -ffast-math -march=native -fopenmp 12.3s
    g++ -O3 -ffast-math -fopemp 13.1s
    g++ -O3 -march=native -fopenmp 14.5s

    你用的是mingw32,楼主用的是cygwin,都号称是GCC,其实大相径庭。呵呵
    另外,你的编译参数,可以显式的加上 -msse4,用sse来优化。
    而-march参数最好和-mtune一起用。
    g++ -O3 -ffast-math -msse4 -mfpmath=sse+387 -march=native -mtune=native -fopenmp
     回复 引用 查看   
  82. #82楼 riverzhou      2010-08-16 23:41
    看了一下python的代码,有点晕。
    既不是面向对象也不是面向过程。
    有空改改看,按python的常规写法重写一下,看看性能有多少变化。
     回复 引用 查看   
  83. #83楼 Shitty      2010-08-28 20:07

    试了一下,比原来快了0.01秒,应该是LZ的配置比我的好太多了
    引用riverzhou:
    引用Shitty:
    楼主你测试性能有没有试过gcc的dw2和SJLJ的区别?

    我的测试结果
    Core2 E6300 OC 2.8GHz 4G ddr2 800 Win7 32bit mingw32 gcc 4.5.0
    g++ -O3 -ffast-math -march=native -fopenmp 12.3s
    g++ -O3 -ffast-math -fopemp 13.1s
    g++ -O3 -march=native -fopenmp 14.5s

    你用的是mingw32,楼主用的是cygwin,都号称是GCC,其实大相径庭。呵呵
    另外,你的编译参数,可以显式的加上 -msse4,用sse来优化。
    而-march参数最好和-mtune一起用。
    g++ -O3 -ffast-math -msse4 -mfpmath=sse+387 -march=native -mtune=native -fopenmp


    试了一下,比原来快了0.01秒,应该是LZ的配置比我的好太多了
     回复 引用 查看   
  84. #84楼 chaogu      2010-09-18 12:05
    我做了一个光线跟踪,速度超慢,C++写成的,用24小时才出16张图片。
    里面基本上是float计算,所以速度慢是正常的,而且本来计算量就超大。
     回复 引用 查看   
  85. #85楼 kk1987      2010-09-25 03:28
    楼主的Ruby实现有错误,第162行应为
    "isRR = (isUseRR and rand < obj.maxC)"
    (and不同于&&,结合优先级比等号更低)

    另外,Python版第201行最好改成
    "samps = int(int(sys.argv[1]) / 4)"
    否则在Python3下有问题。

    我的测试结果如下(每像素8次采样):
    Ruby 1.8.7p249 1494.3s
    Ruby 1.9.1p378 666.5s
    Ruby 1.9.2dev 458.0s
    Python 2.6.5 677.9s
    Python 3.1.2 445.1s

    可见Ruby性能并不差。并且另一方面,Ruby 1.9.2的
    内存占用只是Python 3.1.2的一半多一点。
     回复 引用 查看   
  86. #86楼[楼主] Milo Yip      2010-09-25 22:13
    @kk1987
    非常感謝告之,我會盡快再測試更新本文數據。
     回复 引用 查看   
  87. #87楼 Ayanami Rei      2010-11-14 09:48
    对《C++/C#/F#/Java/JS/Lua/Python/Ruby渲染比试》一文的补充——增加Mono测试
    这篇文章指向的链接不正确,应该为
    http://www.cnblogs.com/miloyip/archive/2010/07/07/languages_brawl_GI.html
     回复 引用 查看   
  88. #88楼 书痕      2010-12-09 17:22
    期待加入mono的对比
     回复 引用 查看   
  89. #89楼 skandhas      2011-02-28 10:41
    你的博客很不错!学习到不少知识。关于这个测试,我有几点意见:
    1.由于各种语言内部的实现机制不一样,所以看似一样的语法,实际上性能的开销却大不一样。如:C++中的new和java中的new
    2 即使同一种语言中,也有性能雷区。比如C++中:
    void funcA(vector<string> vec)和 void funcB(vector<string> & vec)这两个函数。funcB是传引用,而funcA是传值。虽然这两个都能运行,得出同样的结果。但funcA是性能略差,猜中了雷区。正是由于这些问题的存在,才会有《Effective C++》这样的书产生。其他语言中,也有类似的effective的惯用法,这个还需要进一步学习才能体会。
    3 不同的语言都有自己的解决性能问题的方案,具体问题需具体对待。例如,我可以使用object pool机制来对付大量的,频繁的小对象的申请。这样就比native的new性能好很多了。
    4 最后,我觉得这个测试有一定的意义,但是意义呢,也不是很大,请不要见怪:) 尤其是对你不熟悉的语言,虽然你写出了能运行,看起来样子也差不多的脚本,但是很有可能你已经踩到了这个语言的性能雷区。例如Ruby和Python。只有熟练掌握了这门语言后,才能写出合理的测试脚本。
     回复 引用 查看   
  90. #90楼 zzz654321      2011-03-20 23:26
    pypy 1.4 测试 CPU 3.3G AMD 5000+
     回复 引用 查看   
  91. #91楼 zzz654321      2011-03-20 23:28
    pypy 1.4 测试 CPU 3.3G AMD 5000+
    16 ssp 耗时 77.6 用 random.random 替换 rand
    luajit 165.8
    看来 pypy 还是很强大的哈! :)
     回复 引用 查看   
  92. #92楼 zzz654321      2011-03-20 23:32
    gcc mingw32 TDM 4.5.1 dw2 100 ssp 耗时 5.9 秒
     回复 引用 查看   
  93. #93楼 sun@china      2011-06-20 20:16
    Milo Yip大神,我有一个问题想向您请教:
    我用你的测试代码在windows7pro平台上进行了测试。
    C#是在.net4.0平台下,java是在JDK7.0(1.7.0-ea-b145)平台下。C#的时间92秒(三次平均,下同),C#_outref的时间是70秒;Java(添加client参数)的时间大约是91秒,Java(添加server参数)的时间大约是59秒。所有测试过程中我的双核CPU的使用率都稳定在50%左右。我现在无法理解的是为什么Java(添加server参数)的效率会那么高?Java(添加client参数)和Java(添加server参数)在虚拟机实现过程中最本质的区别是什么?在我使用Java(添加client参数)的时候内存占用率大约为10M左右,但是在使用Java(添加server参数)的时候,内存占用率会飙升到170M左右,虚拟机是怎样用空间换取时间的?是不是每个程序由client换成server都会导致内存使用率的大幅度(至少5倍以上)增加?微软的.net平台有类似于Java的server启动参数吗?如果没有,为什么微软不采用这种方法大幅度提高效率?
    我的问题可能有点多,也有点凌乱。在此先谢谢Milo Yip大神,辛苦你了!
     回复 引用 查看   
  94. #94楼[楼主] Milo Yip      2011-06-22 09:48
    @sun@china
    我對這兩個平台熟悉尚淺,建議你在一些相關論壇討論。憑空猜想的話,要用空間換取時間,在JIT時可能會用更多的內聯,或是在內存管理上更進取一些。
     回复 引用 查看   
  95. #95楼 Parallet      2011-06-23 22:28
    用我的Parallet测试了一下.
    非编译模式为C#时间的26倍, 相当于LUA.
    编译模式没完全实现, 下次再测.
    http://www.cnblogs.com/parallet/archive/2011/06/23/2088463.html
     回复 引用 查看   
  96. #96楼 【当耐特砖家】      2011-11-08 21:35
    已选入HTML5实验室目录, 多谢分享http://www.cnblogs.com/iamzhanglei/archive/2011/11/06/2237870.html
     回复 引用 查看   
  97. #97楼 杨博      2011-12-23 03:17
    改用JRE7试试,JRE7默认打开了逃逸分析的优化,对这种大量产生临时对象的应用有巨大帮助。
     回复 引用 查看