Module:Sandbox/Aidan9382/Benchmarker

This is an old revision of this page, as edited by Aidan9382 (talk | contribs) at 20:59, 21 March 2024 (dumb). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

-- 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