cooldown: throttle before the work, not after

The 0.1s gate sat below the hidden-cooldown check, so every frame, for every
ticking cooldown, the update built "<parent>Cooldown" twice and did two _G
lookups with it. Lua 5.0 interns on every concat -- it allocates and hashes
even when the string already exists -- so this was allocating garbage at the
frame rate times the number of live cooldowns. A profiler run had it at 24s
of accumulated CPU.

Move the gate to the top so a non-tick frame costs one GetTime() and a
compare. The name lookup goes away entirely: pfCreateCoolDown already has the
cooldown frame, so it stashes the reference instead. That is also more
correct than deriving it from the parent's name, which silently skipped the
check for any cooldown not named "<parent>Cooldown".

The text frame and its fontstring were both created with a fixed name, so
every one of the hundreds in a UI clobbered _G.pfCooldownFrame and left it
pointing at whichever was made last. Name them after the cooldown they render
for, falling back to a counter for anonymous ones.

One behavior change: the hidden-cooldown check is now throttled too, so text
can linger up to 100ms after its cooldown frame hides. It only refreshes at
0.1s anyway, and expiry still runs through the remaining < 0 branch.
This commit is contained in:
Brues
2026-09-07 18:14:33 -05:00
parent 4eab494a01
commit 879d7afe83
+26 -16
View File
@@ -6,30 +6,35 @@ pfUI:RegisterModule("cooldown", function ()
-- local hourcolor = {strsplit(",", C.appearance.cd.hourcolor)}
-- local daycolor = {strsplit(",", C.appearance.cd.daycolor)}
local parent, parent_name
local function pfCooldownOnUpdate()
parent = this:GetParent()
-- Throttle FIRST. One of these runs per visible cooldown text, every frame,
-- so anything above this gate is multiplied by the frame rate and by how
-- many cooldowns are ticking.
local now = GetTime()
if (this.tick or 0) > now then return end
this.tick = now + .1
local parent = this:GetParent()
if not parent then this:Hide() return end
parent_name = parent:GetName()
-- avoid to set cooldowns on invalid frames
if parent_name and _G[parent_name .. "Cooldown"] then
if not _G[parent_name .. "Cooldown"]:IsShown() then
this:Hide()
end
-- avoid to set cooldowns on invalid frames. The cooldown frame is stashed
-- at creation: resolving it as _G[parent:GetName() .. "Cooldown"] built and
-- interned that string twice per call, and this is the hottest path in the
-- UI. The stashed reference is also the frame itself rather than a guess
-- from its parent's name, so it holds for cooldowns named anything else.
if this.cooldown and not this.cooldown:IsShown() then
this:Hide()
return
end
-- only run every 0.1 seconds from here on
if ( this.tick or .1) > GetTime() then return else this.tick = GetTime() + .1 end
-- fix own alpha value (should be inherited, but somehow isn't always)
if this:GetAlpha() ~= parent:GetAlpha() then
this:SetAlpha(parent:GetAlpha())
end
if this.start < GetTime() then
if this.start < now then
-- calculating remaining time as it should be
local remaining = this.duration - (GetTime() - this.start)
local remaining = this.duration - (now - this.start)
if remaining >= 0 then
this.text:SetText(GetColoredTimeString(remaining))
else
@@ -39,7 +44,7 @@ pfUI:RegisterModule("cooldown", function ()
-- I have absolutely no idea, but it works:
-- https://github.com/Stanzilla/WoWUIBugs/issues/47
local time = time()
local startupTime = time - GetTime()
local startupTime = time - now
-- just a simplification of: ((2^32) - (start * 1000)) / 1000
local cdTime = (2 ^ 32) / 1000 - this.start
local cdStartTime = startupTime - cdTime
@@ -55,11 +60,16 @@ pfUI:RegisterModule("cooldown", function ()
end
local height, size
local textcount = 0
local function pfCreateCoolDown(cooldown, start, duration)
cooldown.pfCooldownText = CreateFrame("Frame", "pfCooldownFrame", cooldown:GetParent())
textcount = textcount + 1
local name = cooldown.GetName and cooldown:GetName() or "pfCooldown" .. textcount
cooldown.pfCooldownText = CreateFrame("Frame", name .. "Text", cooldown:GetParent())
cooldown.pfCooldownText.cooldown = cooldown
cooldown.pfCooldownText:SetAllPoints(cooldown)
cooldown.pfCooldownText:SetFrameLevel(cooldown:GetParent():GetFrameLevel() + 2)
cooldown.pfCooldownText.text = cooldown.pfCooldownText:CreateFontString("pfCooldownFrameText", "OVERLAY")
cooldown.pfCooldownText.text = cooldown.pfCooldownText:CreateFontString(name .. "TextString", "OVERLAY")
if not cooldown.pfCooldownType then
size = tonumber(C.appearance.cd.font_size_foreign)