This function takes a workload and chips away at it, moving to the next frame after a budgeted amount of time. The budget is set to 50% of the target FPS, or 50% of the current FPS (if there is no target).
Better alternatives might check after X iterations, or sample the frame rate at more than a single point and maybe average it out.
Lua Code:
-- Budgets 50% of target or current FPS to perform a workload.
-- finished = start(workload, onFinish, onDelay)
-- Arguments:
-- workload table Stack (last in, first out) of functions to call.
-- onFinish function? Optional callback when the table is empty.
-- onDelay function? Optional callback each time work delays to the next frame.
-- Returns:
-- finished boolean True when finished without any delay; false otherwise.
local function start(workload, onFinish, onDelay)
local maxDuration = 500/(tonumber(C_CVar.GetCVar("targetFPS")) or GetFrameRate())
local startTime = debugprofilestop()
local function continue()
local startTime = debugprofilestop()
local task = tremove(workload)
while (task) do
task()
if (debugprofilestop() - startTime > maxDuration) then
C_Timer.After(0, continue)
if (onDelay) then
onDelay()
end
return false
end
task = tremove(workload)
end
if (onFinish) then
onFinish()
end
return true
end
return continue()
end
And here is the testing code I used to make sure it works...
Lua Code:
-- Simple testing code
-- /sillyloop Runs a brief atomic workload (same as /sillyloop 1)
-- /sillyloop 0 Runs an empty workload
-- /sillyloop 10000 Runs a long workload with 10000 parts
-- This overwrites existing workloads, so call /sillyloop to stop an ongoing workload
local workload = {}
local function sillyLoop()
local x=1
for i=1, 10000 do
x = x+1+2+3+4+5+6+7+8+9
x = x-1-2-3-4-5-6-7-8-9
x = x/2/3/4/5/6/7/8/9
x = x*i*2*3*4*5*6*7*8*9
end
end
SlashCmdList["DEBUG_SILLYLOOP"] = function(msg)
wipe(workload)
for i=1, tonumber(msg) or 1 do
workload[i] = sillyLoop
end
local overallStart = debugprofilestop()
start(
workload,
function() print("done!") end,
function() print(#workload.." remaining after "..("%.2d"):format(debugprofilestop()-overallStart)/1000) end
)
end
SLASH_DEBUG_SILLYLOOP1 = "/sillyloop"