From 877560cb58f54e441040bb5ac98258785419906e Mon Sep 17 00:00:00 2001 From: omicron Date: Thu, 27 Jul 2023 13:18:29 +0200 Subject: [PATCH] Rework profiler for 10.1.0 Since GetFunctionCPUUsage was removed in 10.1.0 the entire profler stopped working. This has been replaced by wrapping the functions in a closure that runs GetTimePreciseSec before and after and keeps track of the total runtime per function. --- src/profiler.lua | 133 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 96 insertions(+), 37 deletions(-) diff --git a/src/profiler.lua b/src/profiler.lua index 090f0e5..99e9657 100644 --- a/src/profiler.lua +++ b/src/profiler.lua @@ -1,7 +1,7 @@ -- Copyright 2023 -- -- This file is part of Omicron Frames --- +-- -- Omicron Frames is free software: you can redistribute it and/or modify it -- under the terms of the GNU General Public License as published by the Free -- Software Foundation, either version 3 of the License, or (at your option) @@ -13,7 +13,7 @@ -- more details. -- -- You should have received a copy of the GNU General Public License along with --- Omicron Frames. If not, see . +-- Omicron Frames. If not, see . local addonName, omi = ... -- Profiler is only active if the optional Commander dependency is included @@ -26,56 +26,115 @@ local Printf = Commander.Printf local types = omi.GetModule("types") local data = {} +local startTime +local stopTime +local functionTimers = {} +local functionNames = {} + +-- Permanently wrap all functions to do profiling +local function EnableFunctionProfiler() + if #functionTimers ~= 0 then + return + end + local GetTimePreciseSec = GetTimePreciseSec + local counter = 1 + for typeName, T in pairs(types) do + if type(T) == "table" then + PrintLn("Type:", typeName, T) + for fnName, fn in pairs(T) do + if type(fn) == "function" then + local fnIdx = counter + counter = counter + 1 + local name = string.format("%s:%s", typeName, fnName) + functionTimers[fnIdx] = 0 + functionNames[fnIdx] = name + local wrapped = function(...) + local start = GetTimePreciseSec() + local a, b, c, d, e, f, g, h = fn(...) + local elapsed = GetTimePreciseSec() - start + functionTimers[fnIdx] = functionTimers[fnIdx] + elapsed + return a, b, c, d, e, f, g, h + end + T[fnName] = wrapped + end + end + end + end +end + +-- Set all function timers back to 0 +local function ResetFunctionProfiler() + for i, _ in ipairs(functionTimers) do + functionTimers[i] = 0 + end +end Commander.RegisterCommand("omi-pstart", { - description="Start/reset the OmicronFrames profiler", - command=function() + description = "Start/reset the OmicronFrames profiler", + command = function() local profiler = C_CVar.GetCVar("scriptProfile") - if profiler ~= "1" then - PrintLn("scriptProfiler is off") - PrintLn("set it to on with `/console scriptProfile 1`, then reload the UI.") + PrintLn("OmicronFrames: start profiling") + EnableFunctionProfiler() + ResetFunctionProfiler() + startTime = GetTimePreciseSec() + stopTime = nil + if profiler == "1" then + ResetCPUUsage() + else + PrintLn("WoW scriptProfiler is off. Addon totals will not be shown,") + PrintLn("only individual functions.The profiler will not show total") + PrintLn("addon time, only function profiler.") + PrintLn("") + PrintLn("To enable the script profiler run `/console scriptProfile 1`, then reload the UI.") return end - PrintLn("OmicronFrames: start profiling") - ResetCPUUsage() end }) Commander.RegisterCommand("omi-pstop", { - description="Stop the OmicronFrames profiler", - command=function() - PrintLn("OmicronFrames: stop profiling") - UpdateAddOnCPUUsage() - local total = GetAddOnCPUUsage(addonName) - data = {{ - name = "Total OmicronFrames time", - time = total, - pct = 1.0 - }} - - for typeName, T in pairs(types) do - if type(T) == "table" then - for fnName, fn in pairs(T) do - if type(fn) == "function" then - local time = GetFunctionCPUUsage(fn, true) - table.insert(data, { - name = string.format("%s:%s", typeName, fnName), - time = time, - pct = time/total - }) - end - end - end + description = "Stop the OmicronFrames profiler", + command = function() + if not startTime then + PrintLn("Profiling not started. Run omi-pstart first.") + return end - table.sort(data, function(a, b) return a.time > b.time end) + PrintLn("OmicronFrames: stop profiling") + local profiler = C_CVar.GetCVar("scriptProfile") == "1" + data = {} + stopTime = GetTimePreciseSec() + if profiler then + UpdateAddOnCPUUsage() + local total = GetAddOnCPUUsage(addonName) + table.insert(data, { + name = "Total OmicronFrames time", + time = total, + }) + end + for i, time in ipairs(functionTimers) do + local name = functionNames[i] + table.insert(data, { + name = name, + time = time * 1000, + }) + end + table.sort(data, function(a, b) return a.time < b.time end) end, }) Commander.RegisterCommand("omi-pprint", { - description="Print the collected OmicronFrames profiling data", - command=function() + description = "Print the collected OmicronFrames profiling data", + command = function() + if not stopTime then + PrintLn("Profiling data not collected yet. Run omi-pstop first.") + return + end + local top = data[#data].time + local total = stopTime - startTime for _, item in ipairs(data) do - Printf("% 5.1f%% % 5fms %s\n", item.pct*100, item.time, item.name) + local time = item.time + local pct = time / top * 100 + local ms_per_sec = time / total + Printf("% 6.1f%% % 7.2fms %7.2fms/s %s\n", pct, time, ms_per_sec, item.name) end end })