DolphinDB即时编译(JIT)详解

本页介绍文章信息与引言背景,并概述 DolphinDB 与其对即时编译(JIT)的引入说明。

Source: https://dolphindb.cn/blogs/24

What this page covers

技能认证特训营第二期报名促销

页面顶部提供活动通知与限时报名链接,并强调专属福利优惠。

DolphinDB即时编译(JIT)详解(文章信息与引言)

本节给出文章标题、作者与发布日期,并引出 DolphinDB 与 JIT 的背景说明。

JIT简介

本节定义即时编译(JIT),对比编译执行与解释执行,并说明 JIT 的效率优势与常见应用。

JIT在DolphinDB中的作用(含性能对比与适用场景)

本节说明 DolphinDB 解释执行的开销,阐述 JIT 对循环与分支的加速效果,并用示例对比非JIT、JIT与向量化/内置函数性能。

如何在DolphinDB中使用JIT(方法、支持范围、缓存与局限)

本节介绍 @jit 的使用方式、支持的语句/运算符/函数、空值处理、JIT函数互调、LLVM 编译成本与缓存机制,以及当前局限。

类型推导

本节解释生成 LLVM IR 前需要类型推导,并通过示例说明推导成功/失败的原因与表现。

实例

本节通过隐含波动率、Greeks(Charm)与止损点(stoploss)示例展示 JIT 用法与性能对比。

未来计划

本节列出后续版本计划支持的能力扩展方向。

总结

本节重申 DolphinDB 为自定义函数提供 JIT 以提升循环与分支执行速度,并指出典型适用场景。

Facts Index

