Multidimensional typed arrays in JS
MIT License
What is the most efficient way to implement multidimensional arrays in JavaScript?
UPDATE Experiments for numeric.js, cwise and ndarray-ops added
To run the experiment in node, just do:
node experiment.js
If you want to try it in your browser, you can install beefy by typing:
npm install -g beefy
Then running
beefy experiment.js --open
These are the results of running the experiment in the latest version of Chrome V8.
With:
Running experiment with dimensions = 16 x 16 x 16 experiment.js:30
Proposal #1 raw native array Total Init = 0ms Execution = 8ms
Proposal #2 raw typed array Total Init = 0ms Execution = 9ms
Proposal #3 object with array accessor Total Init = 0ms Execution = 15ms
Proposal #4 object with flat accessor Total Init = 0ms Execution = 10ms
Proposal #5 object with flat accessor, no offset Total Init = 1ms Execution = 11ms
Proposal #6 array of native arrays Total Init = 1ms Execution = 25ms
Proposal #7 array of native arrays (fast init) Total Init = 1ms Execution = 5ms
Proposal #8 array of typed arrays Total Init = 0ms Execution = 9ms
Proposal #9 array of contiguous typed arrays Total Init = 1ms Execution = 9ms
Proposal #10 numeric.js simple Total Init = 0ms Execution = 47ms
Proposal #11 numeric.js pointwise() Total Init = 0ms Execution = 64ms
Proposal #12 ndarray-raw Total Init = 4ms Execution = 8ms
Proposal #13 ndarray-ops Total Init = 0ms Execution = 52ms
Proposal #14 cwise Total Init = 0ms Execution = 9ms
Running experiment with dimensions = 64 x 64 x 64 experiment.js:30
Proposal #1 raw native array Total Init = 57ms Execution = 660ms
Proposal #2 raw typed array Total Init = 0ms Execution = 471ms
Proposal #3 object with array accessor Total Init = 1ms Execution = 732ms
Proposal #4 object with flat accessor Total Init = 1ms Execution = 470ms
Proposal #5 object with flat accessor, no offset Total Init = 1ms Execution = 464ms
Proposal #6 array of native arrays Total Init = 3ms Execution = 1516ms
Proposal #7 array of native arrays (fast init) Total Init = 22ms Execution = 244ms
Proposal #8 array of typed arrays Total Init = 7ms Execution = 462ms
Proposal #9 array of contiguous typed arrays Total Init = 4ms Execution = 556ms
Proposal #10 numeric.js simple Total Init = 9ms Execution = 11902ms
Proposal #11 numeric.js pointwise() Total Init = 5ms Execution = 3399ms
Proposal #12 ndarray-raw Total Init = 1ms Execution = 256ms
Proposal #13 ndarray-ops Total Init = 3ms Execution = 770ms
Proposal #14 cwise Total Init = 0ms Execution = 201ms
Running experiment with dimensions = 512 x 512 x 4 experiment.js:30
Proposal #1 raw native array Total Init = 199ms Execution = 1130ms
Proposal #2 raw typed array Total Init = 4ms Execution = 1857ms
Proposal #3 object with array accessor Total Init = 5ms Execution = 3025ms
Proposal #4 object with flat accessor Total Init = 5ms Execution = 1895ms
Proposal #5 object with flat accessor, no offset Total Init = 1ms Execution = 1853ms
Proposal #6 array of native arrays Total Init = 162ms Execution = 6221ms
Proposal #7 array of native arrays (fast init) Total Init = 138ms Execution = 1147ms
Proposal #8 array of typed arrays Total Init = 543ms Execution = 1975ms
Proposal #9 array of contiguous typed arrays Total Init = 395ms Execution = 1921ms
Proposal #10 numeric.js simple Total Init = 81ms Execution = 59890ms
Proposal #11 numeric.js pointwise() Total Init = 81ms Execution = 17571ms
Proposal #12 ndarray-raw Total Init = 3ms Execution = 1172ms
Proposal #13 ndarray-ops Total Init = 3ms Execution = 3799ms
Proposal #14 cwise Total Init = 3ms Execution = 940ms
Running experiment with dimensions = 512 x 4 x 512 experiment.js:30
Proposal #1 raw native array Total Init = 228ms Execution = 1841ms
Proposal #2 raw typed array Total Init = 1ms Execution = 1856ms
Proposal #3 object with array accessor Total Init = 1ms Execution = 2886ms
Proposal #4 object with flat accessor Total Init = 1ms Execution = 1871ms
Proposal #5 object with flat accessor, no offset Total Init = 1ms Execution = 1869ms
Proposal #6 array of native arrays Total Init = 34ms Execution = 6015ms
Proposal #7 array of native arrays (fast init) Total Init = 25ms Execution = 741ms
Proposal #8 array of typed arrays Total Init = 6ms Execution = 1875ms
Proposal #9 array of contiguous typed arrays Total Init = 4ms Execution = 1891ms
Proposal #10 numeric.js simple Total Init = 31ms Execution = 45547ms
Proposal #11 numeric.js pointwise() Total Init = 15ms Execution = 13322ms
Proposal #12 ndarray-raw Total Init = 3ms Execution = 1003ms
Proposal #13 ndarray-ops Total Init = 5ms Execution = 2766ms
Proposal #14 cwise Total Init = 3ms Execution = 767ms
Running experiment with dimensions = 4 x 512 x 512 experiment.js:30
Proposal #1 raw native array Total Init = 208ms Execution = 2232ms
Proposal #2 raw typed array Total Init = 1ms Execution = 1885ms
Proposal #3 object with array accessor Total Init = 1ms Execution = 2907ms
Proposal #4 object with flat accessor Total Init = 1ms Execution = 1884ms
Proposal #5 object with flat accessor, no offset Total Init = 1ms Execution = 1870ms
Proposal #6 array of native arrays Total Init = 37ms Execution = 5959ms
Proposal #7 array of native arrays (fast init) Total Init = 26ms Execution = 762ms
Proposal #8 array of typed arrays Total Init = 6ms Execution = 1883ms
Proposal #9 array of contiguous typed arrays Total Init = 4ms Execution = 1912ms
Proposal #10 numeric.js simple Total Init = 23ms Execution = 39231ms
Proposal #11 numeric.js pointwise() Total Init = 16ms Execution = 13258ms
Proposal #12 ndarray-raw Total Init = 3ms Execution = 1002ms
Proposal #13 ndarray-ops Total Init = 5ms Execution = 2773ms
Proposal #14 cwise Total Init = 3ms Execution = 770ms
Running experiment with dimensions = 2 x 2 x 2048 experiment.js:30
Proposal #1 raw native array Total Init = 0ms Execution = 16ms
Proposal #2 raw typed array Total Init = 0ms Execution = 16ms
Proposal #3 object with array accessor Total Init = 0ms Execution = 26ms
Proposal #4 object with flat accessor Total Init = 0ms Execution = 17ms
Proposal #5 object with flat accessor, no offset Total Init = 0ms Execution = 17ms
Proposal #6 array of native arrays Total Init = 0ms Execution = 49ms
Proposal #7 array of native arrays (fast init) Total Init = 0ms Execution = 7ms
Proposal #8 array of typed arrays Total Init = 0ms Execution = 16ms
Proposal #9 array of contiguous typed arrays Total Init = 0ms Execution = 16ms
Proposal #10 numeric.js simple Total Init = 0ms Execution = 230ms
Proposal #11 numeric.js pointwise() Total Init = 1ms Execution = 139ms
Proposal #12 ndarray-raw Total Init = 0ms Execution = 8ms
Proposal #13 ndarray-ops Total Init = 0ms Execution = 49ms
Proposal #14 cwise Total Init = 0ms Execution = 9ms
Running experiment with dimensions = 2048 x 2 x 2 experiment.js:30
Proposal #1 raw native array Total Init = 1ms Execution = 15ms
Proposal #2 raw typed array Total Init = 0ms Execution = 15ms
Proposal #3 object with array accessor Total Init = 0ms Execution = 34ms
Proposal #4 object with flat accessor Total Init = 0ms Execution = 25ms
Proposal #5 object with flat accessor, no offset Total Init = 0ms Execution = 23ms
Proposal #6 array of native arrays Total Init = 1ms Execution = 51ms
Proposal #7 array of native arrays (fast init) Total Init = 2ms Execution = 17ms
Proposal #8 array of typed arrays Total Init = 7ms Execution = 20ms
Proposal #9 array of contiguous typed arrays Total Init = 6ms Execution = 19ms
Proposal #10 numeric.js simple Total Init = 21ms Execution = 458ms
Proposal #11 numeric.js pointwise() Total Init = 2ms Execution = 303ms
Proposal #12 ndarray-raw Total Init = 0ms Execution = 17ms
Proposal #13 ndarray-ops Total Init = 0ms Execution = 83ms
Proposal #14 cwise Total Init = 0ms Execution = 18ms
Interesting things to note:
get([i,j,k])
for indexing is terrible. get(i,j,k)
is more than 10x faster.Excluding obviously stupid things,
Flat typed array, with manual index
subarray
not supported, can only slice along first axis.Array-of-native arrays
Array-of-typed-arrays
Custom multidimensional array object
Based on performance considerations, I am currently leaning toward option 4, but dissenting opinions are welcome.