被QTextStream的坑的经历

316 阅读2分钟

起因

我在解析某个格式文件时用到了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

当初分析输出图如下:

valgrind.png

看着这个图,可以看出一点端倪,在不知名的 一个地址调用中,占大部分时间。

接下来我又用 kcachegrind 来看了一下调用时间

这次,发现了凶手。

image.png

可以看到,就是这个pos占用时间非常大。

思考

在我的映像中,pos和seek一个对应着一个位置而已,复杂度应该不会这么大。

那只有看看Qt我这个版本源码里面是怎么说的了。

源码位置在这里:qtbase/qtextstream.cpp at 5.4 · qt/qtbase · GitHub

导致pos如此慢的原因原来是每一次这个readbuffer都会清空掉,然后又要一个一个字符的填充到 oldreadbuffer处

image.png

这样导致一个非常美妙的坏结果,那就是和整体pos所在的位置有关系,并且buffer越长,越慢。

这是一个非常昂贵的操作。

image.png

总结

作为一个小白,这确实触及到我的知识盲区了。

QTextStream 是一个buffer,是和file不一样的,在我解析文本的时候,还多次用到这些操作;导致时间变得非常糟糕。 不过,这个例子也拷打了我的找出性能瓶颈的能力。特此记录~