11cb0ef41Sopenharmony_ci'use strict'; 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ciconst child_process = require('child_process'); 41cb0ef41Sopenharmony_ciconst http_benchmarkers = require('./_http-benchmarkers.js'); 51cb0ef41Sopenharmony_ci 61cb0ef41Sopenharmony_cifunction allow() { 71cb0ef41Sopenharmony_ci return true; 81cb0ef41Sopenharmony_ci} 91cb0ef41Sopenharmony_ci 101cb0ef41Sopenharmony_ciclass Benchmark { 111cb0ef41Sopenharmony_ci constructor(fn, configs, options = {}) { 121cb0ef41Sopenharmony_ci // Used to make sure a benchmark only start a timer once 131cb0ef41Sopenharmony_ci this._started = false; 141cb0ef41Sopenharmony_ci 151cb0ef41Sopenharmony_ci // Indicate that the benchmark ended 161cb0ef41Sopenharmony_ci this._ended = false; 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_ci // Holds process.hrtime value 191cb0ef41Sopenharmony_ci this._time = 0n; 201cb0ef41Sopenharmony_ci 211cb0ef41Sopenharmony_ci // Use the file name as the name of the benchmark 221cb0ef41Sopenharmony_ci this.name = require.main.filename.slice(__dirname.length + 1); 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_ci // Execution arguments i.e. flags used to run the jobs 251cb0ef41Sopenharmony_ci this.flags = process.env.NODE_BENCHMARK_FLAGS ? 261cb0ef41Sopenharmony_ci process.env.NODE_BENCHMARK_FLAGS.split(/\s+/) : 271cb0ef41Sopenharmony_ci []; 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_ci // Parse job-specific configuration from the command line arguments 301cb0ef41Sopenharmony_ci const argv = process.argv.slice(2); 311cb0ef41Sopenharmony_ci const parsed_args = this._parseArgs(argv, configs, options); 321cb0ef41Sopenharmony_ci this.options = parsed_args.cli; 331cb0ef41Sopenharmony_ci this.extra_options = parsed_args.extra; 341cb0ef41Sopenharmony_ci if (options.flags) { 351cb0ef41Sopenharmony_ci this.flags = this.flags.concat(options.flags); 361cb0ef41Sopenharmony_ci } 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_ci if (typeof options.combinationFilter === 'function') 391cb0ef41Sopenharmony_ci this.combinationFilter = options.combinationFilter; 401cb0ef41Sopenharmony_ci else 411cb0ef41Sopenharmony_ci this.combinationFilter = allow; 421cb0ef41Sopenharmony_ci 431cb0ef41Sopenharmony_ci // The configuration list as a queue of jobs 441cb0ef41Sopenharmony_ci this.queue = this._queue(this.options); 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ci if (this.queue.length === 0) 471cb0ef41Sopenharmony_ci return; 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_ci // The configuration of the current job, head of the queue 501cb0ef41Sopenharmony_ci this.config = this.queue[0]; 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_ci process.nextTick(() => { 531cb0ef41Sopenharmony_ci if (process.env.NODE_RUN_BENCHMARK_FN !== undefined) { 541cb0ef41Sopenharmony_ci fn(this.config); 551cb0ef41Sopenharmony_ci } else { 561cb0ef41Sopenharmony_ci // _run will use fork() to create a new process for each configuration 571cb0ef41Sopenharmony_ci // combination. 581cb0ef41Sopenharmony_ci this._run(); 591cb0ef41Sopenharmony_ci } 601cb0ef41Sopenharmony_ci }); 611cb0ef41Sopenharmony_ci } 621cb0ef41Sopenharmony_ci 631cb0ef41Sopenharmony_ci _parseArgs(argv, configs, options) { 641cb0ef41Sopenharmony_ci const cliOptions = {}; 651cb0ef41Sopenharmony_ci 661cb0ef41Sopenharmony_ci // Check for the test mode first. 671cb0ef41Sopenharmony_ci const testIndex = argv.indexOf('--test'); 681cb0ef41Sopenharmony_ci if (testIndex !== -1) { 691cb0ef41Sopenharmony_ci for (const [key, rawValue] of Object.entries(configs)) { 701cb0ef41Sopenharmony_ci let value = Array.isArray(rawValue) ? rawValue[0] : rawValue; 711cb0ef41Sopenharmony_ci // Set numbers to one by default to reduce the runtime. 721cb0ef41Sopenharmony_ci if (typeof value === 'number') { 731cb0ef41Sopenharmony_ci if (key === 'dur' || key === 'duration') { 741cb0ef41Sopenharmony_ci value = 0.05; 751cb0ef41Sopenharmony_ci } else if (value > 1) { 761cb0ef41Sopenharmony_ci value = 1; 771cb0ef41Sopenharmony_ci } 781cb0ef41Sopenharmony_ci } 791cb0ef41Sopenharmony_ci cliOptions[key] = [value]; 801cb0ef41Sopenharmony_ci } 811cb0ef41Sopenharmony_ci // Override specific test options. 821cb0ef41Sopenharmony_ci if (options.test) { 831cb0ef41Sopenharmony_ci for (const [key, value] of Object.entries(options.test)) { 841cb0ef41Sopenharmony_ci cliOptions[key] = Array.isArray(value) ? value : [value]; 851cb0ef41Sopenharmony_ci } 861cb0ef41Sopenharmony_ci } 871cb0ef41Sopenharmony_ci argv.splice(testIndex, 1); 881cb0ef41Sopenharmony_ci } else { 891cb0ef41Sopenharmony_ci // Accept single values instead of arrays. 901cb0ef41Sopenharmony_ci for (const [key, value] of Object.entries(configs)) { 911cb0ef41Sopenharmony_ci if (!Array.isArray(value)) 921cb0ef41Sopenharmony_ci configs[key] = [value]; 931cb0ef41Sopenharmony_ci } 941cb0ef41Sopenharmony_ci } 951cb0ef41Sopenharmony_ci 961cb0ef41Sopenharmony_ci const extraOptions = {}; 971cb0ef41Sopenharmony_ci const validArgRE = /^(.+?)=([\s\S]*)$/; 981cb0ef41Sopenharmony_ci // Parse configuration arguments 991cb0ef41Sopenharmony_ci for (const arg of argv) { 1001cb0ef41Sopenharmony_ci const match = arg.match(validArgRE); 1011cb0ef41Sopenharmony_ci if (!match) { 1021cb0ef41Sopenharmony_ci console.error(`bad argument: ${arg}`); 1031cb0ef41Sopenharmony_ci process.exit(1); 1041cb0ef41Sopenharmony_ci } 1051cb0ef41Sopenharmony_ci const [, key, value] = match; 1061cb0ef41Sopenharmony_ci if (configs[key] !== undefined) { 1071cb0ef41Sopenharmony_ci if (!cliOptions[key]) 1081cb0ef41Sopenharmony_ci cliOptions[key] = []; 1091cb0ef41Sopenharmony_ci cliOptions[key].push( 1101cb0ef41Sopenharmony_ci // Infer the type from the config object and parse accordingly 1111cb0ef41Sopenharmony_ci typeof configs[key][0] === 'number' ? +value : value, 1121cb0ef41Sopenharmony_ci ); 1131cb0ef41Sopenharmony_ci } else { 1141cb0ef41Sopenharmony_ci extraOptions[key] = value; 1151cb0ef41Sopenharmony_ci } 1161cb0ef41Sopenharmony_ci } 1171cb0ef41Sopenharmony_ci return { cli: { ...configs, ...cliOptions }, extra: extraOptions }; 1181cb0ef41Sopenharmony_ci } 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_ci _queue(options) { 1211cb0ef41Sopenharmony_ci const queue = []; 1221cb0ef41Sopenharmony_ci const keys = Object.keys(options); 1231cb0ef41Sopenharmony_ci const { combinationFilter } = this; 1241cb0ef41Sopenharmony_ci 1251cb0ef41Sopenharmony_ci // Perform a depth-first walk through all options to generate a 1261cb0ef41Sopenharmony_ci // configuration list that contains all combinations. 1271cb0ef41Sopenharmony_ci function recursive(keyIndex, prevConfig) { 1281cb0ef41Sopenharmony_ci const key = keys[keyIndex]; 1291cb0ef41Sopenharmony_ci const values = options[key]; 1301cb0ef41Sopenharmony_ci 1311cb0ef41Sopenharmony_ci for (const value of values) { 1321cb0ef41Sopenharmony_ci if (typeof value !== 'number' && typeof value !== 'string') { 1331cb0ef41Sopenharmony_ci throw new TypeError( 1341cb0ef41Sopenharmony_ci `configuration "${key}" had type ${typeof value}`); 1351cb0ef41Sopenharmony_ci } 1361cb0ef41Sopenharmony_ci if (typeof value !== typeof values[0]) { 1371cb0ef41Sopenharmony_ci // This is a requirement for being able to consistently and 1381cb0ef41Sopenharmony_ci // predictably parse CLI provided configuration values. 1391cb0ef41Sopenharmony_ci throw new TypeError(`configuration "${key}" has mixed types`); 1401cb0ef41Sopenharmony_ci } 1411cb0ef41Sopenharmony_ci 1421cb0ef41Sopenharmony_ci const currConfig = { [key]: value, ...prevConfig }; 1431cb0ef41Sopenharmony_ci 1441cb0ef41Sopenharmony_ci if (keyIndex + 1 < keys.length) { 1451cb0ef41Sopenharmony_ci recursive(keyIndex + 1, currConfig); 1461cb0ef41Sopenharmony_ci } else { 1471cb0ef41Sopenharmony_ci // Check if we should allow the current combination 1481cb0ef41Sopenharmony_ci const allowed = combinationFilter({ ...currConfig }); 1491cb0ef41Sopenharmony_ci if (typeof allowed !== 'boolean') { 1501cb0ef41Sopenharmony_ci throw new TypeError( 1511cb0ef41Sopenharmony_ci 'Combination filter must always return a boolean', 1521cb0ef41Sopenharmony_ci ); 1531cb0ef41Sopenharmony_ci } 1541cb0ef41Sopenharmony_ci if (allowed) 1551cb0ef41Sopenharmony_ci queue.push(currConfig); 1561cb0ef41Sopenharmony_ci } 1571cb0ef41Sopenharmony_ci } 1581cb0ef41Sopenharmony_ci } 1591cb0ef41Sopenharmony_ci 1601cb0ef41Sopenharmony_ci if (keys.length > 0) { 1611cb0ef41Sopenharmony_ci recursive(0, {}); 1621cb0ef41Sopenharmony_ci } else { 1631cb0ef41Sopenharmony_ci queue.push({}); 1641cb0ef41Sopenharmony_ci } 1651cb0ef41Sopenharmony_ci 1661cb0ef41Sopenharmony_ci return queue; 1671cb0ef41Sopenharmony_ci } 1681cb0ef41Sopenharmony_ci 1691cb0ef41Sopenharmony_ci http(options, cb) { 1701cb0ef41Sopenharmony_ci const http_options = { ...options }; 1711cb0ef41Sopenharmony_ci http_options.benchmarker = http_options.benchmarker || 1721cb0ef41Sopenharmony_ci this.config.benchmarker || 1731cb0ef41Sopenharmony_ci this.extra_options.benchmarker || 1741cb0ef41Sopenharmony_ci http_benchmarkers.default_http_benchmarker; 1751cb0ef41Sopenharmony_ci http_benchmarkers.run( 1761cb0ef41Sopenharmony_ci http_options, (error, code, used_benchmarker, result, elapsed) => { 1771cb0ef41Sopenharmony_ci if (cb) { 1781cb0ef41Sopenharmony_ci cb(code); 1791cb0ef41Sopenharmony_ci } 1801cb0ef41Sopenharmony_ci if (error) { 1811cb0ef41Sopenharmony_ci console.error(error); 1821cb0ef41Sopenharmony_ci process.exit(code || 1); 1831cb0ef41Sopenharmony_ci } 1841cb0ef41Sopenharmony_ci this.config.benchmarker = used_benchmarker; 1851cb0ef41Sopenharmony_ci this.report(result, elapsed); 1861cb0ef41Sopenharmony_ci }, 1871cb0ef41Sopenharmony_ci ); 1881cb0ef41Sopenharmony_ci } 1891cb0ef41Sopenharmony_ci 1901cb0ef41Sopenharmony_ci _run() { 1911cb0ef41Sopenharmony_ci // If forked, report to the parent. 1921cb0ef41Sopenharmony_ci if (process.send) { 1931cb0ef41Sopenharmony_ci process.send({ 1941cb0ef41Sopenharmony_ci type: 'config', 1951cb0ef41Sopenharmony_ci name: this.name, 1961cb0ef41Sopenharmony_ci queueLength: this.queue.length, 1971cb0ef41Sopenharmony_ci }); 1981cb0ef41Sopenharmony_ci } 1991cb0ef41Sopenharmony_ci 2001cb0ef41Sopenharmony_ci const recursive = (queueIndex) => { 2011cb0ef41Sopenharmony_ci const config = this.queue[queueIndex]; 2021cb0ef41Sopenharmony_ci 2031cb0ef41Sopenharmony_ci // Set NODE_RUN_BENCHMARK_FN to indicate that the child shouldn't 2041cb0ef41Sopenharmony_ci // construct a configuration queue, but just execute the benchmark 2051cb0ef41Sopenharmony_ci // function. 2061cb0ef41Sopenharmony_ci const childEnv = { ...process.env }; 2071cb0ef41Sopenharmony_ci childEnv.NODE_RUN_BENCHMARK_FN = ''; 2081cb0ef41Sopenharmony_ci 2091cb0ef41Sopenharmony_ci // Create configuration arguments 2101cb0ef41Sopenharmony_ci const childArgs = []; 2111cb0ef41Sopenharmony_ci for (const [key, value] of Object.entries(config)) { 2121cb0ef41Sopenharmony_ci childArgs.push(`${key}=${value}`); 2131cb0ef41Sopenharmony_ci } 2141cb0ef41Sopenharmony_ci for (const [key, value] of Object.entries(this.extra_options)) { 2151cb0ef41Sopenharmony_ci childArgs.push(`${key}=${value}`); 2161cb0ef41Sopenharmony_ci } 2171cb0ef41Sopenharmony_ci 2181cb0ef41Sopenharmony_ci const child = child_process.fork(require.main.filename, childArgs, { 2191cb0ef41Sopenharmony_ci env: childEnv, 2201cb0ef41Sopenharmony_ci execArgv: this.flags.concat(process.execArgv), 2211cb0ef41Sopenharmony_ci }); 2221cb0ef41Sopenharmony_ci child.on('message', sendResult); 2231cb0ef41Sopenharmony_ci child.on('close', (code) => { 2241cb0ef41Sopenharmony_ci if (code) { 2251cb0ef41Sopenharmony_ci process.exit(code); 2261cb0ef41Sopenharmony_ci } 2271cb0ef41Sopenharmony_ci 2281cb0ef41Sopenharmony_ci if (queueIndex + 1 < this.queue.length) { 2291cb0ef41Sopenharmony_ci recursive(queueIndex + 1); 2301cb0ef41Sopenharmony_ci } 2311cb0ef41Sopenharmony_ci }); 2321cb0ef41Sopenharmony_ci }; 2331cb0ef41Sopenharmony_ci 2341cb0ef41Sopenharmony_ci recursive(0); 2351cb0ef41Sopenharmony_ci } 2361cb0ef41Sopenharmony_ci 2371cb0ef41Sopenharmony_ci start() { 2381cb0ef41Sopenharmony_ci if (this._started) { 2391cb0ef41Sopenharmony_ci throw new Error('Called start more than once in a single benchmark'); 2401cb0ef41Sopenharmony_ci } 2411cb0ef41Sopenharmony_ci this._started = true; 2421cb0ef41Sopenharmony_ci this._time = process.hrtime.bigint(); 2431cb0ef41Sopenharmony_ci } 2441cb0ef41Sopenharmony_ci 2451cb0ef41Sopenharmony_ci end(operations) { 2461cb0ef41Sopenharmony_ci // Get elapsed time now and do error checking later for accuracy. 2471cb0ef41Sopenharmony_ci const time = process.hrtime.bigint(); 2481cb0ef41Sopenharmony_ci 2491cb0ef41Sopenharmony_ci if (!this._started) { 2501cb0ef41Sopenharmony_ci throw new Error('called end without start'); 2511cb0ef41Sopenharmony_ci } 2521cb0ef41Sopenharmony_ci if (this._ended) { 2531cb0ef41Sopenharmony_ci throw new Error('called end multiple times'); 2541cb0ef41Sopenharmony_ci } 2551cb0ef41Sopenharmony_ci if (typeof operations !== 'number') { 2561cb0ef41Sopenharmony_ci throw new Error('called end() without specifying operation count'); 2571cb0ef41Sopenharmony_ci } 2581cb0ef41Sopenharmony_ci if (!process.env.NODEJS_BENCHMARK_ZERO_ALLOWED && operations <= 0) { 2591cb0ef41Sopenharmony_ci throw new Error('called end() with operation count <= 0'); 2601cb0ef41Sopenharmony_ci } 2611cb0ef41Sopenharmony_ci 2621cb0ef41Sopenharmony_ci this._ended = true; 2631cb0ef41Sopenharmony_ci 2641cb0ef41Sopenharmony_ci if (time === this._time) { 2651cb0ef41Sopenharmony_ci if (!process.env.NODEJS_BENCHMARK_ZERO_ALLOWED) 2661cb0ef41Sopenharmony_ci throw new Error('insufficient clock precision for short benchmark'); 2671cb0ef41Sopenharmony_ci // Avoid dividing by zero 2681cb0ef41Sopenharmony_ci this.report(operations && Number.MAX_VALUE, 0n); 2691cb0ef41Sopenharmony_ci return; 2701cb0ef41Sopenharmony_ci } 2711cb0ef41Sopenharmony_ci 2721cb0ef41Sopenharmony_ci const elapsed = time - this._time; 2731cb0ef41Sopenharmony_ci const rate = operations / (Number(elapsed) / 1e9); 2741cb0ef41Sopenharmony_ci this.report(rate, elapsed); 2751cb0ef41Sopenharmony_ci } 2761cb0ef41Sopenharmony_ci 2771cb0ef41Sopenharmony_ci report(rate, elapsed) { 2781cb0ef41Sopenharmony_ci sendResult({ 2791cb0ef41Sopenharmony_ci name: this.name, 2801cb0ef41Sopenharmony_ci conf: this.config, 2811cb0ef41Sopenharmony_ci rate, 2821cb0ef41Sopenharmony_ci time: nanoSecondsToString(elapsed), 2831cb0ef41Sopenharmony_ci type: 'report', 2841cb0ef41Sopenharmony_ci }); 2851cb0ef41Sopenharmony_ci } 2861cb0ef41Sopenharmony_ci} 2871cb0ef41Sopenharmony_ci 2881cb0ef41Sopenharmony_cifunction nanoSecondsToString(bigint) { 2891cb0ef41Sopenharmony_ci const str = bigint.toString(); 2901cb0ef41Sopenharmony_ci const decimalPointIndex = str.length - 9; 2911cb0ef41Sopenharmony_ci if (decimalPointIndex <= 0) { 2921cb0ef41Sopenharmony_ci return `0.${'0'.repeat(-decimalPointIndex)}${str}`; 2931cb0ef41Sopenharmony_ci } 2941cb0ef41Sopenharmony_ci return `${str.slice(0, decimalPointIndex)}.${str.slice(decimalPointIndex)}`; 2951cb0ef41Sopenharmony_ci} 2961cb0ef41Sopenharmony_ci 2971cb0ef41Sopenharmony_cifunction formatResult(data) { 2981cb0ef41Sopenharmony_ci // Construct configuration string, " A=a, B=b, ..." 2991cb0ef41Sopenharmony_ci let conf = ''; 3001cb0ef41Sopenharmony_ci for (const key of Object.keys(data.conf)) { 3011cb0ef41Sopenharmony_ci conf += ` ${key}=${JSON.stringify(data.conf[key])}`; 3021cb0ef41Sopenharmony_ci } 3031cb0ef41Sopenharmony_ci 3041cb0ef41Sopenharmony_ci let rate = data.rate.toString().split('.'); 3051cb0ef41Sopenharmony_ci rate[0] = rate[0].replace(/(\d)(?=(?:\d\d\d)+(?!\d))/g, '$1,'); 3061cb0ef41Sopenharmony_ci rate = (rate[1] ? rate.join('.') : rate[0]); 3071cb0ef41Sopenharmony_ci return `${data.name}${conf}: ${rate}\n`; 3081cb0ef41Sopenharmony_ci} 3091cb0ef41Sopenharmony_ci 3101cb0ef41Sopenharmony_cifunction sendResult(data) { 3111cb0ef41Sopenharmony_ci if (process.send) { 3121cb0ef41Sopenharmony_ci // If forked, report by process send 3131cb0ef41Sopenharmony_ci process.send(data, () => { 3141cb0ef41Sopenharmony_ci if (process.env.NODE_RUN_BENCHMARK_FN !== undefined) { 3151cb0ef41Sopenharmony_ci // If, for any reason, the process is unable to self close within 3161cb0ef41Sopenharmony_ci // a second after completing, forcefully close it. 3171cb0ef41Sopenharmony_ci require('timers').setTimeout(() => { 3181cb0ef41Sopenharmony_ci process.exit(0); 3191cb0ef41Sopenharmony_ci }, 5000).unref(); 3201cb0ef41Sopenharmony_ci } 3211cb0ef41Sopenharmony_ci }); 3221cb0ef41Sopenharmony_ci } else { 3231cb0ef41Sopenharmony_ci // Otherwise report by stdout 3241cb0ef41Sopenharmony_ci process.stdout.write(formatResult(data)); 3251cb0ef41Sopenharmony_ci } 3261cb0ef41Sopenharmony_ci} 3271cb0ef41Sopenharmony_ci 3281cb0ef41Sopenharmony_ciconst urls = { 3291cb0ef41Sopenharmony_ci long: 'http://nodejs.org:89/docs/latest/api/foo/bar/qua/13949281/0f28b/' + 3301cb0ef41Sopenharmony_ci '/5d49/b3020/url.html#test?payload1=true&payload2=false&test=1' + 3311cb0ef41Sopenharmony_ci '&benchmark=3&foo=38.38.011.293&bar=1234834910480&test=19299&3992&' + 3321cb0ef41Sopenharmony_ci 'key=f5c65e1e98fe07e648249ad41e1cfdb0', 3331cb0ef41Sopenharmony_ci short: 'https://nodejs.org/en/blog/', 3341cb0ef41Sopenharmony_ci idn: 'http://你好你好.在线', 3351cb0ef41Sopenharmony_ci auth: 'https://user:pass@example.com/path?search=1', 3361cb0ef41Sopenharmony_ci file: 'file:///foo/bar/test/node.js', 3371cb0ef41Sopenharmony_ci ws: 'ws://localhost:9229/f46db715-70df-43ad-a359-7f9949f39868', 3381cb0ef41Sopenharmony_ci javascript: 'javascript:alert("node is awesome");', 3391cb0ef41Sopenharmony_ci percent: 'https://%E4%BD%A0/foo', 3401cb0ef41Sopenharmony_ci dot: 'https://example.org/./a/../b/./c', 3411cb0ef41Sopenharmony_ci}; 3421cb0ef41Sopenharmony_ci 3431cb0ef41Sopenharmony_ciconst searchParams = { 3441cb0ef41Sopenharmony_ci noencode: 'foo=bar&baz=quux&xyzzy=thud', 3451cb0ef41Sopenharmony_ci multicharsep: 'foo=bar&&&&&&&&&&baz=quux&&&&&&&&&&xyzzy=thud', 3461cb0ef41Sopenharmony_ci encodefake: 'foo=%©ar&baz=%A©uux&xyzzy=%©ud', 3471cb0ef41Sopenharmony_ci encodemany: '%66%6F%6F=bar&%62%61%7A=quux&xyzzy=%74h%75d', 3481cb0ef41Sopenharmony_ci encodelast: 'foo=bar&baz=quux&xyzzy=thu%64', 3491cb0ef41Sopenharmony_ci multivalue: 'foo=bar&foo=baz&foo=quux&quuy=quuz', 3501cb0ef41Sopenharmony_ci multivaluemany: 'foo=bar&foo=baz&foo=quux&quuy=quuz&foo=abc&foo=def&' + 3511cb0ef41Sopenharmony_ci 'foo=ghi&foo=jkl&foo=mno&foo=pqr&foo=stu&foo=vwxyz', 3521cb0ef41Sopenharmony_ci manypairs: 'a&b&c&d&e&f&g&h&i&j&k&l&m&n&o&p&q&r&s&t&u&v&w&x&y&z', 3531cb0ef41Sopenharmony_ci manyblankpairs: '&&&&&&&&&&&&&&&&&&&&&&&&', 3541cb0ef41Sopenharmony_ci altspaces: 'foo+bar=baz+quux&xyzzy+thud=quuy+quuz&abc=def+ghi', 3551cb0ef41Sopenharmony_ci}; 3561cb0ef41Sopenharmony_ci 3571cb0ef41Sopenharmony_cifunction getUrlData(withBase) { 3581cb0ef41Sopenharmony_ci const data = require('../test/fixtures/wpt/url/resources/urltestdata.json'); 3591cb0ef41Sopenharmony_ci const result = []; 3601cb0ef41Sopenharmony_ci for (const item of data) { 3611cb0ef41Sopenharmony_ci if (item.failure || !item.input) continue; 3621cb0ef41Sopenharmony_ci if (withBase) { 3631cb0ef41Sopenharmony_ci // item.base might be null. It should be converted into `undefined`. 3641cb0ef41Sopenharmony_ci result.push([item.input, item.base ?? undefined]); 3651cb0ef41Sopenharmony_ci } else if (item.base !== null) { 3661cb0ef41Sopenharmony_ci result.push(item.base); 3671cb0ef41Sopenharmony_ci } 3681cb0ef41Sopenharmony_ci } 3691cb0ef41Sopenharmony_ci return result; 3701cb0ef41Sopenharmony_ci} 3711cb0ef41Sopenharmony_ci 3721cb0ef41Sopenharmony_ci/** 3731cb0ef41Sopenharmony_ci * Generate an array of data for URL benchmarks to use. 3741cb0ef41Sopenharmony_ci * The size of the resulting data set is the original data size * 2 ** `e`. 3751cb0ef41Sopenharmony_ci * The 'wpt' type contains about 400 data points when `withBase` is true, 3761cb0ef41Sopenharmony_ci * and 200 data points when `withBase` is false. 3771cb0ef41Sopenharmony_ci * Other types contain 200 data points with or without base. 3781cb0ef41Sopenharmony_ci * @param {string} type Type of the data, 'wpt' or a key of `urls` 3791cb0ef41Sopenharmony_ci * @param {number} e The repetition of the data, as exponent of 2 3801cb0ef41Sopenharmony_ci * @param {boolean} withBase Whether to include a base URL 3811cb0ef41Sopenharmony_ci * @param {boolean} asUrl Whether to return the results as URL objects 3821cb0ef41Sopenharmony_ci * @return {string[] | string[][] | URL[]} 3831cb0ef41Sopenharmony_ci */ 3841cb0ef41Sopenharmony_cifunction bakeUrlData(type, e = 0, withBase = false, asUrl = false) { 3851cb0ef41Sopenharmony_ci let result = []; 3861cb0ef41Sopenharmony_ci if (type === 'wpt') { 3871cb0ef41Sopenharmony_ci result = getUrlData(withBase); 3881cb0ef41Sopenharmony_ci } else if (urls[type]) { 3891cb0ef41Sopenharmony_ci const input = urls[type]; 3901cb0ef41Sopenharmony_ci const item = withBase ? [input, 'about:blank'] : input; 3911cb0ef41Sopenharmony_ci // Roughly the size of WPT URL test data 3921cb0ef41Sopenharmony_ci result = new Array(200).fill(item); 3931cb0ef41Sopenharmony_ci } else { 3941cb0ef41Sopenharmony_ci throw new Error(`Unknown url data type ${type}`); 3951cb0ef41Sopenharmony_ci } 3961cb0ef41Sopenharmony_ci 3971cb0ef41Sopenharmony_ci if (typeof e !== 'number') { 3981cb0ef41Sopenharmony_ci throw new Error(`e must be a number, received ${e}`); 3991cb0ef41Sopenharmony_ci } 4001cb0ef41Sopenharmony_ci 4011cb0ef41Sopenharmony_ci for (let i = 0; i < e; ++i) { 4021cb0ef41Sopenharmony_ci result = result.concat(result); 4031cb0ef41Sopenharmony_ci } 4041cb0ef41Sopenharmony_ci 4051cb0ef41Sopenharmony_ci if (asUrl) { 4061cb0ef41Sopenharmony_ci if (withBase) { 4071cb0ef41Sopenharmony_ci result = result.map(([input, base]) => new URL(input, base)); 4081cb0ef41Sopenharmony_ci } else { 4091cb0ef41Sopenharmony_ci result = result.map((input) => new URL(input)); 4101cb0ef41Sopenharmony_ci } 4111cb0ef41Sopenharmony_ci } 4121cb0ef41Sopenharmony_ci return result; 4131cb0ef41Sopenharmony_ci} 4141cb0ef41Sopenharmony_ci 4151cb0ef41Sopenharmony_cimodule.exports = { 4161cb0ef41Sopenharmony_ci Benchmark, 4171cb0ef41Sopenharmony_ci PORT: http_benchmarkers.PORT, 4181cb0ef41Sopenharmony_ci bakeUrlData, 4191cb0ef41Sopenharmony_ci binding(bindingName) { 4201cb0ef41Sopenharmony_ci try { 4211cb0ef41Sopenharmony_ci const { internalBinding } = require('internal/test/binding'); 4221cb0ef41Sopenharmony_ci 4231cb0ef41Sopenharmony_ci return internalBinding(bindingName); 4241cb0ef41Sopenharmony_ci } catch { 4251cb0ef41Sopenharmony_ci return process.binding(bindingName); 4261cb0ef41Sopenharmony_ci } 4271cb0ef41Sopenharmony_ci }, 4281cb0ef41Sopenharmony_ci buildType: process.features.debug ? 'Debug' : 'Release', 4291cb0ef41Sopenharmony_ci createBenchmark(fn, configs, options) { 4301cb0ef41Sopenharmony_ci return new Benchmark(fn, configs, options); 4311cb0ef41Sopenharmony_ci }, 4321cb0ef41Sopenharmony_ci sendResult, 4331cb0ef41Sopenharmony_ci searchParams, 4341cb0ef41Sopenharmony_ci urlDataTypes: Object.keys(urls).concat(['wpt']), 4351cb0ef41Sopenharmony_ci urls, 4361cb0ef41Sopenharmony_ci}; 437