Entity Attribute Value Confidence
技能认证特训营第二期status正式开启并提供限时报名链接与专属福利优惠medium
限时报名链接urlhttps://www.qingsuyun.com/h5/e/217471/5/high
文章发布日期date2021-05-18high
文章作者署名nameJunxihigh
DolphinDBpositioning高性能分布式时序数据库,内置丰富的计算功能和强大多范式编程语言medium
DolphinDBJIT support introduced从 1.01 版本开始支持即时编译(JIT)high
即时编译(JIT)definition动态编译的一种形式,可提高程序运行效率high
编译执行characteristics程序执行前全部翻译为机器码,运行效率较高;以 C/C++ 为代表high
解释执行characteristics由解释器逐句解释并执行,灵活性强但执行效率较低;以 Python 为代表high
即时编译(JIT)mechanism运行时将代码翻译为机器码,可达到与静态编译语言相近的执行效率high
PyPyuses JIT for performancePython 的第三方实现 PyPy 通过 JIT 明显改善了解释器的性能medium
Java 实现uses JIT绝大多数 Java 实现依赖 JIT 提高代码运行效率medium
DolphinDB 编程语言执行方式execution_model解释执行:运行时先进行语法分析生成语法树,然后递归执行high
DolphinDB 解释执行成本cause在不能使用向量化情况下解释成本较高;脚本一次函数调用会转化为多次 C++ 内虚拟函数调用high
循环与分支语句在 DolphinDB 中的开销performance_issuefor/while/if-else 反复调用函数,十分耗时,某些场景不能满足实时性需求high
DolphinDB JITperformance_effect显著提高 for、while、if-else 等语句运行速度;适合无法向量化且对速度要求极高场景(如高频因子计算、实时流数据处理)high
do-while 求和示例(无 JIT)time_mstimer(100) sum_without_jit(vec) // 120552.740 mshigh
do-while 求和示例(JIT)time_mstimer(100) sum_with_jit(vec) // 290.065 mshigh
内置 sum 函数求和示例time_mstimer(100) sum(vec) // 48.922 mshigh
do-while 求和示例性能倍数ratio不使用 JIT 的耗时是使用 JIT 的 415 倍high
内置 sum 比 JIT 快的原因(无 NULL 时)reasonJIT 生成代码包含大量 NULL 检查指令;内置 sum 若发现输入 array 没有 NULL 值则会省略该步high
内置 sum(加入 NULL 后)time_msvec[100] = NULL; timer(100) sum(vec) // 118.063 mshigh
内置 sum 与 JIT 的相对速度(有 NULL 时)ratio加入 NULL 值后,内置 sum 的速度约为 JIT 的 2.5 倍(更快)medium
内置 sum 更快的原因(有 NULL 时)reason内置 sum 还进行了手动展开优化medium
JIT 与向量化的选择建议guidance若任务可向量化可视情况不使用 JIT;但将循环转为向量化需要技巧(如高频因子生成等应用)medium
知乎专栏(向量化运算示例)urlhttps://zhuanlan.zhihu.com/p/77988657high
买卖信号向量化表达式exampledirection = (iif(...) - iif(...)).ffill().nullFill(0h)high
for 循环改写向量化表达式的可读性observation对初学者而言,了解 iif 才能写出向量化语句;用 for 循环改写更容易medium
calculate_with_jit 示例uses_jit函数定义前使用 @jit,包含 for 循环与 if-else 分支,返回 output arrayhigh
信号计算示例(向量化)time_mstimer(100) 向量化表达式 // 41092.019 mshigh
信号计算示例(JIT)time_mstimer(100) calculate_with_jit(...) // 17075.127 mshigh
信号计算示例(非 JIT 循环版)time_mstimer(100) calculate_without_jit(...) // 1404406.413 mshigh
信号计算示例性能倍数(JIT vs 向量化)ratio使用 JIT 的速度是向量化运算的 2.4 倍medium
信号计算示例性能倍数(JIT vs 非JIT)ratio使用 JIT 的速度是不用 JIT 的 82 倍high
JIT 比向量化更快的原因(该示例)reason向量化调用多次内置函数产生中间结果,涉及多次内存分配与虚拟函数调用;JIT 生成代码没有这些额外开销high
期权隐含波动率计算(牛顿法)vectorization_applicability某些计算无法向量化(如牛顿法求隐含波动率),可选择 C++ 插件或使用 JITmedium
DolphinDB 插件链接urlhttps://github.com/dolphindb/DolphinDBPluginhigh
插件与 JIT 的差异comparison插件:任何场景可用但需 C++ 编写较复杂;JIT:编写更容易但适用场景有限;JIT 速度与 C++ 插件非常接近medium
DolphinDB JIT 支持范围scope目前仅支持对用户自定义函数进行 JIThigh
DolphinDB JIT 使用方式syntax在用户自定义函数前一行添加 @jit 标识:@jit def myFunc(/* arguments */) { /* implementation */ }high
DolphinDB JIT 执行方式behavior_on_call调用 JIT 函数时,系统将函数代码实时编译为机器码后执行high
DolphinDB JIT 支持的语句supported_statements赋值、return、if-else、do-while、for;并支持任意嵌套high
DolphinDB JIT 多重赋值not_supportedmultiple assign 不支持(示例 a, b = 1, 2 将抛出异常)high
DolphinDB JIT 支持的运算符supported_operatorsadd(+), sub(-), multiply(*), divide(/), and(&&), or(||), bitand(&), bitor(|), bitxor(^), eq(==), neq(!=), ge(>=), gt(>), le(<=), lt(<), neg(-), mod(%), seq(..), at([]);实现与非JIT一致high
DolphinDB JIT 支持的数学函数supported_math_functionsexp, log, sin, asin, cos, acos, tan, atan, abs, ceil, floor, sqrthigh
DolphinDB JIT 数学函数调用策略implementation_detail参数为 scalar 时调用 glibc 对应函数或优化的 C 实现;参数为 array 时调用 DolphinDB 提供的数学函数,以提升效率并减少虚拟函数调用与内存分配medium
DolphinDB JIT 支持的内置函数supported_builtinstake, array, size, isValid, rand, cdfNormalhigh
JIT 中 array 函数constraint第一个参数必须直接指定具体数据类型,不能通过变量传递指定;因为 JIT 编译时必须知道所有变量类型,array 返回类型由第一个参数决定high
JIT 空值处理null_handlingJIT 中所有函数和运算符处理空值方法与原生一致:每个数据类型用该类型的最小值表示空值,用户不需专门处理空值high
JIT 函数之间调用supportedJIT 函数可以调用另一个 JIT 函数high
JIT 函数互调的性能机制implementation_detail会先编译被调用函数生成 native 函数(示例签名 double myfunc1(double)),调用方机器码直接调用该 native 函数而非运行时判断,以达到最高执行效率medium
JIT 函数内部调用限制not_allowedJIT 函数内不可以调用非 JIT 的用户自定义函数,因为无法进行类型推导high
DolphinDB JIT 依赖dependency底层依赖 LLVM 实现high
LLVM 官网链接urlhttps://llvm.org/high
JIT 编译单元module_isolation每个用户自定义函数编译时生成自己的 module,相互独立high
JIT 编译步骤steps初始化 LLVM 相关变量和环境;根据语法树生成 LLVM IR;LLVM 优化 IR 并编译为机器码high
JIT 编译成本(初始化)time_ms第一步耗时一般在 5ms 以内medium
JIT 编译成本(总体)time_ms总体编译耗时基本在 50ms 以内(后两步与脚本复杂度成正比)medium
JIT 编译缓存compilation_cache对于一个 JIT 函数及一个参数类型组合,只编译一次;结果会缓存high
JIT 缓存查找机制mechanism根据调用时参数数据类型生成字符串,在哈希表中查找对应编译结果;存在则直接调用,不存在则编译并写入哈希表后执行high
JIT 适用任务类型when_beneficial对需要反复执行或运行时间远超编译耗时的任务,JIT 会显著提高运行速度high
DolphinDB JIT 当前局限(范围)limitations仅支持用户自定义函数 JIT;仅接受 scalar 和 array 参数(table/dict/pair/string/symbol 等暂不支持);不接受 subarray 作为参数high
类型推导necessity使用 LLVM 生成 IR 之前必须知道脚本中所有变量的类型(类型推导步骤)high
DolphinDB JIT 类型推导方式approach使用局部推导(通过赋值与表达式逐步确定变量与返回值类型)high
带参数函数的返回类型depends_on_inputJIT 函数返回类型可能依赖输入参数类型(示例 foo(x){return x+1})high
类型推导失败的结果runtime_effect函数内部出现不支持类型或输入类型不支持,会导致类型推导失败并在运行时抛出异常high
JIT 不支持的输入类型示例examplesSTRING、pair、tuple 等输入会抛出异常(示例 foo("abc"), foo(1:2), foo((1 2, 3 4, 5 6)))high
JIT 不支持的函数导致推导失败示例examplecumprod 尚不支持,无法得知返回类型导致类型推导失败(示例 foo 中使用 cumprod)high
使用 JIT 的建议(类型与函数)guidance避免在函数内或参数中使用 tuple/string 等未支持类型,不要使用尚不支持的函数medium
示例:计算隐含波动率(implied volatility)implemented_with_jit提供 GBlackScholes、ImpliedVolatility 与 test_jit 等 @jit 函数示例high
隐含波动率示例(JIT 版本)time_mstimer(10) test_jit(...) // 2621.73 mshigh
隐含波动率示例(非 JIT 版本)time_mstimer(10) test_non_jit(...) // 302714.74 mshigh
隐含波动率示例性能倍数ratioJIT 版本 test_jit 运行速度是非 JIT 版本 test_non_jit 的 115 倍high
Greeks 风险评估context量化金融中经常使用 Greeks 进行风险评估;示例以 Charm 展示 JIT 使用medium
Greeks(finance)参考链接urlhttps://link.zhihu.com/?target=https%3A//www.wikiwand.com/en/Greeks_%28finance%29high
示例:计算 Charm(Greeks)implemented_with_jit提供多个 @jit 函数(myMax、NormDist、ND、CalculateCharm、test_jit)并给出向量化对照实现high
Charm 示例(JIT 版本)time_mstimer(10) test_jit(...) // 1834.342 mshigh
Charm 示例(非 JIT 版本)time_mstimer(10) test_none_jit(...) // 224099.805 mshigh
Charm 示例(向量化版本)time_mstimer(10) CalculateCharm_vectorized(...) // 3117.761 mshigh
Charm 示例性能对比结论ratioJIT 版本比非 JIT 版本快 121 倍左右;比向量化版本快 0.7 倍左右medium
知乎专栏(技术信号回测)urlhttps://zhuanlan.zhihu.com/p/47236676high
示例:计算止损点(stoploss)implemented_with_jit提供 stoploss_JIT、stoploss_no_JIT 与 stoploss_vectorization 三种实现并对比耗时high
stoploss 示例(JIT 版本)time_mstimer(10) stoploss_JIT(...) // 58.674 mshigh
stoploss 示例(非 JIT 版本)time_mstimer(10) stoploss_no_JIT(...) // 14622.142 mshigh
stoploss 示例(向量化版本)time_mstimer(10) stoploss_vectorization(...) // 151.884 mshigh
stoploss 示例性能倍数ratioJIT 实现比向量化快约 1.5 倍;比非 JIT 快 248 倍左右high
stoploss 示例中的 break 支持not_supported示例注释表明 break 目前不支持(通过 i = n 方式替代)high
stoploss 末日触发情形的性能描述observation若最后一天才触发 stoploss,JIT 版本速度会与向量化一样,但远快于非 JITmedium
后续版本计划roadmap_items计划支持:for/do-while 中的 break/continue;dictionary 等结构与 string 等类型;更多数学统计函数;增强类型推导识别更多内置函数返回值类型;支持为参数/返回值/局部变量声明数据类型medium
文章总结的核心结论conclusionDolphinDB 为自定义函数提供 JIT,可显著提升 for/while/if-else 等语句运行速度,适合无法向量化且对速度要求极高场景(如高频因子计算、实时流数据处理)high