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