查找 Python 内置函数的调用者

3
这与Python中的分析:谁调用了函数?类似,但有一个小变化。我正在使用cProfile对Python函数进行分析。在第一次运行时,统计数据显示它大部分时间都花在了datetimes.py中的get_loc()上。好吧,我在系统上找到了datetimes.py文件,并在get_loc()顶部临时添加了import pdbpdb.set_trace(),然后随机使用调试器命令where多次,其中夹杂着更多或者更少的continue。这向我展示了,根据我的随机样本,几乎所有对get_loc()的数千次调用最终都来自于我的代码中的同一位置。我修改了那段代码以显著减少调用次数。太好了!
接下来,我发现在超过 66,000 次调用 builtins.isinstance() 中花费了大量时间;问题是我找不到源代码来实现堆栈跟踪以找出是谁在调用 isinstance()。(根据我对 Python 的有限了解,我猜想 isinstance 实际上是 C 代码,直接或通过共享对象链接到 Python 解释器中)。无论如何,我找不到谁在调用 isinstance。我尝试了 Profiling in Python: Who called the function? 答案中还发现的 Gprof2dot 方法,但那只显示了 isinstance() 被 is_dtype() 调用,并且调用图在此处停止(在 is_dtype 处)。
有什么想法吗?
1个回答

2
我进行了一些调查,并将尝试至少部分回答我的问题(希望其他人能看到并提供更多的想法来使其更容易)。以下是如何对我的函数进行分析:

这是如何分析我的函数的方式

pr = cProfile.Profile()                # create a cProfiler object 
pr.enable()                            # turn profiling on
pr.runcall( myfunc, arg1, arg2, ... )  # profile my function
pr.disable()                           # turn profiling off

然后,这里是找到呼叫者的关键:
import pstats
p = pstats.Stats(pr)           # create pstats obj based on profiler above.
p.print_callers('isinstance')  # find all the callers of isinstance.

print_callers函数打印出130个isinstance的调用者,以及每个调用者调用isinstance的次数。这是很多信息需要消化,但为了进行性能分析,有意义的是关注那些调用最多的几个,并找到它们的调用者。以下是列表的一部分(print_callers以大致随机的顺序呈现,但我在此基础上根据调用次数对它们进行了排序)...

Function {built-in method builtins.isinstance} was called by...
                                           ncalls  tottime  cumtime
                                             2808    0.002    0.002  /anaconda3/lib/python3.7/site-packages/pandas/core/indexes/datetimes.py:974(get_loc)
                                             2158    0.006    0.018 /anaconda3/lib/python3.7/site-packages/pandas/core/dtypes/base.py:75(is_dtype)
                                             2030    0.001    0.001  /anaconda3/lib/python3.7/site-packages/pandas/core/dtypes/common.py:1845(_is_dtype_type)
                                             1930    0.001    0.001  /anaconda3/lib/python3.7/site-packages/pandas/core/dtypes/common.py:1981(pandas_dtype)
                                             1440    0.001    0.001  /anaconda3/lib/python3.7/site-packages/pandas/core/dtypes/dtypes.py:68(find)
                                             1058    0.001    0.001  /anaconda3/lib/python3.7/site-packages/pandas/core/indexes/datetimes.py:924(get_value)
                                              841    0.000    0.000  /anaconda3/lib/python3.7/site-packages/pandas/core/dtypes/common.py:1809(_get_dtype)
                                              726    0.000    0.000  /anaconda3/lib/python3.7/site-packages/pandas/core/dtypes/common.py:1702(is_extension_arr
...
                                                6    0.000    0.000  /anaconda3/lib/python3.7/site-packages/pandas/core/indexing.py:153(_get_setitem_indexer)
                                                5    0.000    0.000  /anaconda3/lib/python3.7/site-packages/pandas/core/ops.py:1660(wrapper)
                                                5    0.000    0.000  /anaconda3/lib/python3.7/site-packages/pandas/core/ops.py:1447(_align_method_SERIES)
                                                5    0.000    0.000 /anaconda3/lib/python3.7/site-packages/pandas/core/computation/expressions.py:163(_has_bool_dtype)
                                                4    0.000    0.000 /anaconda3/lib/python3.7/site-packages/pandas/core/internals/blocks.py:3100(_extend_blocks)
                                                4    0.000    0.000  /anaconda3/lib/python3.7/site-packages/pandas/core/indexing.py:2501(check_setitem_lengths)
                                                3    0.000    0.000  /anaconda3/lib/python3.7/site-packages/pandas/core/indexes/base.py:566(_shallow_copy)
                                                3    0.000    0.000  /anaconda3/lib/python3.7/site-packages/pandas/core/dtypes/common.py:702(is_datetimelike)
                                                3    0.000    0.000  /anaconda3/lib/python3.7/posixpath.py:41(_get_sep)
                                                2    0.000    0.000  /anaconda3/lib/python3.7/distutils/version.py:331(_cmp)

目前,我认为我可以冗长地列举最大的调用者(找到他们的最大调用者,以此类推),或编写一个脚本来完成。将继续挖掘并稍后发布进展。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接