Measuring Performance in Flash/AS3
by
kirupa
& friends | 24 January 2011
Have questions? Discuss this Flash / ActionScript
tutorial with others on the forums.
In programming, there are many ways to write lines of
code to return the same result. Of these many ways,
some are going to be faster than others. In general, fast is
good!
The trick then is to both come up with faster
solutions and be able to prove to
yourself that a faster solution is indeed faster
than something else you have tried. This article isn't going
to help you with the first part, but it will certainly try to help
you with the second part.
When measuring performance, it is always good to have
things to compare against. For this article, let's say you have two
ways of squaring a number - Math.pow and
xn). What you
want to do is figure out which of these approaches is faster:
Let's let the battle begin!
Meet the
Stopwatch Before we pit our two contestants into a
bloody battle where only one will walk out alive, we need to
figure out what to use to measure performance. In real life,
to help
measure how fast something is, people tend to
use stopwatches. In ActionScript, your stopwatch equivalent
is the
getTimer function:
- var
startingTime:Number
=
getTimer();
-
- // have some code here whose
running time you are measuring
-
- var
endingTime:Number
=
getTimer();
-
- trace("Elapsed
time: " +
endingTime
-
startingTime);
To be able to use this function, make sure you have the the
import flash.utils.getTimer;
statement added to the top of your code file.
What this function does is quite simple. The getTimer function returns the number of milliseconds
that have elapsed since your application started running.
Behind the scenes, the instant your application breathes life, an
internal timer starts kicking. All getTimer does is return
the value of that internal timer each time you call it.
By calling
the getTimer function before and after some code, you can measure how many
milliseconds it took to run that code by taking the
difference of the two getTimer calls. The smaller the number, the faster your code!
Now that
you know what the getTimer function does, let's revisit the
initial problem by looking at a small example:
- var
startingTime:Number
=
getTimer();
-
- for
(var
i:Number
= 0;
i <
10000;
i++)
- {
- var
xA:Number
=
Math.random()
*
1000;
- var
xB:Number
=
Math.random()
*
1000;
- var
yA:Number
=
Math.random()
*
1000;
- var
yB:Number
=
Math.random()
*
1000;
-
- var
xDiff:Number
=
xA -
xB;
- var
yDiff:Number
=
yA -
yB;
-
- Math.sqrt(Math.pow(xDiff,2)
+
Math.pow(yDiff,2));
- }
-
- var
endingTime:Number
=
getTimer();
-
- trace("Elapsed
time: " +
endingTime
-
startingTime);
What I want to measure is the performance of calculating
the
Pythagorean theorem using the Math.pow function
first. Because
a single call in this case is too fast to measure, I am
using a loop to artificially inflate the number of times
that our one line gets called. Once you have run this code a few
times, your elapsed time in milliseconds should start to
fall within a very narrow range.
Next up, we want to change our theorem to use the x2
approach instead and compare the results. When comparing two particular approaches to see
which one is faster, try to keep everything as same as
possible with the exception of the variation you are
measuring.
The x2 approach looks as follows:
- var
startingTime:Number
=
getTimer();
-
- for
(var
i:Number
= 0;
i <
10000;
i++)
- {
- var
xA:Number
=
Math.random()
*
1000;
- var
xB:Number
=
Math.random()
*
1000;
- var
yA:Number
=
Math.random()
*
1000;
- var
yB:Number
=
Math.random()
*
1000;
-
- var
xDiff:Number
=
xA -
xB;
- var
yDiff:Number
=
yA -
yB;
-
- Math.sqrt(xDiff
*
xDiff +
yDiff
*
yDiff);
- }
-
- var
endingTime:Number
=
getTimer();
-
- trace("Elapsed
time: " +
endingTime
-
startingTime);
Notice that almost everything is identical with the
exception of the last line in the for loop where we replace
Math.pow with x2.
At the end of both experiments, you can get an idea of which
approach is faster. As you may have guessed from the very
beginning, x2 is actually faster. Before
going further and pursuing any action against Math.pow, read
the following section first on how to increase the accuracy
of your measurements.
The example I used earlier is a quick and dirty way for
measuring the performance between two different approaches
that return the same result. If you are looking for more
accurate performance comparisons or wish to make sweeping
generalizations, try to keep the following list in mind.
- If you are just measuring the performance of some
code (as we are in the squaring example),
try to avoid rendering any
visuals unless it is critical for your
comparison.
- While they are both intertwined,
avoid using trace statements
and avoid using the debug Flash player that you see when
you test from within the Flash IDE. The reason is that there
are optimizations made to speed things up when your
content is viewed at run-time in the browser. Instead of
the trace statement, use a simple textfield to output
your results so that it is viewable at run-time instead.
- For testing simple statements, avoid wrapping them
into function calls if
possible:
- for
(var
i:Number
= 0;
i <
10000;
i++)
- {
- var
randomA:Number
=
Math.random()
*
1000;
- var
randomB:Number
=
Math.random()
*
1000;
- var
randomC:Number
=
Math.random()
*
1000;
- var
randomD:Number
=
Math.random()
*
1000;
-
- //
- // Toggle the commenting
on the lines below to see which performs faster
- //
- var
distance:Number
=
GetDistanceSquare(randomA,randomB,randomC,randomD);
- //var distance:Number =
GetDistanceSquare(randomA,randomB,randomC,randomD);
- }
-
There is a non-trivial amount
of overhead to do the magic necessary to call a function,
and that overhead will add milliseconds to your getTimer
call. Inline what you are measuring instead.
- When using a loop to measure some code,
change the number of iterations you run your loop for.
Some memory or performance issues may only be noticeable
after a certain number of runs. With that said, keep
your iterations reasonable and somewhat representative
of how your code may be used.
- Never run your test once and consider yourself good
to go. Run your tests a few times to get an average.
Ideally, the numbers between each test shouldn't vary a
whole lot. If they do vary, then you have a problem!
- The order and timing between tests matter. If you
are running several tests at once, see if changing the
order of the tests or whether inserting a pause of a few
frames or a few seconds changes the results a whole lot.
Hopefully you
found this article on how to measure performance useful.
This article was inspired by
this thread, and the contents of the "Things to Keep in
Mind" section came largely from feedback by
Krilnon,
rumblesushi,
bwhiting, and
maskedman.
Just a final word before we wrap up. If you have a question and/or want to be part of a friendly, collaborative community of over 220k other developers like yourself, post on the forums for a quick response!
|