From 734ad72e3939e62bcff0f686b8ec426b8aaa22e3 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Thu, 13 Jul 2017 08:56:06 -0700 Subject: [PATCH] http2: initial benchmarks PR-URL: https://github.com/nodejs/http2/pull/180 Reviewed-By: Matteo Collina --- benchmark/README.md | 6 +++ benchmark/_http-benchmarkers.js | 55 +++++++++++++++++++- benchmark/http2/respond-with-fd.js | 43 +++++++++++++++ benchmark/http2/simple.js | 38 ++++++++++++++ doc/guides/writing-and-running-benchmarks.md | 9 ++++ 5 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 benchmark/http2/respond-with-fd.js create mode 100644 benchmark/http2/simple.js diff --git a/benchmark/README.md b/benchmark/README.md index 17c733e6eb..dfdf319b9c 100644 --- a/benchmark/README.md +++ b/benchmark/README.md @@ -97,6 +97,12 @@ directory, see [the guide on benchmarks](../doc/guides/writing-and-running-bench Benchmarks for the http subsystem. + + http2 + + Benchmarks for the http2 subsystem. + + misc diff --git a/benchmark/_http-benchmarkers.js b/benchmark/_http-benchmarkers.js index 3f17f05f83..f9359b13d5 100644 --- a/benchmark/_http-benchmarkers.js +++ b/benchmark/_http-benchmarkers.js @@ -111,10 +111,63 @@ class TestDoubleBenchmarker { } } +/** + * HTTP/2 Benchmarker + */ +class H2LoadBenchmarker { + constructor() { + this.name = 'h2load'; + this.executable = 'h2load'; + const result = child_process.spawnSync(this.executable, ['-h']); + this.present = !(result.error && result.error.code === 'ENOENT'); + } + + create(options) { + const args = []; + if (typeof options.requests === 'number') + args.push('-n', options.requests); + if (typeof options.clients === 'number') + args.push('-c', options.clients); + if (typeof options.threads === 'number') + args.push('-t', options.threads); + if (typeof options.maxConcurrentStreams === 'number') + args.push('-m', options.maxConcurrentStreams); + if (typeof options.initialWindowSize === 'number') + args.push('-w', options.initialWindowSize); + if (typeof options.sessionInitialWindowSize === 'number') + args.push('-W', options.sessionInitialWindowSize); + if (typeof options.rate === 'number') + args.push('-r', options.rate); + if (typeof options.ratePeriod === 'number') + args.push(`--rate-period=${options.ratePeriod}`); + if (typeof options.duration === 'number') + args.push('-T', options.duration); + if (typeof options.timeout === 'number') + args.push('-N', options.timeout); + if (typeof options.headerTableSize === 'number') + args.push(`--header-table-size=${options.headerTableSize}`); + if (typeof options.encoderHeaderTableSize === 'number') { + args.push( + `--encoder-header-table-size=${options.encoderHeaderTableSize}`); + } + const scheme = options.scheme || 'http'; + const host = options.host || '127.0.0.1'; + args.push(`${scheme}://${host}:${options.port}${options.path}`); + const child = child_process.spawn(this.executable, args); + return child; + } + + processResults(output) { + const rex = /(\d+(?:\.\d+)) req\/s/; + return rex.exec(output)[1]; + } +} + const http_benchmarkers = [ new WrkBenchmarker(), new AutocannonBenchmarker(), - new TestDoubleBenchmarker() + new TestDoubleBenchmarker(), + new H2LoadBenchmarker() ]; const benchmarkers = {}; diff --git a/benchmark/http2/respond-with-fd.js b/benchmark/http2/respond-with-fd.js new file mode 100644 index 0000000000..d7a312c78b --- /dev/null +++ b/benchmark/http2/respond-with-fd.js @@ -0,0 +1,43 @@ +'use strict'; + +const common = require('../common.js'); +const PORT = common.PORT; +const path = require('path'); +const fs = require('fs'); + +const file = path.join(path.resolve(__dirname, '../fixtures'), 'alice.html'); + +var bench = common.createBenchmark(main, { + requests: [100, 1000, 10000, 100000, 1000000], + streams: [100, 200, 1000], + clients: [1, 2] +}, { flags: ['--expose-http2', '--no-warnings'] }); + +function main(conf) { + + fs.open(file, 'r', (err, fd) => { + if (err) + throw err; + + const n = +conf.requests; + const m = +conf.streams; + const c = +conf.clients; + const http2 = require('http2'); + const server = http2.createServer(); + server.on('stream', (stream) => { + stream.respondWithFD(fd); + stream.on('error', (err) => {}); + }); + server.listen(PORT, () => { + bench.http({ + path: '/', + requests: n, + maxConcurrentStreams: m, + clients: c, + threads: c + }, () => server.close()); + }); + + }); + +} diff --git a/benchmark/http2/simple.js b/benchmark/http2/simple.js new file mode 100644 index 0000000000..d12b20fc5a --- /dev/null +++ b/benchmark/http2/simple.js @@ -0,0 +1,38 @@ +'use strict'; + +const common = require('../common.js'); +const PORT = common.PORT; + +const path = require('path'); +const fs = require('fs'); + +const file = path.join(path.resolve(__dirname, '../fixtures'), 'alice.html'); + +var bench = common.createBenchmark(main, { + requests: [100, 1000, 10000, 100000], + streams: [100, 200, 1000], + clients: [1, 2] +}, { flags: ['--expose-http2', '--no-warnings'] }); + +function main(conf) { + const n = +conf.requests; + const m = +conf.streams; + const c = +conf.clients; + const http2 = require('http2'); + const server = http2.createServer(); + server.on('stream', (stream) => { + const out = fs.createReadStream(file); + stream.respond(); + out.pipe(stream); + stream.on('error', (err) => {}); + }); + server.listen(PORT, () => { + bench.http({ + path: '/', + requests: n, + maxConcurrentStreams: m, + clients: c, + threads: c + }, () => { server.close(); }); + }); +} diff --git a/doc/guides/writing-and-running-benchmarks.md b/doc/guides/writing-and-running-benchmarks.md index 148082de4b..3624b435bf 100644 --- a/doc/guides/writing-and-running-benchmarks.md +++ b/doc/guides/writing-and-running-benchmarks.md @@ -41,6 +41,14 @@ benchmarker to be used should be specified by providing it as an argument: `node benchmark/http/simple.js benchmarker=autocannon` +#### HTTP/2 Benchmark Requirements + +To run the `http2` benchmarks, the `h2load` benchmarker must be used. The +`h2load` tool is a component of the `nghttp2` project and may be installed +from [nghttp.org][] or built from source. + +`node benchmark/http2/simple.js benchmarker=autocannon` + ### Benchmark Analysis Requirements To analyze the results, `R` should be installed. Use one of the available @@ -423,3 +431,4 @@ Supported options keys are: [wrk]: https://github.com/wg/wrk [t-test]: https://en.wikipedia.org/wiki/Student%27s_t-test#Equal_or_unequal_sample_sizes.2C_unequal_variances [git-for-windows]: http://git-scm.com/download/win +[nghttp2.org]: http://nghttp2.org