perf: Optimize Header Validation
The current implementation of header validation in the codebase uses Uint8Array to store character validity maps for HTTP tokens, URIs, and header values. While this approach works, it can be further optimized using bitmasking to reduce memory usage and improve performance.
https://github.com/nodejs/undici/blob/e1496cfd285f45165a29c2aefb7a2ee128fadf38/lib/core/util.js#L733
const TOKEN_MAP = new Uint8Array([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
]);
const URI_MAP = new Uint8Array([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
]);
const HEADER_VALUE_MAP = new Uint8Array([
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
]);
export function isHTTPToken(c: number) {
return c < 256 && TOKEN_MAP[c] === 1;
}
export function isHeaderValueToken(c: number) {
return c < 256 && HEADER_VALUE_MAP[c] === 1;
}
export function isURIToken(c: number) {
return c < 256 && URI_MAP[c] === 1;
}
export function isValidHeaderName(name: string) {
for (let i = 0, len = name.length; i < len; i++) {
if (!isHTTPToken(name.charCodeAt(i))) return false;
}
return true;
}
export function isValidHeaderValue(value: string) {
for (let i = 0, len = value.length; i < len; i++) {
if (!isHeaderValueToken(value.charCodeAt(i))) return false;
}
return true;
}
// undici
const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/;
export function isValidHeaderValue2(characters: string): boolean {
return !headerCharRegex.test(characters);
}
export function isTokenCharCode(c: number) {
switch (c) {
case 0x22:
case 0x28:
case 0x29:
case 0x2c:
case 0x2f:
case 0x3a:
case 0x3b:
case 0x3c:
case 0x3d:
case 0x3e:
case 0x3f:
case 0x40:
case 0x5b:
case 0x5c:
case 0x5d:
case 0x7b:
case 0x7d:
// DQUOTE and "(),/:;<=>?@[\]{}"
return false;
default:
// VCHAR %x21-7E
return c >= 0x21 && c <= 0x7e;
}
}
export function isValidHTTPToken(characters: string) {
for (let i = 0; i < characters.length; ++i) {
if (!isTokenCharCode(characters.charCodeAt(i))) {
return false;
}
}
return true;
}
Benchmarks
import * as utils from './constants.ts';
async function bench() {
const { bench, run, summary } = await import('mitata');
summary(() => {
bench('isValidHeaderValue one char', () => {
for (let index = 0; index < 512; index++) {
utils.isValidHeaderValue(String.fromCharCode(index));
}
});
bench('undici.isValidHeaderValue one char', () => {
for (let index = 0; index < 512; index++) {
utils.isValidHeaderValue2(String.fromCharCode(index));
}
});
});
summary(() => {
bench('isValidHeaderValue', () => {
for (let index = 0; index < 512; index++) {
utils.isValidHeaderValue('accessToken=HFVTGWBNJNMDJNDJNDHBDHJDD123');
}
});
bench('undici.isValidHeaderValue (re)', () => {
for (let index = 0; index < 512; index++) {
utils.isValidHeaderValue2('accessToken=HFVTGWBNJNMDJNDJNDHBDHJDD123');
}
});
});
summary(() => {
bench('isHTTPToken', () => {
for (let index = 0; index < 512; index++) {
utils.isHTTPToken(index);
}
});
bench('undici.isTokenCharCode', () => {
for (let index = 0; index < 512; index++) {
utils.isTokenCharCode(index);
}
});
});
summary(() => {
bench('isValidHeaderName', () => {
for (let index = 0; index < 512; index++) {
utils.isValidHeaderName('X-Authorization-User-Id');
}
});
bench('undici.isValidHTTPToken', () => {
for (let index = 0; index < 512; index++) {
utils.isValidHTTPToken('X-Authorization-User-Id');
}
});
});
summary(() => {
bench('isValidHeaderName invalid', () => {
for (let index = 0; index < 512; index++) {
utils.isValidHeaderName('X-Authorization-User\n-Id');
}
});
bench('undici.isValidHTTPToken invalid', () => {
for (let index = 0; index < 512; index++) {
utils.isValidHTTPToken('X-Authorization-User\n-Id');
}
});
});
for (let index = 0; index < 256; index++) {
const char = String.fromCharCode(index);
const [a, b] = [utils.isValidHeaderName(char), utils.isValidHTTPToken(char)];
const [c, d] = [utils.isValidHeaderValue(char), utils.isValidHeaderValue2(char)];
if ((a !== b) || (c !== d)) {
console.warn({ index, char, a, b, c, d});
}
}
run();
}
bench();
Results
clk: ~3.04 GHz
cpu: Apple M1 Max
runtime: node 22.12.0 (arm64-darwin)
benchmark avg (min … max) p75 p99 (min … top 1%)
------------------------------------------- -------------------------------
isValidHeaderValue one char 1.34 µs/iter 1.38 µs ▄ █ ▂
(1.26 µs … 1.48 µs) 1.43 µs ▅█▅█▅▅▂▁▁▂▁▂█▅██▅▂▁▂▂
undici.isValidHeaderValue .. 7.40 µs/iter 7.33 µs ▂█▂
(7.26 µs … 8.19 µs) 7.82 µs ███▇▁▄▁▁▁▁▁▁▁▄▁▁▁▁▁▁▄
summary
isValidHeaderValue one char
5.53x faster than undici.isValidHeaderValue one char
------------------------------------------- -------------------------------
isValidHeaderValue 19.84 µs/iter 20.16 µs █ █
(19.41 µs … 20.27 µs) 20.20 µs ▆█▁▆▁▁▁▁▁▁▁▁▆▆▁▁▁▁▁█▆
undici.isValidHeaderValue .. 20.48 µs/iter 20.44 µs █
(20.36 µs … 21.11 µs) 20.70 µs ▅██▅▁▅▁▁▅▁▁▁▁▁▁▁▁▁▁▁▅
summary
isValidHeaderValue
1.03x faster than undici.isValidHeaderValue (re)
------------------------------------------- -------------------------------
isHTTPToken 350.50 ns/iter 373.16 ns █
(182.86 ns … 389.65 ns) 381.80 ns ▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█▂
undici.isTokenCharCode 732.03 ns/iter 747.38 ns █
(676.33 ns … 796.38 ns) 786.35 ns ▅▂▁▁▁▁▁▁▁▁▁▁▁█▂▁▁▁▁▁▁
summary
isHTTPToken
2.09x faster than undici.isTokenCharCode
------------------------------------------- -------------------------------
isValidHeaderName 13.53 µs/iter 14.96 µs ▇ █
(11.21 µs … 68.92 µs) 16.46 µs █▂▂▁▁▁▁▁▁▁▁▁▁▁█▂▃▁▂▁▁
undici.isValidHTTPToken 22.95 µs/iter 23.04 µs █ ▄
(21.96 µs … 83.75 µs) 31.96 µs █▂█▃▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁
summary
isValidHeaderName
1.7x faster than undici.isValidHTTPToken
------------------------------------------- -------------------------------
isValidHeaderName invalid 10.34 µs/iter 10.41 µs █ █
(10.18 µs … 10.53 µs) 10.51 µs █▁█▁▁▁██▁▁▁▁███▁▁▁█▁█
undici.isValidHTTPToken in.. 20.10 µs/iter 20.36 µs ▃ █
(19.62 µs … 20.82 µs) 20.37 µs ▆█▁▁▆▁▁▁▁▁▆▁▁▁▆▆▁▁▆▁█
summary
isValidHeaderName invalid
1.94x faster than undici.isValidHTTPToken invalid
Regular expressions start winning after about 20 characters, so you can use different implementations based on the number of characters.
export function isValidHeaderValue(value: string) {
for (let i = 0, len = value.length; i < len; i++) {
if (!isHeaderValueToken(value.charCodeAt(i))) return false;
}
return true;
}
export function isValidHeaderValueOptimized(value: string){
return value.length >= 20 ? isValidHeaderValue2(value) : isValidHeaderValue(value);
}
// undici
const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/;
export function isValidHeaderValue2(characters: string): boolean {
return !headerCharRegex.test(characters);
}
import { bench, compact, lineplot, run } from 'mitata';
import * as utils from './constants.ts'; //
async function benchmark() {
lineplot(() => {
compact(() => {
bench('isValidHeaderValue($size)', function* (state) {
const size = state.get('size');
yield () => utils.isValidHeaderValue('a'.repeat(size));
}).range('size', 1, 512, 2);
bench('isValidHeaderValue2($size)', function* (state) {
const size = state.get('size');
yield () => utils.isValidHeaderValue2('a'.repeat(size));
}).range('size', 1, 512, 2).highlight('green');
bench('isValidHeaderValueOp($size)', function* (state) {
const size = state.get('size');
yield () => utils.isValidHeaderValueOptimized('a'.repeat(size));
}).range('size', 1, 512, 2).highlight('blue');
});
});
run();
}
benchmark();
clk: ~2.98 GHz
cpu: Apple M1 Max
runtime: node 22.12.0 (arm64-darwin)
benchmark avg (min … max) p75 p99 (min … top 1%)
------------------------------------------- -------------------------------
isValidHeaderValue(1) 6.44 ns/iter 6.09 ns 13.39 ns █▂▁▁▁▁▁▁▁▁▁
isValidHeaderValue(2) 13.48 ns/iter 13.01 ns 36.89 ns █▁▁▁▁▁▁▁▁▁▁
isValidHeaderValue(4) 22.71 ns/iter 22.59 ns 42.43 ns █▂▁▁▁▁▁▁▁▁▁
isValidHeaderValue(8) 35.61 ns/iter 35.10 ns 55.83 ns █▂▁▁▁▁▁▁▁▁▁
isValidHeaderValue(16) 89.79 ns/iter 89.51 ns 111.66 ns █▄▁▁▁▁▁▁▁▁▁
isValidHeaderValue(32) 148.24 ns/iter 146.65 ns 180.44 ns ▂▇█▂▁▁▁▁▁▁▁
isValidHeaderValue(64) 244.00 ns/iter 244.31 ns 272.60 ns ▂▁▁▃█▁▁▁▁▁▁
isValidHeaderValue(128) 430.87 ns/iter 434.69 ns 489.22 ns ▂▁▁▁█▂▂▁▁▁▁
isValidHeaderValue(256) 784.24 ns/iter 801.97 ns 831.61 ns ▃▂▁▁▁▁▁█▁▂▁
isValidHeaderValue(512) 1.48 µs/iter 1.54 µs 1.58 µs ▇▃▂▁▁▁▁▁█▂▂
isValidHeaderValue2(1) 14.00 ns/iter 13.80 ns 18.68 ns █▁▁▁▁▁▁▁▁▁▁
isValidHeaderValue2(2) 19.95 ns/iter 19.53 ns 25.35 ns █▂▁▁▁▁▁▁▁▁▁
isValidHeaderValue2(4) 27.76 ns/iter 27.76 ns 47.04 ns █▂▁▁▁▁▁▁▁▁▁
isValidHeaderValue2(8) 37.00 ns/iter 36.50 ns 57.35 ns █▂▁▁▁▁▁▁▁▁▁
isValidHeaderValue2(16) 97.36 ns/iter 96.73 ns 120.33 ns █▃▁▁▁▁▁▁▁▁▁
isValidHeaderValue2(32) 119.66 ns/iter 120.23 ns 162.14 ns █▅▂▁▁▁▁▁▁▁▁
isValidHeaderValue2(64) 163.11 ns/iter 163.44 ns 194.48 ns █▃▂▁▁▁▁▁▁▁▁
isValidHeaderValue2(128) 229.44 ns/iter 226.66 ns 311.33 ns █▄▂▁▁▁▁▁▁▁▁
isValidHeaderValue2(256) 337.58 ns/iter 339.38 ns 369.10 ns ▄█▅▃▂▁▂▂▂▁▁
isValidHeaderValue2(512) 548.84 ns/iter 551.52 ns 575.91 ns ▅█▄▂▁▁▂▃▂▁▁
isValidHeaderValueOp(1) 6.12 ns/iter 6.06 ns 7.03 ns █▂▁▁▁▁▁▁▁▁▁
isValidHeaderValueOp(2) 13.20 ns/iter 12.95 ns 17.33 ns █▂▁▁▁▁▁▁▁▁▁
isValidHeaderValueOp(4) 22.80 ns/iter 22.42 ns 42.80 ns █▁▁▁▁▁▁▁▁▁▁
isValidHeaderValueOp(8) 37.17 ns/iter 37.28 ns 67.53 ns █▄▁▁▁▁▁▁▁▁▁
isValidHeaderValueOp(16) 93.46 ns/iter 93.99 ns 131.66 ns ██▃▂▁▁▁▁▁▁▁
isValidHeaderValueOp(32) 118.41 ns/iter 118.92 ns 147.88 ns █▄▂▁▁▁▁▁▁▁▁
isValidHeaderValueOp(64) 166.91 ns/iter 164.30 ns 235.86 ns █▃▂▁▁▁▁▁▁▁▁
isValidHeaderValueOp(128) 227.26 ns/iter 229.28 ns 268.29 ns ▆▅█▃▂▁▁▁▁▁▁
isValidHeaderValueOp(256) 336.57 ns/iter 340.00 ns 376.96 ns █▅▃▂▂▂▁▁▁▁▁
isValidHeaderValueOp(512) 560.46 ns/iter 569.84 ns 615.56 ns ██▄▇▅▃▂▂▂▁▁
┌ ┐
isValidHeaderValue($size) ⡜ 1.48 µs
isValidHeaderValue2($size) ⢰⠁
isValidHeaderValueOp($size) ⢀⠇
⡜
⢰⠁
⢀⠇
⡜
⡰⠁
⡰⠁
⡜ ⢀
⢀⠎ ⢀⡴⠋
⢀⡠⠊ ⢀⠔⠋
⣀⠔⠁ ⣀⡤⠖⠁
⣀⡠⠔⠊⣀⣀⣤⠴⠖⠋⠁
⣀⣀⣤⠤⠶⠶⠝⠒⠒⠉⠉⠁
⣀⣀⣀⣤⣤⣤⣤⡤⠤⠤⠤⠤⠤⠤⠤⠔⠒⠊⠉ 6.12 ns
└ ┘
Wow, this is a comprehensive anaylisis. Would you like to send a PR? We'd indeed need to use both approaches, one for short headers and one for long ones.
How did you come by this improvement? Did you find that header validation was a bottleneck for a specific case in Undici? Does this improvement speed up our benchmarks?
I would prefer to just use regular expressions. Seems like a good balance between performance and maintainability.
@mcollina , In applications where a large number of network requests are required, it is important that they are as productive as possible, not only without headers, but also with headers. I measured queries without headers and with headers in profiling mode.
Also, such services often have the same requests, and it would be good to do something like a PreparedRequest that will create a structure that does not require further validation of headers and transformation of the request body.
Here are the functions that need to be reviewed for optimization: *processHeader /undici/lib/core/request.js:322:24 *Request /undici/lib/core/request.js:31:15 *parseHeaders /undici/lib/core/util.js:408:23 RegExp: [^\t\x20-\x7e\x80-\xff] *resumeH1 /undici/lib/dispatcher/client-h1.js:958:19
// @ts-nocheck
import { Agent, request } from 'undici';
const dispatcher = new Agent({ connections: 100 });
const header = new Headers();
header.set(`x-authorization-user-id-1`, `a`.repeat(10 * 20 * 25));
const headers = new Headers();
for (let index = 0; index < 20; index++) {
headers.set(`x-authorization-user-id-${index}`, `a`.repeat(10));
}
const optionsWithHeaders = {
method: 'GET',
dispatcher,
headers: headers,
};
const optionsWithOneHeader = {
method: 'GET',
dispatcher,
headers: header,
};
const optionsWithoutHeaders = {
method: 'GET',
dispatcher,
};
let rpc = 0;
const rpcInterval = setInterval(() => {
const curr = rpc;
rpc = 0;
curr > 0 && console.log(`rps:`, curr);
}, 1000);
async function worker(options) {
const resp = await request('http://localhost:8000', options);
await resp.body.dump();
rpc += 1;
}
async function main() {
{
const start = performance.now();
const tasks = Array.from({ length: 1e6 }, () => worker(optionsWithOneHeader));
await Promise.all(tasks);
const end = performance.now();
console.log(`with one header:`, (end - start).toFixed(2)); // with one header: 23557.95
}
{
const start = performance.now();
const tasks = Array.from({ length: 1e6 }, () => worker(optionsWithHeaders));
await Promise.all(tasks);
const end = performance.now();
console.log(`with Headers:`, (end-start).toFixed(2)); // with Headers: 20957.07
}
{
const start = performance.now();
const tasks = Array.from({ length: 1e6 }, () => worker(optionsWithoutHeaders));
await Promise.all(tasks);
const end = performance.now();
console.log(`without Headers:`, (end-start).toFixed(2)); // without Headers: 17486.71
}
}
main().then(() => clearInterval(rpcInterval));
one header (5000 len)
[JavaScript]:
ticks total nonlib name
2807 14.5% 14.5% RegExp: [^\t\x20-\x7e\x80-\xff]
277 1.4% 1.4% JS: *wasm-function[20]
269 1.4% 1.4% Builtin: KeyedLoadIC_Megamorphic
195 1.0% 1.0% JS: *parseHeaders /node_modules/.pnpm/[email protected]/node_modules/undici/lib/core/util.js:408:23
158 0.8% 0.8% Builtin: LoadIC
133 0.7% 0.7% JS: *resumeH1 /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/client-h1.js:958:19
133 0.7% 0.7% JS: *_resume /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/client.js:533:18
125 0.6% 0.6% Builtin: CreateTypedArray
105 0.5% 0.5% Builtin: RecordWriteSaveFP
101 0.5% 0.5% JS: *processTicksAndRejections node:internal/process/task_queues:72:35
100 0.5% 0.5% JS: *Request /node_modules/.pnpm/[email protected]/node_modules/undici/lib/core/request.js:31:15
91 0.5% 0.5% JS: *<anonymous> /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/pool.js:75:20
81 0.4% 0.4% Builtin: RunMicrotasks
76 0.4% 0.4% Builtin: KeyedStoreIC_Megamorphic
62 0.3% 0.3% JS: *Readable.read node:internal/streams/readable:647:35
61 0.3% 0.3% JS: *nextTick node:internal/process/task_queues:113:18
60 0.3% 0.3% JS: *<anonymous> /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/client.js:279:15
59 0.3% 0.3% JS: *dump /node_modules/.pnpm/[email protected]/node_modules/undici/lib/api/readable.js:258:14
57 0.3% 0.3% JS: *Readable.on node:internal/streams/readable:1127:33
56 0.3% 0.3% JS: *wasm_on_header_value /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/client-h1.js:127:29
54 0.3% 0.3% JS: *processHeader /node_modules/.pnpm/[email protected]/node_modules/undici/lib/core/request.js:322:24
52 0.3% 0.3% Builtin: LoadIC_Megamorphic
51 0.3% 0.3% JS: *writeH1 /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/client-h1.js:998:18
44 0.2% 0.2% RegExp: [^\u0021-\u00ff]
43 0.2% 0.2% JS: *onHeaders /node_modules/.pnpm/[email protected]/node_modules/undici/lib/core/request.js:236:13
41 0.2% 0.2% JS: *worker file:///http/bench/1.ts:1:711
38 0.2% 0.2% JS: *onDrain /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/pool-base.js:31:39
20 headers with 10 len
[JavaScript]:
ticks total nonlib name
915 4.9% 8.0% JS: *processHeader /node_modules/.pnpm/[email protected]/node_modules/undici/lib/core/request.js:322:24
304 1.6% 2.7% JS: *wasm-function[20]
254 1.4% 2.2% JS: *Request /node_modules/.pnpm/[email protected]/node_modules/undici/lib/core/request.js:31:15
197 1.1% 1.7% JS: *parseHeaders /node_modules/.pnpm/[email protected]/node_modules/undici/lib/core/util.js:408:23
151 0.8% 1.3% RegExp: [^\t\x20-\x7e\x80-\xff]
119 0.6% 1.0% JS: *resumeH1 /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/client-h1.js:958:19
110 0.6% 1.0% JS: *<anonymous> /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/pool.js:75:20
108 0.6% 0.9% JS: *processTicksAndRejections node:internal/process/task_queues:72:35
106 0.6% 0.9% JS: *writeH1 /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/client-h1.js:998:18
97 0.5% 0.8% JS: *_resume /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/client.js:533:18
89 0.5% 0.8% JS: *wasm_on_header_value /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/client-h1.js:127:29
72 0.4% 0.6% RegExp: [^\u0021-\u00ff]
72 0.4% 0.6% JS: *Readable.read node:internal/streams/readable:647:35
69 0.4% 0.6% JS: *nextTick node:internal/process/task_queues:113:18
54 0.3% 0.5% JS: *dump /node_modules/.pnpm/[email protected]/node_modules/undici/lib/api/readable.js:258:14
52 0.3% 0.5% JS: *<anonymous> /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/client.js:279:15
50 0.3% 0.4% JS: *runInAsyncScope node:async_hooks:204:18
48 0.3% 0.4% JS: *wasm_on_header_field /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/client-h1.js:116:29
43 0.2% 0.4% JS: *worker file:///http/bench/1.ts:1:555
42 0.2% 0.4% JS: *Readable.on node:internal/streams/readable:1127:33
37 0.2% 0.3% JS: *emitReadable node:internal/streams/readable:819:22
37 0.2% 0.3% JS: *Readable.push node:internal/streams/readable:387:35
36 0.2% 0.3% JS: *wasm_on_message_complete /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/client-h1.js:158:33
31 0.2% 0.3% JS: *emit node:events:471:44
30 0.2% 0.3% JS: *Readable node:internal/streams/readable:320:18
29 0.2% 0.3% JS: wasm-to-js
29 0.2% 0.3% JS: *onHeadersComplete /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/client-h1.js:525:21
26 0.1% 0.2% JS: *wasm_on_body /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/client-h1.js:149:21
26 0.1% 0.2% JS: *innerOk node:internal/assert/utils:259:17
25 0.1% 0.2% JS: *onDrain /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/pool-base.js:31:39
without headers
[JavaScript]:
ticks total nonlib name
330 2.4% 2.4% JS: *wasm-function[20]
239 1.7% 1.7% Builtin: KeyedLoadIC_Megamorphic
188 1.4% 1.4% JS: *parseHeaders /node_modules/.pnpm/[email protected]/node_modules/undici/lib/core/util.js:408:23
136 1.0% 1.0% Builtin: CreateTypedArray
128 0.9% 0.9% JS: *resumeH1 /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/client-h1.js:958:19
109 0.8% 0.8% JS: *Request /node_modules/.pnpm/[email protected]/node_modules/undici/lib/core/request.js:31:15
108 0.8% 0.8% Builtin: RecordWriteSaveFP
107 0.8% 0.8% Builtin: LoadIC
89 0.6% 0.6% JS: *_resume /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/client.js:533:18
85 0.6% 0.6% JS: *<anonymous> /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/pool.js:75:20
84 0.6% 0.6% JS: *processTicksAndRejections node:internal/process/task_queues:72:35
81 0.6% 0.6% Builtin: KeyedStoreIC_Megamorphic
80 0.6% 0.6% JS: *Readable.read node:internal/streams/readable:647:35
72 0.5% 0.5% JS: *wasm_on_header_value /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/client-h1.js:127:29
70 0.5% 0.5% JS: *nextTick node:internal/process/task_queues:113:18
69 0.5% 0.5% JS: *dump /node_modules/.pnpm/[email protected]/node_modules/undici/lib/api/readable.js:258:14
59 0.4% 0.4% Builtin: LoadIC_Megamorphic
58 0.4% 0.4% RegExp: [^\u0021-\u00ff]
56 0.4% 0.4% Builtin: RunMicrotasks
53 0.4% 0.4% JS: *<anonymous> /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/client.js:279:15
49 0.4% 0.4% JS: *writeH1 /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/client-h1.js:998:18
46 0.3% 0.3% JS: *runInAsyncScope node:async_hooks:204:18
45 0.3% 0.3% JS: *Readable node:internal/streams/readable:320:18
44 0.3% 0.3% Builtin: CallApiCallbackOptimizedNoProfiling
37 0.3% 0.3% JS: *wasm_on_header_field /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/client-h1.js:116:29
37 0.3% 0.3% Builtin: JSConstructStubGeneric
37 0.3% 0.3% Builtin: FulfillPromise
35 0.3% 0.3% JS: *request /node_modules/.pnpm/[email protected]/node_modules/undici/lib/api/api-request.js:176:18
34 0.2% 0.2% JS: *onDrain /node_modules/.pnpm/[email protected]/node_modules/undici/lib/dispatcher/pool-base.js:31:39