Skip to content

Commit

Permalink
added experiments for cwise, ndarray-ops and numeric
Browse files Browse the repository at this point in the history
  • Loading branch information
mikolalysenko committed Mar 9, 2013
1 parent 508ec63 commit 2ea792b
Show file tree
Hide file tree
Showing 14 changed files with 4,679 additions and 57 deletions.
150 changes: 95 additions & 55 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

What is the most efficient way to implement multidimensional arrays in JavaScript?

**UPDATE** Experiments for [numeric.js](http://www.numericjs.com/), [cwise](https://github.com/mikolalysenko/cwise) and [ndarray-ops](https://github.com/mikolalysenko/ndarray-ops) added

# Experiment
To run the experiment, just do:

Expand All @@ -10,70 +12,99 @@ To run the experiment, just do:
# Results:

Running experiment with dimensions = 16 x 16 x 16
Proposal # 0 raw native array Elapsed time = 14
Proposal # 1 raw typed array Elapsed time = 8
Proposal # 2 object with array accessor Elapsed time = 99
Proposal # 3 object with flat accessor Elapsed time = 11
Proposal # 4 object with flat accessor, no offset Elapsed time = 9
Proposal # 5 array of native arrays Elapsed time = 30
Proposal # 6 array of typed arrays Elapsed time = 82
Proposal # 7 array of contiguous typed arrays Elapsed time = 86
Proposal # 0 raw native array Elapsed time = 19
Proposal # 1 raw typed array Elapsed time = 7
Proposal # 2 object with array accessor Elapsed time = 97
Proposal # 3 object with flat accessor Elapsed time = 10
Proposal # 4 object with flat accessor, no offset Elapsed time = 10
Proposal # 5 array of native arrays Elapsed time = 28
Proposal # 6 array of typed arrays Elapsed time = 81
Proposal # 7 array of contiguous typed arrays Elapsed time = 77
Proposal # 8 numeric.js simple Elapsed time = 43
Proposal # 9 numeric.js pointwise() Elapsed time = 67
Proposal # 10 ndarray-ops Elapsed time = 25
Proposal # 11 cwise Elapsed time = 7
Running experiment with dimensions = 64 x 64 x 64
Proposal # 0 raw native array Elapsed time = 3559
Proposal # 1 raw typed array Elapsed time = 293
Proposal # 2 object with array accessor Elapsed time = 5828
Proposal # 3 object with flat accessor Elapsed time = 460
Proposal # 4 object with flat accessor, no offset Elapsed time = 406
Proposal # 5 array of native arrays Elapsed time = 1846
Proposal # 6 array of typed arrays Elapsed time = 1514
Proposal # 7 array of contiguous typed arrays Elapsed time = 1495
Proposal # 0 raw native array Elapsed time = 8673
Proposal # 1 raw typed array Elapsed time = 285
Proposal # 2 object with array accessor Elapsed time = 5643
Proposal # 3 object with flat accessor Elapsed time = 437
Proposal # 4 object with flat accessor, no offset Elapsed time = 394
Proposal # 5 array of native arrays Elapsed time = 1696
Proposal # 6 array of typed arrays Elapsed time = 1534
Proposal # 7 array of contiguous typed arrays Elapsed time = 1403
Proposal # 8 numeric.js simple Elapsed time = 11255
Proposal # 9 numeric.js pointwise() Elapsed time = 8156
Proposal # 10 ndarray-ops Elapsed time = 761
Proposal # 11 cwise Elapsed time = 258
Running experiment with dimensions = 512 x 512 x 4
Proposal # 0 raw native array Elapsed time = 14289
Proposal # 1 raw typed array Elapsed time = 1183
Proposal # 2 object with array accessor Elapsed time = 23133
Proposal # 3 object with flat accessor Elapsed time = 1896
Proposal # 4 object with flat accessor, no offset Elapsed time = 1692
Proposal # 5 array of native arrays Elapsed time = 9411
Proposal # 6 array of typed arrays Elapsed time = 78900
Proposal # 7 array of contiguous typed arrays Elapsed time = 71694
Proposal # 0 raw native array Elapsed time = 13855
Proposal # 1 raw typed array Elapsed time = 1153
Proposal # 2 object with array accessor Elapsed time = 23834
Proposal # 3 object with flat accessor Elapsed time = 1893
Proposal # 4 object with flat accessor, no offset Elapsed time = 1779
Proposal # 5 array of native arrays Elapsed time = 11578
Proposal # 6 array of typed arrays Elapsed time = 90506
Proposal # 7 array of contiguous typed arrays Elapsed time = 81326
Proposal # 8 numeric.js simple Elapsed time = 84642
Proposal # 9 numeric.js pointwise() Elapsed time = 54247
Proposal # 10 ndarray-ops Elapsed time = 3696
Proposal # 11 cwise Elapsed time = 1222
Running experiment with dimensions = 512 x 4 x 512
Proposal # 0 raw native array Elapsed time = 14555
Proposal # 1 raw typed array Elapsed time = 1141
Proposal # 2 object with array accessor Elapsed time = 23183
Proposal # 3 object with flat accessor Elapsed time = 1703
Proposal # 4 object with flat accessor, no offset Elapsed time = 1557
Proposal # 5 array of native arrays Elapsed time = 6995
Proposal # 6 array of typed arrays Elapsed time = 1851
Proposal # 7 array of contiguous typed arrays Elapsed time = 1787
Proposal # 0 raw native array Elapsed time = 13834
Proposal # 1 raw typed array Elapsed time = 1164
Proposal # 2 object with array accessor Elapsed time = 23363
Proposal # 3 object with flat accessor Elapsed time = 1690
Proposal # 4 object with flat accessor, no offset Elapsed time = 1552
Proposal # 5 array of native arrays Elapsed time = 6993
Proposal # 6 array of typed arrays Elapsed time = 1878
Proposal # 7 array of contiguous typed arrays Elapsed time = 1872
Proposal # 8 numeric.js simple Elapsed time = 42563
Proposal # 9 numeric.js pointwise() Elapsed time = 30237
Proposal # 10 ndarray-ops Elapsed time = 2953
Proposal # 11 cwise Elapsed time = 901
Running experiment with dimensions = 4 x 512 x 512
Proposal # 0 raw native array Elapsed time = 14489
Proposal # 1 raw typed array Elapsed time = 1137
Proposal # 2 object with array accessor Elapsed time = 23257
Proposal # 3 object with flat accessor Elapsed time = 1728
Proposal # 4 object with flat accessor, no offset Elapsed time = 1557
Proposal # 5 array of native arrays Elapsed time = 6906
Proposal # 6 array of typed arrays Elapsed time = 1850
Proposal # 7 array of contiguous typed arrays Elapsed time = 1787
Proposal # 0 raw native array Elapsed time = 13979
Proposal # 1 raw typed array Elapsed time = 1155
Proposal # 2 object with array accessor Elapsed time = 23452
Proposal # 3 object with flat accessor Elapsed time = 1709
Proposal # 4 object with flat accessor, no offset Elapsed time = 1570
Proposal # 5 array of native arrays Elapsed time = 7009
Proposal # 6 array of typed arrays Elapsed time = 1866
Proposal # 7 array of contiguous typed arrays Elapsed time = 1860
Proposal # 8 numeric.js simple Elapsed time = 42783
Proposal # 9 numeric.js pointwise() Elapsed time = 30353
Proposal # 10 ndarray-ops Elapsed time = 2920
Proposal # 11 cwise Elapsed time = 946
Running experiment with dimensions = 2 x 2 x 2048
Proposal # 0 raw native array Elapsed time = 86
Proposal # 0 raw native array Elapsed time = 87
Proposal # 1 raw typed array Elapsed time = 9
Proposal # 2 object with array accessor Elapsed time = 178
Proposal # 2 object with array accessor Elapsed time = 191
Proposal # 3 object with flat accessor Elapsed time = 13
Proposal # 4 object with flat accessor, no offset Elapsed time = 12
Proposal # 5 array of native arrays Elapsed time = 52
Proposal # 4 object with flat accessor, no offset Elapsed time = 13
Proposal # 5 array of native arrays Elapsed time = 51
Proposal # 6 array of typed arrays Elapsed time = 10
Proposal # 7 array of contiguous typed arrays Elapsed time = 10
Proposal # 7 array of contiguous typed arrays Elapsed time = 16
Proposal # 8 numeric.js simple Elapsed time = 190
Proposal # 9 numeric.js pointwise() Elapsed time = 161
Proposal # 10 ndarray-ops Elapsed time = 25
Proposal # 11 cwise Elapsed time = 14
Running experiment with dimensions = 2048 x 2 x 2
Proposal # 0 raw native array Elapsed time = 76
Proposal # 1 raw typed array Elapsed time = 9
Proposal # 2 object with array accessor Elapsed time = 188
Proposal # 3 object with flat accessor Elapsed time = 16
Proposal # 4 object with flat accessor, no offset Elapsed time = 16
Proposal # 5 array of native arrays Elapsed time = 68
Proposal # 6 array of typed arrays Elapsed time = 1181
Proposal # 7 array of contiguous typed arrays Elapsed time = 1114
Proposal # 0 raw native array Elapsed time = 81
Proposal # 1 raw typed array Elapsed time = 10
Proposal # 2 object with array accessor Elapsed time = 194
Proposal # 3 object with flat accessor Elapsed time = 17
Proposal # 4 object with flat accessor, no offset Elapsed time = 15
Proposal # 5 array of native arrays Elapsed time = 99
Proposal # 6 array of typed arrays Elapsed time = 1286
Proposal # 7 array of contiguous typed arrays Elapsed time = 1149
Proposal # 8 numeric.js simple Elapsed time = 612
Proposal # 9 numeric.js pointwise() Elapsed time = 484
Proposal # 10 ndarray-ops Elapsed time = 50
Proposal # 11 cwise Elapsed time = 17

#Observations:
#Generic Observations

* Obviously 1D typed arrays are best performance
* Using `get([i,j,k])` for indexing is terrible. `get(i,j,k)` is more than 10x faster.
Expand All @@ -83,7 +114,7 @@ To run the experiment, just do:
* Contiguous typed array allocation is strictly faster by a small margin (~5%), so if you are going down that route might as well do it.
* For arrays of arrays, it is a trade off by between typed arrays and native arrays. Native arrays are faster if the last dimension is small, while typed arrays are faster if it is large.

# Reasonable Options
## Reasonable Approaches to Arrays

Excluding obviously stupid things,

Expand Down Expand Up @@ -119,3 +150,12 @@ Excluding obviously stupid things,
+ Awkward/non-standard interface, will require libraries standardize on convention

Based on performance considerations, I am currently leaning toward option 4, but dissenting opinions are welcome.


# **UPDATE** Observations about Libraries

* numeric.js is internally built using the array-of-native-arrays approach, and so it is naturally slower than using a typed array
* Also, the implementation of numeric_simple.js uses mul() which returns a copy (and so it is much slower)
* ndarray-ops uses cwise internally, and so it is generally speaking slower than cwise, but may still be useful for some simple operations (like array copying/assignment/basic pointwise operations)
* cwise uses macro expansion to inline functions and unroll loops, and reaches performance which is comparable to a native 1D typed array, with some small overhead due to unboxing primitives.

22 changes: 22 additions & 0 deletions cwise.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
var ndarray = require("ndarray")
var cwise = require("cwise")

var operator = cwise({
args: ["array", "array"],
body: function(a, b) {
a += b + 0.1
b -= a * 0.5
}
})

function benchmark(nx, ny, nz, num_iter) {
var A = ndarray.zeros([nx,ny,nz])
var B = ndarray.zeros([nx,ny,nz])

for(var count=0; count<num_iter; ++count) {
operator(A,B)
}
}

module.exports = benchmark
module.exports.prop_name = "cwise"
6 changes: 5 additions & 1 deletion experiment.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ var proposals = [
require("./object_flat_no_offset.js"),
require("./multi_native.js"),
require("./multi_typed.js"),
require("./multi_cont.js")
require("./multi_cont.js"),
require("./numeric_simple.js"),
require("./numeric_pointwise.js"),
require("./ndarrayops.js"),
require("./cwise.js")
];

function padTo(str, nchars) {
Expand Down
2 changes: 1 addition & 1 deletion native_1d.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ function benchmark(nx, ny, nz, num_iter) {
A[i] = B[i] = 0.0;
}
for(var count=0; count<num_iter; ++count) {
for(var i=0; i<sz; ++i) {
for(var i=sz-1; i>=0; --i) {
A[i] += B[i] + 0.1;
B[i] -= A[i] * 0.5;
}
Expand Down
16 changes: 16 additions & 0 deletions ndarrayops.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
var ndarray = require("ndarray")
, ops = require("ndarray-ops")

function benchmark(nx, ny, nz, num_iter) {
var A = ndarray.zeros([nx,ny,nz])
var B = ndarray.zeros([nx,ny,nz])
var C = ndarray.zeros([nx,ny,nz])

for(var count=0; count<num_iter; ++count) {
ops.addseq(ops.addeq(A, B), 0.1)
ops.subeq(B, ops.muls(C, A, 0.5))
}
}

module.exports = benchmark
module.exports.prop_name = "ndarray-ops"
1 change: 1 addition & 0 deletions node_modules/cwise

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions node_modules/ndarray

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions node_modules/ndarray-ops

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

51 changes: 51 additions & 0 deletions node_modules/numeric/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 2ea792b

Please sign in to comment.