Replacing ENTER_FRAME – Testing Tickers
Last week I posted a reflection on a discussion about strategies for replacing ENTER_FRAME listeners. The ActionScript 3 event model requires an event object to be constructed every time an event is dispatched. Constructing objects is slow, which doesn’t matter in many contexts, but in speed-critical contexts, we would like to minimise the amount of time we spend dispatching events. The article considered a way to do this.
This article discusses a first attempt to test the relative performance of two ’solutions’ to the problem of optimising a game loop ‘ticker’, and is based on this source code:
http://github.com/alecmce/TickerStrategies/
Two Approaches To The Problem
If you have already read the previous article, you might want to skip this section.
From the discussion, it appears that most developers who’ve run into this problem have created a ‘ticker’, which creates one ENTER_FRAME listener:
stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
Robert Penner introduced a second idea which uses a two-frame MovieClip and exploits the undocumented addFrameScript method to attach methods to the timeline frames. Both do the same thing: each frame they iterate over an array of methods and call them:
addFrameScript(0, onEnterFrame, 1, onEnterFrame);
This idea stems from an hypothesis that because the scripts are called from a MovieClip timeline, they do not have an associated event object. There should therefore be a small but potentially significant time-saving in using the frame script approach.
Compiling For The FrameLoop Approach
The two-frame loop is required because if you try to ‘play’ a one-frame timeline, Flash is smart enough to recognise that it’s a bit pointless, and will do nothing. If you play a two-frame timeline, it will loop continuously.
One solution is to create a symbol in an FLA with two empty frames, but I rarely if ever touch the Flash IDE as a developer, and would prefer an elegant solution which does not require the IDE.
My first thought was to use the [Frame(factoryClass=etc)] metadata structure, but this turns out to be problematic. I could build without problems and what I built ran within certain player contexts, but not others.
The metadata structure is unsatisfactory, because it required creating two classes that act as ‘main classes’ – it looked messy. Happily, I have since found (via senocular.com’s documentation of the MXML compiler) a rather pleasing way of creating a 2-frame (or more) MovieClip through MXMLC. By adding the following line to the end of the compiler arguments, I force the SWF to be built with a second frame (frame 1, zero-based indices):
-frames.frame 1 flash.display.Sprite
Testing The Hypothesis
My implementations of the ‘ticker’ can be found in the tests that I have created can be found at http://github.com/alecmce/TickerStrategies/. Comments, critiques and suggestions would be gratefully received.
The solution therefore was to create MovieClips with minimal structure built on top of them that would put the player under stress, and to implement both strategies. They could then be run side-by-side and evaluated. Here are the test builds. They run only if you mouse-over them.
EnterFrame Ticker
FrameLoop Ticker
The Flash plugin is required to view this object.
Notes on the Tests
The profiling tool at the top is a hacked version of the Lost In Actionscript SWFProfiler tool. I modified the styles and exposed more of the API by making some minor changes to his original. My variation can be found here.
Unlike the original idea of replacing an event listener with a signal from #as3signals, the frame loop implementation I created is as pared down as possible. This is in order to make the test as fair as possible.
As far as I can interpret the tests so far, there is almost no performance difference between the two, but there might be a small memory gain by using the frame loop. Every time I run the tests I get different results however, and a thorough record of results in order to find their normal distribution is probably needed.
The test probably need to be more rigorous. They currently test one particular point of heavy stress for the player, but there may be circumstances in which one or the other strategy starts more obviously out-performing the other. If you have an idea about how to improve these tests, please post it.
I did consider using Grant Skinner’s Performance Harness but dismissed it in this circumstance. Test harnesses perform tests on synchronous code very well, but it is not clear to me how you could test this sort of performance on a similar basis. Rather than testing milliseconds for execution, this test is trying to evaluate the memory overhead of events object construction and destruction and any potential performance implications of that and the different mechanisms for firing methods on entering a frame.
-
Simone
-
shaun
-
alecmce
-
jacksondunstan
-
alecmce
-
jacksondunstan
