一、测试结果汇总
将前面的测试结果进行汇总,按照三点取中方式筛选结果,整理为表格(单位是毫秒,数值越小越好)——
测试 | f0_if | f1_min | f2_neg | f3_sar | f4_mmx | f5_sse |
VC6 on 32bit | 2016 | 2063 | 719 | 672 | 37.5 | 25.7 |
VC6 on 64bit | 2028 | 2075 | 718 | 687 | 37.1 | 25.3 |
VC2010(32) on 32bit | 1793 | 2112 | 512 | 437 | ||
VC2010(32) on 64bit | 1716 | 2106 | 514 | 437 | ||
VC2010(64) on 64bit | 1623 | 1997 | 421 | 328 | ||
C#2010(any) on 32bit | 1922 | 2147 | 2471 | 559 | ||
C#2010(any) on 64bit | 1871 | 1918 | 2406 | 651 | ||
C#2010(x86) on 32bit | 1930 | 2142 | 2462 | 545 | ||
C#2010(x86) on 64bit | 1829 | 2073 | 2340 | 516 | ||
C#2010(x64) on 64bit | 1865 | 1911 | 2399 | 651 | ||
VB6 on 32bit | 2844 | 1078 | ||||
VB6 on 64bit | 2839 | 1061 |
注:CPU:Intel Core i3-2310M, 2100 MHz。
上图是以毫秒为单位,因数据量很多,看起来有点吃力。于是又做了一个表格,将各列的数据除以“f0_if”列,即以倍数为单位,数值越大越好——
测试 | f0_if | f1_min | f2_neg | f3_sar | f4_mmx | f5_sse |
VC6 on 32bit | 1.00 | 0.98 | 2.80 | 3.00 | 53.76 | 78.44 |
VC6 on 64bit | 1.00 | 0.98 | 2.82 | 2.95 | 54.66 | 80.16 |
VC2010(32) on 32bit | 1.00 | 0.85 | 3.50 | 4.10 | ||
VC2010(32) on 64bit | 1.00 | 0.81 | 3.34 | 3.93 | ||
VC2010(64) on 64bit | 1.00 | 0.81 | 3.86 | 4.95 | ||
C#2010(any) on 32bit | 1.00 | 0.90 | 0.78 | 3.44 | ||
C#2010(any) on 64bit | 1.00 | 0.98 | 0.78 | 2.87 | ||
C#2010(x86) on 32bit | 1.00 | 0.90 | 0.78 | 3.54 | ||
C#2010(x86) on 64bit | 1.00 | 0.88 | 0.78 | 3.54 | ||
C#2010(x64) on 64bit | 1.00 | 0.98 | 0.78 | 2.86 | ||
VB6 on 32bit | 1.00 | 2.64 | ||||
VB6 on 64bit | 1.00 | 2.68 |
对应图表(因MMX/SSE的性能太鹤立鸡群,影响图表阅读,故省略)——
二、各算法的性能分析
现在我们按照列顺序(即各个算法的顺序)来进行分析——
1.首先,f0_if是采用if语句的基础算法,当作标杆用来评比其他算法。
2.f1_min采用了系统函数min、max。因现代编译器会对min、max做内联优化的,理论上应该与f0_if差不多。但实际测试后发现,f1_min比f0_if慢了一些。原因可能是因为min/max的语义与if不同,编译优化的深度不及if语句。
3.f2_neg算法采用了位运算来避免分支跳转,处理速度有了较大提高,平均性能大约是f0_if的3倍。可惜C#不支持将bool型强制转换为整型,而调用Convert.ToInt16带来了性能开销,使其比f0_if还慢。
4.f3_sar算法利用带符号移位避免了状态寄存器的访问,处理速度又有了一定的提升,平均性能大约是f0_if的3.5倍。
5.f4_mmx、f5_sse算法因为用到MMX、SSE这些SIMD指令集,所以处理速度比前面那些高级语言算法高了一个级别。
算法 | 最小倍数 | 最大倍数 | 平均倍数 | 备注 |
f1_min | 0.81 | 0.98 | 0.91 | 无VB6 |
f2_neg | 2.64 | 3.86 | 3.09 | 无C# |
f3_sar | 2.86 | 4.95 | 3.52 | 无VB6 |
f4_mmx | 53.76 | 54.66 | 54.21 | 仅VC6 |
f5_sse | 78.44 | 80.16 | 79.3 | 仅VC6 |
三、其他发现
分析测试结果,还发现——
1.VC2010的的编译优化能力比VC6要强,同样程序的运行速度要快很多。这可能是因为VC2010的编译优化更能适应最新处理器的指令级并行性。
2.在64位系统中能运行32位程序,除了C#以外,其运行速度与在32位系统中的差不多。
3.C#2010的程序,有时在64位系统上的运行速度比32位系统还慢,甚至包括了“x64”平台方式编译的程序。似乎“x86”平台方式编译的程序的平均性能最好。可能是因为64位JIT(即时编译器)不如32位的成熟。
4.对于VC2010编译器来说,编译的64位程序比32位程序的运行速度有比较明显的提升。看来编写64位程序的最好还是用VC等C/C++编译器。
5.在传统印象中,VB、C#的运行速度比C语言慢很多。但通过这次测试发现,虽然它们的性能是有一定差距,但是是处于同一级别的,甚至C#与VC6打平还略占优势。影响程序运算速度的最关键因素是算法,用编译能力最差的VB6实现的f2_neg,比编译能力最好的VC2010实现的f0_if要快得多。
四、总结
使用位掩码代替分支能带来较大的性能提升,而且该方案能推广到任何高级语言,能充分利用高级语言的可移植性,能满足大多数的性能优化需求。
但当对性能要求极高、且不要求可移植性时,强烈推荐MMX、SSE等SIMD指令集,能使处理速度提高一个级别。
附:测试程序打包下载——
http://files.cnblogs.com/zyl910/noif_Test.rar
http://dl.dbank.com/c069c6thd7
(完)
《深入探讨用位掩码代替分支》系列文章——
1、利用带符号移位生成掩码:http://blog.csdn.net/zyl910/article/details/7345655
2、汇编代码分析:http://blog.csdn.net/zyl910/article/details/7378171
3、VC6速度测试:http://blog.csdn.net/zyl910/article/details/7399236
4、VC2010速度测试:http://blog.csdn.net/zyl910/article/details/7403497
5、C#2010速度测试:http://blog.csdn.net/zyl910/article/details/7408013
6、VB6速度测试:http://blog.csdn.net/zyl910/article/details/7412216
7、MMX指令集速度测试:http://blog.csdn.net/zyl910/article/details/7443141
8、SSE指令集速度测试:http://blog.csdn.net/zyl910/article/details/7455830
9、测试成绩总结:http://blog.csdn.net/zyl910/article/details/7458757
网友的测试成绩
~~~~~~~~~~~~~~
参与帖子——
http://topic.csdn.net/u/20120413/17/11aaf5cb-6ca1-4477-9271-2f071435e9f8.html
http://topic.csdn.net/u/20120413/17/d0f0dd3f-ca55-41f6-9fa0-321a85be5668.html
成绩汇总——
序 | 测试 | CPU | GHz | f0_if | f1_min | f2_neg | f3_sar | f4_mmx | f5_sse | 倍f1 | 倍f2 | 倍f3 | 倍f4 | 倍f5 | id | time |
1 | VC2010(32) on 32bit | Intel G530 | 2.80 | 1506 | 1854 | 447 | 382 | 0.81 | 3.37 | 3.94 | dianyancao | 2012-4-13 18:10 | ||||
2 | VC6 on 32bit | Intel Celeron | 2.40 | 2844 | 3422 | 1921 | 1796 | 1191.4 | 1303.8 | 0.83 | 1.48 | 1.58 | 2.39 | 2.18 | laviewpbt | 2012-4-14 9:35 |
3 | VC2010(32) on 32bit | Intel Celeron | 2.40 | 5984 | 7735 | 2609 | 2547 | 0.77 | 2.29 | 2.35 | laviewpbt | 2012-4-14 9:35 | ||||
4 | VB6 on 32bit | Intel Celeron | 2.40 | 7609 | 3329 | 2.29 | laviewpbt | 2012-4-14 9:35 | ||||||||
5 | VC6 on 32bit | Intel i3 380M | 2.53 | 3602 | 2937 | 1563 | 1530 | 75.0 | 41.6 | 1.23 | 2.30 | 2.35 | 48.03 | 86.59 | laviewpbt | 2012-4-14 13:40 |
6 | VC2010(32) on 32bit | Intel i3 380M | 2.53 | 2415 | 2929 | 497 | 388 | 0.82 | 4.86 | 6.22 | laviewpbt | 2012-4-14 13:40 | ||||
7 | C#2010(any) on 32bit | Intel i3 380M | 2.53 | 2967 | 1846 | 2372 | 476 | 1.61 | 1.25 | 6.23 | laviewpbt | 2012-4-14 13:40 | ||||
8 | C#2010(x86) on 32bit | Intel i3 380M | 2.53 | 2391 | 1834 | 2371 | 472 | 1.30 | 1.01 | 5.07 | laviewpbt | 2012-4-14 13:40 | ||||
9 | VB6 on 32bit | Intel i3 380M | 2.53 | 8115 | 2240 | 3.62 | laviewpbt | 2012-4-14 13:40 | ||||||||
10 | VB6 on 32bit | AMD 四核 | 2.00 | 2108 | 1260 | 1.67 | Veron_04 | 2012-4-14 14:56 | ||||||||
11 | VC6 on 32bit | Intel i7 2620M | 2.70 | 1452 | 1529 | 498 | 495 | 0.95 | 2.92 | 2.93 | unicodestring | 2012-4-16 21:52 | ||||
12 | VC6 on 32bit | ? | ? | 1813 | 1981 | 780 | 751 | 105.3 | 108.5 | 0.92 | 2.32 | 2.41 | 17.22 | 16.71 | likid1412 | 2012-4-16 21:52 |
13 | VC6 on 64bit | Intel i7 920 | 2.60 | 2048 | 1572 | 964 | 816 | 38.8 | 25.7 | 1.30 | 2.12 | 2.51 | 52.78 | 79.69 | CandPointer | 2012-4-17 4:24 |
14 | VC2010(32) on 64bit | Intel i7 920 | 2.60 | 1511 | 2181 | 420 | 322 | 0.69 | 3.60 | 4.69 | CandPointer | 2012-4-17 4:24 | ||||
15 | VC2010(64) on 64bit | Intel i7 920 | 2.60 | 1451 | 1557 | 383 | 248 | 0.93 | 3.79 | 5.85 | CandPointer | 2012-4-17 4:24 | ||||
16 | C#2010(any) on 64bit | Intel i7 920 | 2.60 | 1540 | 1547 | 2064 | 403 | 1.00 | 0.75 | 3.82 | CandPointer | 2012-4-17 4:24 | ||||
17 | C#2010(x86) on 64bit | Intel i7 920 | 2.60 | 2061 | 1590 | 2052 | 411 | 1.30 | 1.00 | 5.01 | CandPointer | 2012-4-17 4:24 | ||||
18 | C#2010(x64) on 64bit | Intel i7 920 | 2.60 | 1539 | 1554 | 2069 | 404 | 0.99 | 0.74 | 3.81 | CandPointer | 2012-4-17 4:24 | ||||
19 | VC6 on 32bit | Intel i5 520M | 2.40 | 2258 | 1848 | 1070 | 1013 | 52.7 | 31.8 | 1.22 | 2.11 | 2.23 | 42.85 | 71.01 | VBAdvisor | 2012-4-17 7:58 |
20 | VC2010(32) on 32bit | Intel i5 520M | 2.40 | 1782 | 2512 | 583 | 432 | 0.71 | 3.06 | 4.13 | VBAdvisor | 2012-4-17 7:58 | ||||
21 | C#2010 on 32bit | Intel i5 520M | 2.40 | 2488 | 1762 | 2326 | 494 | 1.41 | 1.07 | 5.04 | VBAdvisor | 2012-4-17 7:58 | ||||
22 | C#2010(any) on 32bit | Intel i5 520M | 2.40 | 2262 | 1785 | 2352 | 469 | 1.27 | 0.96 | 4.82 | VBAdvisor | 2012-4-17 7:58 | ||||
23 | VB6 on 32bit | Intel i5 520M | 2.40 | 2874 | 1386 | 2.07 | VBAdvisor | 2012-4-17 7:58 | ||||||||
24 | VC6 on 32bit | Inter Core2 E6550 | 2.33 | 2486 | 1840 | 1020 | 994 | 58.9 | 41.3 | 1.35 | 2.44 | 2.50 | 42.21 | 60.19 | Tiger_Zhao | 2012-4-17 10:40 |
25 | VB6 on 32bit | Inter Core2 E6550 | 2.33 | 2791 | 1252 | 2.23 | Tiger_Zhao | 2012-4-17 10:40 | ||||||||
26 | VC6 on 64bit | Intel i5 560M | 2.40 | 2117 | 1715 | 912 | 926 | 42.8 | 28.4 | 1.23 | 2.32 | 2.29 | 49.46 | 74.54 | ggt87125 | 2012-4-17 10:43 |
27 | VC2010(32) on 64bit | Intel i5 560M | 2.40 | 1617 | 2345 | 463 | 353 | 0.69 | 3.49 | 4.58 | ggt87125 | 2012-4-17 10:43 | ||||
28 | VC2010(64) on 64bit | Intel i5 560M | 2.40 | 1558 | 1687 | 433 | 301 | 0.92 | 3.60 | 5.18 | ggt87125 | 2012-4-17 10:43 | ||||
29 | C#2010(any) on 64bit | Intel i5 560M | 2.40 | 1658 | 1684 | 2229 | 453 | 0.98 | 0.74 | 3.66 | ggt87125 | 2012-4-17 10:43 | ||||
30 | C#2010(x86) on 64bit | Intel i5 560M | 2.40 | 2220 | 1709 | 2222 | 450 | 1.30 | 1.00 | 4.93 | ggt87125 | 2012-4-17 10:43 | ||||
31 | C#2010(x64) on 64bit | Intel i5 560M | 2.40 | 1643 | 1674 | 2240 | 447 | 0.98 | 0.73 | 3.68 | ggt87125 | 2012-4-17 10:43 | ||||
32 | VC6 on 32bit | Intel i3 2120 | 3.30 | 1296 | 1313 | 453 | 438 | 23.4 | 16.6 | 0.99 | 2.86 | 2.96 | 55.38 | 78.07 | chenjl1031 | 2012-4-17 11:40 |
33 | VC2010(32) on 32bit | Intel i3 2120 | 3.30 | 1078 | 1328 | 328 | 281 | 0.81 | 3.29 | 3.84 | chenjl1031 | 2012-4-17 11:40 | ||||
34 | VB6 on 32bit | Intel i3 2120 | 3.30 | 1813 | 687 | 2.64 | chenjl1031 | 2012-4-17 11:40 | ||||||||
35 | VC6 on 32bit | Intel Pentium E5500 | 2.80 | 2139 | 1583 | 858 | 827 | 50.3 | 34.4 | 1.35 | 2.49 | 2.59 | 42.52 | 62.18 | bigbaldy | 2012-4-17 13:01 |
36 | VC2010(32) on 32bit | Intel Pentium E5500 | 2.80 | 1467 | 2177 | 389 | 342 | 0.67 | 3.77 | 4.29 | bigbaldy | 2012-4-17 13:01 | ||||
37 | C#2010(any) on 32bit | Intel Pentium E5500 | 2.80 | 1991 | 1617 | 2082 | 442 | 1.23 | 0.96 | 4.50 | bigbaldy | 2012-4-17 13:01 | ||||
38 | C#2010(x86) on 32bit | Intel Pentium E5500 | 2.80 | 2013 | 1588 | 2013 | 450 | 1.27 | 1.00 | 4.47 | bigbaldy | 2012-4-17 13:01 | ||||
39 | VB6 on 32bit | Intel Pentium E5500 | 2.80 | 2363 | 1050 | 2.25 | bigbaldy | 2012-4-17 13:01 | ||||||||
40 | VC6 on 32bit | Intel Pentium E5300 | 2.60 | 2250 | 1672 | 906 | 891 | 52.8 | 37.1 | 1.35 | 2.48 | 2.53 | 42.61 | 60.65 | CandPointer | 2012-4-17 14:22 |
41 | C#2010(any) on 32bit | Intel Pentium E5300 | 2.60 | 2105 | 1675 | 2149 | 468 | 1.26 | 0.98 | 4.50 | CandPointer | 2012-4-17 14:22 | ||||
42 | C#2010(x86) on 32bit | Intel Pentium E5300 | 2.60 | 2108 | 1678 | 2151 | 468 | 1.26 | 0.98 | 4.50 | CandPointer | 2012-4-17 14:22 | ||||
43 | C#2010(any) on 32bit | Intel Pentium E5300 | 2.60 | 2158 | 1707 | 2192 | 482 | 1.26 | 0.98 | 4.48 | xinzhongyoucheng | 2012-4-18 8:55 | ||||
44 | C#2010(x86) on 32bit | Intel Pentium E5300 | 2.60 | 2159 | 1710 | 2196 | 475 | 1.26 | 0.98 | 4.55 | xinzhongyoucheng | 2012-4-18 8:55 | ||||
45 | VB6 on 32bit | Intel Pentium E5300 | 2.60 | 2574 | 1132 | 2.27 | xinzhongyoucheng | 2012-4-18 8:55 |
目前发现——
1.f1_min(使用min、max函数做饱和处理)有时是比f0_if(使用if分支做饱和处理)要快的。但差距不大。
2.对于较老的CPU,VC6编译的程序比VC2010编译的程序要快。可能是因为VC2010是为最新的CPU优化的。
3.Celeron处理上的MMX、SSE指令集的运行速度较慢,没能与高级语言算法拉开差距。