View Full Version : ENTER_FRAME versus Timer for Animations in RIA Dev
Sleeve
06-04-2008, 01:10 AM
Hi-
I'm on a fact finding mission and need some opinions from experienced RIA developers regarding using the ENTER_FRAME event or the Timer object for animations.
Which is best under ideal management?
As I understand it, with each frame, the flash player iterates through the display list looking for DisplayObjects that need updating thus adding a small amount of CPU overhead that grows incrementally as more DisplayObjects get added or as the framerate gets higher. If nothing is happening, you still incur this overhead.
On the other hand, the Timer object can be run only when animations occur, independent of the framerate allowing developers to get smooth animations at very low framerates in conjunction with updateAfterEvent() thus eliminating the overhead from high framerates or large numbers of displayobjects on stage.
To provide an example of this overhead, use the following codevar i : int = 20000
while(i--)
{
var sprite : Sprite = new Sprite();
with(sprite.graphics)
{
beginFill(0x000000, 1);
drawRect(0, 0, 25, 25)
endFill()
}
this.addChild(sprite);
}
Publish the movie and make sure your mouse is over the stage and still. press Ctrl+Shift+Esc for the task manager and note the CPU usage for the flashplayer process. No animations are going and on my 9300 Quad core, this causes a 7-9% CPU overhead at 30 FPS but at 3 FPS it is barely noticeable.
Obviously this is an extreme case unless you are building a monster app or game that required 30,000 objects on stage at once but it provides compelling evidence that the Timer object may be the best choice for animating.
What say you?
pj-co
06-04-2008, 01:45 AM
updateAfterEvent() is rumoured to become deprecated, (sort of) in the sense that it may only apply to buttons in future versions of the flash player. Colin Moock Discussed this in his book.
But other than that you have an interesting theory there. It would be cool to see it in action.
Sleeve
06-04-2008, 03:13 AM
updateAfterEvent() is rumoured to become deprecated, (sort of) in the sense that it may only apply to buttons in future versions of the flash player. Colin Moock Discussed this in his book.
Which book is that? I would believe it since flash player 10 already supports hardware acceleration. Maybe they fixed the problem?
pj-co
06-04-2008, 03:57 AM
Essential ActionScrip 3.0, published by O'reilly. I'm not saying don't use it though, in fact your idea is a good one, just saying that I read that once. Basically that updateAfterEvent() would only remain for Button and Keyboard events (so the rumour goes), and not timer events.
In a sense though, you might be adding extra overhead, as you are basically asking flash to render the screen an aditional time if it has anything else to render on the next frame.
I suspect that Event.ENTER_FRAME might be more effecient/stable but that's really just a kind of a superstious guess that they built in optimizations to the rendering of frames that might not be present in the rendering of an updateAfterEvent() call.
Anyway! none of the above is meant to discourage you, i think as long as you keep those things in mind it would make for an awesome experiment :)
lordofduct
06-04-2008, 05:27 AM
What I've always wondered is how does the Timer update itself?
Cause I've noticed that the timer doesn't reset or run accurately either.
var timer:Timer = new Timer(1000);
timer.addEventListener(TimerEvent.TIMER, update);
timer.start();
var lastTime:int = getTimer();
var thisTime:int = 0;
var dif:Number = 0;
function update(e:TimerEvent):void
{
thisTime = getTimer();
dif = thisTime - lastTime;
lastTime = thisTime;
trace( thisTime, dif, dif % 1000);
}
run this and youll notice that the timer falls out of sync. On my machine it is by ~50 milliseconds per update.
ken1171
06-04-2008, 09:41 AM
What I've always wondered is how does the Timer update itself?
Cause I've noticed that the timer doesn't reset or run accurately either.
Colin Moock also mentioned in his book (Essential ActionScript 3.0) that neither EnterFrame or Timer updates are supposed to be accurate because of the "runtime" nature of Flash.
There is no guarantee that updates will happen when expected, in the same way that nobody knows when Garbage Collection will kick in to free up valuable resources you program may be needing.
Therefore if you need precise timings for your program, perhaps Flash/AS3 is not your best pick. For those cases compiled languages can do a better if you want speed and timing precision. ^__^
Bombdogs
06-04-2008, 12:03 PM
Due to the way they work Timers are pretty woeful for anything other than "approximately accurate". EnterFrame can't guarantee when it will happen due to CPU load, so needs to be coupled with the GetTimer() method, which is always accurate to the nearest millisecond, to acheive frame-rate independant animation. As far as I'm aware this is the only way to acheive perfect timing in flash.
As for the original post, I'm not sure, but with updateAfterEvent if the objects overlap won't you be redrawing certain portions of the screen many times for a single frame?
PMF
senocular
06-04-2008, 12:16 PM
Bombdogs has it right.
Neither enterFrame nor timers will be perfect in their timing. In fact, timers rely on frame rate and their accuracy can be dependant on it. Timers also offer no advantage to animation and the use of updateAfterEvent is actually detrimental because its forcing an additional screen update outside of the normal frame rate. This could actually hurt performance. Additionally, if you timer runs at intervals faster than the frame rate itself, it could mean extra processing compared to that within an enterFrame event. They're best use is for longer, delayed intervals such as maybe polling a server every 20 seconds or something to that effect.
The enterFrame event is where you would want to handle you animations. This allows them to be sync with the normal screen refresh of the player as indicated by the defined framerate keeping it inline with other timeline (etc.) animations. Of course, given basic usage, this could cause variations in timing depending on CPU speed or other frame rate influences. So if you're looking for time-based animation rather than frame based, you would use getTimer or the Date object to get the system time and base your animations off of that, where they would only visually be updated within the enterFrame event.
Sleeve
06-04-2008, 12:52 PM
This is all useful information but I want to bring this thread back in to context a bit.
In the case of large RIA's where animations occur once in a while, like a CB opening or a transition used on a control. If you have 10,000 objects in the Display list as is the case for some beefy RIA's, a framerate of 30+ will incur a steady 10% CPU usage on fast machines and 30%+ on slower ones even when no animations are running. The code I posted above gives an example of this.
Correct me if I'm wrong but, this overhead occurs because of the fact that with each pass, the player has to iterate the list of display objects and look for objects that need updating. Doing this 30 times a second vs 3 times a second is obviously going to have an impact on performance.
The cure seem to be to set a low framerate and use the Timer object to run animations. The CPU is only loaded when the animation runs and since the Timer is framerate independent, you can run your animations at ~120fps while the main movie is only at 5fps.
I have used timer objects against enter frame events and I see much smoother animations with the timer object until I get above 60fps where they are both about the same. I can't see where it makes sense to run a movie at 60+fps when animations are infrequent.
senocular
06-04-2008, 05:01 PM
For one, frame rate doesn't just affect animations. It also affects rollover response time and even text field input refresh. If you're running at 5fps, you're RIA will still *feel* slow despite a few animations here and there running smoothly.
Also, it doesn't matter when you perform animations (moving things around, fading images, etc.), whether it be in an enterFrame event, or a timer event, the display list is updated the same way and drawn when rendering is needed. Generally this happens as per frame rate settings, but can also occur within an asychronous event using updateAfterEvent - this being compounded to the already set frame rate refresh.
But also, if nothing on the screen is changing, Flash Player isn't going to redraw it. Using the debugger player you can actually see the areas Flash Player is drawing by right-clicking and enabling the redraw regions. So even if you have a lot of content on the screen in a high frame rate movie, Flash isn't going to start eating up your CPU unless you give it a reason to, i.e. start animating.
Sleeve
06-05-2008, 01:02 AM
...So even if you have a lot of content on the screen in a high frame rate movie, Flash isn't going to start eating up your CPU unless you give it a reason to, i.e. start animating.
So why is there a CPU overhead when the above code is run and no animations are going at 30fps but not at 3fps? I am interested to hear your thoughts on this. Have you tested it yet?
For one, frame rate doesn't just affect animations. It also affects rollover response time and even text field input refresh. If you're running at 5fps, you're RIA will still *feel* slow despite a few animations here and there running smoothly.
Rollover response times are not affected per se, but the visual indication that a rollover has occurred is. Nonetheless, all that can easily be addressed since KeyBoardEvent, MouseEvent and TimerEvents all can use updateAfterEvent.
Also, it doesn't matter when you perform animations (moving things around, fading images, etc.), whether it be in an enterFrame event, or a timer event, the display list is updated the same way and drawn when rendering is needed. Generally this happens as per frame rate settings, but can also occur within an asychronous event using updateAfterEvent - this being compounded to the already set frame rate refresh.
I read some adobe documentation that stated updateAfterEvent is not triggered when a screen refresh is about to occur anyway. So if updateAfterEvent is called less than 10-20ms before a frame, it is disregarded. Also, updateAfterEvent forces a redraw ONLY if the screen needs updating just like EnterFrame thus preventing wasted CPU usage.
It all boils down to the test code above. I think it provides some pretty strong evidence that the flash player starts to incur some overhead when you combine high framerates with large amounts of DisplayObjects in the Display List. I would sure like to find some definitive info on this.
lordofduct
06-05-2008, 01:43 AM
So why is there a CPU overhead when the above code is run and no animations are going at 30fps but not at 3fps? I am interested to hear your thoughts on this. Have you tested it yet?
I just tested it, and well first off there is a high cpu useage to first start running it because you generate 20,000 sprites (well over the limit that adobe says you shouldn't exceed). And I just ran it and my CPU useage only spiked when I moved my mouse around over the window. If I left the mouse off the window and did nothing my CPU useage settled back down to 1 or 2 % (what I average with only a few basic programs running like Firefox, itunes, GAIM, flash CS3 and Visual C#).
Thusly the updates were mostly influenced by the movement of my mouse, and the need to capture the new information. It probably did a quick read through of the displayList or something (I don't know specifically), which probably took one hell of a hit. I also noticed resizing the screen creates a MASSIVE hit... probably because it had to redraw all 20,000 sprites.
It all boils down to the test code above. I think it provides some pretty strong evidence that the flash player starts to incur some overhead when you combine high framerates with large amounts of DisplayObjects in the Display List. I would sure like to find some definitive info on this.
That's kind of obvious. Wouldn't you think?
ken1171
06-05-2008, 01:48 AM
the flash player starts to incur some overhead when you combine high framerates with large amounts of DisplayObjects in the Display List.
I am only a newbie with AS3 but I read from "ActionScript 3.0 Animation" by Keith Peters and also somewhere in other books that frame rate in Flash obeys a simple law: it will NOT interrupt code execution to update the screen until ALL of the current code execution has been processed.
Trying to run animations from inside a FOR loop is a classic example of that because no matter how many times the animation iterates inside the loop, only the last frame will be seen - no matter what the frame rate may be. This is a fundamental Flash architecture rule.
This means that no matter if you use ENTER_FRAME or timers, it is the code granularity that will determine how fast the screen will update. In other words, many calls to smaller code will result into better refresh rates than fewer calls to longer codes.
Code complexity will also affect screen refreshing because if it takes long for Flash to execute some code, it might miss the next screen refresh and the animation may appear to be choppy or slow. All this no matter if you used frame rate or timers.
And as already mentioned here, calls to force a screen update from a timer event will NOT cause overhead because it cannot break the Flash rule I've mentioned above. In other words, it cannot update the screen if it's not time to do so, and it CANNOT interrupt code execution to update the screen. The Flash architecture will simply never allow for that to happen.
Either frame rate or timers are not better or worse then each other. They have their own applications depending on what you need. Frame rate applies to the entire program and is tied up to the timeline. Timers are completely independent, not related to any timeline but cause some impact on memory usage if not used with moderation. In other words, too many timers can degrade Flash performance in general.
I have also read on those books that Flash was not designed for frame rates much above 24fps. Ideally, Flash will be happy with frame rates of 12-15fps, while rates above that will be left mostly to luck since you don't know in what kind of computer the code will be executed at.
Colin Moock mentioned in one of his books that expecting Flash to run even at 30fps is a bit on the unrealistic side when we consider that many out there still use older computers with old video cards.
Keith Peters said that the faster you push Flash to refresh the screen the less time you are giving your code to finish executing (remember this cannot be interrupted to update the screen!). At slower computers this means your program will be missing a LOT of screen updates, and thus have a poor performance.
Sorry for the long post, but those are all things to consider when we talk about screen update performance.
Sleeve
06-05-2008, 05:25 AM
ken1171-
That was probably the most helpful post I have seen on this subject. All the information you gave is really good stuff. Thank you thank you for taking the time! I have a much more clear direction now. I have also just ordered that book you mentioned "ActionScript 3.0 Animation". It looks like a great read.
@lordofduct-
I appreciate the time you have taken to read this post. I am not too sure how much experience you have with Flex and the components within, but it's very easy to get over 10,000 objects in the display list, even with a mid-sized app. Not all may be visible at once but they are in the display list nonetheless. Also, the instruction was to run the movie with your mouse STILL somewhere over the stage and take note of the CPU usage for the flashplayer.exe process, not your entire PC. When your mouse is off the stage or if the movie is not in focus, the flash player stops many of the internal routines that contribute to this overhead. Try it again and you'll see what I'm seeing.
P.S. I am running a quad core 9300 overclocked to ~3.0ghz with 4GB PC3 RAM OCZ 1600Mhz and I get a 7-9% load with this test.
lordofduct
06-05-2008, 06:45 AM
@lordofduct-
I appreciate the time you have taken to read this post. I am not too sure how much experience you have with Flex and the components within, but it's very easy to get over 10,000 objects in the display list, even with a mid-sized app. Not all may be visible at once but they are in the display list nonetheless. Also, the instruction was to run the movie with your mouse STILL somewhere over the stage and take note of the CPU usage for the flashplayer.exe process, not your entire PC. When your mouse is off the stage or if the movie is not in focus, the flash player stops many of the internal routines that contribute to this overhead. Try it again and you'll see what I'm seeing.
P.S. I am running a quad core 9300 overclocked to ~3.0ghz with 4GB PC3 RAM OCZ 1600Mhz and I get a 7-9% load with this test.
First I did do that in my test, I just didn't ramble on about all of it (I talk enough as is). My point is it kinda verified what senocular was saying.
It isn't a question of my asking why you would have so many symbols in the display list. It was more of a quote of a limit adobe suggests not to pass to keep stability in your system. That limit being 16,000 that adobe suggests.
My experience with flash isn't all that masssive, actually it's kinda mediocre (I've only been using it since late January of this year). My one personal concern about having that much stuff in the displayList though is that flash is for rich web development. Loading on the API with that much stuff is a bit overkill for what Flash is. You may surpass this limit a lot yourself, but I wouldn't. I wouldn't merely because my perogative for a flash api isn't to push it to its limits. I'll go write my program in C++ if I want to do that. But hey, you do what you want... there's nothing wrong with that. As I said, I was only quoting.
oh, and if I had over 10,000 symbols sitting around not visible... I probably wouldn't have them in my displayList.
Flash Gordon
06-09-2008, 08:34 PM
i've been lurking on this thread, and didn't want to see it go by the waste side. A while ago, I was filling my backgrounds in Flash site by manually tiling bitmaps (or was it sprites...). Anyway, I had the same mouse issue that if you moved the mouse over my site the CPU would hit the wall 50%. I then just used the beginBitmapFill method to take care of this. To me it implied that all 2000+ object were dispatching their mouse events which is why the cpu was getting hammered. When bitmaped filled the issue was gone.
I've tried running several test and while I can't stop the events or even catch them when dispatching, my thoughts on the reason was the displayobject are being checked to dispatch it's event. It's merely and guess....and maybe not even a good one.
Sleeve
06-10-2008, 01:25 AM
Flash Gordon-
I am glad to see that I am not the only one that has had this problem. I am curious to know if changing the frameRate helped the load on your CPU when you were using Sprites. As it turns out, the flash player dispatches mouse events independent of framerate. You just see the visual result on the next frame when the screen redraws.
In fact, the flex components use updateAfterEvent quite extensively for mouse events on their Button controls in order to make them update their states independent of framerate. Here is the simplified usagevar sprite : Sprite = new Sprite();
addChild(sprite)
function drawShape(color : uint)
{
with (sprite.graphics)
{
clear();
beginFill(color, 1)
drawRect(0, 0, 50, 50)
endFill();
}
}
drawShape(0);
sprite.addEventListener(MouseEvent.MOUSE_OVER, mouseOverEvent);
sprite.addEventListener(MouseEvent.MOUSE_OUT, mouseOutEvent);
function mouseOverEvent(event : MouseEvent) : void
{
this.drawShape(0xff0000);
event.updateAfterEvent();
}
function mouseOutEvent(event : MouseEvent) : void
{
this.drawShape(0x000000);
event.updateAfterEvent();
}
Set your framerate to 1 and you'll see that the response time to the mouse events are unaffected.
Because events (except enter_frame) are not fired in sync with the framerate, this would be a strong argument against your guess.
I am holding on to the hunch that the CPU overhead has more to do with iterating through the displayList 30 times a second.
Bombdogs
06-10-2008, 07:15 AM
I think you're right, tho I'm still struggling to understand why any RIA would need over 10,000 elements on screen. Anyway that's by the by, I have limited experience of these things - to confirm your hunch, have you tried putting 10,000 shape objects on the display list? They're non-interactive, so if it's the same then it should confirm it's a display list iteration effect that you're seeing??
PMF
Flash Gordon
06-10-2008, 07:16 AM
I am holding on to the hunch that the CPU overhead has more to do with iterating through the displayList 30 times a second.
Yea, that very well may be true because when using bitmaps and manually tiling it produces the same result. And bitmap is not supposed to be an interactive object, so no mouseEvents should be getting dispatched.
However, there is no redraw region so nothing is actually getting redrawing just by moving the mouse....which takes me back to the events....but bitmap isn't an interactive object....which goes back to redraw.....
Honestly, I have no idea what is going on. I know Flash's limitation are after 1000 display items on the stage things become clunky. I don't do any flex, however, it's the same virtual machine so I imagine they are closely related. I'd like to see some more discussion!
senocular
06-10-2008, 03:11 PM
Flex is Flash, just built on a beefy pre-written ActionScript framework. Anything you do in Flex could just as well be done in Flash (for the most part). Flex just does a lot of hand holding for your way into a SWF.
And its true that mouse events are independant of framerate. If the Flex framework does in fact use updateAfterEvent for their component interactions, then you could very well have a low framerate movie that wouldn't "feel" as slow (as I mentioned earlier). In fact it was very common in AS2 to use updateAfterEvent to drag objects smoothly when using onMouseMove since mouse move events happened independant of the frame rate (whenever the mouse moved). Same applies to other mouse events and keyboard events as well. Asyncronous events like Event.COMPLETE are also like this.
And certainly, with a huge number of interactive objects, especially deep within a display hierarchy, you'll start to feel some CPU hurt as mouse events originate from those objects and work their way through the display list hierarchy. I am not sure myself, but it would be worth it to see how much improvement you'll see using mouseChildren = false. The events still have to originate from the original object, but given that they are not dispatched to the children of the hierarchy directly, could it improve performance?
Mazoonist
06-13-2008, 01:46 PM
I understand time-based animation combined with the ENTER_FRAME event. But what about time-based animation combined with a timer? It would seem you get the best of both worlds: an object being animated is guaranteed to be in a certain place at a certain time (framerate independence) and you still get the updateAfterEvent() method, making all the movement smoother. However, what would be the effect on a slower machine? Here's an example:
var rightArrow, leftArrow, upArrow, downArrow:Boolean;
var lastTime:Number = 0;
var passed:Number;
var speed:Number = 0.25;
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);
stage.addEventListener(KeyboardEvent.KEY_UP, keyReleased);
var timer:Timer = new Timer(2);
timer.addEventListener(TimerEvent.TIMER, handler);
timer.start();
function keyPressed(event:KeyboardEvent):void {
if (event.keyCode == Keyboard.RIGHT) {
rightArrow = true;
}
if (event.keyCode == Keyboard.LEFT) {
leftArrow = true;
}
if (event.keyCode == Keyboard.UP) {
upArrow = true;
}
if (event.keyCode == Keyboard.DOWN) {
downArrow = true;
}
}
function keyReleased(event:KeyboardEvent):void {
if (event.keyCode == Keyboard.RIGHT) {
rightArrow = false;
}
if (event.keyCode == Keyboard.LEFT) {
leftArrow = false;
}
if (event.keyCode == Keyboard.UP) {
upArrow = false;
}
if (event.keyCode == Keyboard.DOWN) {
downArrow = false;
}
}
function handler(event:TimerEvent):void {
if (lastTime == 0) {
lastTime = getTimer();
}
passed = getTimer() - lastTime;
lastTime += passed;
if (rightArrow) {
ball.x += speed * passed;
}
if (leftArrow) {
ball.x -= speed * passed;
}
if (upArrow) {
ball.y -= speed * passed;
}
if (downArrow) {
ball.y += speed * passed;
}
event.updateAfterEvent();
}
I ran the above at a framerate of 30. There is a movie clip on the stage with an instance name of "ball."
Is it asking too much of the timer to tick this fast? Is there really a huge performance loss by using updateAfterEvent, given that (in this case) you're only asking for a screen update for one object? The equivalent time-based code that uses ENTER_FRAME instead results in comparatively choppy animation, especially at lower frame rates than this (say, 12).
So if you're looking for time-based animation rather than frame based, you would use getTimer or the Date object to get the system time and base your animations off of that, where they would only visually be updated within the enterFrame event.
This is a really interesting discussion. Could you give an example of both of these used together?
Mazoonist
I ran your code above on my intel-based mac (2.4 GHz w. 4GB RAM). My results were this:
======12 fps:================================
For the most part smooth animation, every once and awhile I saw graphic left behind (very rarely).
CPU usage when first published: 5.7%
As I PRESSED KEYS: 10.1 - 5%
If I went crazy with the key strokes I got over 11%
this is all without mouse movement
With mouse movement: slightly over 13%
======30 fps:================================
CPU usage when first published: 10.6 - 10.8%
As I pressed keys: 9.9 - 10.2%
With mouse movement: 12.7 - 13.2%
pj-co
06-14-2008, 04:46 AM
var timer:Timer = new Timer(2);
That's mighty fast! I cant imagine what needs to update 500 times a second :)
|
vBulletin® v3.8.5, Copyright ©2000-2012, Jelsoft Enterprises Ltd.