起因
我在解析某个格式文件时用到了QTextStream来读取文件内容和做处理。解析代码写好之后,测试时发现运行十分慢,大概3000多行的内容需要60多秒。
分析过程
程序性能分析,我首先想到的就是看一下调用图分析一下程序。
分析工具用的valgrind来分析 gprof2dot.py 来输出图形
先用 callgrind 来分析一下程序的调用
valgrind --tool=callgrind ./parser
然后利用 gprof2dot 将 调用文件转成dot
python3 gprof2dot.py -f callgrind -n10 -s callgrind.out.4411 > valgrind.dot
再将其输出为可视化的图片。
dot -Tpng valgrind.dot -o valgrind.png
当初分析输出图如下:
看着这个图,可以看出一点端倪,在不知名的 一个地址调用中,占大部分时间。
接下来我又用 kcachegrind 来看了一下调用时间
这次,发现了凶手。
可以看到,就是这个pos占用时间非常大。
思考
在我的映像中,pos和seek一个对应着一个位置而已,复杂度应该不会这么大。
那只有看看Qt我这个版本源码里面是怎么说的了。
源码位置在这里:qtbase/qtextstream.cpp at 5.4 · qt/qtbase · GitHub
导致pos如此慢的原因原来是每一次这个readbuffer都会清空掉,然后又要一个一个字符的填充到 oldreadbuffer处
这样导致一个非常美妙的坏结果,那就是和整体pos所在的位置有关系,并且buffer越长,越慢。
这是一个非常昂贵的操作。
总结
作为一个小白,这确实触及到我的知识盲区了。
QTextStream 是一个buffer,是和file不一样的,在我解析文本的时候,还多次用到这些操作;导致时间变得非常糟糕。 不过,这个例子也拷打了我的找出性能瓶颈的能力。特此记录~