Files
gen1recomp/tests/drivers/hitch_profile.lua
T
2026-10-05 15:45:58 -04:00

101 lines
3.6 KiB
Lua

local INNER = assert(os.getenv("HITCH_INNER"), "HITCH_INNER=tests/drivers/<driver>.lua")
local LIMIT_MS = tonumber(os.getenv("HITCH_MS") or "8") or 8
local DEPTH = tonumber(os.getenv("HITCH_DEPTH") or "10") or 10
if os.getenv("HITCH_JIT") ~= "1" and jit then jit.off(); jit.flush() end
local okProf, profile = pcall(require, "jit.profile")
if os.getenv("HITCH_STACKS") == "0" then okProf = false end
local frame, stacks, vm, samples = 0, {}, {}, 0
local hitches, all, known = {}, {}, {}
local frameStart, stuckShown
local clock = love.timer.getTime
local function top(map, n)
local rows = {}
for k, v in pairs(map) do rows[#rows + 1] = { k, v } end
table.sort(rows, function(a, b) return a[2] > b[2] end)
local out = {}
for i = 1, math.min(n, #rows) do out[i] = rows[i] end
return out
end
if okProf then
profile.start("i1", function(th, n, state)
samples = samples + n
vm[state] = (vm[state] or 0) + n
local s = profile.dumpstack(th, "pl < ", DEPTH)
stacks[s] = (stacks[s] or 0) + n
if frameStart and clock() - frameStart > 5 and not stuckShown then
stuckShown = true
print("HITCH_STUCK " .. profile.dumpstack(th, "pl\n", 40))
end
end)
end
local function reset() stacks, vm, samples = {}, {}, 0 end
local baseUpdate, baseDraw = love.update, love.draw
local tu, td, kb0
love.update = function(dt)
frame = frame + 1
reset()
kb0 = collectgarbage("count")
local t = clock()
frameStart = t
baseUpdate(dt)
tu = (clock() - t) * 1000
end
love.draw = function()
local t = clock()
baseDraw()
td = (clock() - t) * 1000
local total = (tu or 0) + td
all[#all + 1] = total
if os.getenv("HITCH_STATUS") and frame % 60 == 0 then
local B = package.loaded["src.core.game3.battle"]
local T = package.loaded["src.core.game3.battle_transition"]
print(string.format("HITCH_STATUS frame=%d battle=%s phase=%s transition=%s",
frame, tostring(B and B.isActive and B.isActive()), tostring(B and B._phase),
tostring(T and T._transitionId)))
end
for name in pairs(package.loaded) do
if not known[name] then
known[name] = true
if frame > 1 then print(string.format("LAZY_REQUIRE frame=%d %s", frame, name)) end
end
end
if total >= LIMIT_MS then
local Map = package.loaded["src.core.game3.map"]
hitches[#hitches + 1] = total
print(string.format("HITCH frame=%d total=%.1fms update=%.1f draw=%.1f gcKB=%+.0f heapKB=%.0f map=%s samples=%d vm[N=%d I=%d C=%d G=%d J=%d]",
frame, total, tu or 0, td, collectgarbage("count") - (kb0 or 0), collectgarbage("count"),
tostring(Map and Map.current), samples, vm.N or 0, vm.I or 0, vm.C or 0, vm.G or 0, vm.J or 0))
for _, row in ipairs(top(stacks, 6)) do
print(string.format(" %3d %s", row[2], row[1]))
end
end
end
local quit = love.event.quit
love.event.quit = function(...)
table.sort(all)
local n = #all
local function p(q) return all[math.max(1, math.ceil(n * q))] or 0 end
print(string.format("HITCH_SUMMARY frames=%d hitches=%d p50=%.2f p95=%.2f p99=%.2f max=%.2f jit=%s",
n, #hitches, p(.5), p(.95), p(.99), all[n] or 0, tostring(jit and jit.status())))
local foreign = {}
for name in pairs(package.loaded) do
if name:find("^src%.[%w_]+%.gen2%.") or name:find("^src%.[%w_]+%.gen2$")
or name == "src.core.Game" or name == "src.core.Game2" or name == "src.world.OverworldController"
or name == "src.battle.BattleState" then
foreign[#foreign + 1] = name
end
end
table.sort(foreign)
print(string.format("FOREIGN_MODULES n=%d %s", #foreign, table.concat(foreign, " ")))
if okProf then profile.stop() end
return quit(...)
end
return assert(loadfile(INNER))()