LuaProfiler = {}
|
|
LuaProfiler.is_playing = false
|
|
|
|
function LuaProfiler.SwitchState()
|
|
LuaProfiler.is_playing = not LuaProfiler.is_playing
|
|
if LuaProfiler.is_playing then
|
|
LuaProfiler.start()
|
|
else
|
|
LuaProfiler.stop()
|
|
end
|
|
end
|
|
|
|
-- get the function title
|
|
function LuaProfiler._func_title(funcinfo)
|
|
|
|
-- check
|
|
assert(funcinfo)
|
|
|
|
-- the function name
|
|
local name = funcinfo.name or 'none_name'
|
|
|
|
-- the function line
|
|
-- print("_func_title = ", name)
|
|
local line = string.format("%d", funcinfo.linedefined or 0)
|
|
|
|
-- the function source
|
|
local source = funcinfo.short_src or 'C_FUNC'
|
|
-- if os.isfile(source) then
|
|
-- source = path.relative(source, xmake._PROGRAM_DIR)
|
|
-- end
|
|
|
|
-- make title
|
|
return string.format("%-30s: %s: %s", name, source, line), source
|
|
end
|
|
|
|
-- get the function report
|
|
function LuaProfiler._func_report(funcinfo)
|
|
|
|
-- get the function title
|
|
local title, source = LuaProfiler._func_title(funcinfo)
|
|
|
|
-- get the function report
|
|
local report = LuaProfiler._REPORTS_BY_TITLE[title]
|
|
if not report then
|
|
|
|
-- init report
|
|
report =
|
|
{
|
|
title = LuaProfiler._func_title(funcinfo)
|
|
, source = source
|
|
, callcount = 0
|
|
, totaltime = 0
|
|
}
|
|
|
|
-- save it
|
|
LuaProfiler._REPORTS_BY_TITLE[title] = report
|
|
table.insert(LuaProfiler._REPORTS, report)
|
|
end
|
|
|
|
-- ok?
|
|
return report
|
|
end
|
|
|
|
-- profiling call
|
|
function LuaProfiler._profiling_call(funcinfo)
|
|
|
|
-- get the function report
|
|
local report = LuaProfiler._func_report(funcinfo)
|
|
assert(report)
|
|
|
|
-- save the call time
|
|
report.calltime = os.clock()
|
|
|
|
-- update the call count
|
|
report.callcount = report.callcount + 1
|
|
|
|
end
|
|
|
|
-- profiling return
|
|
function LuaProfiler._profiling_return(funcinfo)
|
|
|
|
-- get the stoptime
|
|
local stoptime = os.clock()
|
|
|
|
-- get the function report
|
|
local report = LuaProfiler._func_report(funcinfo)
|
|
assert(report)
|
|
|
|
-- update the total time
|
|
if report.calltime and report.calltime > 0 then
|
|
report.totaltime = report.totaltime + (stoptime - report.calltime)
|
|
report.calltime = 0
|
|
end
|
|
end
|
|
|
|
-- the profiling handler
|
|
function LuaProfiler._profiling_handler(hooktype)
|
|
|
|
-- the function info
|
|
local funcinfo = debug.getinfo(2, 'nS')
|
|
-- print("_profiling_handler = ", hooktype)
|
|
-- dispatch it
|
|
if hooktype == "call" then
|
|
LuaProfiler._profiling_call(funcinfo)
|
|
elseif hooktype == "return" then
|
|
LuaProfiler._profiling_return(funcinfo)
|
|
end
|
|
end
|
|
|
|
-- the tracing handler
|
|
function LuaProfiler._tracing_handler(hooktype)
|
|
|
|
-- the function info
|
|
local funcinfo = debug.getinfo(2, 'nS')
|
|
|
|
-- is call?
|
|
if hooktype == "call" then
|
|
|
|
-- is xmake function?
|
|
local name = funcinfo.name
|
|
local source = funcinfo.short_src or 'C_FUNC'
|
|
if name then-- and os.isfile(source) then
|
|
|
|
-- the function line
|
|
local line = string.format("%d", funcinfo.linedefined or 0)
|
|
|
|
-- get the relative source
|
|
-- source = path.relative(source, xmake._PROGRAM_DIR)
|
|
|
|
-- trace it
|
|
print(string.format("%-30s: %s: %s", name, source, line))
|
|
end
|
|
end
|
|
end
|
|
|
|
-- start profiling
|
|
function LuaProfiler.start(mode)
|
|
|
|
-- trace?
|
|
if mode and mode == "trace" then
|
|
debug.sethook(LuaProfiler._tracing_handler, 'cr', 0)
|
|
else
|
|
-- init reports
|
|
LuaProfiler._REPORTS = {}
|
|
LuaProfiler._REPORTS_BY_TITLE = {}
|
|
LuaProfiler._CUSTOM_REPORTS = ""
|
|
print("----------------------------------------------->>LuaProfiler.start")
|
|
|
|
-- save the start time
|
|
LuaProfiler._STARTIME = os.clock()
|
|
|
|
-- start to hook
|
|
debug.sethook(LuaProfiler._profiling_handler, 'cr', 0)
|
|
end
|
|
end
|
|
|
|
-- stop profiling
|
|
function LuaProfiler.stop(mode)
|
|
|
|
-- trace?
|
|
if mode and mode == "trace" then
|
|
|
|
-- stop to hook
|
|
debug.sethook()
|
|
|
|
else
|
|
print("----------------------------------------------->>LuaProfiler.stop")
|
|
-- save the stop time
|
|
LuaProfiler._STOPTIME = os.clock()
|
|
|
|
-- stop to hook
|
|
debug.sethook()
|
|
|
|
-- calculate the total time
|
|
local totaltime = LuaProfiler._STOPTIME - LuaProfiler._STARTIME
|
|
print("totaltime = " , totaltime)
|
|
|
|
-- sort reports
|
|
table.sort(LuaProfiler._REPORTS, function(a, b)
|
|
return a.totaltime > b.totaltime
|
|
end)
|
|
|
|
-- show reports
|
|
local total_percent = 0
|
|
local class_list = {}
|
|
for _, report in ipairs(LuaProfiler._REPORTS) do
|
|
|
|
-- calculate percent
|
|
local percent = (report.totaltime / totaltime) * 100
|
|
total_percent = total_percent + percent
|
|
if percent < 0.1 then
|
|
break
|
|
end
|
|
local vo = class_list[report.source]
|
|
if vo == nil then
|
|
vo = {}
|
|
class_list[report.source] = vo
|
|
vo.totaltime = 0
|
|
vo.percent = 0
|
|
vo.callcount = 0
|
|
end
|
|
|
|
vo.totaltime = vo.totaltime + report.totaltime
|
|
vo.percent = vo.percent + percent
|
|
vo.callcount = vo.callcount + report.callcount
|
|
-- trace
|
|
local temp_str = string.format("totaltime = %6.3f, percent = %6.2f%%, count =%7d, pos = %s", report.totaltime, percent, report.callcount, report.title)
|
|
-- print(temp_str)
|
|
LuaProfiler._CUSTOM_REPORTS = LuaProfiler._CUSTOM_REPORTS .. temp_str .."\n"
|
|
end
|
|
|
|
print("----------------------------------------------->>class_list")
|
|
local new_list = {}
|
|
for k,v in pairs(class_list) do
|
|
v.source = k
|
|
table.insert(new_list, v)
|
|
end
|
|
table.sort(new_list, function(a, b)
|
|
return a.totaltime > b.totaltime
|
|
end)
|
|
|
|
for source, info in ipairs(new_list) do
|
|
local temp_str = string.format("totaltime = %6.3f, percent = %6.2f%%, count =%7d, pos = %s", info.totaltime, info.percent, info.callcount, info.source)
|
|
-- print(temp_str)
|
|
LuaProfiler._CUSTOM_REPORTS = LuaProfiler._CUSTOM_REPORTS .. temp_str .."\n"
|
|
end
|
|
end
|
|
end
|