Thread Tools Display Modes
02-25-11, 05:08 PM   #1
Duugu
Premium Member
 
Duugu's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 851
Frame reuse performance problem

Hi all

I'm currently drawing "lines" in an addon. To do this I create a texture frame for every single line and rotate/scale the texture via SetTexCoord. That part is working as intended.

My problem with this is, I need a LOT of lines ... let's say 1000/minute. Fortunately these lines are not permanent visible. So I should be able to "reuse" the frames from lines that are not longer visible.

My approach to reuse the frames is to store every newly created frame into a table. If a frame is not longer visible I'll flag the frame in the table as "not in use". If I'll draw a new line I'll take the first frame from the table that is flagged as "not in use" and reuse it. Only if all existing frames are "in use" I'll create a new one.

My first try to do this was

Code:
local FrameStack = {}
 

function GetTexture()
	local Texture = nil
	table.foreach(
		FrameStack, 
		function(index, value) 
			if value.InUse == false and Texture == nil then
				value.InUse = true
				Texture = value
			end
		end
		)

	if Texture == nil then
		Texture = _G["TestParentFrame"]:CreateTexture(nil,"ARTWORK")
		Texture:ClearAllPoints()
		Texture.InUse = true
		table.insert(FrameStack, Texture)
	end
 
	return Texture
end
This is working as intended. Unfortunately table.foreach is slow as hell if FrameStack has ... let's say 4.000 entries.

My sesond approach was

Code:
local FrameStack = {}

function GetTexture()
	local Texture = nil
	local x = 1
	while not Texture do
		if FrameStack[x] then
			if FrameStack[x].InUse == false then
				FrameStack[x].InUse = true
				Texture = FrameStack[x]
			else
				x = x + 1
			end
		else
			break
		end
	end
 
	if Texture == nil then
		Texture = _G["TestParentFrame"]:CreateTexture(nil,"ARTWORK")
		Texture:ClearAllPoints()
		Texture.InUse = true
		table.insert(FrameStack, Texture)
	end
	
	return Texture
end
It's working too. But it's as slow as the first version.

So my question is, how can I do this job in a faster way?
  Reply With Quote
02-25-11, 05:29 PM   #2
Starinnia
Ninja Code Monkey
AddOn Author - Click to view addons
Join Date: Apr 2007
Posts: 84
I usually have a table just for unused frames. Then I called next() on that table to get an unused frame, if nothing is returned I'll create the frame.
  Reply With Quote
02-25-11, 05:29 PM   #3
Ailae
A Rage Talon Dragon Guard
 
Ailae's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2007
Posts: 318
I believe table.foreach is deprecated, in favor of pairs(), so probably shouldn't use that in any case.

Have you tried using two tables? One to store active lines and another to store reused frames?

So when you want a new frame you create a function similar to this
Code:
local FrameStack, Cache = {}, {}

local function getFrame()
	if #Cache > 0 then return table.remove(Cache, 1) end
	-- create new frame f
	return f
end
It's just the basic gist of it. When a frames' current use comes to an end, you move that frame from FrameStack to Cache. I really don't know how much faster, if at all, this is with that high amounts of data but I've often seen it done this way.
__________________
Oh, the simulated horror!
  Reply With Quote
02-26-11, 11:31 AM   #4
Duugu
Premium Member
 
Duugu's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 851
Thanks a lot to both of you.

I'm now add an object reference for frame I "release" to the table. If I need a new frame I test with next() if the table contains an entry. If this is the case I remove the table entry and return the object reference.

Drawback: if the returned frame object reference is "lost" (eg. the return value is not handled) the frame itself is "lost" too (no reference to the frame left).
My first approach to store all frames in a large table and to flag them as "used" and "unused" was a try to avoid this. Unfortunately it's way to slow with a large table.

Replaced foreach() with pairs() btw. ty
  Reply With Quote
02-26-11, 01:12 PM   #5
Starinnia
Ninja Code Monkey
AddOn Author - Click to view addons
Join Date: Apr 2007
Posts: 84
Originally Posted by Duugu View Post
Drawback: if the returned frame object reference is "lost" (eg. the return value is not handled) the frame itself is "lost" too (no reference to the frame left).
While this is true, since you have exclusive access to the recycling table, your code will be the only one dealing with returns from that table. You can ensure that a return is never unhandled and references are never leaked.
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Frame reuse performance problem


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off