summaryrefslogtreecommitdiff
path: root/benchmark/buffers
diff options
context:
space:
mode:
authorZach Bjornson <bjornson@stanford.edu>2016-06-04 13:38:08 -0700
committerTrevor Norris <trev.norris@gmail.com>2016-06-27 14:38:37 -0600
commita1059afd3963a2a8f916aa0874865658c0479672 (patch)
tree767edfaa430a6aaab1e57ed544e3c3455dcb9902 /benchmark/buffers
parent561548702e3ee30525dd3a72a9cdf0dd923d0beb (diff)
downloadandroid-node-v8-a1059afd3963a2a8f916aa0874865658c0479672.tar.gz
android-node-v8-a1059afd3963a2a8f916aa0874865658c0479672.tar.bz2
android-node-v8-a1059afd3963a2a8f916aa0874865658c0479672.zip
buffer: speed up swap16/32, add swap64
* Speed up buffer.swap16 and swap32 by using builtins. Up to ~6x gain. Drop transition point between JS and C++ implementations accordingly. Amount of performance improvement not only depends on buffer size but also memory alignment. * Fix tests: C++ impl tests were testing 0-filled buffers so were always passing. * Add similar buffer.swap64 method. * Make buffer-swap benchmark mirror JS impl. doc/api/buffer.markdown has an entry of "added: REPLACEME" that should be changed to the correct release number before tagged. Because node is currently using a very old version of cpplint.py it doesn't know that std::swap() has moved from <algorithm> to <utility> in c++11. So until cpplint.py is updated simply NOLINT the line. Technically it should be NOLINT(build/include_what_you_use), but that puts the line over 80 characters causing another lint error. PR-URL: https://github.com/nodejs/node/pull/7157 Reviewed-By: Trevor Norris <trev.norris@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'benchmark/buffers')
-rw-r--r--benchmark/buffers/buffer-swap.js75
1 files changed, 52 insertions, 23 deletions
diff --git a/benchmark/buffers/buffer-swap.js b/benchmark/buffers/buffer-swap.js
index 4ff9a23d41..0793c77c8f 100644
--- a/benchmark/buffers/buffer-swap.js
+++ b/benchmark/buffers/buffer-swap.js
@@ -1,61 +1,90 @@
'use strict';
const common = require('../common.js');
+const v8 = require('v8');
const bench = common.createBenchmark(main, {
- method: ['swap16', 'swap32', 'htons', 'htonl'],
- len: [4, 64, 512, 768, 1024, 1536, 2056, 4096, 8192],
- n: [1e6]
+ aligned: ['true', 'false'],
+ method: ['swap16', 'swap32', 'swap64'/*, 'htons', 'htonl', 'htonll'*/],
+ len: [8, 64, 128, 256, 512, 768, 1024, 1536, 2056, 4096, 8192],
+ n: [5e7]
});
// The htons and htonl methods below are used to benchmark the
// performance difference between doing the byteswap in pure
// javascript regardless of Buffer size as opposed to dropping
-// down to the native layer for larger Buffer sizes.
+// down to the native layer for larger Buffer sizes. Commented
+// out by default because they are slow for big buffers. If
+// re-evaluating the crossover point, uncomment those methods
+// and comment out their implementations in lib/buffer.js so
+// C++ version will always be used.
+
+function swap(b, n, m) {
+ const i = b[n];
+ b[n] = b[m];
+ b[m] = i;
+}
Buffer.prototype.htons = function htons() {
if (this.length % 2 !== 0)
throw new RangeError();
- for (var i = 0, n = 0; i < this.length; i += 2) {
- n = this[i];
- this[i] = this[i + 1];
- this[i + 1] = n;
+ for (var i = 0; i < this.length; i += 2) {
+ swap(this, i, i + 1);
}
return this;
};
Buffer.prototype.htonl = function htonl() {
- if (this.length % 2 !== 0)
+ if (this.length % 4 !== 0)
+ throw new RangeError();
+ for (var i = 0; i < this.length; i += 4) {
+ swap(this, i, i + 3);
+ swap(this, i + 1, i + 2);
+ }
+ return this;
+};
+
+Buffer.prototype.htonll = function htonl() {
+ if (this.length % 8 !== 0)
throw new RangeError();
- for (var i = 0, n = 0; i < this.length; i += 4) {
- n = this[i];
- this[i] = this[i + 3];
- this[i + 3] = n;
- n = this[i + 1];
- this[i + 1] = this[i + 2];
- this[i + 2] = n;
+ for (var i = 0; i < this.length; i += 8) {
+ swap(this, i, i + 7);
+ swap(this, i + 1, i + 6);
+ swap(this, i + 2, i + 5);
+ swap(this, i + 3, i + 4);
}
return this;
};
-function createBuffer(len) {
+function createBuffer(len, aligned) {
+ len += aligned ? 0 : 1;
const buf = Buffer.allocUnsafe(len);
for (var i = 1; i <= len; i++)
buf[i - 1] = i;
- return buf;
+ return aligned ? buf : buf.slice(1);
}
-function bufferSwap(n, buf, method) {
- for (var i = 1; i <= n; i++)
- buf[method]();
+function genMethod(method) {
+ const fnString =
+ 'return function ' + method + '(n, buf) {' +
+ ' for (var i = 0; i <= n; i++)' +
+ ' buf.' + method + '();' +
+ '}';
+ return (new Function(fnString))();
}
function main(conf) {
const method = conf.method;
const len = conf.len | 0;
const n = conf.n | 0;
- const buf = createBuffer(len);
+ const aligned = conf.aligned || 'true';
+ const buf = createBuffer(len, aligned === 'true');
+ const bufferSwap = genMethod(method);
+
+ v8.setFlagsFromString('--allow_natives_syntax');
+ eval('%OptimizeFunctionOnNextCall(bufferSwap)');
+
bench.start();
- bufferSwap(n, buf, method);
+ bufferSwap(n, buf);
bench.end(n);
}