From d39ace16bacd57cce2fa2063fe0b5503c544e743 Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Tue, 10 Nov 2015 03:04:26 -0700 Subject: [PATCH] http_parser: use pushValueToArray for headers For performance add headers to the headers Array by pushing them on from JS. Benchmark added to demonstrate this case. PR-URL: https://github.com/nodejs/node/pull/3780 Reviewed-By: Fedor Indutny --- benchmark/http/bench-parser.js | 55 ++++++++++++++++++++++++++++++++++ src/node_http_parser.cc | 23 ++++++++++---- 2 files changed, 72 insertions(+), 6 deletions(-) create mode 100644 benchmark/http/bench-parser.js diff --git a/benchmark/http/bench-parser.js b/benchmark/http/bench-parser.js new file mode 100644 index 0000000000..989d9a994f --- /dev/null +++ b/benchmark/http/bench-parser.js @@ -0,0 +1,55 @@ +'use strict'; + +const common = require('../common'); +const HTTPParser = process.binding('http_parser').HTTPParser; +const REQUEST = HTTPParser.REQUEST; +const kOnHeaders = HTTPParser.kOnHeaders | 0; +const kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0; +const kOnBody = HTTPParser.kOnBody | 0; +const kOnMessageComplete = HTTPParser.kOnMessageComplete | 0; +const CRLF = '\r\n'; + +const bench = common.createBenchmark(main, { + fields: [4, 8, 16, 32], + n: [1e5], +}); + + +function main(conf) { + const fields = conf.fields >>> 0; + const n = conf.n >>> 0; + var header = `GET /hello HTTP/1.1${CRLF}Content-Type: text/plain${CRLF}`; + + for (var i = 0; i < fields; i++) { + header += `X-Filler${i}: ${Math.random().toString(36).substr(2)}${CRLF}`; + } + header += CRLF; + + processHeader(new Buffer(header), n); +} + + +function processHeader(header, n) { + const parser = newParser(REQUEST); + + bench.start(); + for (var i = 0; i < n; i++) { + parser.execute(header, 0, header.length); + parser.reinitialize(REQUEST); + } + bench.end(n); +} + + +function newParser(type) { + const parser = new HTTPParser(type); + + parser.headers = []; + + parser[kOnHeaders] = function() { }; + parser[kOnHeadersComplete] = function() { }; + parser[kOnBody] = function() { }; + parser[kOnMessageComplete] = function() { }; + + return parser; +} diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc index ff3dfb26e5..28322f95c4 100644 --- a/src/node_http_parser.cc +++ b/src/node_http_parser.cc @@ -632,12 +632,23 @@ class Parser : public BaseObject { Local CreateHeaders() { // num_values_ is either -1 or the entry # of the last header // so num_values_ == 0 means there's a single header - Local headers = Array::New(env()->isolate(), 2 * num_values_); - - for (int i = 0; i < num_values_; ++i) { - headers->Set(2 * i, fields_[i].ToString(env())); - headers->Set(2 * i + 1, values_[i].ToString(env())); - } + Local headers = Array::New(env()->isolate()); + Local fn = env()->push_values_to_array_function(); + Local argv[NODE_PUSH_VAL_TO_ARRAY_MAX * 2]; + int i = 0; + + do { + size_t j = 0; + while (i < num_values_ && j < ARRAY_SIZE(argv) / 2) { + argv[j * 2] = fields_[i].ToString(env()); + argv[j * 2 + 1] = values_[i].ToString(env()); + i++; + j++; + } + if (j > 0) { + fn->Call(env()->context(), headers, j * 2, argv).ToLocalChecked(); + } + } while (i < num_values_); return headers; }