AS3 2D read/write test: BitmapData vs Array vs Vector vs Object

I’m looking into speeding up the creation of animations with my perlin noise vectorfield, and one aspect of doing that is by improving the way the data of the particles’ trajectories is handled. In short, the images are created by increasing the brightness of a pixel whenever a particle is present on that location, resulting in brighter pixels on busy spots.

Right now there is too much overhead by displaying the result of each iteration, which is something I can skip completely; the endresult of a complete set of iterations is what interests me – how it grows during that process is fun to watch, but also very slow. If I skip that part during the process, I can look at other options for storing the data other than the BitmapData object. All I need is something that accepts an x,y coordinate, looks up a value for that combination and stores something new in there.

There are several options to choose from, and several ways of using those options. I tried BitmapData, Vector, Array and Object, and since I obviously want the fastest one, I wrote a little testenvironment to see how much time they all took for a certain task. Using a 500 by 500 storage filled with uints, I loop through every location in it and do a read and write command. The data isn’t modified in any way, for now I just read the value and put it back.

[SWF]http://www.petervandernoord.nl/swf/2d_storage_benchmark/main.swf, 640, 480[/SWF]

The test-subjects

  • Bitmap: A regular BitmapData instance, accessed with the setPixel() and getPixel() functions.
  • Bitmap32: Again a BitmapData instance, this time accessed by setPixel32() and getPixel32().
  • Array2D: A two dimensional array, which is an array of size width, each entry containing an array of size height.
  • Array1D: A one dimensional array, in which all rows of the 2D-matrix are sequentially stored. A little calculation is needed every time I read or write to convert the supplied x,y values into the correct index in the 1D-Array: i = (y * width) + x. This way, we don’t need to access two arrays (which is costly) when accessing a value.
  • Vector2D: Same as the two dimensional array, but done with a (fixed-length) Vector instead of an Array.
  • Vector1D: Same as the one dimensional array, but again using a (fixed-length Vector).

After implementing these, I decided to try an Object as well (which can be seen as an Array with String-based lookup keys) but not expecting much from it. What’s needed is a unique key for every x,y location which I set to: var key:String = x.toString() + "x" + y.toString(). The test for this one was extremely slow compared to the other ones, which was partly caused by the creation of the String-key on every read/write command. To avoid that, I stored the keys in a two dimensional array on creation so I could just look them up using the x,y values and not having to call the expensive toString() functions every time. However, there was no way this was ever going to be quick so I just left it to that and kept them in my test:

  • ObjectNonIndexed: uses an Object to store values, generating the key (var key:String= x.toString() + "x" + y.toString()) on every call.
  • ObjectIndexed: used an Object, with all the keys pregenerated and stored in a two dimensional Array

The results

Because the results of each separate run can vary quite a bit each time, I included the avarage results as well. When looking at that number, the Vector1D usually ends up in 1st place, with Vector2D, Array1D and Array2D not much behind. Using BitmapData is quite a lot slower as expected, and the Object is (due to the problems with their String-keys) not even worth mentioning.

Something I learned about Vectors by the way (this was my very first encounter with them) : the datatype of a Vector isn’t just Vector but includes the type of data that’s stored in it. When I was working on the Vector2D test, I was creating a Vector of Vectors (with the last one containing uints). I started out declaring that as var vector2d:Vector.<Vector>, which resulted in errors I didnt understand, until I realized that I wasnt creating a Vector of Vectors but, more specifically: a Vector of uint-Vectors. Correct declaration of that: var vector2d:Vector.<Vector.<uint>>.

Finally, the full sourcecode can be found here (it uses a CS5 .fla file). Feel free to comment on it!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>