前一阵子写了一个gzip的解压程序,因为是用在嵌入式环境,而且是用于demo的目的,所以就一味的压缩空间,没有太多考虑优化性能。最终实现的程序目标代码8K左右,解压一个2M的gzip文件,我的程序myzip和系统自带的zcat性能如下:
myzip: real 0m0.439s user 0m0.408s sys 0m0.008s
zcat: real 0m0.195s user 0m0.148s sys 0m0.028s
myzip的性能瓶颈一个是读取bit流的函数,另一个是huffman解码。出于节省空间的考虑,huffman树的设计相当紧凑,解码性能的优化空间不大,于是想对第一个瓶颈做点工作。在优化开始之前,先用valgrind侦察一下敌情。
首先把程序用-g参数重新编译。然后先看看程序有没有什么bug,按如下方式运行:
$valgrind --tool=memcheck ./myzip file.gz
运行结束时,valgrind打印如下信息(stripped):
==5111== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 11 from 1)
==5111== malloc/free: in use at exit: 0 bytes in 0 blocks.
==5111== malloc/free: 537 allocs, 537 frees, 239,144 bytes allocated.
恩,看来内存操作方面没啥问题,那接着profile一下:
$valgrind --tool=cachegrind ./myzip file.gz
运行完毕后,valgrind打印出程序运行的一些统计信息,并在当前目录生成一个文件cachegrind.out.xxxx。(xxxx是4个“随机"数字)。虽然这个文件是human readable的,但是有更好的工具来看 -kcachegrind。
用kcachegrind打开这个文件,窗口显示如下:
果不其然,读取bit流的函数get_bits占用了66.37%的cycles,huffman解码函数get_code占用了14.75%。那下面就拿get_bits开刀。
$%#^*&^*&,搞定。
再profile一下,kcachegrind的截图如下:
get_bits的比例下降到45.78%,get_code上升到22.64%。
再用-O3编译的程序解压上面的压缩文件结果如下:
real 0m0.361s user 0m0.340s sys 0m0.004s
总结:
本文的情况是作者非常了解程序的瓶颈,在大部分情况下,这种信息并不明显(特别是如果程序不是自己写的)。通过valgrind的cachegrind功 能,可以直观的得到这些信息。这些定量的信息,对于优化程序很有帮助。即使是对于本文所列的情况,作者知道这两个瓶颈,但要分析出这两个瓶颈哪个更堵,以 及优化后可能达到的最佳效果,valgrind提供的信息仍然很有价值。
没有评论:
发表评论