From e2df7dc96c6c9ef9afd9d9f6abfd2ac0ac026779 Mon Sep 17 00:00:00 2001 From: javacs3 Date: Fri, 16 Aug 2019 21:22:37 +0800 Subject: [PATCH] add benchmark for serialize addon --- .../src/SerializeAddon.ts | 2 +- package.json | 9 +- test/benchmark/SerializeAddon.benchmark.ts | 84 +++++++++++++++++++ test/benchmark/tsconfig.json | 6 +- yarn.lock | 29 +++++++ 5 files changed, 123 insertions(+), 7 deletions(-) create mode 100644 test/benchmark/SerializeAddon.benchmark.ts diff --git a/addons/xterm-addon-serialize/src/SerializeAddon.ts b/addons/xterm-addon-serialize/src/SerializeAddon.ts index 0fa5c3dd..c68abab7 100644 --- a/addons/xterm-addon-serialize/src/SerializeAddon.ts +++ b/addons/xterm-addon-serialize/src/SerializeAddon.ts @@ -182,7 +182,7 @@ export class SerializeAddon implements ITerminalAddon { throw new Error('Cannot use addon until it has been loaded'); } - const maxRows = this._terminal.rows; + const maxRows = this._terminal.buffer.length; const handler = new StringSerializeHandler(this._terminal.buffer); rows = crop(rows, 0, maxRows, maxRows); diff --git a/package.json b/package.json index 68467a89..57af066d 100644 --- a/package.json +++ b/package.json @@ -14,15 +14,15 @@ "lint": "tslint 'src/**/*.ts' 'addons/**/*.ts'", "test": "npm run test-unit", "posttest": "npm run lint", - "test-api": "mocha \"**/*.api.js\"", + "test-api": "mocha \"**/SerializeAddon.api.js\"", "test-unit": "node ./bin/test.js", "build": "tsc -b ./tsconfig.all.json", "prepare": "npm run build", "prepublishOnly": "npm run package", "watch": "tsc -b -w ./tsconfig.all.json --preserveWatchOutput", - "benchmark": "NODE_PATH=./out xterm-benchmark -r 5 -c test/benchmark/benchmark.json", - "benchmark-baseline": "NODE_PATH=./out xterm-benchmark -r 5 -c test/benchmark/benchmark.json --baseline out-test/benchmark/test/benchmark/*benchmark.js", - "benchmark-eval": "NODE_PATH=./out xterm-benchmark -r 5 -c test/benchmark/benchmark.json --eval out-test/benchmark/test/benchmark/*benchmark.js", + "benchmark": "NODE_PATH=./out:./out-test/benchmark xterm-benchmark -r 5 -c test/benchmark/benchmark.json", + "benchmark-baseline": "NODE_PATH=./out:./out-test/benchmark xterm-benchmark -r 5 -c test/benchmark/benchmark.json --baseline out-test/benchmark/test/benchmark/SerializeAddon.benchmark.js", + "benchmark-eval": "NODE_PATH=./out:./out-test/benchmark xterm-benchmark -r 5 -c test/benchmark/benchmark.json --eval out-test/benchmark/test/benchmark/SerializeAddon.benchmark.js", "clean": "rm -rf lib out addons/*/lib addons/*/out" }, "devDependencies": { @@ -49,6 +49,7 @@ "tslint-consistent-codestyle": "^1.13.0", "typescript": "3.5", "utf8": "^3.0.0", + "v8-profiler-node8": "^6.1.1", "webpack": "^4.35.3", "webpack-cli": "^3.1.0", "ws": "^7.0.0", diff --git a/test/benchmark/SerializeAddon.benchmark.ts b/test/benchmark/SerializeAddon.benchmark.ts new file mode 100644 index 00000000..9423f400 --- /dev/null +++ b/test/benchmark/SerializeAddon.benchmark.ts @@ -0,0 +1,84 @@ +/** + * Copyright (c) 2019 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { perfContext, before, after, ThroughputRuntimeCase } from 'xterm-benchmark'; + +import * as fs from 'fs' +import { spawn } from 'node-pty'; +import * as profiler from 'v8-profiler-node8'; +import { Utf8ToUtf32, stringFromCodePoint } from 'common/input/TextDecoder'; +import { Terminal } from 'public/Terminal'; +import { SerializeAddon } from 'addons/xterm-addon-serialize/src/SerializeAddon'; + +class TestTerminal extends Terminal { + writeSync(data: string): void { + (this)._core.writeBuffer.push(data); + (this)._core._innerWrite(); + } + writeSyncUtf8(data: Uint8Array): void { + (this)._core.writeBufferUtf8.push(data); + (this)._core._innerWriteUtf8(); + } +} + +perfContext('Terminal: sh -c "dd if=/dev/random count=40 bs=1k | hexdump | lolcat -f"', () => { + let content = ''; + let contentUtf8: Uint8Array; + + before(async () => { + const p = spawn('sh', ['-c', 'dd if=/dev/random count=40 bs=1k | hexdump | lolcat -f'], { + name: 'xterm-256color', + cols: 80, + rows: 25, + cwd: process.env.HOME, + env: process.env, + encoding: (null as unknown as string) // needs to be fixed in node-pty + }); + const chunks: Buffer[] = []; + let length = 0; + p.on('data', data => { + chunks.push(data as unknown as Buffer); + length += data.length; + }); + await new Promise(resolve => p.on('exit', () => resolve())); + contentUtf8 = Buffer.concat(chunks, length); + // translate to content string + const buffer = new Uint32Array(contentUtf8.length); + const decoder = new Utf8ToUtf32(); + const codepoints = decoder.decode(contentUtf8, buffer); + for (let i = 0; i < codepoints; ++i) { + content += stringFromCodePoint(buffer[i]); + // peek into content to force flat repr in v8 + if (!(i % 10000000)) { + content[i]; + } + } + }); + + perfContext('serialize', () => { + let terminal: TestTerminal; + let serializeAddon = new SerializeAddon(); + before(() => { + terminal = new TestTerminal({ cols: 80, rows: 25, scrollback: 5000 }); + serializeAddon.activate(terminal); + terminal.writeSync(content); + profiler.startProfiling(); + }); + after(() => { + const p1 = profiler.stopProfiling(); + p1.export((err, res) => { + if (err) { + console.error(err); + return; + } + console.log(p1.getHeader()); + fs.writeFileSync('serialize-profile.cpuprofile', res); + }) + }) + new ThroughputRuntimeCase('', () => { + return { payloadSize: serializeAddon.serialize().length }; + }, { fork: false }).showAverageThroughput(); + }); +}); diff --git a/test/benchmark/tsconfig.json b/test/benchmark/tsconfig.json index 8b93dcb1..51abeba5 100644 --- a/test/benchmark/tsconfig.json +++ b/test/benchmark/tsconfig.json @@ -16,7 +16,9 @@ "paths": { "common/*": [ "../../src/common/*" ], "browser/*": [ "../../src/browser/*" ], - "Terminal": [ "../../src/Terminal" ] + "addons/xterm-addon-serialize/src/*": ["../../addons/xterm-addon-serialize/src/*"], + "public/*": ["../../src/public/*"], + "Terminal": ["../../src/Terminal"] }, }, "include": [ @@ -31,4 +33,4 @@ { "path": "../../src/common" }, { "path": "../../src/browser" }, ] -} \ No newline at end of file +} diff --git a/yarn.lock b/yarn.lock index a67ede71..30f2ea79 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3143,6 +3143,11 @@ nan@2.10.0, nan@^2.9.2: resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" integrity sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA== +nan@^2.14.0: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -3237,6 +3242,22 @@ node-pre-gyp@^0.10.0: semver "^5.3.0" tar "^4" +node-pre-gyp@^0.13.0: + version "0.13.0" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.13.0.tgz#df9ab7b68dd6498137717838e4f92a33fc9daa42" + integrity sha512-Md1D3xnEne8b/HGVQkZZwV27WUi1ZRuZBij24TNaZwUPU3ZAFtvT6xxJGaUVillfmMKnn5oD1HoGsp2Ftik7SQ== + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + node-pty@0.7.6: version "0.7.6" resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.7.6.tgz#bff6148c9c5836ca7e73c7aaaec067dcbdac2f7b" @@ -4842,6 +4863,14 @@ v8-compile-cache@^2.0.0: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz#a428b28bb26790734c4fc8bc9fa106fccebf6a6c" integrity sha512-1wFuMUIM16MDJRCrpbpuEPTUGmM5QMUg0cr3KFwra2XgOgFcPGDQHDh3CszSCD2Zewc/dh/pamNEW8CbfDebUw== +v8-profiler-node8@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/v8-profiler-node8/-/v8-profiler-node8-6.1.1.tgz#2046dd46d80744784f9e94bce1411717435c1f76" + integrity sha512-mKS7TXRRYi70hvbv5c1tk9AbuqNrtbLc+jFLlsZ2TpaC1l5lWryBlDLZKJ1JP6hjSbMEjW1ucjWLSaKsaPnGXg== + dependencies: + nan "^2.14.0" + node-pre-gyp "^0.13.0" + vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"