I was reading some article by the Flash developers about the limit to software rendering.
In the article they say, "any memory access, especially random access ... is the most expensive operation."
http://www.kaourantin.net/2007/02/limits-of-software-rendering.html
I dont know why but this made me think about this Matrix library im writing for a graphics engine.
Having some extra time, I wrote up a test comparing Matrices implemented with double[][]
versus unwrapping them into double[]s.
The double[] implementation is almost twice as fast (40% consistently).
The code for matrix multiplication etc are all exactly the same (they all use 2 for loops)
except that instead of m[row][column] i use m[row * 4 column].
This seems like spooky voodoo to me. Should this be the case?
From what I've heard, Java does quite a bit of background bounds checking when arrays are indexed. As such, using a multi-dimensional array would cause (N-1)*M more such checks. I didn't think they would amount to 40% though, especially since the 1-D version needs to use extra math to calculate the index. Very interesting and good to know. Thanks for sharing.
So why doesn't the JVM use a single array of objects for multi-dimensional arrays and simply use a dimension offset (e.g. realArray[x*d+y] is equivalent to declaredArray[x][y]) for their underlying implementation? Seems like a pretty good idea to me.
Edited by: the.maltese.falcon on Nov 8, 2007 3:28 PM
stupid italics tags
So why doesn't the JVM use a single array of objects for multi-dimensional arrays
so that you could have ragged arrays
I think thats only part of it. I think they might (???) see a speed up with ragged arrays too.
I think the actual reason is because you dont have to define the "subarrays" size at
creation.
double[4][3] ... create 12 entries
double[4][] ... create how many?
if we HAD to specify the sizes at creation time with something like:
double[4][{3, 7, 2, 5}] ... then they could do the offsets.
But yea, that would be an AWFUL way to implement multi-dim arrays, lol.
IMHO though, a 40% performance increase DEFINITELY warrants Java considering a new
rectangular multi-dim array language construct.
They could use a single array syntax utilizing commas:
double??? rectArray = newdouble[4, 3];
double value = rectArray[1, 3];
So why doesn't the JVM use a single array of objects for multi-dimensional arrays and simply use a dimension offset
umm... because they defined multidimensional arrays as arrays of arrays so that you could have ragged non-homogeneous object oriented arrays.
seems like even with that overhead and bounds checking they might still be faster than a 40% slowdown, since for memory management of objects you could allocate the array of object pointers in one spot and the actual objects somewhere else
and special thanks to forum.java.sun.com for suddenly not allowing me to edit my posts :(
One thought: a 4x4 matrix is pretty small, and your test appears to be including initialization in its timings. If you're just looking to compare access time, it's probably worthwhile to create single instances of the arrays, and pass those prebuilt instances into the test methods. Would also eliminate garbage collection overhead.
your test appears to be including initialization in its timings
Its not. Test 1 is. Test 1 times how long it takes to fill an array of Matrices.
All subsequent tests use the Matrix objects that were already created and
that populate that array.
kdgregory wrote:
One thought: a 4x4 matrix is pretty small
So I implemented a test with larger matrices :) My results did not show nearly a 66% slowdown...I would actually hesitate to make any conclusions based on the data I collected.
size := length of a side of the two-dim array. So the actual array size is size^2^ one-dim := time (in ms) to perform 5000000 operations of the type
array1[random] += array1[random]
two-dim := time (in ms) to perform 5000000 operations of the type
array2[random][random] += array2[random][random]
slowdown := how much longer it took (in ms) to execute operations on the two-dim array
Statistics (of the slowdown column):
Mean:77.8
Median: 48
Mode: 47
Min: -171
Max: 374
Standard Deviation: 101.53
So, based on these results, I am very hesitant to make any solid conclusions. It seems, that in general, the two-dimensional array tends to be slower. However, if indeed it is slower to use a multiple-dimension array, it seems that the slowdown is miniscule. Consider even the largest difference, of 374 milliseconds - this is the difference in time for 5000000 iterations of a command. That translates to 74.8 microseconds (which, I suppose is a long time in the realm of clock cycles on a GHz processor; but is nothing to a lowly human such as myself).
I guess my point is that, based on my results, I don't care, and will continue to use multi-dimensional arrays. I'll post my code if anyone wants to see it...I'll hold off for now though cause I don't want to make this post any longer...
Some thoughts. I agree that random memory accesses might be costly since the OS might have to page in and page out memory pages, and caches can get invalidated. An array that is 1d is allocated using contiguous memory so it has speed advantages in that way, but there's more to it. Accessing the 1d array is just an offset to a pointer, but accessing a 2d array means adding the offset to a pointer, get another pointer, add an offset to that pointer and then get the data. That together with bounds checks sounds expensive in comparison to the 1d array.