JavaScript string building
I was reading Dennis Forbes’s take on JavaScript string concatenation in Firefox and IE, and I realized I had an opportunity to increase the performance of my raycaster. I’m currently rendering by building a giant string of HTML that is inserted into the frame using innerHTML. But because of the way string are handled, this can get slow. If I can replace concatenation with an Array.join, there should be a noticable speed boost. But first, some benchmarks.
Here’s a standard string builder, like what I’m currently using:
And this is what it might look like using an array:
Both are supplied with a base string and a iteration count. By varying the length of the base string and the count, we can find how the functions compare. Here are the IE7 results from averaging 100 runs. The columns represent the iteration count, the rows are base string length, and each cell gives the standard string building time (in ms) and the time using Array.join.
| 500 | 1000 | 2000 | 4000 | |
|---|---|---|---|---|
| 1 | 1.12 / 0.59 | 2.4 / 1.03 | 6.37 / 2.05 | 14.09 / 4.25 |
| 4 | 1.36 / 0.53 | 3.6 / 1.16 | 10.35 / 2.17 | 32.75 / 4.21 |
| 16 | 2.75 / 0.73 | 8.45 / 1 | 28.78 / 2.19 | 106.67 / 4.74 |
| 64 | 7.45 / 0.75 | 27.16 / 1.29 | 90.38 / 2.51 | 407.3 / 6.02 |
The results are pretty staggering. For the longest strings (which total 256000 characters), using arrays is more than 65 times faster.
Now for Firefox 2:
| 1000 | 2000 | 4000 | 8000 | |
|---|---|---|---|---|
| 1 | 0.95 / 1.71 | 2.24 / 22.37 | 5.64 / 8.28 | 17.3 / 23.51 |
| 4 | 1.54 / 2.27 | 4.79 / 6.12 | 24.73 / 9.18 | 9.41 / 14.9 |
| 16 | 1.86 / 2.52 | 3.33 / 4.09 | 4.46 / 7 | 26.85 / 13.3 |
| 64 | 1.84 / 2.11 | 3.22 / 3.91 | 7.53 / 9.4 | 174.42 / 174.96 |
Notice that the iterator counts for Firefox are twice what they were for IE. This is because Firefox does string concatenation much better than IE.
Also notice that some Firefox numbers are inconsistant. For example, with a base string of length 4, the highest iterator count ran faster than the second highest for standard concatenation. I don’t know why it does this, but every time I ran it, at least one set of results was out of line. Regardless, it’s easy to see that Firefox did not benefit from using Array.join at all. This is probably because Firefox knows that concatenations that are essentially appends can by optimized, as Dennis Forbes explains. If the line s = s + a is replaced with s = a + s, Firefox is considerably slower. Much slower than IE, in fact. But I intentionally used s = s + a because it’s how my raycaster works.
Finally, notice that IE is actually faster than Firefox when using Array.join.
I’ll post another update when I implement this into my raycaster.
Aside
In order to get these results, I had to create some testing functions. I ended up with a pretty solid set of routines, complete with bar-graphs, and I’d like to extend it to something more complete and robust.
Update
I made a quick implementation but it didn’t speed up my raycaster much. After some quick and dirty speed tests, it looks like the bulk of the rendering time is spread across the actual ray casting and intersection testing, and the browser actually drawing the sprites and the walls.