Skip to content

Commit 98d6ae1

Browse files
committed
plain js utf8 is faster for short strings
1 parent 0ae6675 commit 98d6ae1

12 files changed

+167
-123
lines changed

README.md

+15-15
Original file line numberDiff line numberDiff line change
@@ -372,33 +372,33 @@ The package includes a [benchmark](https://github.com/dcodeIO/protobuf.js/tree/m
372372
```
373373
benchmarking encoding performance ...
374374
375-
Type.encode to buffer x 402,572 ops/sec ±1.09% (90 runs sampled)
376-
JSON.stringify to string x 342,004 ops/sec ±1.46% (82 runs sampled)
377-
JSON.stringify to buffer x 184,468 ops/sec ±1.76% (79 runs sampled)
375+
Type.encode to buffer x 514,048 ops/sec ±0.75% (93 runs sampled)
376+
JSON.stringify to string x 355,935 ops/sec ±0.79% (91 runs sampled)
377+
JSON.stringify to buffer x 191,023 ops/sec ±1.39% (86 runs sampled)
378378
379379
Type.encode to buffer was fastest
380-
JSON.stringify to string was 15.4% slower
381-
JSON.stringify to buffer was 54.5% slower
380+
JSON.stringify to string was 30.8% slower
381+
JSON.stringify to buffer was 63.1% slower
382382
383383
benchmarking decoding performance ...
384384
385-
Type.decode from buffer x 1,170,490 ops/sec ±1.49% (88 runs sampled)
386-
JSON.parse from string x 328,975 ops/sec ±0.90% (88 runs sampled)
387-
JSON.parse from buffer x 298,702 ops/sec ±0.82% (89 runs sampled)
385+
Type.decode from buffer x 1,238,587 ops/sec ±1.73% (87 runs sampled)
386+
JSON.parse from string x 312,168 ops/sec ±2.22% (83 runs sampled)
387+
JSON.parse from buffer x 272,975 ops/sec ±2.45% (82 runs sampled)
388388
389389
Type.decode from buffer was fastest
390-
JSON.parse from string was 71.7% slower
391-
JSON.parse from buffer was 74.3% slower
390+
JSON.parse from string was 74.9% slower
391+
JSON.parse from buffer was 78.1% slower
392392
393393
benchmarking combined performance ...
394394
395-
Type to/from buffer x 218,688 ops/sec ±1.49% (90 runs sampled)
396-
JSON to/from string x 144,634 ops/sec ±1.97% (87 runs sampled)
397-
JSON to/from buffer x 102,350 ops/sec ±1.23% (92 runs sampled)
395+
Type to/from buffer x 246,428 ops/sec ±1.52% (89 runs sampled)
396+
JSON to/from string x 136,380 ops/sec ±1.50% (80 runs sampled)
397+
JSON to/from buffer x 95,229 ops/sec ±1.93% (86 runs sampled)
398398
399399
Type to/from buffer was fastest
400-
JSON to/from string was 34.2% slower
401-
JSON to/from buffer was 53.1% slower
400+
JSON to/from string was 44.6% slower
401+
JSON to/from buffer was 61.5% slower
402402
```
403403

404404
Note that JSON is a native binding nowadays and as such is *really* fast. So, how can protobuf.js be faster?

bench/index.js

+2-48
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
var benchmark = require("benchmark"),
2-
chalk = require("chalk");
3-
41
var protobuf = require("../src/index"),
5-
suite = new benchmark.Suite(),
2+
newSuite = require("./suite"),
63
data = require("./bench.json");
74

85
// 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) {
6865
})
6966
.run();
7067

71-
});
72-
73-
var padSize = 27;
74-
75-
function newSuite(name) {
76-
var benches = [];
77-
return new benchmark.Suite(name)
78-
.on("add", function(event) {
79-
benches.push(event.target);
80-
})
81-
.on("start", function() {
82-
console.log("benchmarking " + name + " performance ...\n");
83-
})
84-
.on("error", function(err) {
85-
console.log("ERROR:", err);
86-
})
87-
.on("cycle", function(event) {
88-
console.log(String(event.target));
89-
})
90-
.on("complete", function(event) {
91-
var fastest = this.filter('fastest'),
92-
slowest = this.filter('slowest');
93-
var fastestHz = getHz(fastest[0]);
94-
console.log("\n" + chalk.white(pad(fastest[0].name, padSize)) + " was " + chalk.green("fastest"));
95-
benches.forEach(function(bench) {
96-
if (fastest.indexOf(bench) > -1)
97-
return;
98-
var hz = hz = getHz(bench);
99-
var percent = (1 - (hz / fastestHz)) * 100;
100-
console.log(chalk.white(pad(bench.name, padSize)) + " was " + chalk.red(percent.toFixed(1)+'% slower'));
101-
});
102-
console.log();
103-
});
104-
}
105-
106-
function getHz(bench) {
107-
return 1 / (bench.stats.mean + bench.stats.moe);
108-
}
109-
110-
function pad(str, len, l) {
111-
while (str.length < len)
112-
str = l ? str + " " : " " + str;
113-
return str;
114-
}
68+
});

