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