上手示例

使用比较简单,直接看例子:

import cProfile
import timeline_window

cProfile.run('timeline_window.main()')

timeline_window 是我们要测试的模块,timeline_window.main() 是它的主函数。 执行完之后打印如下信息

C:\Python37\python.exe C:\Users\edison\PycharmProjects\DataViz\performace_test.py 
         865497 function calls (858749 primitive calls) in 2.977 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        4    0.000    0.000    0.000    0.000 <__array_function__ internals>:2(amax)
       19    0.000    0.000    0.001    0.000 <__array_function__ internals>:2(any)
       17    0.000    0.000    0.001    0.000 <__array_function__ internals>:2(argwhere)
        1    0.000    0.000    0.000    0.000 <__array_function__ internals>:2(array_equal)
     1603    0.001    0.000    0.005    0.000 <__array_function__ internals>:2(atleast_1d)
        6    0.000    0.000    0.000    0.000 <__array_function__ internals>:2(atleast_2d)
        6    0.000    0.000    0.000    0.000 <__array_function__ internals>:2(concatenate)
      811    0.001    0.000    0.001    0.000 <__array_function__ internals>:2(copyto)
        7    0.000    0.000    0.000    0.000 <__array_function__ internals>:2(empty_like)
      ...

每一行依次列出了各个子函数的运行分析信息:

  • ncalls 调用次数

  • tottime 在给定函数中花费的总时间(不包括调用子函数的时间)

  • percall tottime除以ncalls的商

  • cumtime 是在这个函数和所有子函数中花费的累积时间(从调用到退出)。

  • percall是cumtime除以原始调用次数的商

  • filename:lineno(function) 提供每个函数的各自信息

    保存性能数据

import cProfile
import timeline_window

cProfile.run('timeline_window.main()', 'restats')

性能数据的文件会保存到当前目录下的restats文件中。

查看性能数据

加载这些数据,可以进行后续的比较分析。

import pstats
from pstats import SortKey

# 加载保存到restats文件中的性能数据
p = pstats.Stats('restats')

# 打印所有统计信息
p.strip_dirs().sort_stats(-1).print_stats()

查看耗时最多的子函数

最常用的是,查看耗时最多的函数排序,比如前十个:

# 打印累计耗时最多的10个函数
p.sort_stats(SortKey.CUMULATIVE).print_stats(10)

# 打印内部耗时最多的10个函数(不包含子函数)
p.sort_stats(SortKey.TIME).print_stats(10)
Mon Dec  5 16:20:20 2022    restats

         42734012 function calls (42727371 primitive calls) in 43.122 seconds

   Ordered by: cumulative time
   List reduced from 2541 to 10 due to restriction <10>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    290/1    0.002    0.000   43.589   43.589 {built-in method builtins.exec}
        1    0.026    0.026   43.589   43.589 timeline_window.py:153(main)
        1    0.000    0.000   40.626   40.626 timeline_window.py:141(load_events_from_file)
        1    0.000    0.000   39.737   39.737 timeline_window.py:131(add_timestamps_scatter)
        1    0.010    0.010   39.722   39.722 timeline_scatter.py:80(set_events)
      801    0.005    0.000   39.419    0.049 PlotItem.py:597(addLine)
      803    0.012    0.000   39.309    0.049 PlotItem.py:521(addItem)
      808    0.008    0.000   39.286    0.049 ViewBox.py:402(addItem)
     1628    0.205    0.000   39.004    0.024 ViewBox.py:896(updateAutoRange)
     3231   10.849    0.003   38.744    0.012 ViewBox.py:1404(childrenBounds)

于是,我们找到了耗时的大头: 调用了 801 次耗时 39ms 的 PlotItem.py:597(addLine) 函数。

参考链接

教你3个python「性能分析」工具,再也不用自己计算函数耗时了