前言:
编译型语言,比如C,C++,Go编译出来的二进制,可以使用perf来分析性能。对于编译出来的elf格式,使用dwarf来分析symbol。
对于python这种解释型语言,就会比较麻烦。因为python进程的stack是Cpython的stack,并非对应的py的stack。
分析:
1,cProfile
python的官方提供了profiling工具,https://docs.python.org/2/library/profile.html
用法上,需要修改代码,重新执行。对于线上业务,其实是不太友好的。另外就是如果父进程启动之后,启动子进程执行,就没法工作了。
相比这种方式,作者更倾向旁路的方式,对于一个running的python进程进行profiling,业务进程不需要修改,也无感知(允许一定范围内的性能下降)。像perf一样,不侵入进程的情况下进行性能分析,用起来更舒服一些。
2,cpython的stack
来一段测试代码:
打印的结果是:
python的内置的traceback的结果,也是我们预期的。
实际上,使用gdb得到的结果:
可见,python进程的stack,是解释器的二进制的stack。
3,py-bt
python提供了gdb的能力,但是对gdb的版本有些要求。搭起来环境,发现gdb可以dump出来python的backtrace。
順藤摸瓜,分析libpython.py的代码发现:
a,使用gdb来dump出来cpython的stack
b,过滤掉非python的stack,方法就是判断frame的名字是不是“PyEval_EvalFrameEx”
c,在python的frame中保存了line number和file name。解释出来frame即可。
可见,gdb提供了一个很好的例子,使用旁路的方法,可以获取到python的backtrace。
那么,我们可以使用另外一个进程,每秒抓取1000次backtrace,哪个backtrace命中的更多,就说明CPU更加密集。好吧,这个动作的准确名词是“采样”,当然采样的频率可以调整才是。
4,pstack
pstack和gdb的原理类似,都是使用kernel提供的ptrace这个syscall实现的。
相比于gdb,pstack更加合适。实际上,目前upstream上已经开始支持了python的trace。
改造pstack是一个不错的方法。
5,pyflame
uber开源了pyflame工具,https://github.com/uber/pyflame
也是完全的旁路profiling工具。目前支持的功能基本满足需求,可以分析出来各个backtrace的命中次数,结合flame graph画出热点图。
值得一说的是,pyflame的实现上,和gdb的方式有很大差别:
a,在cpython中,_PyThreadState_Current这个symbol保存着当前正在运行的thread。
b,在_PyThreadState_Current中保存着当前python栈的frame。
c,从当前的frame信息中得到行号和文件名,以及上一级frame的指针。
d,遍历frame得到所有的backtrace。
综上,pyflame是一个不错的旁路profiling工具。
领取专属 10元无门槛券
私享最新 技术干货