Content deleted Content added
dumb |
allow specifying a custom MinTimeTaken |
||
(13 intermediate revisions by the same user not shown) | |||
Line 1:
-- In-depth execution speed benchmarker - read the /doc for more info▼
-- =================================================================== --
▲-- In-depth execution speed benchmarker
-- Be careful including this module outside of sandboxes --
▲-- This is a meta-module that hooks lots of globals and can be disruptive --
-- =================================================================== --
-- Always use rawget/rawset on _G to bypass strict
if ActiveHooker ~= nil then
return false▼
return ActiveHooker
end
--== Personal stuff ==--
n = n or 4
return math.floor(x*10^n+0.5) / 10^n
end
local function GetVarargInfo(...)
return {...}, select("#", ...)
Line 29 ⟶ 33:
local CompleteCalls = {}
local FunctionCallStack = {}
local NoHookZone = {}
local function FinishUp()
-- Note: Don't currently use caller stats. Eh, whatever
local TotalTimeTaken = 0
local ModuleTotalTimes = {}
local FunctionTotalTimes = {}
local SeenModules = {}
local SeenFunctions = {}
for _, Call in next, CompleteCalls do
local CallTime = Call.TimeTaken - Call.Offset
TotalTimeTaken = TotalTimeTaken + CallTime
if not ModuleTotalTimes[Call.Origin] then
ModuleTotalTimes[Call.Origin] = 0
SeenModules[#SeenModules+1] = Call.Origin
end
ModuleTotalTimes[Call.Origin] = ModuleTotalTimes[Call.Origin] + CallTime
local UniqueName = Call.Origin .. "." .. Call.Name
if not FunctionTotalTimes[UniqueName] then
FunctionTotalTimes[UniqueName] = 0
SeenFunctions[#SeenFunctions+1] = UniqueName
end
FunctionTotalTimes[UniqueName] = FunctionTotalTimes[UniqueName] + CallTime
end
local MinTimeTaken = rawget(_G, "_MinTimeTaken") or 0.01
if TotalTimeTaken > MinTimeTaken then
table.sort(SeenModules, function(a, b)
return ModuleTotalTimes[a] > ModuleTotalTimes[b]
end)
table.sort(SeenFunctions, function(a, b)
return FunctionTotalTimes[a] > FunctionTotalTimes[b]
end)
mw.log("\n-- Benchmarker Finished --")
mw.log("Total time taken: " .. dp(TotalTimeTaken)*1000 .. "ms")
mw.log("\nTop 5 modules by time taken:")
for i = 1, math.min(5, #SeenModules) do
local t = dp(ModuleTotalTimes[SeenModules[i]])
mw.log(SeenModules[i] .. ": " .. t*1000 .. "ms (" .. dp(t/TotalTimeTaken, 3)*100 .. "%)")
end
mw.log("\nTop 5 functions by time taken:")
for i = 1, math.min(5, #SeenFunctions) do
local t = dp(FunctionTotalTimes[SeenFunctions[i]])
mw.log(SeenFunctions[i] .. ": " .. t*1000 .. "ms (" .. dp(t/TotalTimeTaken, 3)*100 .. "%)")
end
mw.log("") -- extra newline
end
CompleteCalls = {}
end
local function HookFunction(f, fname, origin)
if not NoHookZone[f] then
▲ return function(...)
local out = function(...)
local callerinfo = DetermineCaller(debug.traceback()) local StackObject = {
Name=fname, Origin=origin, Offset=0,
Caller=callerinfo.Function, CallLine=callerinfo.Line
}
FunctionCallStack[#FunctionCallStack+1] = StackObject
local s = os.clock()
local response, length = GetVarargInfo(f(...))
local timetaken = os.clock() - s
StackObject.TimeTaken = timetaken
CompleteCalls[#CompleteCalls+1] = StackObject
local maxi = #FunctionCallStack
FunctionCallStack[maxi] = nil
if maxi == 1 then
FinishUp()
else
FunctionCallStack[maxi-1].Offset = FunctionCallStack[maxi-1].Offset + timetaken
end
return unpack(response, 1, length)▼
end
NoHookZone[out] = true
▲ return unpack(response, 1, length)
return out
else
return f
end
end
local function HookTable(obj, origin)
-- safety catch since we export this function
if type(obj) == "function" then
return HookFunction(obj, "<main>", origin)
end
for a, b in next, obj do
if type(b) == "function" then
Line 65 ⟶ 121:
end
end
end
rawset(_G, "_BenchmarkerHooker", HookTable)
--== Global hooking ==--
Line 82 ⟶ 140:
rawset(_G, "require", hookedrequire)
return
|