在Python中分析:谁称这个函数?
我使用cProfile
在Python中进行cProfile
。 我发现一个需要很多CPU时间的function。 如何找出哪个函数最重要的是调用这个重函数?
编辑:
我会解决一个解决方法:我可以在这个沉重的函数里面写一个Python行来打印调用它的函数的名字吗?
这可能不会直接回答你的问题,但肯定会有帮助。 如果使用profiler选项–sort累计,它将按累计时间对函数进行sorting。 这不仅有助于检测重度function,而且还能检测到调用它们的function。
python -m cProfile --sort cumulative myScript.py
有一个解决方法来获取调用者函数:
import inspect print inspect.getframeinfo(inspect.currentframe().f_back)[2]
你可以添加任意多的f_back,如果你想要来电者来电等如果你想计算经常打电话,你可以这样做:
record = {} caller = inspect.getframeinfo(inspect.currentframe().f_back)[2] record[caller] = record.get(caller, 0) + 1
然后按频率顺序打印:
print sorted(record.items(), key=lambda a: a[1])
我几乎总是使用Gprof2dot查看cProfile模块的输出,基本上它将输出转换为graphvis图( .dot
文件),例如:
这使得确定哪个函数最慢,以及哪个函数调用它非常容易。
用法是:
python -m cProfile -o output.pstats path/to/your/script arg1 arg2 gprof2dot.py -f pstats output.pstats | dot -Tpng -o output.png
inspect.stack()会给你当前的调用者堆栈。
你可能想看看pycallgraph 。
我自己并没有使用cProfile,但大多数分析器给你一个调用层次结构。
使用Googlesearch,我发现这个幻灯片关于cProfile。 也许这有帮助。 看起来像cProfile确实提供了一个层次结构。
对不起,我不熟悉Python,但是有一个通用的方法 ,假设你可以随意手动中断执行。
只要这样做,并显示调用堆栈。 它会以很高的概率告诉你你想知道什么。 如果你想要更确定的话,只需要多次。
这是有效的,因为有罪的调用者必须在被浪费的时间的一小部分时间内处于调用堆栈上,这在很长一段时间内暴露给中断,无论是多次短的调用还是一些冗长的调用。
注意:这个过程更像诊断而不是测量。 假设坏的电话正在浪费90%的时间。 然后每次你停下来的时候,坏的调用语句就会出现在调用堆栈中的90%的概率上,你就会发现它很糟糕。 但是,如果你想准确衡量浪费,这是一个不同的问题。 为此,您将需要更多样本,以查看其中包含该呼叫的百分比。 或者,只要修好罪恶的电话,把加速计时,就能准确地告诉你这个浪费是什么。
Pycscope做到这一点。 我今天刚刚find它,所以我不能说它有多好,但我试过的一些例子已经很不错了(虽然不完美)。
https://pypi.python.org/pypi/pycscope/
你可以用它来生成一个cscope文件,然后从一个编辑器,特别是VIM生成一个cscope插件。 我尝试使用它与香草cscope,似乎简单cscope感到困惑。
可以在标准库中使用Profiler cProfile
来完成。
在pstats.Stats
(分析器结果)中有方法print_callees
(或者print_callers
)。
示例代码:
import cProfile, pstats pr = cProfile.Profile() pr.enable() # ... do something ... pr.disable() ps = pstats.Stats(pr).strip_dirs().sort_stats('cumulative') ps.print_callees()
结果将如下所示:
Function called... ncalls tottime cumtime ElementTree.py:1517(_start_list) -> 24093 0.048 0.124 ElementTree.py:1399(start) 46429 0.015 0.041 ElementTree.py:1490(_fixtext) 70522 0.015 0.015 ElementTree.py:1497(_fixname) ElementTree.py:1527(_data) -> 47827 0.017 0.026 ElementTree.py:1388(data) 47827 0.018 0.053 ElementTree.py:1490(_fixtext)
在左边你有来电,在右边你有被叫。
(例如, _fixtext
从_start_list
47827次和_start_list
46429次被调用)
也可以看看:
- docs.python.org/..#print_callees – 显示调用层次结构。 由来电者分组。 (以上使用)
- docs.python.org/..#print_callers – 显示调用层次结构。 被调用者分组。
一对笔记:
- 你的代码需要为此编辑(插入这些configuration文件语句)。
(即不可能从命令行使用像python -m cProfile myscript.py
。虽然有可能为此编写单独的脚本) - 有点不相关,但
strip_dirs()
必须在sort_stats()
之前(否则sorting不起作用)