chroma_solstice/profiler.lua

60 lines
2 KiB
Lua
Raw Permalink Normal View History

2026-08-12 00:12:34 -04:00
-- Developer-only CPU sampler. It is inert until F9 is pressed.
--
-- On stop it writes `chroma-solstice.folded` in LÖVE's save directory. The
-- file uses Brendan Gregg's folded-stack format and can be given directly to
-- FlameGraph's flamegraph.pl.
PerfProfiler = {
active = false,
samples = {},
status = "F9: start CPU profile",
}
local ok, profile = pcall(require, "jit.profile")
PerfProfiler.available = ok
if not ok then
PerfProfiler.status = "LuaJIT sampler unavailable"
end
local function sample(thread, count, vmstate)
-- Negative depth produces caller -> callee order, which is what folded
-- flamegraphs expect. Function-level samples keep the output compact.
local stack = profile.dumpstack(thread, "pF;", -64):gsub(";$", "")
if stack ~= "" then
PerfProfiler.samples[stack] = (PerfProfiler.samples[stack] or 0) + count
end
end
function PerfProfiler:toggle()
if not self.available then return false end
if not self.active then
self.samples = {}
profile.start("fi2", sample)
self.active = true
self.status = "CPU profile recording (F9 to write)"
return true
end
profile.stop()
self.active = false
local lines, sampleCount = {}, 0
for stack, count in pairs(self.samples) do
table.insert(lines, stack .. " " .. count)
sampleCount = sampleCount + count
end
table.sort(lines)
local path = "chroma-solstice.folded"
local saved = love.filesystem.write(path, table.concat(lines, "\n") .. "\n")
local directory = love.filesystem.getSaveDirectory()
self.status = saved and ("CPU profile saved (" .. sampleCount .. " samples); see terminal")
or "Could not write CPU profile"
if saved then print("CPU profile: " .. directory .. "/" .. path) else print(self.status) end
return saved
end
function PerfProfiler:draw()
if not self.active and self.status == "F9: start CPU profile" then return end
love.graphics.setColor(self.active and 1 or 0.6, self.active and 0.75 or 1, self.active and 0.2 or 0.6, 1)
love.graphics.print(self.active and "PROFILING: F9 to save flamegraph data" or self.status, 10, 28)
love.graphics.setColor(1, 1, 1, 1)
end