Python中的分析:谁调用了函数?

时间:2009-05-09 17:10:53

标签: python profiling

我使用cProfile在Python中进行分析。我发现一个占用大量CPU时间的函数。我怎样才能找出哪个函数调用这个重函数?

修改

我会解决一个解决方法:我可以在那个重函数中编写一个Python行来打印调用它的函数的名称吗?

8 个答案:

答案 0 :(得分:104)

我几乎总是使用Gprof2dot查看cProfile模块的输出,基本上它将输出转换为graphvis图(.dot文件),例如:

example gprof2dot output

它可以很容易地确定哪个函数最慢,以及哪个函数调用它。

用法是:

python -m cProfile -o output.pstats path/to/your/script arg1 arg2
gprof2dot.py -f pstats output.pstats | dot -Tpng -o output.png

答案 1 :(得分:34)

这可能无法直接回答您的问题,但肯定有帮助。如果使用带有选项--sort cumulative的探查器,它将按累计时间对函数进行排序。这不仅有助于检测繁重的功能,还可以检测调用它们的功能。

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])

答案 2 :(得分:10)

inspect.stack()将为您提供当前的来电显示。

答案 3 :(得分:3)

您可能需要查看pycallgraph

答案 4 :(得分:2)

可以在标准库中使用分析器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_data 47827次和_start_list 46429次)调用

另见:


几个笔记:

  • 您的代码需要为此进行编辑(插入这些配置文件语句)。
    (即不能像命令行python -m cProfile myscript.py那样使用。虽然可以为此编写单独的脚本)
  • 有点不相关,但strip_dirs()必须在sort_stats()之前(否则排序不起作用)

答案 5 :(得分:1)

我自己没有使用过cProfile,但是大多数个人资料都会给你一个调用层次结构 谷歌搜索我发现这个slides关于cProfile。也许这有帮助。看起来cProfile确实提供了层次结构。

答案 6 :(得分:0)

抱歉,我不熟悉Python,但有一个general method可以正常工作,假设您可以随机手动中断执行。

只需这样做,然后显示调用堆栈。它会很有可能告诉你你想知道什么。如果你想更加确定,可以多次这样做。

它的工作原理是因为有罪的调用者必须在调用堆栈上浪费一小部分时间,这会在很长一段时间内将其暴露给你的中断,无论是分散在很多短暂的电话还是一些冗长的电话上的。

注意:此过程更像是诊断而非测量。假设糟糕的通话浪费了90%的时间。然后,每次你停止它时,错误的调用语句就在调用堆栈上的概率是90%,你可以看到,这将是坏的。但是,如果你想准确衡量浪费,那就是另一个问题。为此,您需要更多样本,以查看它们中包含该调用的百分比。或者,只需修复有罪的电话,计算加速时间,这将告诉你究竟什么是浪费。

答案 7 :(得分:0)

Pycscope这样做。我今天刚刚发现它,所以我不能说它有多好,但我尝试过的几个例子都非常好(虽然并不完美)。

https://pypi.python.org/pypi/pycscope/

您可以使用它来生成cscope文件,然后从编辑器(特别是VIM)生成cscope插件。我尝试将它与vanilla cscope一起使用,似乎普通的cscope感到困惑。