From 5d85f73ad234e4d677b384d02e477a0777fff37b Mon Sep 17 00:00:00 2001 From: "FUJI Goro (gfx)" Date: Wed, 29 May 2019 10:19:31 +0900 Subject: [PATCH 1/7] improve: more smart selection of string decoding functions --- benchmark/decode-string.ts | 77 ++++++++++++++++++-------------------- src/Decoder.ts | 14 ++++--- src/utils/utf8.ts | 62 ++++++++++++++---------------- src/wasmFunctions.ts | 21 +++++++++-- 4 files changed, 92 insertions(+), 82 deletions(-) diff --git a/benchmark/decode-string.ts b/benchmark/decode-string.ts index 331a9e05..ed4813ee 100644 --- a/benchmark/decode-string.ts +++ b/benchmark/decode-string.ts @@ -1,50 +1,45 @@ /* eslint-disable no-console */ -import { utf8Encode, utf8Count, utf8Decode } from "../src/utils/utf8"; +import { utf8Encode, utf8Count, utf8DecodeJs, utf8DecodeTD } from "../src/utils/utf8"; import { utf8DecodeWasm } from "../src/wasmFunctions"; // @ts-ignore import Benchmark from "benchmark"; -const textDecoder = new TextDecoder(); - -const dataSet = [10, 100, 200, 1_000, 10_000, 100_000].map((n) => { - return "a".repeat(n); -}); - -for (const str of dataSet) { - const byteLength = utf8Count(str); - const bytes = new Uint8Array(new ArrayBuffer(byteLength)); - utf8Encode(str, bytes, 0); - - console.log(`\n## string length=${str.length} byteLength=${byteLength}\n`); - - const suite = new Benchmark.Suite(); - - const N = Math.round(100_0000 / str.length); - - // use the result to avoid void-context optimizations - let count = 0; - - suite.add("utf8Decode", () => { - if (utf8Decode(bytes, 0, byteLength) !== str) { - throw new Error("wrong result!"); - } - }); - - suite.add("utf8DecodeWasm", () => { - if (utf8DecodeWasm(bytes, 0, byteLength) !== str) { - throw new Error("wrong result!"); - } - }); - - suite.add("TextDecoder", () => { - if (textDecoder.decode(bytes.subarray(0, byteLength)) !== str) { - throw new Error("wrong result!"); - } - }); - suite.on("cycle", (event: any) => { - console.log(String(event.target)); +for (const baseStr of ["A", "あ", "🌏"]) { + const dataSet = [10, 100, 200, 1_000, 10_000, 100_000].map((n) => { + return baseStr.repeat(n); }); - suite.run(); + for (const str of dataSet) { + const byteLength = utf8Count(str); + const bytes = new Uint8Array(new ArrayBuffer(byteLength)); + utf8Encode(str, bytes, 0); + + console.log(`\n## string "${baseStr}" x ${str.length} (byteLength=${byteLength})\n`); + + const suite = new Benchmark.Suite(); + + suite.add("utf8DecodeJs", () => { + if (utf8DecodeJs(bytes, 0, byteLength) !== str) { + throw new Error("wrong result!"); + } + }); + + suite.add("utf8DecodeWasm", () => { + if (utf8DecodeWasm(bytes, 0, byteLength) !== str) { + throw new Error("wrong result!"); + } + }); + + suite.add("TextDecoder", () => { + if (utf8DecodeTD(bytes, 0, byteLength) !== str) { + throw new Error("wrong result!"); + } + }); + suite.on("cycle", (event: any) => { + console.log(String(event.target)); + }); + + suite.run(); + } } diff --git a/src/Decoder.ts b/src/Decoder.ts index c6c29b63..b8ab4f32 100644 --- a/src/Decoder.ts +++ b/src/Decoder.ts @@ -1,7 +1,7 @@ import { prettyByte } from "./utils/prettyByte"; import { ExtensionCodec } from "./ExtensionCodec"; import { getInt64, getUint64 } from "./utils/int"; -import { utf8Decode } from "./utils/utf8"; +import { utf8DecodeJs, TEXT_DECODER_AVAILABLE, TEXT_DECODER_THRESHOLD, utf8DecodeTD } from "./utils/utf8"; import { createDataView, ensureUint8Array } from "./utils/typedArrays"; import { WASM_AVAILABLE, WASM_STR_THRESHOLD, utf8DecodeWasm } from "./wasmFunctions"; @@ -400,10 +400,14 @@ export class Decoder { } const offset = this.pos + headerOffset; - const object = - WASM_AVAILABLE && byteLength > WASM_STR_THRESHOLD - ? utf8DecodeWasm(this.bytes, offset, byteLength) - : utf8Decode(this.bytes, offset, byteLength); + let object: string; + if (TEXT_DECODER_AVAILABLE && byteLength > TEXT_DECODER_THRESHOLD) { + object = utf8DecodeTD(this.bytes, offset, byteLength); + } else if (WASM_AVAILABLE && byteLength > WASM_STR_THRESHOLD) { + object = utf8DecodeWasm(this.bytes, offset, byteLength); + } else { + object = utf8DecodeJs(this.bytes, offset, byteLength); + } this.pos += headerOffset + byteLength; return object; } diff --git a/src/utils/utf8.ts b/src/utils/utf8.ts index cf5a6112..a64f5113 100644 --- a/src/utils/utf8.ts +++ b/src/utils/utf8.ts @@ -83,49 +83,26 @@ export function utf8Encode(str: string, output: Uint8Array, outputOffset: number const CHUNK_SIZE = 0x10_000; -export function safeStringFromCharCode(units: Array | Uint16Array) { - if (units.length <= CHUNK_SIZE) { - // `String.fromCharCode.apply()` is faster than `String.fromCharCode(...units)` - // in case `units` is a typed array - return String.fromCharCode.apply(String, units as any); - } - - let result = ""; - for (let i = 0; i < units.length; i++) { - const chunk = units.slice(i * CHUNK_SIZE, (i + 1) * CHUNK_SIZE); - result += String.fromCharCode.apply(String, chunk as any); - } - return result; -} - -const MIN_TEXT_DECODER_STRING_LENGTH = 200; -const defaultEncoding = "utf-8"; -const sharedTextDecoder = typeof TextDecoder !== "undefined" ? new TextDecoder(defaultEncoding) : null; - -export function utf8Decode(bytes: Uint8Array, inputOffset: number, byteLength: number): string { +export function utf8DecodeJs(bytes: Uint8Array, inputOffset: number, byteLength: number): string { let offset = inputOffset; const end = offset + byteLength; - if (sharedTextDecoder !== null && byteLength > MIN_TEXT_DECODER_STRING_LENGTH) { - const stringBytes = bytes.subarray(offset, end); - return sharedTextDecoder.decode(stringBytes); - } - - const out: Array = []; + const units: Array = []; + let result = ""; while (offset < end) { const byte1 = bytes[offset++]; if ((byte1 & 0x80) === 0) { // 1 byte - out.push(byte1); + units.push(byte1); } else if ((byte1 & 0xe0) === 0xc0) { // 2 bytes const byte2 = bytes[offset++] & 0x3f; - out.push(((byte1 & 0x1f) << 6) | byte2); + units.push(((byte1 & 0x1f) << 6) | byte2); } else if ((byte1 & 0xf0) === 0xe0) { // 3 bytes const byte2 = bytes[offset++] & 0x3f; const byte3 = bytes[offset++] & 0x3f; - out.push(((byte1 & 0x1f) << 12) | (byte2 << 6) | byte3); + units.push(((byte1 & 0x1f) << 12) | (byte2 << 6) | byte3); } else if ((byte1 & 0xf8) === 0xf0) { // 4 bytes const byte2 = bytes[offset++] & 0x3f; @@ -134,14 +111,33 @@ export function utf8Decode(bytes: Uint8Array, inputOffset: number, byteLength: n let unit = ((byte1 & 0x07) << 0x12) | (byte2 << 0x0c) | (byte3 << 0x06) | byte4; if (unit > 0xffff) { unit -= 0x10000; - out.push(((unit >>> 10) & 0x3ff) | 0xd800); + units.push(((unit >>> 10) & 0x3ff) | 0xd800); unit = 0xdc00 | (unit & 0x3ff); } - out.push(unit); + units.push(unit); } else { - out.push(byte1); + units.push(byte1); + } + + if (units.length - 4 >= CHUNK_SIZE) { + result += String.fromCharCode(...units); + units.length = 0; } } - return safeStringFromCharCode(out); + if (units.length > 0) { + result += String.fromCharCode(...units); + } + + return result; +} + +const sharedTextDecoder = typeof TextDecoder !== "undefined" ? new TextDecoder() : null; +export const TEXT_DECODER_AVAILABLE = process.env.TEXT_DECODER !== "never" && !!sharedTextDecoder; +export const TEXT_DECODER_THRESHOLD = 200; + +export function utf8DecodeTD(bytes: Uint8Array, inputOffset: number, byteLength: number): string { + const stringBytes = bytes.subarray(inputOffset, inputOffset + byteLength); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + return sharedTextDecoder!.decode(stringBytes); } diff --git a/src/wasmFunctions.ts b/src/wasmFunctions.ts index 0c6e14f8..5e92b4f0 100644 --- a/src/wasmFunctions.ts +++ b/src/wasmFunctions.ts @@ -1,5 +1,3 @@ -import { safeStringFromCharCode } from "./utils/utf8"; - // WASM=never - disable WASM functions // WASM=force - force to use WASM functions const WASM: string = process.env.MSGPACK_WASM || process.env.WASM || ""; @@ -63,6 +61,23 @@ export function utf8EncodeWasm(str: string, output: Uint8Array, outputOffset: nu } } +const CHUNK_SIZE = 0x10_000; + +function safeStringFromCharCodeU16(units: Uint16Array) { + if (units.length <= CHUNK_SIZE) { + // `String.fromCharCode.apply()` is faster than `String.fromCharCode(...units)` + // in case `units` is a typed array + return String.fromCharCode.apply(String, units as any); + } + + let result = ""; + for (let i = 0; i < units.length; i++) { + const chunk = units.subarray(i * CHUNK_SIZE, (i + 1) * CHUNK_SIZE); + result += String.fromCharCode.apply(String, chunk as any); + } + return result; +} + // A wrapper function for utf8DecodeToUint16Array() export function utf8DecodeWasm(bytes: Uint8Array, inputOffset: number, byteLength: number): string { const inputPtr: pointer = wm.malloc(byteLength); @@ -73,7 +88,7 @@ export function utf8DecodeWasm(bytes: Uint8Array, inputOffset: number, byteLengt const outputArraySize = wm.utf8DecodeToUint16Array(outputPtr, inputPtr, byteLength); const units = new Uint16Array(wm.memory.buffer, outputPtr, outputArraySize); - return safeStringFromCharCode(units); + return safeStringFromCharCodeU16(units); } finally { wm.free(inputPtr); wm.free(outputPtr); From a788f19b1740bc546ae4877fd78249343b7919b9 Mon Sep 17 00:00:00 2001 From: "FUJI Goro (gfx)" Date: Wed, 29 May 2019 10:33:27 +0900 Subject: [PATCH 2/7] more tests for TextDecoder --- src/utils/utf8.ts | 2 +- test/msgpack-test-suite.test.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/utils/utf8.ts b/src/utils/utf8.ts index a64f5113..78241647 100644 --- a/src/utils/utf8.ts +++ b/src/utils/utf8.ts @@ -134,7 +134,7 @@ export function utf8DecodeJs(bytes: Uint8Array, inputOffset: number, byteLength: const sharedTextDecoder = typeof TextDecoder !== "undefined" ? new TextDecoder() : null; export const TEXT_DECODER_AVAILABLE = process.env.TEXT_DECODER !== "never" && !!sharedTextDecoder; -export const TEXT_DECODER_THRESHOLD = 200; +export const TEXT_DECODER_THRESHOLD = process.env.TEXT_DECODER !== "force" ? 200 : 0; export function utf8DecodeTD(bytes: Uint8Array, inputOffset: number, byteLength: number): string { const stringBytes = bytes.subarray(inputOffset, inputOffset + byteLength); diff --git a/test/msgpack-test-suite.test.ts b/test/msgpack-test-suite.test.ts index 079cb370..f516cb22 100644 --- a/test/msgpack-test-suite.test.ts +++ b/test/msgpack-test-suite.test.ts @@ -89,7 +89,9 @@ describe("msgpack-test-suite", () => { FLOAT64_NEGATIVE_INF: Number.NEGATIVE_INFINITY, FLOAT64_NAN: Number.NaN, STR16: "a".repeat(0x100), + STR16_MBS: "🌏".repeat(0x100), STR32: "b".repeat(0x10_000), + STR32_MBS: "🍣".repeat(0x10_000), STR32LARGE: "c".repeat(0x100_000), // may cause "RangeError: Maximum call stack size exceeded" in simple implelementions STR_INCLUDING_NUL: "foo\0bar", STR_BROKEN_FF: "\xff", From 46f1ec9c1da9f1488cbcd71953bcdfeea3641de5 Mon Sep 17 00:00:00 2001 From: "FUJI Goro (gfx)" Date: Wed, 29 May 2019 10:58:36 +0900 Subject: [PATCH 3/7] tewaks for test coverage --- package.json | 8 +++++--- test/msgpack-test-suite.test.ts | 4 +--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 884982ca..ba866f98 100644 --- a/package.json +++ b/package.json @@ -12,13 +12,15 @@ "prepublishOnly": "run-p 'test:dist:*' && npm run test:browser", "clean": "rimraf build dist dist.*", "test": "mocha 'test/**/*.test.ts'", - "test:purejs": "MSGPACK_WASM=never mocha 'test/**/*.test.ts'", - "test:wasm": "npm run asbuild:production && MSGPACK_WASM=force mocha 'test/**/*.test.ts'", + "test:purejs": "TEXT_DECODER=never MSGPACK_WASM=never mocha 'test/**/*.test.ts'", + "test:wasm": "npm run asbuild:production && TEXT_DECODER=never MSGPACK_WASM=force mocha 'test/**/*.test.ts'", + "test:td": "TEXT_DECODER=force mocha 'test/**/*.test.ts'", "test:dist:purejs": "TS_NODE_PROJECT=tsconfig.test-dist-es5-purejs.json npm run test:purejs -- --reporter=dot", "test:dist:wasm": "TS_NODE_PROJECT=tsconfig.test-dist-es5-wasm.json npm run test:wasm -- --reporter=dot", - "test:cover": "npm run cover:clean && npm run test:cover:purejs && npm run test:cover:wasm && npm run cover:report", + "test:cover": "npm run cover:clean && npm-run-all 'test:cover:*' && npm run cover:report", "test:cover:purejs": "npx nyc --no-clean npm run test:purejs", "test:cover:wasm": "npx nyc --no-clean npm run test:wasm", + "test:cover:td": "npx nyc --no-clean npm run test:td", "cover:clean": "rimraf .nyc_output coverage/", "cover:report": "nyc report --reporter=lcov --reporter=text-summary --reporter=html", "test:browser": "karma start --single-run", diff --git a/test/msgpack-test-suite.test.ts b/test/msgpack-test-suite.test.ts index f516cb22..9b30516b 100644 --- a/test/msgpack-test-suite.test.ts +++ b/test/msgpack-test-suite.test.ts @@ -93,10 +93,8 @@ describe("msgpack-test-suite", () => { STR32: "b".repeat(0x10_000), STR32_MBS: "🍣".repeat(0x10_000), STR32LARGE: "c".repeat(0x100_000), // may cause "RangeError: Maximum call stack size exceeded" in simple implelementions - STR_INCLUDING_NUL: "foo\0bar", + STR_INCLUDING_NUL: "foo\0bar\0", STR_BROKEN_FF: "\xff", - STR_LONE_SURROGATE_1: "\ud800", - STR_LONE_SURROGATE_2: "\udbff", BIN16: new Uint8Array(0x100).fill(0xff), BIN32: new Uint8Array(0x10000).fill(0xff), ARRAY16: new Array(0x100).fill(true), From b8e4de5dd46588a48a2a743db45f20164696c608 Mon Sep 17 00:00:00 2001 From: "FUJI Goro (gfx)" Date: Wed, 29 May 2019 11:19:02 +0900 Subject: [PATCH 4/7] npm update && npm dedupe --- package-lock.json | 54 +++++++++++++++++++++-------------------------- package.json | 6 +++--- 2 files changed, 27 insertions(+), 33 deletions(-) diff --git a/package-lock.json b/package-lock.json index ac7d5915..66fb11fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -58,9 +58,9 @@ "dev": true }, "@types/node": { - "version": "11.13.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.11.tgz", - "integrity": "sha512-blLeR+KIy26km1OU8yTLUlSyVCOvT6+wPq/77tIA+uSHHa4yYQosn+bbaJqPtWId0wjVClUtD7aXzDbZeKWqig==", + "version": "11.13.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.12.tgz", + "integrity": "sha512-HMD9cEGP+k2Y1Lk8LL6Cux9UlxkWst1wJdoMHnvH3XlVecHdjffW829/YzWd/ptFkIWtcbqQDrTkz5PY6pN+0w==", "dev": true }, "@typescript-eslint/eslint-plugin": { @@ -523,7 +523,7 @@ } }, "assemblyscript": { - "version": "github:AssemblyScript/assemblyscript#36040d5b5312f19a025782b5e36663823494c2f3", + "version": "github:AssemblyScript/assemblyscript#5269a6b9c4e14983c43671328257c156cdf1de8a", "from": "github:AssemblyScript/assemblyscript", "dev": true, "requires": { @@ -1285,9 +1285,9 @@ "dev": true }, "core-js": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.1.2.tgz", - "integrity": "sha512-3poRGjbu56leCtZCZCzCgQ7GcKOflDFnjWIepaPFUsM0IXUBrne10sl3aa2Bkcz3+FjRdIxBe9dAMhIJmEnQNA==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.1.3.tgz", + "integrity": "sha512-PWZ+ZfuaKf178BIAg+CRsljwjIMRV8MY00CbZczkR6Zk5LfkSkjGoaab3+bqRQWVITNZxQB7TFYz+CFcyuamvA==", "dev": true }, "core-util-is": { @@ -2416,25 +2416,29 @@ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "is-fullwidth-code-point": { - "version": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { "number-is-nan": "^1.0.0" } }, "semver": { - "version": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" }, "strip-ansi": { - "version": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" } }, "yallist": { - "version": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" } } @@ -2934,6 +2938,12 @@ } } }, + "int64-buffer": { + "version": "0.99.1007", + "resolved": "https://registry.npmjs.org/int64-buffer/-/int64-buffer-0.99.1007.tgz", + "integrity": "sha512-XDBEu44oSTqlvCSiOZ/0FoUkpWu/vwjJLGSKDabNISPQNZ5wub1FodGHBljRsrR0IXRPq7SslshZYMuA55CgTQ==", + "dev": true + }, "interpret": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", @@ -3947,14 +3957,6 @@ "requires": { "int64-buffer": "^0.99.1007", "msg-interface": "^1.1.0" - }, - "dependencies": { - "int64-buffer": { - "version": "0.99.1007", - "resolved": "https://registry.npmjs.org/int64-buffer/-/int64-buffer-0.99.1007.tgz", - "integrity": "sha512-XDBEu44oSTqlvCSiOZ/0FoUkpWu/vwjJLGSKDabNISPQNZ5wub1FodGHBljRsrR0IXRPq7SslshZYMuA55CgTQ==", - "dev": true - } } }, "msg-interface": { @@ -3972,14 +3974,6 @@ "int64-buffer": "^0.99.1007", "msg-ext": "^1.0.1", "timestamp-nano": "^1.0.0" - }, - "dependencies": { - "int64-buffer": { - "version": "0.99.1007", - "resolved": "https://registry.npmjs.org/int64-buffer/-/int64-buffer-0.99.1007.tgz", - "integrity": "sha512-XDBEu44oSTqlvCSiOZ/0FoUkpWu/vwjJLGSKDabNISPQNZ5wub1FodGHBljRsrR0IXRPq7SslshZYMuA55CgTQ==", - "dev": true - } } }, "msgpack-test-js": { @@ -6158,9 +6152,9 @@ } }, "ts-node": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.1.1.tgz", - "integrity": "sha512-nd+mdxDP2BjQlyumBCMSU3IQLEjSla1X3uSzDfQ4M5OEZ3iDC01gjhs0FX29jyolATwLKB7YoRJ1Asbxd9EEoA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.2.0.tgz", + "integrity": "sha512-m8XQwUurkbYqXrKqr3WHCW310utRNvV5OnRVeISeea7LoCWVcdfeB/Ntl8JYWFh+WRoUAdBgESrzKochQt7sMw==", "dev": true, "requires": { "arg": "^4.1.0", diff --git a/package.json b/package.json index ba866f98..6503ede4 100644 --- a/package.json +++ b/package.json @@ -55,12 +55,12 @@ "@bitjourney/check-es-version-webpack-plugin": "^1.0.2", "@types/base64-js": "^1.2.5", "@types/mocha": "^5.2.6", - "@types/node": "^11.13.10", + "@types/node": "^11.13.12", "@typescript-eslint/eslint-plugin": "^1.9.0", "@typescript-eslint/parser": "^1.9.0", "assemblyscript": "github:AssemblyScript/assemblyscript", "assert": "^2.0.0", - "core-js": "^3.0.1", + "core-js": "^3.1.3", "eslint": "^5.16.0", "eslint-config-prettier": "^4.2.0", "eslint-plugin-prettier": "^3.1.0", @@ -80,7 +80,7 @@ "prettier": "^1.17.1", "rimraf": "^2.6.3", "ts-loader": "^5.4.5", - "ts-node": "^8.1.0", + "ts-node": "^8.2.0", "tsconfig-paths": "^3.8.0", "typescript": "^3.4.5", "webpack": "^4.30.0", From dce0045fd79b5f3bdf0730db507b930bd5461889 Mon Sep 17 00:00:00 2001 From: "FUJI Goro (gfx)" Date: Wed, 29 May 2019 11:22:50 +0900 Subject: [PATCH 5/7] update benchmark results in README.md --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 8872dba4..e97e8fa0 100644 --- a/README.md +++ b/README.md @@ -193,17 +193,17 @@ NodeJS v10 is required, but NodeJS v12 or later is recommended because it includ ## Benchmark -Benchmark on NodeJS/v12.1.0 +Benchmark on NodeJS/v12.3.1 operation | op | ms | op/s ----------------------------------------------------------------- | ------: | ----: | ------: -buf = Buffer.from(JSON.stringify(obj)); | 493600 | 5000 | 98720 -buf = JSON.stringify(obj); | 959600 | 5000 | 191920 -obj = JSON.parse(buf); | 346100 | 5000 | 69220 -buf = require("msgpack-lite").encode(obj); | 358300 | 5000 | 71660 -obj = require("msgpack-lite").decode(buf); | 270400 | 5000 | 54080 -buf = require("@msgpack/msgpack").encode(obj); | 594300 | 5000 | 118860 -obj = require("@msgpack/msgpack").decode(buf); | 343100 | 5000 | 68620 +buf = Buffer.from(JSON.stringify(obj)); | 497600 | 5000 | 99520 +buf = JSON.stringify(obj); | 969500 | 5000 | 193900 +obj = JSON.parse(buf); | 345300 | 5000 | 69060 +buf = require("msgpack-lite").encode(obj); | 369100 | 5000 | 73820 +obj = require("msgpack-lite").decode(buf); | 278900 | 5000 | 55780 +buf = require("@msgpack/msgpack").encode(obj); | 556900 | 5000 | 111380 +obj = require("@msgpack/msgpack").decode(buf); | 502200 | 5000 | 100440 Note that `Buffer.from()` for `JSON.stringify()` is added to emulate I/O where a JavaScript string must be converted into a byte array encoded in UTF-8, whereas MessagePack's `encode()` returns a byte array. From 610800675e5c3ac5005862bd7727a30b136f1b52 Mon Sep 17 00:00:00 2001 From: "FUJI Goro (gfx)" Date: Wed, 29 May 2019 11:23:51 +0900 Subject: [PATCH 6/7] changes for 1.2.3 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 837df15f..9cc27f85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ This is the revision history of @msgpack/msgpack +## v1.2.3 2019/05/29 + +https://github.com/msgpack/msgpack-javascript/compare/v1.2.2...v1.2.3 + +* More optimizations for string decoding performance + ## v1.2.2 2019/05/29 https://github.com/msgpack/msgpack-javascript/compare/v1.2.1...v1.2.2 From fa2012b2cde046632119d5617eac8f320200f0f6 Mon Sep 17 00:00:00 2001 From: "FUJI Goro (gfx)" Date: Wed, 29 May 2019 11:25:34 +0900 Subject: [PATCH 7/7] 1.2.3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 66fb11fb..5d102aa8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@msgpack/msgpack", - "version": "1.2.2", + "version": "1.2.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 6503ede4..5bdb58d7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@msgpack/msgpack", - "version": "1.2.2", + "version": "1.2.3", "description": "MessagePack for JavaScript/ECMA-262", "main": "./dist/index.js", "browser": "./dist.es5/msgpack.js",