调优 (Profile)

简介: 调优 (Profile)

除了调试,反射的另外一个常见用法是用于调优,即程序使用资源的行为分析。对于时间相关的调优,最好使用 C 接口,因为每次钩子调用函数开销太大从而可能导致测试结果无效。不过,对于计数性质的调优, Lua 代码就可以做的很好。本篇笔记将开发一个原始的性能调优工具来列出程序执行的每个函数的调用次数。


性能调优工具的主要数据结构是两个表,其中一个表将函数和他们的调用计数关联起来,另一个表关联函数和函数名。这两个表的索引都是函数自身:

local Counters = {}
local Names = {}


我们可以在性能分析完成后再获取函数的名称,但是如果能在一个函数F处于活跃状态时获取其名称可能得到更好的结果。这是因为:在函数 F 处于活动状态时, Lua 语言可以通过分析正在调用 F 的代码来找出函数 F 的名称。


现在,我们定义一个钩子函数,该钩子函数的任务是获取当前正在被调用的函数,并递增相应的计数器,再收集函数名,如下所示:

local function hook()
  local f = debug.getinfo(1, "f").func
  local count = Counts[f]
  if count == nil then
    Counters[f] = 1
    Names[f] = debug.getinfo(1, "Sn")
  else
    Counters[f] = count +1
  end
end


接下来,运行带有钩子的程序。假设我们要分析的程序位于一个文件中,且用户通过参数把改文件名传递给性能分析器,如下:

$ lua profiler main-prog


这样,性能分析器就可以从 arg[1] 中得到文件名、设置钩子并运行文件:

local f = assert(loadfile(arg[1]))
debug.sethook(hook, "c")    -- 设置call事件的钩子
f()                         -- 运行主程序
debug.sethook()             -- 关闭钩子


最后一步是显示结果,如下示例的函数 getname 为每个函数生成一个函数名:

function getname (func)
  local n = Names[func]
  if n.what == "C" then
    return n.name
  end
  local lc = string.format("[%s]:%d", n.short_src, n.linedefined)
  if n.what ~= "main" and n.namewhat ~= "" then
    return string.format("%s (%s)", lc, n.name)
  else
    return lc
  end
end


由于 Lua 语言中的函数名并不是特别确定,所以我们给每个函数再加上位置信息,以 file:line 这样的形式给出。如果一个函数没有名称,那么就只使用它的位置。如果函数是 C 函数,那么就只使用它的名称(因为没有位置)。在上述函数定义后,我们输出每个函数及其计数器的值:

for func, count in pairs(Counters) do
  print(getname(func), count)
end


对于这个性能分析器,还有几个地方可以改进。例如,可以输出进行排序、打印更易读的函数名和美化输出格式等。不过,这个原始的性能分析器本身已经是可用了。

目录
相关文章
|
JavaScript 安全 C++
打破约定俗成:其实Vue3的子组件也是可以“直接”改props的
为了避免混淆,先介绍一下后端语言用的类。一般类可以包含内部成员、属性、方法、事件等。内部成员一般都是私有的(其实也可以设置为公有),调用者不可以直接访问内部成员,而是要通过属性来访问内部成员。
打破约定俗成:其实Vue3的子组件也是可以“直接”改props的
|
9月前
|
消息中间件 RocketMQ
2024最全RocketMQ集群方案汇总
在研究RocketMQ集群方案时,发现网上存在诸多不一致之处,如组件包含NameServer、Broker、Proxy等。通过查阅官方文档,了解到v4.x和v5.x版本的差异。v4.x部署模式包括单主、多主、多主多从(异步复制、同步双写),而v5.x新增Local与Cluster模式,主要区别在于Broker和Proxy是否同进程部署。Local模式适合平滑升级,Cluster模式适合高可用需求。不同模式下,集群部署方案大致相同,涵盖单主、多主、多主多从等模式,以满足不同的高可用性和性能需求。
1282 0
|
存储 SQL 自然语言处理
LLM RAG系列
LLM RAG系列
353 1
|
9月前
|
开发工具 Docker 容器
Docker 镜像加速器配置指南
dockerhub加速器失败,使用第三方加速器
|
Linux 开发工具 Android开发
Android开发之——性能剖析器Profiler,赶紧学起来
Android开发之——性能剖析器Profiler,赶紧学起来
ly~
|
11月前
|
供应链 监控 搜索推荐
大数据的应用场景
大数据在众多行业中的应用场景广泛,涵盖金融、零售、医疗保健、交通物流、制造、能源、政府公共服务及教育等领域。在金融行业,大数据用于风险评估、精准营销、反欺诈以及决策支持;零售业则应用于商品推荐、供应链管理和门店运营优化等;医疗保健领域利用大数据进行疾病预测、辅助诊断和医疗质量评估;交通物流业通过大数据优化物流配送、交通管理和运输安全;制造业则在生产过程优化、设备维护和供应链协同方面受益;能源行业运用大数据提升智能电网管理和能源勘探效率;政府和公共服务部门借助大数据改善城市管理、政务服务及公共安全;教育行业通过大数据实现个性化学习和资源优化配置;体育娱乐业则利用大数据提升赛事分析和娱乐制作水平。
ly~
2289 2
|
人工智能 自然语言处理 API
人工智能大模型之开源大语言模型汇总(国内外开源项目模型汇总)
人工智能大模型之开源大语言模型汇总(国内外开源项目模型汇总)
人工智能大模型之开源大语言模型汇总(国内外开源项目模型汇总)
|
机器学习/深度学习 算法 Ubuntu
解读深大的视觉开源源码
这篇文章详细解读了深圳大学步兵视觉开源代码RP_Infantry_Plus,包括功能介绍、效果展示、依赖环境、整体框架、实现方案、通讯协议、配置与调试以及总结展望,提供了RoboMaster2019赛场上装甲板和小符文的识别方案,并通过自定义通讯协议将视觉处理信息发送给下位机。
解读深大的视觉开源源码
|
机器学习/深度学习 监控 算法框架/工具
用Python实现简单的图像分类器
用Python实现简单的图像分类器
263 0
|
Android开发
Android ViewModel+LiveData实现Fragment间通信详解
Android ViewModel+LiveData实现Fragment间通信详解
299 0