欢迎来到 庞凤仪

又一个WordPress站点

虚幻世界【质分享】luahook获取lua性能!-西山居质量

2020-03-27 全部文章 305

【质分享】luahook获取lua性能!-西山居质量


luahook获取lua性能
?
本文作者:刘马良
背景
目前网络上出现的一些检测lua性能的开源工具,主要利用luahook技术,在lua进入退出函数设置hook,或在每行lua代码执行时安装hook,来得到某个函数或某行lua代码的执行开销。最近项目接触了这一部分内容,这里简单介绍下学到的一些点胡充华 。
龙枪编年史???
实现原理
lua源码实现中治丝益棼,在解释执行CALL指令和RET等luacode时独狼演员表,会调用安装的hook函数(假定已经调用sethook),在执行的luacode行号发生变化时,也会调用安装的hook函数。hook函数通过计算某个lua函数的CALL与RET两个时机的时间差,可以获取到某个lua函数的时间消耗;通过计算行与行之前的lua代码执行时间差王充求学,可以知晓某行lua代码的性能。
部分细节
这里都以函数级hook为例(行hook相似)。当某个lua函数被Call时mezco ,会进入我们安装的hook函数,该函数可以调用lua_getinfo来获取即将调用的lua函数信息,代码如下:
static void callhook(lua_State *L冥界傲君, lua_Debug *ar)
{
// 这部分为了后去究竟在哪行lua代码调用的该函数
if (lua_getstack(L, 1, &previous_ar) == 0) {
currentline = -1;
} else {
lua_getinfo(L, "l"虚幻世界 , &previous_ar);
currentline = previous_ar.currentline;
}
// 这里获取函数的信息
lua_getinfo(L川国演义, "nS", ar);
stackIndex = lua_gettop(L);
//printf("stacklevel = %d", S->stack_level);
if (!ar->event)
{

// do something..
}
else
{

// do something
}
}
lua_getinfo会“尽力”为我们找到待调用的函数信息,包括函数名、文件、定义的行号等等信息,这里“尽力”的意思是:它会进行符号查找,来找到该函数关联的信息古摄影官网,比如如果保存当前函数的寄存器是在前述指令中通过GETGLOBAL获取的,那么它会把GETGLOBAL时传递的key返回给我们,如果是一个局部变量,那么会返回该局部变量的名称(这部分逻辑尝试还挺多的,未全部细看)飞鱼秀。
lua_getinfo失效
很多项目会使用C和LUA混合编程,这时候lua和C交互时,可能会导致lua_getinfo无法找到函数信息,较为简单的例子为:
print("a")
该函数就可以出现lua_getinfo失效的情形。原因如下
{"print", luaB_print},
static int luaB_print (lua_State *L) {
int n = lua_gettop(L);
int i;
lua_getglobal(L, "tostring");
for (i=1; i<=n; i++) {
const char *s;
lua_pushvalue(L, -1);
lua_pushvalue(L千年敬祈 , i);
lua_call(L, 1, 1);
s = lua_tostring(L我的心好冷 , -1);
if (s == NULL)
return luaL_error(L, LUA_QL("tostring") " must return a string to "
LUA_QL("print"));
if (i>1)fputs("\t", stdout);
fputs(s, stdout);
lua_pop(L, 1);
}
fputs("\n", stdout);
return 0;
}
luaB_print中又调用了lua_call,会导致进入hook函数,此时就获取不到函数信息了(因为此时处在c代码中,没有lua函数信息)。如何处理呢?一般来说agopoe,我们的处理方式是:保存它的父函数名(前面加上called from),这样就所有的函数名都不为空了。但也存在缺陷水痘传染期,无法知道具体为哪个C函数(一般来说通过阅读lua代码可以解决这个问题),如果需要该真实信息,可以使用如下方法:
lua_getinfo(L, "nSf", ar);
char tmpBuf[100] = {0};
if(ar->source && strcmp(ar->source, "=[C]") == 0)
{
void* cfun = lua_tocfunction(L, -1);
Dl_info info;
dladdr(cfun, &info);
int xx = (int)((unsigned int)cfun - (unsigned int )info.dli_fbase);
sprintf(tmpBuf, "## %s %x %p %p \n", info.dli_fname, xx, cfun, info.dli_fbase );
}
lua_pop(L, 1);
lua_getinfo参数多传递一个f,这样就获取到了C函数的地址,dladdr就能获取到该函数的信息,配合addr2line或google breakpad就能得到C函数的所有信息(如果调试符号没被删除的话史旭霞 ,服务器程序一般来说会考虑保留符号)。
元方法会导致hook函数被调用
lua5中源码如下:
static void callTMres (lua_State *L, StkId res白金湾府邸 , const TValue *f萨弗隆战锤,黄天戈
const TValue *p1, const TValue *p2) {
ptrdiff_t result = savestack(L烈女斗夫, res);
setobj2s(L, L->top, f);
setobj2s(L, L->top+1, p1);
setobj2s(L豪门小情人 , L->top+2, p2);
luaD_checkstack(L, 3);
L->top += 3;
luaD_call(L, L->top - 3, 1);
res = restorestack(L, result);
L->top--;
setobjs2s(L, res, L->top);
}
由于调用了luaD_call娼妇凯蒂,该函数最终也会导致hook函数被调用。在访问table或userdata时,也许不禁意间hook到了一个函数调用。如下述lua代码:
local p = player.pos
如果最终获取pos是通过元方法调用实现,那么就会触发hook函数。
本文借鉴的代码来自开源项目:
https://github.com/GameBuildingBlocks/LuaProfilingTools
关于西山居质量
西山居质量Test+团队是金山西山居工作室的专业质量团队,对于游戏领域有超过18年的测试经验积累,专注于为手游、端游提供各类自动化测试等全方位质量保障。
西山居质量Test+团队主要为项目提供:崩溃信息收集和跟踪、远程手机调试服务、自动化的客户端/服务端性能优化服务以及全面的客户端/服务端测试服务。
长按指纹
一键关注

相关文章