current commit
261105.11 · http: batch body spans per parser execute
'use strict';

// Measures parsing a chunked request body as the chunk size shrinks.
// The wire buffer is fed to the parser in 64 KiB slices, like socket reads.

const common = require('../common');

const bench = common.createBenchmark(main, {
  chunkSize: [1, 16, 256, 4096],
  len: [64 * 1024],
  n: [500],
}, {
  flags: ['--expose-internals', '--no-warnings'],
});

function main({ chunkSize, len, n }) {
  const { HTTPParser } = common.binding('http_parser');
  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 kMaxHeaderPairs = 2000;
  const kReadSize = 64 * 1024;

  const chunk = `${chunkSize.toString(16)}\r\n${'x'.repeat(chunkSize)}\r\n`;
  const wire = Buffer.from(
    'POST / HTTP/1.1\r\nHost: localhost\r\nTransfer-Encoding: chunked\r\n\r\n' +
    chunk.repeat(Math.ceil(len / chunkSize)) +
    '0\r\n\r\n');

  const reads = [];
  for (let i = 0; i < wire.length; i += kReadSize)
    reads.push(wire.subarray(i, i + kReadSize));

  let bodyBytes = 0;
  const parser = new HTTPParser();
  parser.initialize(REQUEST, {}, 0, 0, undefined, kMaxHeaderPairs);
  parser[kOnHeaders] = function() {};
  parser[kOnHeadersComplete] = function() {};
  parser[kOnBody] = function(b) { bodyBytes += b.length; };
  parser[kOnMessageComplete] = function() {};

  bench.start();
  for (let i = 0; i < n; i++) {
    for (const read of reads)
      parser.execute(read);
    parser.initialize(REQUEST, {}, 0, 0, undefined, kMaxHeaderPairs);
  }
  bench.end(n);

  const expected = Math.ceil(len / chunkSize) * chunkSize * n;
  if (bodyBytes !== expected)
    throw new Error(`Expected ${expected} body bytes, got ${bodyBytes}`);
}