unity

  • Miku-LuaProfiler
    [✔️]lua性能分析工具原理简介

unreadl

  • ELuaProfiler
    [✔️]lua性能分析工具原理简介

lua_sethook

lua_sethook 函数用于给指定的 lua_State 设置钩子函数。它的函数原型为:

lua_Hook lua_sethook(lua_State *L, lua_Hook func, int mask, int count);

函数的参数含义如下:

  • L:要设置钩子函数的 lua_State。
  • func:钩子函数的实践函数,类型为 lua_Hook(typedef 定义的函数指针类型)。
  • mask:一个掩码,指定了要运用哪些类型的钩子。它由下面几个常量按位或组合而成:
    • LUA_MASKCALL:当 Lua 调用函数时产生。
    • LUA_MASKRET:当函数回来时产生。
    • LUA_MASLINE:当履行一行指令时产生。
    • LUA_MASKCOUNT:当 Lua 履行指定数量的指令时产生。
    • LUA_MASKALL:包括一切钩子类型。
  • count:钩子函数被调用的频率。关于 LUA_MASKCOUNT 钩子类型有特殊含义,指定了多少条指令后触发一次钩子函数。关于其他钩子类型,该参数可所以恣意整数。

在上述代码中,lua_sethook(L, myhook, LUA_MASKCOUNT, 1) 指定了运用 LUA_MASKCOUNT 类型的钩子,并将钩子函数 myhook 注册到 L 中,设定每履行一条 Lua 指令时,都会调用 myhook 一次。因此,当履行一行指令后,myhook 函数就会被调用一次,完成对 Lua 程序指令计数的操作。

需求注意的是,Lua 中的钩子机制需求细心设计,由于它可能会影响程序功用,乱用钩子功用可能会导致程序呈现难以调试或了解的问题。主张在运用钩子之前对钩子的运作原理进行深入研究,并充沛测验和验证代码的正确性。

lua_getinfo

lua_getinfo 函数用于获取指定调用层次上的函数信息。这个函数能够在钩子函数中运用,也能够在 Lua 中调用。以下是该函数的详细阐明:

int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);

该函数承受三个参数:

  • L:Lua 状态机。

  • what:一个字符串常量,表明要获取的信息。它由一系列控制字符组成,每个字符表明要获取的某一类信息。以下是可用的控制字符列表:

    • 'n':函数名。
    • 'S':Lua 源码文件名。
    • 'l':代码在源码文件中地点的行号。
    • 'f':函数地址。
    • 'L':当时层次的栈信息。
    • 'u'协程信息。
    • 't':关于主函数或尾调用的信息。
    • 'r':关于正在运行的函数的信息。

    其间,'n''S''l' 是最常用的控制字符。同时指定多个控制字符的方式是将它们组合在一起,例如 "Sln" 表明获取函数名、Lua 源码文件名和代码行号信息。

  • ar:一个 lua_Debug 结构体指针,用于存储获取到的信息。

该函数回来一个整数值表明操作是否成功。假如成功,回来 1;不然回来 0。假如传递了无效参数,例如 what 包含了未定义的控制字符,则回来 0。

在调用 lua_getinfo 函数后,假如获取到了所需信息,则这些信息会被存储在 lua_Debug 结构体中。例如:

lua_Debug ar;
lua_getinfo(L, "nSl", &ar);
std::cout << "function name: " << ar.name << std::endl;   // 函数名
std::cout << "source file name: " << ar.source << std::endl;  // 源码文件名
std::cout << "current line number: " << ar.currentline << std::endl;  // 当时行号

在以上示例中,我们经过将 "nSl" 作为 what 参数传递给 lua_getinfo 函数,来获取函数名、源码文件名和代码行号信息。注意,在获取某些信息(例如代码行号)时,你需求在 Lua 中敞开调试模式(经过 lua_sethook 函数完成)。此外,lua_getinfo 函数的效率较低,假如需求高效功用的话,主张仅获取必要的信息,并尽量减少调用次数。

注意:

运用 lua_getinfo 函数获取 Lua 函数信息时,该函数会将相关信息压入仓库中,这些信息以一个 Lua 表(table)的方式保存在仓库顶部。

验证代码

int size1 = lua_gettop(L); // 0
lua_getinfo(L, "Slnf", ar);
int size2 = lua_gettop(L); // 1

完成原理

大部分 Lua 功用剖析东西一般运用了以下几个接口

  1. lua_getinfo – 获取函数的信息。能够用于获取当时正在履行的函数的调用信息,包括当时履行的行号、文件名等。

  2. lua_sethook – 设置钩子函数。经过设置钩子函数能够在程序履行过程中插入额外的操作,例如收集履行时间、记录调用深度等。其间的 mask 参数能够根据需求挑选不同的钩子类型,例如调用、回来和行数。

  3. lua_toclose – 获取当时函数地点的履行环境。当调用栈的某一层被弹出时,会调用该函数来获得该层的上下文信息。

经过这些接口,功用剖析东西能够盯梢函数调用、捕获函数履行时间并输出相关信息,从而帮助开发人员发现程序瓶颈并优化功用。

除此之外,还有一些其他的 Lua 接口能够用于功用剖析,例如 lua_pcalllua_nextlua_pushstring 等。开发人员也能够根据自己的需求以及对 Lua 内部机制的深入了解,设计更加专业、高效的功用剖析东西。