Sage中的剖析

本页列出了Sage中可用来测量和分析一段代码性能的几种方法。有关分析的更多常规信息,请参见 :wikipedia:`Profiling_(computer_programming)`

需要多长时间?时间百分比和时间百分比

IPython的两个魔术 %time%timeit 测量运行命令所需的时间::

sage: %time p=random_prime(2**300)
CPU times: user 152 ms, sys: 0 ns, total: 152 ms
Wall time: 150 ms

sage: %timeit p=random_prime(2**300)
10 loops, best of 3: 62.2 ms per loop

请注意,虽然 %time 只运行该命令一次, %timeit 尝试在几次运行中返回更有意义的值。

有关详细信息,请参阅 %timeit? or this page

请注意,Sage提供了一个 timeit 功能,该功能也在Sage笔记本中运行。

Python级函数调用:%prun

使用 %prun ,您可以获得计算中涉及的所有Python函数的列表,以及每个函数所花费的时间:

sage: %prun  _=random_prime(2**500)
      468 function calls in 0.439 seconds

Ordered by: internal time

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    32    0.438    0.014    0.438    0.014 {method 'is_prime' of 'sage.rings.integer.Integer' objects}
    32    0.001    0.000    0.439    0.014 arith.py:407(is_prime)
    32    0.000    0.000    0.001    0.000 random.py:175(randrange)
    32    0.000    0.000    0.000    0.000 random.py:244(_randbelow)
 ...

最耗时的函数应该出现在顶部。不同列的说明如下 available here

备注

您可能希望对此列表进行不同的排序,例如:使用 %prun -s cumulative 用于减少累积时间。

或者,您可以将此数据“保存”到 Stats 进一步检查的对象::

sage: %prun -r random_prime(2**500)
sage: stats_object = _
sage: stats_object.total_calls
2547

有关详细信息,请参阅 %prun? or this page

Visualize the statistics: 您可以使用以下命令获得更图形化的输出 RunSnake 和Sage的功能 runsnake() **

sage: runsnake('random_prime(2**500)')

Python级别的逐行分析:%lprun

使用 line_profiler 以及它的 %lprun 神奇,您可以找出一个(或多个)函数的哪些行是最耗时的。语法如下:

%lprun -f function1 -f function2 code_to_run

这将显示逐行分析 function1function2 什么时候 code_to_run 已执行::

sage: %lprun -f random_prime random_prime(2**500)
Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
1193                                           def random_prime(n, proof=None, lbound=2):
...                                                ...
1251                                               # since we don't want current_randstate to get
1252                                               # pulled when you say "from sage.arith.all import *".
1253         1           11     11.0      0.0      from sage.misc.randstate import current_randstate
1254         1            7      7.0      0.0      from sage.structure.proof.proof import get_flag
1255         1            6      6.0      0.0      proof = get_flag(proof, "arithmetic")
1256         1           17     17.0      0.0      n = ZZ(n)
...

为了安装 line_profiler 您必须首先运行以下命令:

[user@localhost ~] sage -pip install "line_profiler"

C级函数调用:%crun

使用 %crun ,您可以获得计算中涉及的所有C函数的列表,以及在每个函数上花费的时间。你将需要有 the Google performance analysis tools 安装在您的系统上:

sage: %crun p=random_prime(2**500)
PROFILE: interrupts/evictions/bytes = 45/0/18344
Total: 45 samples
       0   0.0%   0.0%       35  77.8% PyEval_EvalCode
       0   0.0%   0.0%       35  77.8% PyEval_EvalCodeEx
       0   0.0%   0.0%       35  77.8% PyEval_EvalFrameEx
       0   0.0%   0.0%       35  77.8% PyObject_Call
       0   0.0%   0.0%       35  77.8% PyRun_StringFlags
       0   0.0%   0.0%       35  77.8% __Pyx_PyObject_Call.constprop.73
...

有关以下内容的更多信息 %crun ,见 sage.misc.gperftools

C级逐行分析:PERF(仅限Linux)

如果您的代码是用C语言或Cython语言编写的,您可以逐行找出使用最昂贵的代码 perf (包含在Ubuntu包中 linux-tools )。

使用它最简单的方法是在Sage中运行一些(非常长的)计算,然后在控制台中键入

[user@localhost ~] sudo perf top

选择您感兴趣的条目,然后按 Enter 。这个 annotate 命令将向您显示:

  • CPU指令

  • 源代码

  • 关联的时间

      │     *         cdef unsigned long word = (<unsigned long>1) << (v & self.radix_mod_mask)
      │     *         return (self.edges[place] & word) >> (v & self.radix_mod_mask)             # <<<<<<<<<<<<<<
      │     *
      │     *     cpdef bint has_arc(self, int u, int v) except -1:
      │     */
      │      __pyx_r = (((__pyx_v_self->edges[__pyx_v_place]) & __pyx_v_word) >> (__pyx_v_v & __pyx_v_self->radix_mod_mask));
10.88 │      movslq %esi,%rsi
 6.52 │      and    (%rdi,%rsi,8),%rax
12.84 │      shr    %cl,%rax

备注

  • 按下 s 切换源代码视图

  • 按下 H 循环浏览最热门的指令

  • 按下 h 寻求帮助

或者,如果您没有 sudo 权限,您可以将特定进程的统计信息记录到文件中 perf.data 从它的PID。然后,使用以下命令可视化结果 perf report

[user@localhost ~] perf record -p PID
[user@localhost ~] perf report --vmlinux vmlinux