VizTracer的一个重要的小优化

今天这篇文章稍微短一点,我打算以后每个minor版本更新发一篇总结文章,大概说一下这个更新都做了什么新的feature。

repo的star数缓缓地突破了30,再接再厉。

今天聊一个很有意思的小优化。

当我开始在一些项目上正式使用VizTracer的时候,还是发现了一些不理想的地方。在function call太多的情况下,由于数据量巨大,导致从raw data到json的parse时间(变成python的数据结构)、dump时间(到string),以及最后出来的文件大小本身都有点大。大概估算了一下,每一个entry大约需要100 byte多一点,所以在思考这个方向的优化。

我现在记录event的方式,是用的Chrome Trace Event里的Duration Event。也就是开始的时候有一个entry,结束的时候有一个entry。这样的好处是程序处理非常简单,每次function call和return直接打个点就行,后面的事情都让trace viewer处理。

而Chrome Trace Event还提供了一种方式,就是Complete Event,你可以直接把一个时间的开始时间和持续时间都写好,放到一个entry里,这样相当于节省了50%的空间。

在具体的程序上,就是要想办法找到每个return对应的call在哪里,然后直接在raw data上面记录一下持续时间。

这个事情本身没那么难,如果leetcode刷的比较熟的同学一下就能反应过来,本质就是记录一个stack,每次return的时候出栈,call的时候入栈就好。但是在C的环境下,实现一个无限大stack稍微有点麻烦。用linkedlist是一种可能性,但是这意味着在程序运行时(而不是parse时)的malloc额外开销。当然一次malloc很多然后不够了再来也是很可行的方案(本质就是实现一个stack)。

但是我太懒了,于是在我本身已经存在的raw data的linkedlist上直接加了一个pointer,指向这个点的parent。然后再每个thread维护一个栈顶指针,这样每次call和return的时候换栈顶指针就好了,省去了一个额外的数据结构。

这个优化本身代码量其实很小,但是效果很明显。首先file size基本降低了一半,对应的parse和dump时间也降低了一半(因为event少了)。更重要的是,overhead也被带低了,因为每次function return的时候,不需要再从frame里提取function的背景,直接找到call的node然后写一个持续时间就好了。

经过了这个优化之后,benchmark变得好看了很多,worst case下的overhead提升都挺明显,距离production use又近了一步。

另外,今天我额外花了点时间去做我的demo result,因为之前有朋友说其实没太懂我做的到底是什么,希望这些额外的demo result可以让大家更理解这个项目的意义吧!把demo放上来。

http://www.minkoder.com/viztracer/result.htmlwww.minkoder.com

老规矩,最后还是放一下项目链接,欢迎大家试用和反馈~路过点个star也是好的~

gaogaotiantian/viztracergithub.com图标

发布于 08-20

文章被以下专栏收录