mirror of
https://github.com/protobufjs/protobuf.js.git
synced 2026-02-01 17:21:20 +00:00
plain js utf8 is faster for short strings
This commit is contained in:
parent
0ae6675236
commit
98d6ae186a
30
README.md
30
README.md
@ -372,33 +372,33 @@ The package includes a [benchmark](https://github.com/dcodeIO/protobuf.js/tree/m
|
||||
```
|
||||
benchmarking encoding performance ...
|
||||
|
||||
Type.encode to buffer x 402,572 ops/sec ±1.09% (90 runs sampled)
|
||||
JSON.stringify to string x 342,004 ops/sec ±1.46% (82 runs sampled)
|
||||
JSON.stringify to buffer x 184,468 ops/sec ±1.76% (79 runs sampled)
|
||||
Type.encode to buffer x 514,048 ops/sec ±0.75% (93 runs sampled)
|
||||
JSON.stringify to string x 355,935 ops/sec ±0.79% (91 runs sampled)
|
||||
JSON.stringify to buffer x 191,023 ops/sec ±1.39% (86 runs sampled)
|
||||
|
||||
Type.encode to buffer was fastest
|
||||
JSON.stringify to string was 15.4% slower
|
||||
JSON.stringify to buffer was 54.5% slower
|
||||
JSON.stringify to string was 30.8% slower
|
||||
JSON.stringify to buffer was 63.1% slower
|
||||
|
||||
benchmarking decoding performance ...
|
||||
|
||||
Type.decode from buffer x 1,170,490 ops/sec ±1.49% (88 runs sampled)
|
||||
JSON.parse from string x 328,975 ops/sec ±0.90% (88 runs sampled)
|
||||
JSON.parse from buffer x 298,702 ops/sec ±0.82% (89 runs sampled)
|
||||
Type.decode from buffer x 1,238,587 ops/sec ±1.73% (87 runs sampled)
|
||||
JSON.parse from string x 312,168 ops/sec ±2.22% (83 runs sampled)
|
||||
JSON.parse from buffer x 272,975 ops/sec ±2.45% (82 runs sampled)
|
||||
|
||||
Type.decode from buffer was fastest
|
||||
JSON.parse from string was 71.7% slower
|
||||
JSON.parse from buffer was 74.3% slower
|
||||
JSON.parse from string was 74.9% slower
|
||||
JSON.parse from buffer was 78.1% slower
|
||||
|
||||
benchmarking combined performance ...
|
||||
|
||||
Type to/from buffer x 218,688 ops/sec ±1.49% (90 runs sampled)
|
||||
JSON to/from string x 144,634 ops/sec ±1.97% (87 runs sampled)
|
||||
JSON to/from buffer x 102,350 ops/sec ±1.23% (92 runs sampled)
|
||||
Type to/from buffer x 246,428 ops/sec ±1.52% (89 runs sampled)
|
||||
JSON to/from string x 136,380 ops/sec ±1.50% (80 runs sampled)
|
||||
JSON to/from buffer x 95,229 ops/sec ±1.93% (86 runs sampled)
|
||||
|
||||
Type to/from buffer was fastest
|
||||
JSON to/from string was 34.2% slower
|
||||
JSON to/from buffer was 53.1% slower
|
||||
JSON to/from string was 44.6% slower
|
||||
JSON to/from buffer was 61.5% slower
|
||||
```
|
||||
|
||||
Note that JSON is a native binding nowadays and as such is *really* fast. So, how can protobuf.js be faster?
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
var benchmark = require("benchmark"),
|
||||
chalk = require("chalk");
|
||||
|
||||
var protobuf = require("../src/index"),
|
||||
suite = new benchmark.Suite(),
|
||||
newSuite = require("./suite"),
|
||||
data = require("./bench.json");
|
||||
|
||||
// NOTE: This benchmark is flawed in that it compares protocol buffers, which is purely a binary
|
||||
@ -68,47 +65,4 @@ protobuf.load(require.resolve("./bench.proto"), function onload(err, root) {
|
||||
})
|
||||
.run();
|
||||
|
||||
});
|
||||
|
||||
var padSize = 27;
|
||||
|
||||
function newSuite(name) {
|
||||
var benches = [];
|
||||
return new benchmark.Suite(name)
|
||||
.on("add", function(event) {
|
||||
benches.push(event.target);
|
||||
})
|
||||
.on("start", function() {
|
||||
console.log("benchmarking " + name + " performance ...\n");
|
||||
})
|
||||
.on("error", function(err) {
|
||||
console.log("ERROR:", err);
|
||||
})
|
||||
.on("cycle", function(event) {
|
||||
console.log(String(event.target));
|
||||
})
|
||||
.on("complete", function(event) {
|
||||
var fastest = this.filter('fastest'),
|
||||
slowest = this.filter('slowest');
|
||||
var fastestHz = getHz(fastest[0]);
|
||||
console.log("\n" + chalk.white(pad(fastest[0].name, padSize)) + " was " + chalk.green("fastest"));
|
||||
benches.forEach(function(bench) {
|
||||
if (fastest.indexOf(bench) > -1)
|
||||
return;
|
||||
var hz = hz = getHz(bench);
|
||||
var percent = (1 - (hz / fastestHz)) * 100;
|
||||
console.log(chalk.white(pad(bench.name, padSize)) + " was " + chalk.red(percent.toFixed(1)+'% slower'));
|
||||
});
|
||||
console.log();
|
||||
});
|
||||
}
|
||||
|
||||
function getHz(bench) {
|
||||
return 1 / (bench.stats.mean + bench.stats.moe);
|
||||
}
|
||||
|
||||
function pad(str, len, l) {
|
||||
while (str.length < len)
|
||||
str = l ? str + " " : " " + str;
|
||||
return str;
|
||||
}
|
||||
});
|
||||
45
bench/suite.js
Normal file
45
bench/suite.js
Normal file
@ -0,0 +1,45 @@
|
||||
var benchmark = require("benchmark"),
|
||||
chalk = require("chalk");
|
||||
|
||||
var padSize = 27;
|
||||
|
||||
module.exports = function newSuite(name) {
|
||||
var benches = [];
|
||||
return new benchmark.Suite(name)
|
||||
.on("add", function(event) {
|
||||
benches.push(event.target);
|
||||
})
|
||||
.on("start", function() {
|
||||
console.log("benchmarking " + name + " performance ...\n");
|
||||
})
|
||||
.on("error", function(err) {
|
||||
console.log("ERROR:", err);
|
||||
})
|
||||
.on("cycle", function(event) {
|
||||
console.log(String(event.target));
|
||||
})
|
||||
.on("complete", function(event) {
|
||||
var fastest = this.filter('fastest'),
|
||||
slowest = this.filter('slowest');
|
||||
var fastestHz = getHz(fastest[0]);
|
||||
console.log("\n" + chalk.white(pad(fastest[0].name, padSize)) + " was " + chalk.green("fastest"));
|
||||
benches.forEach(function(bench) {
|
||||
if (fastest.indexOf(bench) > -1)
|
||||
return;
|
||||
var hz = hz = getHz(bench);
|
||||
var percent = (1 - (hz / fastestHz)) * 100;
|
||||
console.log(chalk.white(pad(bench.name, padSize)) + " was " + chalk.red(percent.toFixed(1)+'% slower'));
|
||||
});
|
||||
console.log();
|
||||
});
|
||||
}
|
||||
|
||||
function getHz(bench) {
|
||||
return 1 / (bench.stats.mean + bench.stats.moe);
|
||||
}
|
||||
|
||||
function pad(str, len, l) {
|
||||
while (str.length < len)
|
||||
str = l ? str + " " : " " + str;
|
||||
return str;
|
||||
}
|
||||
45
bench/write.js
Normal file
45
bench/write.js
Normal file
@ -0,0 +1,45 @@
|
||||
var protobuf = require("../src/index"),
|
||||
newSuite = require("./suite");
|
||||
|
||||
newSuite("float")
|
||||
.add("Writer#float", function() {
|
||||
var writer = new protobuf.Writer();
|
||||
writer.float(0.1);
|
||||
writer.finish();
|
||||
})
|
||||
.add("BufferWriter#float", function() {
|
||||
var writer = new protobuf.BufferWriter();
|
||||
writer.float(0.1);
|
||||
writer.finish();
|
||||
})
|
||||
.run();
|
||||
|
||||
newSuite("double")
|
||||
.add("Writer#double", function() {
|
||||
var writer = new protobuf.Writer();
|
||||
writer.double(0.1);
|
||||
writer.finish();
|
||||
})
|
||||
.add("BufferWriter#double", function() {
|
||||
var writer = new protobuf.BufferWriter();
|
||||
writer.double(0.1);
|
||||
writer.finish();
|
||||
})
|
||||
.run();
|
||||
|
||||
var bytes = [0, 0, 0, 0, 0, 0, 0, 0];
|
||||
var arrayBytes = new Uint8Array(bytes);
|
||||
var bufferBytes = Buffer.from(bytes);
|
||||
|
||||
newSuite("bytes")
|
||||
.add("Writer#bytes", function() {
|
||||
var writer = new protobuf.Writer();
|
||||
writer.bytes(arrayBytes);
|
||||
writer.finish();
|
||||
})
|
||||
.add("BufferWriter#bytes", function() {
|
||||
var writer = new protobuf.BufferWriter();
|
||||
writer.bytes(bufferBytes);
|
||||
writer.finish();
|
||||
})
|
||||
.run();
|
||||
56
dist/protobuf.js
vendored
56
dist/protobuf.js
vendored
@ -1,6 +1,6 @@
|
||||
/*!
|
||||
* protobuf.js v6.0.1 (c) 2016 Daniel Wirtz
|
||||
* Compiled Sat, 03 Dec 2016 11:37:47 UTC
|
||||
* Compiled Sat, 03 Dec 2016 12:34:45 UTC
|
||||
* Licensed under the Apache License, Version 2.0
|
||||
* see: https://github.com/dcodeIO/protobuf.js for details
|
||||
*/
|
||||
@ -5498,9 +5498,9 @@ function writeString(buf, pos, val) {
|
||||
if (c1 < 128) {
|
||||
buf[pos++] = c1;
|
||||
} else if (c1 < 2048) {
|
||||
buf[pos++] = c1 >> 6 | 192;
|
||||
buf[pos++] = c1 & 63 | 128;
|
||||
} else if ((c1 & 0xFC00) === 0xD800 && i + 1 < val.length && ((c2 = val.charCodeAt(i + 1)) & 0xFC00) === 0xDC00) {
|
||||
buf[pos++] = c1 >> 6 | 192;
|
||||
buf[pos++] = c1 & 63 | 128;
|
||||
} else if ((c1 & 0xFC00) === 0xD800 && ((c2 = val.charCodeAt(i + 1)) & 0xFC00) === 0xDC00) {
|
||||
c1 = 0x10000 + ((c1 & 0x03FF) << 10) + (c2 & 0x03FF);
|
||||
++i;
|
||||
buf[pos++] = c1 >> 18 | 240;
|
||||
@ -5517,23 +5517,20 @@ function writeString(buf, pos, val) {
|
||||
|
||||
function byteLength(val) {
|
||||
var strlen = val.length >>> 0;
|
||||
if (strlen) {
|
||||
var len = 0;
|
||||
for (var i = 0, c1; i < strlen; ++i) {
|
||||
c1 = val.charCodeAt(i);
|
||||
if (c1 < 128)
|
||||
len += 1;
|
||||
else if (c1 < 2048)
|
||||
len += 2;
|
||||
else if ((c1 & 0xFC00) === 0xD800 && i + 1 < strlen && (val.charCodeAt(i + 1) & 0xFC00) === 0xDC00) {
|
||||
++i;
|
||||
len += 4;
|
||||
} else
|
||||
len += 3;
|
||||
}
|
||||
return len;
|
||||
var len = 0;
|
||||
for (var i = 0; i < strlen; ++i) {
|
||||
var c1 = val.charCodeAt(i);
|
||||
if (c1 < 128)
|
||||
len += 1;
|
||||
else if (c1 < 2048)
|
||||
len += 2;
|
||||
else if ((c1 & 0xFC00) === 0xD800 && (val.charCodeAt(i + 1) & 0xFC00) === 0xDC00) {
|
||||
++i;
|
||||
len += 4;
|
||||
} else
|
||||
len += 3;
|
||||
}
|
||||
return 0;
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -5666,17 +5663,22 @@ BufferWriterPrototype.bytes = function write_bytes_buffer(value) {
|
||||
};
|
||||
|
||||
function writeStringBuffer(buf, pos, val) {
|
||||
buf.write(val, pos);
|
||||
if (val.length < 40) // plain js is faster for short strings
|
||||
writeString(buf, pos, val);
|
||||
else
|
||||
buf.write(val, pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
BufferWriterPrototype.string = function write_string_buffer(value) {
|
||||
var len = byteLength(value);
|
||||
BufferWriterPrototype.string = function write_string_buffer(value) {
|
||||
var len = value.length < 40
|
||||
? byteLength(value)
|
||||
: util.Buffer.byteLength(value);
|
||||
return len
|
||||
? this.uint32(len).push(writeStringBuffer, len, value)
|
||||
: this.push(writeByte, 1, 0);
|
||||
? this.uint32(len).push(writeStringBuffer, len, value)
|
||||
: this.push(writeByte, 1, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -5702,8 +5704,6 @@ configure();
|
||||
"use strict";
|
||||
var protobuf = global.protobuf = exports;
|
||||
|
||||
var util = require(21);
|
||||
|
||||
/**
|
||||
* Loads one or multiple .proto or preprocessed .json files into a common root namespace.
|
||||
* @param {string|string[]} filename One or multiple files to load
|
||||
@ -5755,7 +5755,7 @@ protobuf.inherits = require(7);
|
||||
// Utility
|
||||
protobuf.types = require(20);
|
||||
protobuf.common = require(2);
|
||||
protobuf.util = util;
|
||||
protobuf.util = require(21);
|
||||
|
||||
// Be nice to AMD
|
||||
/* eslint-disable no-undef */
|
||||
|
||||
2
dist/protobuf.js.map
vendored
2
dist/protobuf.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/protobuf.min.js
vendored
4
dist/protobuf.min.js
vendored
File diff suppressed because one or more lines are too long
BIN
dist/protobuf.min.js.gz
vendored
BIN
dist/protobuf.min.js.gz
vendored
Binary file not shown.
2
dist/protobuf.min.js.map
vendored
2
dist/protobuf.min.js.map
vendored
File diff suppressed because one or more lines are too long
@ -1,8 +1,6 @@
|
||||
"use strict";
|
||||
var protobuf = global.protobuf = exports;
|
||||
|
||||
var util = require("./util");
|
||||
|
||||
/**
|
||||
* Loads one or multiple .proto or preprocessed .json files into a common root namespace.
|
||||
* @param {string|string[]} filename One or multiple files to load
|
||||
@ -54,7 +52,7 @@ protobuf.inherits = require("./inherits");
|
||||
// Utility
|
||||
protobuf.types = require("./types");
|
||||
protobuf.common = require("./common");
|
||||
protobuf.util = util;
|
||||
protobuf.util = require("./util");
|
||||
|
||||
// Be nice to AMD
|
||||
/* eslint-disable no-undef */
|
||||
|
||||
@ -367,9 +367,9 @@ function writeString(buf, pos, val) {
|
||||
if (c1 < 128) {
|
||||
buf[pos++] = c1;
|
||||
} else if (c1 < 2048) {
|
||||
buf[pos++] = c1 >> 6 | 192;
|
||||
buf[pos++] = c1 & 63 | 128;
|
||||
} else if ((c1 & 0xFC00) === 0xD800 && i + 1 < val.length && ((c2 = val.charCodeAt(i + 1)) & 0xFC00) === 0xDC00) {
|
||||
buf[pos++] = c1 >> 6 | 192;
|
||||
buf[pos++] = c1 & 63 | 128;
|
||||
} else if ((c1 & 0xFC00) === 0xD800 && ((c2 = val.charCodeAt(i + 1)) & 0xFC00) === 0xDC00) {
|
||||
c1 = 0x10000 + ((c1 & 0x03FF) << 10) + (c2 & 0x03FF);
|
||||
++i;
|
||||
buf[pos++] = c1 >> 18 | 240;
|
||||
@ -386,23 +386,20 @@ function writeString(buf, pos, val) {
|
||||
|
||||
function byteLength(val) {
|
||||
var strlen = val.length >>> 0;
|
||||
if (strlen) {
|
||||
var len = 0;
|
||||
for (var i = 0, c1; i < strlen; ++i) {
|
||||
c1 = val.charCodeAt(i);
|
||||
if (c1 < 128)
|
||||
len += 1;
|
||||
else if (c1 < 2048)
|
||||
len += 2;
|
||||
else if ((c1 & 0xFC00) === 0xD800 && i + 1 < strlen && (val.charCodeAt(i + 1) & 0xFC00) === 0xDC00) {
|
||||
++i;
|
||||
len += 4;
|
||||
} else
|
||||
len += 3;
|
||||
}
|
||||
return len;
|
||||
var len = 0;
|
||||
for (var i = 0; i < strlen; ++i) {
|
||||
var c1 = val.charCodeAt(i);
|
||||
if (c1 < 128)
|
||||
len += 1;
|
||||
else if (c1 < 2048)
|
||||
len += 2;
|
||||
else if ((c1 & 0xFC00) === 0xD800 && (val.charCodeAt(i + 1) & 0xFC00) === 0xDC00) {
|
||||
++i;
|
||||
len += 4;
|
||||
} else
|
||||
len += 3;
|
||||
}
|
||||
return 0;
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -535,17 +532,22 @@ BufferWriterPrototype.bytes = function write_bytes_buffer(value) {
|
||||
};
|
||||
|
||||
function writeStringBuffer(buf, pos, val) {
|
||||
buf.write(val, pos);
|
||||
if (val.length < 40) // plain js is faster for short strings
|
||||
writeString(buf, pos, val);
|
||||
else
|
||||
buf.write(val, pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
BufferWriterPrototype.string = function write_string_buffer(value) {
|
||||
var len = byteLength(value);
|
||||
BufferWriterPrototype.string = function write_string_buffer(value) {
|
||||
var len = value.length < 40
|
||||
? byteLength(value)
|
||||
: util.Buffer.byteLength(value);
|
||||
return len
|
||||
? this.uint32(len).push(writeStringBuffer, len, value)
|
||||
: this.push(writeByte, 1, 0);
|
||||
? this.uint32(len).push(writeStringBuffer, len, value)
|
||||
: this.push(writeByte, 1, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
2
types/protobuf.js.d.ts
vendored
2
types/protobuf.js.d.ts
vendored
@ -3,7 +3,7 @@
|
||||
|
||||
/*
|
||||
* protobuf.js v6.0.1 TypeScript definitions
|
||||
* Generated Sat, 03 Dec 2016 11:38:06 UTC
|
||||
* Generated Sat, 03 Dec 2016 12:34:52 UTC
|
||||
*/
|
||||
declare module "protobufjs" {
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user