LuaJIT计算相关代码性能指引

一. 前言

  本文为luajit作者所写文章Numerical Computing Performance Guide的译文,属于个人记录。

二. 指引

Lua涉及到计算的时候,会有很多错误的应用导致程序性能受到较大影响,各种错误情况及对应处理方案如下。

  • 减少无法预知的分支数
    • 有极高可能性偏向一方的条件分支不会影响(95%以上)
    • 可以改用无分支的算法替换,如
      • 使用math.min()math.max()
      • 使用bit.*
  • 使用FFI数据结构
    • 使用int32_t,避免使用uint32_t类型
    • 使用double,避免使用float
    • 不要滥用元方法
  • 仅通过FFI调用C函数
    • 避免调用很小的函数,更好的做法是在Lua重写
    • 避免回调函数,使用推送(read/write)或者迭代器来代替
  • 使用诸如 for i=start,stop,step do ... end的循环语句
    • 数组索引也类似, e.g. a[i+2].
    • 避免使用指针计算
  • 展开适度
    • 避免循环量少的内联循环
    • 当且仅当循环体有太多指令时展开循环
    • 考虑使用模板代替手动展开(如GSL Shell)
  • 最好仅在模块(module)内定义并调用函数
  • 对于其他模块的函数,如果常用,则缓存为上值(upvalue)
    • 如,local sin = math.sin
    • 对于FFI C的函数不要这么做,缓存名字空间即可,如local lib = ffi.load("lib")
  • 避免自己创建派遣机制,而是改用系统自带的,如元方法
  • 不要过度优化,JIT编译器可能已经优化过了
    • 例如,z = x[a+b] + y[a+b]的写法是没有问题的,如果手动增加一个临时变量存放a+b,不仅不会提升性能,还会导致多占用了一个寄存器或者栈空间,得不偿失
    • 例如,a[i][j] = a[i][j] * a[i][j+1]也一样没有问题
    • 在使用LuaJIT的时候,这些细小的优化点编译器均帮忙做了更优的实现,程序员更需要关心的是更为宏大的优化,如算法复杂度的优化
  • 不同于C/JAVA,变量的声明和定义尽量放在要用的地方,而不是函数开头
  • 不要过度使用昂贵或未编译的操作
    • assert(type(x) == "number", "x is a "..mytype(x)"),该语句最大的问题在于字符串拼接,该操作无论断言是否生效均需要每次操作
    • 通过-jv/-jdump来看output确认是否有不需要的操作

参考文献

【1】Numerical Computing Performance Guide

坚持原创,坚持分享,谢谢鼓励和支持