是否有可能使用line_profiler与Numba?
上饰有%lprun
函数调用@numba.jit
返回一个空的个人资料:
Timer unit: 1e-06 s
Total time: 0 s
File: <ipython-input-29-486f0a3cdf73>
Function: conv at line 1
Line # Hits Time Per Hit % Time Line Contents
==============================================================
1 @numba.jit
2 def conv(f, w):
3 f_full = np.zeros(np.int(f.size + (2 * w.size) - 2), dtype=np.float64)
4 for i in range(0, f_full.size):
5 if i >= w.size - 1 and i < w.size + f.size - 1:
6 f_full[i] = f[i - w.size + 1]
7 w = w[::-1]
8 g = np.zeros(f_full.size-w.size + 1, dtype=np.float64)
9 for i in range(0, f_full.size - w.size):
10 g[i] = np.sum(np.multiply(f_full[i:i+w.size], w))
11 return g
还有的用Cython代码的方法,但找不到任何Numba。
TL; DR:线路配置的是numba功能可能不是(在技术上)可能的,但即使是可能的线轮廓A numba函数的结果可能不准确。
这是复杂的使用与“编译”语言分析器(甚至在一定程度上与这取决于运行时允许做非编译语言),因为编译器被允许重写代码。仅举几个例子:constant folding,inline function calls,unroll loops(利用SIMD instructions的),hoisting,一般重新排序/重新排列表达式(甚至多行)。一般来说,编译器被允许,只要做任何事情的结果和副作用"as if"功能不是“优化”。
原理:
+---------------+ +-------------+ +----------+
| Source file | -> | Optimizer | -> | Result |
+---------------+ +-------------+ +----------+
这是一个问题,因为分析器需要插入语句插入代码,例如函数探查可能在开始和每个函数的开头插入一个说法,可能工作即使代码进行优化,内联函数 - 仅仅是因为在“探查声明”内联为好。但是如果一个编译器决定不内联,因为附加的探查语句的功能?那么你个人资料可能实际上是从如何“真实计划”将执行不同的。
例如,如果你有(我在这里,即使它不是编译使用Python,只是假设我在C写这样的程序或左右):
def give_me_ten():
return 10
def main():
n = give_me_ten()
...
然后,优化可以改写为:
def main():
n = 10 # <-- inline the function
但是,如果您插入探查语句:
def give_me_ten():
profile_start('give_me_ten')
n = 10
profile_end('give_me_ten')
return n
def main():
profile_start('main')
n = give_me_ten()
...
profile_end('main')
优化器可能只是发出相同的代码,因为它不内联函数。
一条线廓竟插入代码中的很多“探查声明”。比赛一开始,并在每个行的末尾。这可能会阻止很多编译器优化。我不是太熟悉的“为假设”规则,但我的猜测是,很多优化工作是不可能的呢。所以你用分析器编译的程序的行为从编译的程序显著不同而不探查。
例如,如果你有这样的程序:
def main():
n = 1
for _ in range(1000):
n += 1
...
优化器可以(不知道任何编译器会做到这一点),重写为:
def main():
n = 1001 # all statements are compile-time constants and no side-effects visible
但是,如果你有行剖析陈述,则:
def main():
profile_start('main', line=1)
n = 1
profile_end('main', line=1)
profile_start('main', line=2)
for _ in range(1000):
profile_end('main', line=2)
profile_start('main', line=3)
n += 1
profile_end('main', line=3)
profile_start('main', line=2)
...
再由“为假设”统治循环有副作用,不能凝结为单个语句(也许代码仍然可以优化,但不是作为一个单独的语句)。
请注意,这些都是简单的例子,编译器/优化通常是真正成熟,有很多可能的优化。
根据不同的语言,编译器和分析器有可能减轻这些影响。但是,这是不可能的面向Python的分析器(如线分析器)针对C / C ++编译器。
还要注意因为Python只是执行,这不是与Python一个真正的问题的程序真的一步一步(不是真的但是Python非常,很少改变你的“编写的代码”,然后仅在小的方面)。
+-------------+ +--------+ +----------+ +-----------+ +--------+
| Source file | -> | Cython | -> | C source | -> | Optimizer | -> | Result |
+-------------+ +--------+ +----------+ +-----------+ +--------+
+-------------+ +-------+ +------------------+ +--------+
| Source file | -> | Numba | -> | LLVM / Optimizer | -> | Result |
+-------------+ +-------+ +------------------+ +--------+
两者有一个编译器,可以进行广泛的优化。如果您将剖析语句到你的代码编译它之前很多优化将是不可能的。因此,即使它有可能行分析代码的结果可能不准确(在那个真正的程序将执行这样的意义上准确)。
线路分析器是为纯Python编写的,所以我不一定会相信对于用Cython / Numba输出,如果它的工作。它可能会提供一些提示,但总体而言,它可能只是太不精确。
特别是Numba可能是非常棘手的,因为numba翻译需要支持的分析报表(否则你最终会得到一个对象的模式numba功能,会产生完全不准确的结果),你的即时编译功能不只是一个功能了。它实际上是取决于参数的类型委托给一个“隐藏”功能的调度。所以,当你调用相同的“调度员”与int
或者它可以执行一个完全不同的功能float
。有趣的事实:与功能探查剖析的行为已经规定显著的开销,因为numba开发商想使这项工作(见cProfile adds significant overhead when calling numba jit functions)。
你应该有一个分析器,它可与翻译代码编译器的工作设定档。这些可以(可能)产生比Python代码编写的分析器更准确的结果。这将是更为复杂,因为这些廓线仪将返回有再次手动转移到原代码翻译代码的结果。此外,它可能甚至是不可能的 - 通常用Cython / Numba管理结果的翻译和编译和执行,所以你需要检查,如果他们提供额外的探查挂钩。我没有经验在那里。
而作为一个一般的规则:如果你有优化则始终将成型部作为“指南”并不一定是“事实”。并始终使用而设计的编译器/优化廓线仪,否则你会失去大量的可靠性和/或准确性。