-
Senior Member
The display chain has a dirty secret...
I've been coding AS since 1997, and AS3 since before it was released. But I never knew this.
I had an app that was starting to slow down. It's huge, ~300,000 lines of AS3, so in a way that's not a surprise. Turns out, however, that one tiny line of missing code was eating up 50% of the CPU usage for the app.
The line was an addChild(), which fired in a little loop while dragging something under the cursor. An independent piece of code checked where the cursor was and put highlights in different places when the cursor was over them. What it didn't do was say if(!this.contains(sprite)) first. Why should it? Just an extra piece of logic, I figured. If it's already added, just let the VM ignore the addChild(). We're not actually adding or creating any more instances, right?
Right. But for some reason, adding that little bit of if() logic to check for containment first, literally just shaved half right off the CPU use while hovering. Unbelievable, because if I were writing a display chain the first thing I'd do would be return() if I found the child was already a member at the same point in the chain. Apparently AVM2 doesn't do that.
I don't usually do this; normally I'm careful to check before I add, just out of good practice. But the point here is that I didn't check this time because I thought it would be faster. I wonder how much of the complaining about "Flash is so slow" from the HTML5 crowd could have been avoided if people knew the speed penalty for readding sprites that are already children. Took me 4 years of writing this app to figure it out, and 15 years of my professional life; I've never read it anywhere, even from senocular. Maybe it's such a dumb mistake that the gurus assumed everyone knew it. But my guess is it's rampant, and the cause of a huge number of slowdowns. Live and learn.
-
So removing the child from its current displaylist and adding it to the new one is sucking all the CPU?
-
If I understand Josh right, he's not even moving it. He had what should have been a no-op addChild because the child was already on that parent and at the top of that parent's children. Instead of optimizing that case out, it seems to take just as long as an addChild call that does have an effect. So by explicitly checking whether the addChild call is necessary he can save a lot of processing time.
-
Senior Member
Originally Posted by 5TonsOfFlax
If I understand Josh right, he's not even moving it. He had what should have been a no-op addChild because the child was already on that parent and at the top of that parent's children. Instead of optimizing that case out, it seems to take just as long as an addChild call that does have an effect. So by explicitly checking whether the addChild call is necessary he can save a lot of processing time.
Exactly. Although I'm now questioning whether that was the whole of it. There's a lot going on in the script and I haven't done a lot of testing on this proposition; but the child in question was also a rather large gradient fill. It wasn't being redrawn or moved during the loop, just added to the same parent with the assumption that if it was already there the addChild would do nothing in an optimized way. But it *does* have a mouseOver listener on it, so now I'm wondering whether the combination of addChild with the existence of the mouse listener was forcing a redraw, or at least a recalculation of the bounding box, where there didn't need to be one. I'll do some experiments when I get the time...
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|