C语言strlen实现之不科学测试


代码放在这里:

http://gist.github.com/419473 

————————————-

其中strlenBSD为delphij实现的FreeBSD使用的strlen标准库函数。http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libc/string/strlen.c?rev=1.10

strlenVC来自VS2010的CRT src,我建立了一个内嵌汇编函数,其实是有问题的,因为MSDN说的很清楚,内嵌汇编这种方式是没法做优化的。

strlenDiet这个函数来自DietlibC,使用的是0.32版本。

strlenStandard是最一般常见的实现方式,比如wiki上、《c标准库》上都是类似写法。

logger是我自己写的一个高精度计时函数,里面用的QueryPerformanceFrequency这个函数,每段strlen计算都是单独start()以及stop(),然后计算运行时间。

还有一个重要的问题就是project setting。

首先我们使用release版本,在VC2010 project property page里面

image

最后一个问题就是测试字符串,我们使用了windowsUpdate.txt这个文本文件,大概1.2M左右。

当字符串个数为80000时,运行两次,我们得到测试结果如下(时间单位都是us):

Result strlen 0.000000 ##

Result strlenBSD 0.102586 ##

Result strlenVC 3012.946893 ##

Result strlenDiet 2802.122562 ##

Result strlenStandard 3485.999846 ##

—– second time ——–

Result strlen 0.000000 ##

Result strlenBSD 0.000000 ##

Result strlenVC 3015.086831 ##

Result strlenDiet 2806.302525 ##

Result strlenStandard 3676.002553 ##

可以看到这时候使用CRT标准库的strlen最快,而strlenBSD也是非常非常快乐,而标准实现是最慢的。

 

去掉优化看看。

image

Result strlen 4161.887115 ##

Result strlenBSD 3968.818857 ##

Result strlenVC 3078.673800 ##

Result strlenDiet 3819.303217 ##

Result strlenStandard 5035.940199 ##

—————– second ————

Result strlen 3165.460250 ##

Result strlenBSD 4013.348883 ##

Result strlenVC 3764.022041 ##

Result strlenDiet 5623.339493 ##

Result strlenStandard 6379.640180 ##

这个结果就比较有意思了,除了标准实现方式的版本最慢,其他差别不是很大,相比来说VC++内嵌汇编的实现比较快一些。

第二个测试文本来自ironruby的changelog.txt,大概5000行左右,我们依然试图读取80000个字符串(也就是只改变了代码中fopen的源文件)。

全优化版本两次测试结果如下:

Result strlen 0.000000 ##

Result strlenBSD 0.433735 ##

Result strlenVC 1011.775006 ##

Result strlenDiet 826.736862 ##

Result strlenStandard 1050.510424 ##

—————————-

Result strlen 0.000000 ##

Result strlenBSD 0.165407 ##

Result strlenVC 1030.929523 ##

Result strlenDiet 836.285049 ##

Result strlenStandard 1057.499975 ##

 

无优化设置版本两次测试结果如下:

Result strlen 1166.623783 ##

Result strlenBSD 1438.473774 ##

Result strlenVC 1265.279138 ##

Result strlenDiet 1456.994396 ##

Result strlenStandard 1546.674976 ##

—————————-

Result strlen 1166.989685 ##

Result strlenBSD 1480.218605 ##

Result strlenVC 1033.686648 ##

Result strlenDiet 1239.002409 ##

Result strlenStandard 1450.543506 ##

 

得到什么结论呢?除了我比较无聊,好像没有什么科学性的结论。如果硬要想,可以说两个:一个是内嵌汇编未必很快,因为编译器没法做优化。另外是,如果你想写一个优化版本strlen,delphij实现的FreeBSD版本是非常好的例子,而dietlibc的实现几乎没有什么改进,反而因为代码复杂容易引入bug。

有几个问题其实可以好好研究的,比如为何delphij的版本会如此快?VC++以及GCC优化选项哪个比较有用?该如何写一个类似CRT这样的strlen(也就是汇编代码编译为so或者lib然后连接进来)。只是这些话题有些超出我水平,就不乱说了。

updated:

新测试代码在这里,增加了一个没对齐情况的测试(p+1),另外测试字符串个数增加到300000,对testbyte,增加一个版本,直接写testbyte在代码里。

http://gist.github.com/419585

测试结果如下:

———–对齐———————–
      Result strlenVC 84904.335012 ##

Result strlenDiet 82614.256452 ##

Result strlenStandard 99900.620863 ##

Result strlen 0.000000 ##

Result strlenBSD 0.002673 ##

Result strlenBSD2 0.032413 ##

————未对齐————————

Result strlenVC 87593.624963 ##

Result strlenDiet 83682.625534 ##

Result strlenStandard 99746.446413 ##

Result strlen 0.002339 ##

Result strlenBSD 0.002673 ##

Result strlenBSD2 0.015037 ##

可以看到对齐没对齐差别不是很大,至于0.000000,那是因为太快了,计时器没法计算出差别。


《“C语言strlen实现之不科学测试”》 有 4 条评论

  1. 我觉得那个跟你推荐的libc的strcpy的算法没本质区别,就是把四字节(或者八字节)的循环操作展开了而已

回复 Kenny Yuan 取消回复

您的电子邮箱地址不会被公开。 必填项已用*标注