Lua 虚拟机 C 函数级采样分析工具
把 Lua VM 内部 C 函数(如 luaH_getshortstr、luaH_newkey、internshrstr 等)的 CPU 消耗精确归因到 Lua 源码行,并输出完整调用栈。
perf 能看到 luaH_getshortstr 占 13% CPU,但看不到是哪些 Lua 代码在贡献这 13%。vLua 解决的就是这个问题。
- 精准,SIGPROF 定时采样 + PC 范围判断,只在目标 C 函数执行时捕获 Lua 调用栈
- 轻量,100Hz 采样下 overhead ≈ 0.03%,可长期常开
- 安全,signal handler 内就地解析,ring buffer 只存值类型不存指针;SIGSEGV trampoline 兜底,热更期间不会崩
- 兼容,输出 pLua 格式的 .pro 文件,可直接用 pprof、火焰图 工具链分析
- 灵活,目标函数名作为参数传入,可以分析任意 Lua VM 内部 C 函数
./build.sh输出 bin/libvlua.so 及 tools/vlua、tools/png。
local v = require "libvlua"
-- 参数1:要采样的 C 函数名
-- 参数2:采样结果文件(pLua 兼容的二进制格式)
v.start("luaH_getshortstr", "call.pro")
do_some_thing()
-- 结束采样,返回文本摘要报告
local text = v.stop()
print(text)或者用 hookso 注入
# a) 获取进程中的 lua_State 指针,比如进程的 xxx.so 调用了 lua_settop(L),取第一个参数
./hookso arg $PID xxx.so lua_settop 1
# 输出: 123456
# b) 加载 libvlua.so
./hookso dlopen $PID ./libvlua.so
# c) 开启采样,等价于 lrealstart(L, "luaH_getshortstr", "./call.pro")
./hookso call $PID libvlua.so lrealstart i=123456 s="luaH_getshortstr" s="./call.pro"
# d) 关闭采样,等价于 lrealstop(L)
./hookso call $PID libvlua.so lrealstop i=123456cd tools
./show.sh ../test或手动:
./vlua -i call.pro -pprof call.prof
./pprof --collapsed call.prof 2>/dev/null > call.fl
./flamegraph.pl call.fl > call.svg模拟 table get-by-string 热点场景(深嵌套 player.role.battle.stat.kill 等链式访问),采样 luaH_getshortstr:
Top hotspots (source:line -> count, pct of analysable)
count pct location
152 31.67% @test_getstr.lua:24 -- calc_damage: player.role.battle.weapon.damage = ...
131 27.29% @test_getstr.lua:36 -- update_kill: player.role.battle.stat.kill = ...
63 13.12% @test_getstr.lua:49 -- update_pos: player.role.pos.y = ...
57 11.88% @test_getstr.lua:48 -- update_pos: player.role.pos.x = ...
42 8.75% @test_getstr.lua:30 -- calc_ammo: player.role.battle.weapon.ammo = ...
18 3.75% @test_getstr.lua:42 -- update_death: player.role.battle.stat.death = ...
17 3.54% @test_getstr.lua:55 -- check_bag: player.role.bag.capacity
...
- 二进制不要
strip,luaH_getshortstr等 static 符号只在.symtab中- 验证:
nm <binary> | grep luaH_getshortstr
- 验证:
- 热更期间可以常开,不会崩(三层防护:值类型 Sample + 指针校验 + SIGSEGV trampoline)
- 当前假设单 Lua VM(
g_L),多 lua_State 场景需要扩展
