7.5。关于 Numba Runtime 的注意事项
原文: http://numba.pydata.org/numba-doc/latest/developer/numba-runtime.html
Numba Runtime(NRT) 为 _nopython 模式 _ Python 子集提供语言运行时。 NRT 是一个带有 Python 绑定的独立 C 库。这允许在没有 GIL 的情况下使用 NPM 运行时功能。目前,NRT 中实现的唯一语言功能是内存管理。
7.5.1。内存管理
NRT 实现 NPM 代码的内存管理。它使用 _ 原子引用计数 _ 进行线程安全的确定性内存管理。 NRT 维护一个单独的MemInfo
结构,用于存储有关每个分配的信息。
7.5.1.1。与 CPython 合作
为了让 NRT 与 CPython 合作,NRT python 绑定提供了用于转换导出内存区域的 python 对象的适配器。当这样的对象用作 NPM 函数的参数时,会创建一个新的MemInfo
并获取对 Python 对象的引用。当 NPM 值返回到 Python 解释器时,将检查关联的MemInfo
(如果有)。如果MemInfo
引用 Python 对象,则会释放并返回基础 Python 对象。否则,MemInfo
将包装在 Python 对象中并返回。根据类型,可能需要额外的过程。
当前实现支持 Numpy 数组和任何缓冲区导出类型。
7.5.1.2。编译器方面的合作
NRT 引用计数要求编译器根据用法发出递增/递减操作。当引用计数降为零时,编译器必须在 NRT 中调用析构函数例程。
7.5.1.3。优化
允许编译器天真地发出递增/递减操作。它依赖于优化传递来删除冗余引用计数操作。
优化过程在块级别上运行以避免控制流分析。它取决于 LLVM 函数优化传递,以简化控制流,堆栈到寄存器和简化指令。它的工作原理是匹配和删除每个块中的 incrementf 和 decref 对。
7.5.1.4。怪癖
由于引用计数优化传递需要 LLVM 函数优化传递,因此传递在 LLVM IR 上作为文本工作。然后,优化的 IR 再次实现为新的 LLVM 内存中 bitcode 对象。
7.5.1.5。调试泄漏
要调试 NRT MemInfo 中的引用泄漏,每个 MemInfo python 对象都有一个.refcount
属性用于检查。要从 NRT 分配的 ndarray 获取 MemInfo,请使用.base
属性。
要调试 NRT 中的内存泄漏,numba.runtime.rtsys
定义.get_allocation_stats()
。它返回一个 namedtuple,它包含自程序启动以来的分配和释放次数。检查分配和释放计数器是否匹配是了解 NRT 是否泄漏的最简单方法。
7.5.1.6。调试 C 中的泄漏
numba / runtime / nrt.h 的开头有以下几行:
/* Debugging facilities - enabled at compile-time */
/* #undef NDEBUG */
#if 0
# define NRT_Debug(X) X
#else
# define NRT_Debug(X) if (0) { X; }
#endif
取消定义 NDEBUG(取消注释#undef NDEBUG
行)可以在 NRT 中启用断言检查。
启用 NRT_Debug(用#if 1
替换#if 0
)将打开 NRT 内的调试打印。
7.5.2。递归支持
在编译一对相互递归函数期间,其中一个函数将包含未解析的符号引用,因为编译器一次处理一个函数。在 LLVM 生成机器代码之前,未分解符号的存储器被分配并初始化为 _ 未解析符号中止 _ 函数(nrt_unresolved_abort
)的地址。在编译新函数时跟踪和解析这些符号。如果错误阻止了这些符号的解析,则将调用中止函数,从而引发RuntimeError
异常。
_ 未解析符号中止 _ 函数在 NRT 中定义为零参数签名。调用者可以安全地使用任意数量的参数调用它。因此,可以安全地用于预定的被叫者。
7.5.3。未来计划
NRT 的计划是创建一个可以链接到 Numba 编译代码的独立共享库,包括在 Python 解释器中使用而不需要 Python 解释器。为了做到这一点,我们将进行一些重构:
- numba NPM 代码引用“helperlib.c”中的静态编译代码。这些功能应该转移到 NRT。