最近把xmake的luaprofile从它那里抽出来单独使用,以防有时需要对lua api进行性能分析
module("profiler",package.seeall)
function profiler:start(mode)
if mode and mode == "trace" then
debug.sethook(profiler._traceing_handler,'cr',0)
else
self._REPORTS = {}
self._REPORTS_BY_TITLE = {}
self._STARTIME = os.clock()
debug.sethook(profiler._profiling_handler,'cr',0)
end
end
function profiler:stop(mode)
if mode and mode == "trace" then
debug.sethook()
else
self._STOPTIME = os.clock()
debug.sethook()
local totaltime = self._STOPTIME - self._STARTIME
table.sort(self._REPORTS,function(a,b)
return a.totaltime > b.totaltime
end)
for _,report in ipairs(self._REPORTS) do
local percent = (report.totaltime/ totaltime) * 100
if percent < 1 then
break
end
print(string.format("%.3f, %.2f%%, %d, %s", report.totaltime, percent, report.callcount, report.title))
end
end
end
function profiler._profiling_handler(hooktype)
local funcinfo = debug.getinfo(2,"nS")
if hooktype == "call" then
profiler:_profiling_call(funcinfo)
elseif hooktype == "return" then
profiler:_profiling_return(funcinfo)
end
end
function profiler._traceing_handler(hooktype)
local funcinfo = debug.getinfo(2,'nS')
if hooktype == "call" then
local name = funcinfo.name
local source = funcinfo.short_src or 'C_FUNC'
if name and os.isfile(source) then
local line = string.format("%d",funcinfo.linedefined or 0)
--source = path.relative(source,_PROGRAM_DIR)
--utils.print("%-30s: %s: %s", name, source, line)
print(string.format("%s: %s: %s", name, source, line))
end
end
end
function profiler:_profiling_call(funcinfo)
local stoptime = os.clock()
local report = self:_func_report(funcinfo)
assert(report)
report.calltime = os.clock()
report.callcount = report.callcount + 1
end
function profiler:_profiling_return(funcinfo)
local stoptime = os.clock()
local report = self:_func_report(funcinfo)
assert(report)
if report.calltime and report.calltime > 0 then
report.totaltime = report.totaltime + (stoptime - report.calltime)
report.calltime = 0
end
end
function profiler:_func_title(funcinfo)
assert(funcinfo)
local name = funcinfo.name or "anonymous"
local line = string.format("%d",funcinfo.linedefined or 0)
local source = funcinfo.short_src or "C_FUNC"
-- if os.isfile(source) then
-- source = path.relative(source,_PROGRAM_DIR)
-- end
return string.format("%s: %s: %s", name, source, line)
end
function profiler:_func_report(funcinfo)
local functitle = self:_func_title(funcinfo)
local report = self._REPORTS_BY_TITLE[functitle]
if not report then
report = {
title = functitle,
callcount = 0,
totaltime = 0,
}
self._REPORTS_BY_TITLE[functitle] = report
table.insert(self._REPORTS,report)
end
return report
end
return profiler