![]() | This module is rated as alpha. It is ready for third-party input, and may be used on a few pages to see if problems arise, but should be watched. Suggestions for new features or changes in their input and output mechanisms are welcome. |
A module benchmarker aimed at benchmarking at a wider scope and reliably. This differs from the standard MediaWiki Lua Profile in that it profiles specifically exported module functions instead of every function (e.g. standard string library functions). This lets you figure out what module is making expensive calls rather than what expensive calls are being made.
Usage
To benchmark a module and all submodules it calls, put local __prepare = require("Module:Sandbox/Aidan9382/Benchmarker")
on the first line and __prepare(p, "<Module name>")
(or the equivilant to p) at the very bottom just before the return in the highest level module you want to benchmark from. You do not need to include the benchmarker in any other modules; any module fetched using require
will automatically have its returned value hooked.
Example output
-- Benchmarker Finished -- Total time taken: 91.1ms Top 5 modules by time taken: Module:Pagetype/sandbox: 55.7ms (61.1%) Module:Wikitext Parsing: 25.5ms (28%) Module:WikiProject banner/sandbox: 7.8ms (8.6%) Module:Template parameter value: 1.9ms (2.1%) Module:Arguments: 0.2ms (0.2%) Top 5 functions by time taken: Module:Pagetype/sandbox._main: 55.7ms (61.1%) Module:Wikitext Parsing.PrepareText: 25.5ms (28%) Module:WikiProject banner/sandbox._main: 7.4ms (8.1%) Module:Template parameter value.getValue: 1ms (1.1%) Module:Template parameter value.getTemplate: 1ms (1.1%)
-- This is TODO, expect stuff to combust on use
-- In-depth execution speed benchmarker
-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --
-- This is a meta-module that hooks lots of globals and can be disruptive --
-- Avoid using this outside of "Show preview" testing and sandboxes --
-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --
-- Always use rawget/rawset on _G to bypass strict
if rawget(_G, "_BenchmarkerActive") ~= nil then
return false
end
rawset(_G, "_BenchmarkerActive", true)
--== Personal stuff ==--
local function GetVarargInfo(...)
return {...}, select("#", ...)
end
local function DetermineCaller(stacktrace)
for line in stacktrace:gmatch("[^\n]+") do
if not line:find("^stack traceback:") and not line:find("Aidan9382/Benchmarker") then
local f, l = line:match("^%s*([^:]+):([^:]+)")
return {Function=f, Line=tonumber(l)}
end
end
end
local CompleteCalls = {}
local FunctionCallStack = {}
local function FinishUp()
mw.log("TODO!")
mw.logObject(CompleteCalls)
CompleteCalls = {}
end
local function HookFunction(f, fname, origin)
return 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
end
local function HookTable(obj, origin)
for a, b in next, obj do
if type(b) == "function" then
obj[a] = HookFunction(b, a, origin)
end
end
end
--== Global hooking ==--
local require = require
local function hookedrequire(source)
local out = require(source)
if source ~= "strict" and source ~= "Module:Sandbox/Aidan9382/Benchmarker" then
if type(out) == "table" then
HookTable(out, source)
elseif type(out) == "function" then
out = HookFunction(out, "<main>", source)
end
end
return out
end
rawset(_G, "require", hookedrequire)
return true -- Nothing to return