bench/suite.js

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
var benchmark = require("benchmark"),
2+
chalk = require("chalk");
3+
4+
var padSize = 27;
5+
6+
module.exports = function newSuite(name) {
7+
var benches = [];
8+
return new benchmark.Suite(name)
9+
.on("add", function(event) {
10+
benches.push(event.target);
11+
})
12+
.on("start", function() {
13+
console.log("benchmarking " + name + " performance ...\n");
14+
})
15+
.on("error", function(err) {
16+
console.log("ERROR:", err);
17+
})
18+
.on("cycle", function(event) {
19+
console.log(String(event.target));
20+
})
21+
.on("complete", function(event) {
22+
var fastest = this.filter('fastest'),
23+
slowest = this.filter('slowest');
24+
var fastestHz = getHz(fastest[0]);
25+
console.log("\n" + chalk.white(pad(fastest[0].name, padSize)) + " was " + chalk.green("fastest"));
26+
benches.forEach(function(bench) {
27+
if (fastest.indexOf(bench) > -1)
28+
return;
29+
var hz = hz = getHz(bench);
30+
var percent = (1 - (hz / fastestHz)) * 100;
31+
console.log(chalk.white(pad(bench.name, padSize)) + " was " + chalk.red(percent.toFixed(1)+'% slower'));
32+
});
33+
console.log();
34+
});
35+
}
36+
37+
function getHz(bench) {
38+
return 1 / (bench.stats.mean + bench.stats.moe);
39+
}
40+
41+
function pad(str, len, l) {
42+
while (str.length < len)
43+
str = l ? str + " " : " " + str;
44+
return str;
45+
}

bench/write.js

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
var protobuf = require("../src/index"),
2+
newSuite = require("./suite");
3+
4+
newSuite("float")
5+
.add("Writer#float", function() {
6+
var writer = new protobuf.Writer();
7+
writer.float(0.1);
8+
writer.finish();
9+
})
10+
.add("BufferWriter#float", function() {
11+
var writer = new protobuf.BufferWriter();
12+
writer.float(0.1);
13+
writer.finish();
14+
})
15+
.run();
16+
17+
newSuite("double")
18+
.add("Writer#double", function() {
19+
var writer = new protobuf.Writer();
20+
writer.double(0.1);
21+
writer.finish();
22+
})
23+
.add("BufferWriter#double", function() {
24+
var writer = new protobuf.BufferWriter();
25+
writer.double(0.1);
26+
writer.finish();
27+
})
28+
.run();
29+
30+
var bytes = [0, 0, 0, 0, 0, 0, 0, 0];
31+
var arrayBytes = new Uint8Array(bytes);
32+
var bufferBytes = Buffer.from(bytes);
33+
34+
newSuite("bytes")
35+
.add("Writer#bytes", function() {
36+
var writer = new protobuf.Writer();
37+
writer.bytes(arrayBytes);
38+
writer.finish();
39+
})
40+
.add("BufferWriter#bytes", function() {
41+
var writer = new protobuf.BufferWriter();
42+
writer.bytes(bufferBytes);
43+
writer.finish();
44+
})
45+
.run();

dist/protobuf.js

+28-28
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/protobuf.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/protobuf.min.js

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/protobuf.min.js.gz

1 Byte
Binary file not shown.

dist/protobuf.min.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/index.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
"use strict";
22
var protobuf = global.protobuf = exports;
33

4-
var util = require("./util");
5-
64
/**
75
* Loads one or multiple .proto or preprocessed .json files into a common root namespace.
86
* @param {string|string[]} filename One or multiple files to load
@@ -54,7 +52,7 @@ protobuf.inherits = require("./inherits");
5452
// Utility
5553
protobuf.types = require("./types");
5654
protobuf.common = require("./common");
57-
protobuf.util = util;
55+
protobuf.util = require("./util");
5856

5957
// Be nice to AMD
6058
/* eslint-disable no-undef */

0 commit comments

Comments
 (0)