找到 python 内置函数的调用者

find caller of python builtins

这类似于 Profiling in Python: Who called the function? ,但有所不同。 我有一个 python 函数,我正在使用 cProfile 进行分析。在我的第一个 运行 上,统计数据显示它的大部分时间都花在了 get_loc() 上,从 datetimes.py 开始;

好吧,我在我的系统上找到了 datetimes.py 文件并在 get_loc() 的顶部临时添加了 import pdbpdb.set_trace() 然后随机使用调试器命令 where 几次,在 where 之间有一个或多或少的随机数 continue。这向我表明,根据我的随机样本,几乎所有对 get_loc() 的数千次调用最终都来自我自己代码中的同一个地方。我修改了该代码以显着减少调用次数。太棒了!

接下来,我现在看到 超过 66,000builtins.isinstance() 调用花费了大量时间;问题是我找不到源代码来实现堆栈跟踪以找出调用的内容 isinstance()。 (根据我对 Python 的有限了解,我 猜测 isinstance 实际上是直接或通过共享对象链接到Python 翻译)。无论如何,我找不到调用的是isinstance。我尝试了 Gprof2dot 方法,该方法也在 Profiling in Python: Who called the function? 的答案中找到,但这只告诉我 isinstance() 正在被 is_dtype() 并且调用图停在那里(在 is_dtype)。

有什么想法吗?

我已经做了一些挖掘工作,并将尝试至少部分地回答我的问题(希望其他人能够看到并提供更多关于如何使这更容易的想法)。

下面是我如何分析我的函数

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 函数打印出 isinstance 的 130 个调用者,以及每个调用者调用 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)

在这一点上,我想我可以单调乏味地浏览最大的来电者(找到他们最大的来电者,等等)或编写脚本来完成。将继续挖掘和 post 以后的额外进展。