assert: typed array deepequal performance fix
authorClaudio Rodriguez <cjrodr@yahoo.com>
Thu, 17 Dec 2015 13:05:45 +0000 (10:05 -0300)
committerMyles Borins <mborins@us.ibm.com>
Tue, 19 Jan 2016 19:52:32 +0000 (11:52 -0800)
assert.deepEqual: when actual and expected are typed arrays,
wrap them in a new Buffer each to increase performance
significantly.

PR-URL: https://github.com/nodejs/node/pull/4330
Fixes: https://github.com/nodejs/node/issues/4294
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Roman Reiss <me@silverwind.io>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
benchmark/assert/deepequal-prims-and-objs-big-array.js [new file with mode: 0644]
benchmark/assert/deepequal-prims-and-objs-big-loop.js [new file with mode: 0644]
benchmark/assert/deepequal-typedarrays.js [new file with mode: 0644]
lib/assert.js
test/parallel/test-assert-typedarray-deepequal.js [new file with mode: 0644]

diff --git a/benchmark/assert/deepequal-prims-and-objs-big-array.js b/benchmark/assert/deepequal-prims-and-objs-big-array.js
new file mode 100644 (file)
index 0000000..d8d2b57
--- /dev/null
@@ -0,0 +1,37 @@
+'use strict';
+var common = require('../common.js');
+var assert = require('assert');
+var bench = common.createBenchmark(main, {
+  prim: [
+    null,
+    undefined,
+    'a',
+    1,
+    true,
+    {0: 'a'},
+    [1, 2, 3],
+    new Array([1, 2, 3])
+  ],
+  n: [25]
+});
+
+function main(conf) {
+  var prim = conf.prim;
+  var n = +conf.n;
+  var primArray;
+  var primArrayCompare;
+  var x;
+
+  primArray = new Array();
+  primArrayCompare = new Array();
+  for (x = 0; x < (1e5); x++) {
+    primArray.push(prim);
+    primArrayCompare.push(prim);
+  }
+
+  bench.start();
+  for (x = 0; x < n; x++) {
+    assert.deepEqual(primArray, primArrayCompare);
+  }
+  bench.end(n);
+}
diff --git a/benchmark/assert/deepequal-prims-and-objs-big-loop.js b/benchmark/assert/deepequal-prims-and-objs-big-loop.js
new file mode 100644 (file)
index 0000000..5f0519b
--- /dev/null
@@ -0,0 +1,30 @@
+'use strict';
+var common = require('../common.js');
+var assert = require('assert');
+var bench = common.createBenchmark(main, {
+  prim: [
+    null,
+    undefined,
+    'a',
+    1,
+    true,
+    {0: 'a'},
+    [1, 2, 3],
+    new Array([1, 2, 3])
+  ],
+  n: [1e5]
+});
+
+function main(conf) {
+  var prim = conf.prim;
+  var n = +conf.n;
+  var x;
+
+  bench.start();
+
+  for (x = 0; x < n; x++) {
+    assert.deepEqual(new Array([prim]), new Array([prim]));
+  }
+
+  bench.end(n);
+}
diff --git a/benchmark/assert/deepequal-typedarrays.js b/benchmark/assert/deepequal-typedarrays.js
new file mode 100644 (file)
index 0000000..99c1320
--- /dev/null
@@ -0,0 +1,22 @@
+'use strict';
+var common = require('../common.js');
+var assert = require('assert');
+var bench = common.createBenchmark(main, {
+  type: ('Int8Array Uint8Array Int16Array Uint16Array Int32Array Uint32Array ' +
+    'Float32Array Float64Array Uint8ClampedArray').split(' '),
+  n: [1]
+});
+
+function main(conf) {
+  var type = conf.type;
+  var clazz = global[type];
+  var n = +conf.n;
+
+  bench.start();
+  var actual = new clazz(n * 1e6);
+  var expected = new clazz(n * 1e6);
+
+  assert.deepEqual(actual, expected);
+
+  bench.end(n);
+}
index 6b99098..f8dc97d 100644 (file)
@@ -170,6 +170,11 @@ function _deepEqual(actual, expected, strict) {
              (expected === null || typeof expected !== 'object')) {
     return strict ? actual === expected : actual == expected;
 
+  // If both values are instances of typed arrays, wrap them in
+  // a Buffer each to increase performance
+  } else if (ArrayBuffer.isView(actual) && ArrayBuffer.isView(expected)) {
+    return compare(new Buffer(actual), new Buffer(expected)) === 0;
+
   // 7.5 For all other Object pairs, including Array objects, equivalence is
   // determined by having the same number of owned properties (as verified
   // with Object.prototype.hasOwnProperty.call), the same set of keys
diff --git a/test/parallel/test-assert-typedarray-deepequal.js b/test/parallel/test-assert-typedarray-deepequal.js
new file mode 100644 (file)
index 0000000..3274878
--- /dev/null
@@ -0,0 +1,41 @@
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+const a = require('assert');
+
+function makeBlock(f) {
+  var args = Array.prototype.slice.call(arguments, 1);
+  return function() {
+    return f.apply(this, args);
+  };
+}
+
+const equalArrayPairs = [
+  [new Uint8Array(1e5), new Uint8Array(1e5)],
+  [new Uint16Array(1e5), new Uint16Array(1e5)],
+  [new Uint32Array(1e5), new Uint32Array(1e5)],
+  [new Uint8ClampedArray(1e5), new Uint8ClampedArray(1e5)],
+  [new Int8Array(1e5), new Int8Array(1e5)],
+  [new Int16Array(1e5), new Int16Array(1e5)],
+  [new Int32Array(1e5), new Int32Array(1e5)],
+  [new Float32Array(1e5), new Float32Array(1e5)],
+  [new Float64Array(1e5), new Float64Array(1e5)]
+];
+
+const notEqualArrayPairs = [
+  [new Uint8Array(2), new Uint8Array(3)],
+  [new Uint8Array([1, 2, 3]), new Uint8Array([4, 5, 6])],
+  [new Uint8ClampedArray([300, 2, 3]), new Uint8Array([300, 2, 3])]
+];
+
+equalArrayPairs.forEach((arrayPair) => {
+  assert.deepEqual(arrayPair[0], arrayPair[1]);
+});
+
+notEqualArrayPairs.forEach((arrayPair) => {
+  assert.throws(
+    makeBlock(a.deepEqual, arrayPair[0], arrayPair[1]),
+    a.AssertionError
+  );
+});