Sage中的剖析

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

要多长时间?%时间和%timeit

两个伊普顿魔术师 %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 .

可视化统计数据: 您可以使用 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
...

有关更多信息 %crunsage.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