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