Hello!
2014-12-23 19:17 GMT-08:00 李辉:
> 1. flame
> graph(使用lj-lua-stacks.sxx)的调用栈有时候会出现问题,比如在lj_alloc_free上方会出现content_by_lua的flame,这样一来调用关系就有点乱。
请确保你使用的是 LuaJIT 2.1,因为 lj-lua-stacks 工具是针对 LuaJIT 2.1 的。较新版本的
OpenResty 中自带的 LuaJIT 都是 v2.1 版本的。
如果不是因为使用了 LuaJIT 2.0 的缘故,请提供你原始的 SVG 格式的火焰图文件。
> 2. 使用lj-vm-states时,其结果是
> C Code (by interpreted Lua): 74% (5026 samples)
> Interpreted: 11% (803 samples)
> Compiled: 9% (612 samples)
> Garbage Collector (not compiled): 3% (205 samples)
> Garbage Collector (compiled): 0% (58 samples)
> Trace exiting: 0% (23 samples)
>
显然,只有极少数的热 Lua 代码路径被实际 JIT 编译;换言之,绝大部分的 CPU 时间都花在了解释执行的 Lua 代码上面。
>
> 根据文档的说法是,compiled的比例过低是存在优化的空间,但是问题是如何确定那部分代码是需要优化的。
有多种分析办法。
首先,可以使用 lj-lua-stacks 工具分别作出解释部分的 Lua 火焰图和 JIT 部分的 Lua
火焰图,这样你可以知道哪些热代码路径是解释执行的,哪些是 JIT编译过的。具体见其官方文档中对 --arg nojit=1 和 --arg
nointerp=1 这两个命令行选项的解释:
https://github.com/openresty/stapxx#lj-lua-stacks
更进一步地,可以使用 LuaJIT 自带的 jit.v 或者 jit.dump 模块进行分析。它们会给出 JIT 编译被中断(即 trace
abort)的具体位置和原因。例如可以这么配置:
init_by_lua '
local v = require "jit.v"
v.on("/tmp/v.log")
';
用足够多的请求预热之后,检查 /tmp/v.log 文件里的输出即可。
使用 jit.dump 可以得到更多的细节:
local dump = require "jit.dump"
dump.on("b", "/tmp/dump.log")
由于 LuaJIT 的 JIT 编译器并不支持所有的原语,所以当它遇见它不支持的原语(即 NYI)时,便会自动中断 JIT 编译过程。关于
LuaJIT 的 JIT 编译器不支持哪些原语,支持哪些原语,可以参见下面这一篇官方文档:
http://wiki.luajit.org/NYI
显然,LuaJIT 2.1 比 2.0 支持编译更多的原语。
> 有时候ffi调用,属于compiled,有时候则是C
> Code(测试了一个hash算法,ffi调用的),因此如何让c code变成compiled而不是C Code?
见上。
值得一提的是,使用 lua-resty-core 库可以让很多 ngx_lua 提供的 Lua API 变得可以被 JIT 编译。只需在
init_by_lua 里加一行 require "resty.core" 就 OK 了。
Regards,
-agentzh