overtake 1.1.3 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cli.cjs +1 -1
- package/build/cli.cjs.map +1 -1
- package/build/cli.js +1 -1
- package/build/cli.js.map +1 -1
- package/build/executor.cjs +27 -6
- package/build/executor.cjs.map +1 -1
- package/build/executor.d.ts +4 -2
- package/build/executor.js +28 -7
- package/build/executor.js.map +1 -1
- package/build/index.cjs +41 -1
- package/build/index.cjs.map +1 -1
- package/build/index.d.ts +3 -1
- package/build/index.js +36 -1
- package/build/index.js.map +1 -1
- package/build/reporter.cjs +14 -13
- package/build/reporter.cjs.map +1 -1
- package/build/reporter.js +14 -13
- package/build/reporter.js.map +1 -1
- package/build/runner.cjs +10 -10
- package/build/runner.cjs.map +1 -1
- package/build/runner.js +11 -11
- package/build/runner.js.map +1 -1
- package/build/types.cjs +8 -0
- package/build/types.cjs.map +1 -1
- package/build/types.d.ts +10 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -1
- package/package.json +4 -2
- package/src/cli.ts +1 -0
- package/src/executor.ts +40 -7
- package/src/index.ts +39 -2
- package/src/reporter.ts +14 -14
- package/src/runner.ts +11 -11
- package/src/types.ts +13 -0
package/build/cli.cjs
CHANGED
|
@@ -61,7 +61,7 @@ commander.name(name).description(description).version(version).argument('<paths.
|
|
|
61
61
|
'json',
|
|
62
62
|
'pjson',
|
|
63
63
|
'table'
|
|
64
|
-
])).addOption(new _commander.Option('--abs-threshold [absThreshold]', 'absolute error threshold in nanoseconds').argParser(parseFloat)).addOption(new _commander.Option('--rel-threshold [relThreshold]', 'relative error threshold (fraction between 0 and 1)').argParser(parseFloat)).addOption(new _commander.Option('--warmup-cycles [warmupCycles]', 'number of warmup cycles before measuring').argParser(parseInt)).addOption(new _commander.Option('--max-cycles [maxCycles]', 'maximum measurement cycles per feed').argParser(parseInt)).addOption(new _commander.Option('--min-cycles [minCycles]', 'minimum measurement cycles per feed').argParser(parseInt)).addOption(new _commander.Option('--no-gc-observer', 'disable GC overlap detection')).action(async (patterns, executeOptions)=>{
|
|
64
|
+
])).addOption(new _commander.Option('--abs-threshold [absThreshold]', 'absolute error threshold in nanoseconds').argParser(parseFloat)).addOption(new _commander.Option('--rel-threshold [relThreshold]', 'relative error threshold (fraction between 0 and 1)').argParser(parseFloat)).addOption(new _commander.Option('--warmup-cycles [warmupCycles]', 'number of warmup cycles before measuring').argParser(parseInt)).addOption(new _commander.Option('--max-cycles [maxCycles]', 'maximum measurement cycles per feed').argParser(parseInt)).addOption(new _commander.Option('--min-cycles [minCycles]', 'minimum measurement cycles per feed').argParser(parseInt)).addOption(new _commander.Option('--no-gc-observer', 'disable GC overlap detection')).addOption(new _commander.Option('--progress', 'show progress bar during benchmark execution')).action(async (patterns, executeOptions)=>{
|
|
65
65
|
const files = new Set();
|
|
66
66
|
await Promise.all(patterns.map(async (pattern)=>{
|
|
67
67
|
const matches = await (0, _glob.glob)(pattern, {
|
package/build/cli.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { createRequire, Module } from 'node:module';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\nimport { SyntheticModule, createContext, SourceTextModule } from 'node:vm';\nimport { stat, readFile } from 'node:fs/promises';\nimport { Command, Option } from 'commander';\nimport { glob } from 'glob';\nimport { Benchmark, printTableReports, printJSONReports, printSimpleReports, DEFAULT_REPORT_TYPES, DEFAULT_WORKERS } from './index.js';\nimport { transpile } from './utils.js';\nimport { REPORT_TYPES } from './types.js';\n\nconst require = createRequire(import.meta.url);\nconst { name, description, version } = require('../package.json');\nconst BENCHMARK_URL = Symbol.for('overtake.benchmarkUrl');\n\nconst commander = new Command();\n\ncommander\n .name(name)\n .description(description)\n .version(version)\n .argument('<paths...>', 'glob pattern to find benchmarks')\n .addOption(new Option('-r, --report-types [reportTypes...]', 'statistic types to include in the report').choices(REPORT_TYPES).default(DEFAULT_REPORT_TYPES))\n .addOption(new Option('-w, --workers [workers]', 'number of concurent workers').default(DEFAULT_WORKERS).argParser(parseInt))\n .addOption(new Option('-f, --format [format]', 'output format').default('simple').choices(['simple', 'json', 'pjson', 'table']))\n .addOption(new Option('--abs-threshold [absThreshold]', 'absolute error threshold in nanoseconds').argParser(parseFloat))\n .addOption(new Option('--rel-threshold [relThreshold]', 'relative error threshold (fraction between 0 and 1)').argParser(parseFloat))\n .addOption(new Option('--warmup-cycles [warmupCycles]', 'number of warmup cycles before measuring').argParser(parseInt))\n .addOption(new Option('--max-cycles [maxCycles]', 'maximum measurement cycles per feed').argParser(parseInt))\n .addOption(new Option('--min-cycles [minCycles]', 'minimum measurement cycles per feed').argParser(parseInt))\n .addOption(new Option('--no-gc-observer', 'disable GC overlap detection'))\n .action(async (patterns: string[], executeOptions) => {\n const files = new Set<string>();\n await Promise.all(\n patterns.map(async (pattern) => {\n const matches = await glob(pattern, { absolute: true, cwd: process.cwd() }).catch(() => []);\n matches.forEach((file) => files.add(file));\n }),\n );\n\n for (const file of files) {\n const stats = await stat(file).catch(() => false as const);\n if (stats && stats.isFile()) {\n const content = await readFile(file, 'utf8');\n const identifier = pathToFileURL(file).href;\n const code = await transpile(content);\n let instance: Benchmark<unknown> | undefined;\n const benchmark = (...args: Parameters<(typeof Benchmark)['create']>) => {\n if (instance) {\n throw new Error('Only one benchmark per file is supported');\n }\n instance = Benchmark.create(...args);\n return instance;\n };\n const script = new SourceTextModule(code, {\n identifier,\n context: createContext({\n benchmark,\n Buffer,\n console,\n }),\n initializeImportMeta(meta) {\n meta.url = identifier;\n },\n async importModuleDynamically(specifier, referencingModule) {\n if (Module.isBuiltin(specifier)) {\n return import(specifier);\n }\n const baseIdentifier = referencingModule.identifier ?? identifier;\n const resolveFrom = createRequire(fileURLToPath(baseIdentifier));\n const resolved = resolveFrom.resolve(specifier);\n return import(resolved);\n },\n });\n const imports = new Map<string, SyntheticModule>();\n await script.link(async (specifier: string, referencingModule) => {\n const baseIdentifier = referencingModule.identifier ?? identifier;\n const resolveFrom = createRequire(fileURLToPath(baseIdentifier));\n const target = Module.isBuiltin(specifier) ? specifier : resolveFrom.resolve(specifier);\n const cached = imports.get(target);\n if (cached) {\n return cached;\n }\n const mod = await import(target);\n const exportNames = Object.keys(mod);\n const imported = new SyntheticModule(\n exportNames,\n () => {\n exportNames.forEach((key) => imported.setExport(key, mod[key]));\n },\n { identifier: target, context: referencingModule.context },\n );\n\n imports.set(target, imported);\n return imported;\n });\n await script.evaluate();\n\n if (instance) {\n const reports = await instance.execute({\n ...executeOptions,\n [BENCHMARK_URL]: identifier,\n } as typeof executeOptions);\n switch (executeOptions.format) {\n case 'json':\n {\n printJSONReports(reports);\n }\n break;\n case 'pjson':\n {\n printJSONReports(reports, 2);\n }\n break;\n case 'table':\n {\n printTableReports(reports);\n }\n break;\n default:\n printSimpleReports(reports);\n }\n }\n }\n }\n });\n\ncommander.parse(process.argv);\n"],"names":["require","createRequire","name","description","version","BENCHMARK_URL","Symbol","for","commander","Command","argument","addOption","Option","choices","REPORT_TYPES","default","DEFAULT_REPORT_TYPES","DEFAULT_WORKERS","argParser","parseInt","parseFloat","action","patterns","executeOptions","files","Set","Promise","all","map","pattern","matches","glob","absolute","cwd","process","catch","forEach","file","add","stats","stat","isFile","content","readFile","identifier","pathToFileURL","href","code","transpile","instance","benchmark","args","Error","Benchmark","create","script","SourceTextModule","context","createContext","Buffer","console","initializeImportMeta","meta","url","importModuleDynamically","specifier","referencingModule","Module","isBuiltin","baseIdentifier","resolveFrom","fileURLToPath","resolved","resolve","imports","Map","link","target","cached","get","mod","exportNames","Object","keys","imported","SyntheticModule","key","setExport","set","evaluate","reports","execute","format","printJSONReports","printTableReports","printSimpleReports","parse","argv"],"mappings":";;;;4BAAsC;yBACO;wBACoB;0BAClC;2BACC;sBACX;0BACqG;0BAChG;0BACG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAE7B,MAAMA,WAAUC,IAAAA,yBAAa,EAAC;AAC9B,MAAM,EAAEC,IAAI,EAAEC,WAAW,EAAEC,OAAO,EAAE,GAAGJ,SAAQ;AAC/C,MAAMK,gBAAgBC,OAAOC,GAAG,CAAC;AAEjC,MAAMC,YAAY,IAAIC,kBAAO;AAE7BD,UACGN,IAAI,CAACA,MACLC,WAAW,CAACA,aACZC,OAAO,CAACA,SACRM,QAAQ,CAAC,cAAc,mCACvBC,SAAS,CAAC,IAAIC,iBAAM,CAAC,uCAAuC,4CAA4CC,OAAO,CAACC,sBAAY,EAAEC,OAAO,CAACC,8BAAoB,GAC1JL,SAAS,CAAC,IAAIC,iBAAM,CAAC,2BAA2B,+BAA+BG,OAAO,CAACE,yBAAe,EAAEC,SAAS,CAACC,WAClHR,SAAS,CAAC,IAAIC,iBAAM,CAAC,yBAAyB,iBAAiBG,OAAO,CAAC,UAAUF,OAAO,CAAC;IAAC;IAAU;IAAQ;IAAS;CAAQ,GAC7HF,SAAS,CAAC,IAAIC,iBAAM,CAAC,kCAAkC,2CAA2CM,SAAS,CAACE,aAC5GT,SAAS,CAAC,IAAIC,iBAAM,CAAC,kCAAkC,uDAAuDM,SAAS,CAACE,aACxHT,SAAS,CAAC,IAAIC,iBAAM,CAAC,kCAAkC,4CAA4CM,SAAS,CAACC,WAC7GR,SAAS,CAAC,IAAIC,iBAAM,CAAC,4BAA4B,uCAAuCM,SAAS,CAACC,WAClGR,SAAS,CAAC,IAAIC,iBAAM,CAAC,4BAA4B,uCAAuCM,SAAS,CAACC,WAClGR,SAAS,CAAC,IAAIC,iBAAM,CAAC,oBAAoB,
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { createRequire, Module } from 'node:module';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\nimport { SyntheticModule, createContext, SourceTextModule } from 'node:vm';\nimport { stat, readFile } from 'node:fs/promises';\nimport { Command, Option } from 'commander';\nimport { glob } from 'glob';\nimport { Benchmark, printTableReports, printJSONReports, printSimpleReports, DEFAULT_REPORT_TYPES, DEFAULT_WORKERS } from './index.js';\nimport { transpile } from './utils.js';\nimport { REPORT_TYPES } from './types.js';\n\nconst require = createRequire(import.meta.url);\nconst { name, description, version } = require('../package.json');\nconst BENCHMARK_URL = Symbol.for('overtake.benchmarkUrl');\n\nconst commander = new Command();\n\ncommander\n .name(name)\n .description(description)\n .version(version)\n .argument('<paths...>', 'glob pattern to find benchmarks')\n .addOption(new Option('-r, --report-types [reportTypes...]', 'statistic types to include in the report').choices(REPORT_TYPES).default(DEFAULT_REPORT_TYPES))\n .addOption(new Option('-w, --workers [workers]', 'number of concurent workers').default(DEFAULT_WORKERS).argParser(parseInt))\n .addOption(new Option('-f, --format [format]', 'output format').default('simple').choices(['simple', 'json', 'pjson', 'table']))\n .addOption(new Option('--abs-threshold [absThreshold]', 'absolute error threshold in nanoseconds').argParser(parseFloat))\n .addOption(new Option('--rel-threshold [relThreshold]', 'relative error threshold (fraction between 0 and 1)').argParser(parseFloat))\n .addOption(new Option('--warmup-cycles [warmupCycles]', 'number of warmup cycles before measuring').argParser(parseInt))\n .addOption(new Option('--max-cycles [maxCycles]', 'maximum measurement cycles per feed').argParser(parseInt))\n .addOption(new Option('--min-cycles [minCycles]', 'minimum measurement cycles per feed').argParser(parseInt))\n .addOption(new Option('--no-gc-observer', 'disable GC overlap detection'))\n .addOption(new Option('--progress', 'show progress bar during benchmark execution'))\n .action(async (patterns: string[], executeOptions) => {\n const files = new Set<string>();\n await Promise.all(\n patterns.map(async (pattern) => {\n const matches = await glob(pattern, { absolute: true, cwd: process.cwd() }).catch(() => []);\n matches.forEach((file) => files.add(file));\n }),\n );\n\n for (const file of files) {\n const stats = await stat(file).catch(() => false as const);\n if (stats && stats.isFile()) {\n const content = await readFile(file, 'utf8');\n const identifier = pathToFileURL(file).href;\n const code = await transpile(content);\n let instance: Benchmark<unknown> | undefined;\n const benchmark = (...args: Parameters<(typeof Benchmark)['create']>) => {\n if (instance) {\n throw new Error('Only one benchmark per file is supported');\n }\n instance = Benchmark.create(...args);\n return instance;\n };\n const script = new SourceTextModule(code, {\n identifier,\n context: createContext({\n benchmark,\n Buffer,\n console,\n }),\n initializeImportMeta(meta) {\n meta.url = identifier;\n },\n async importModuleDynamically(specifier, referencingModule) {\n if (Module.isBuiltin(specifier)) {\n return import(specifier);\n }\n const baseIdentifier = referencingModule.identifier ?? identifier;\n const resolveFrom = createRequire(fileURLToPath(baseIdentifier));\n const resolved = resolveFrom.resolve(specifier);\n return import(resolved);\n },\n });\n const imports = new Map<string, SyntheticModule>();\n await script.link(async (specifier: string, referencingModule) => {\n const baseIdentifier = referencingModule.identifier ?? identifier;\n const resolveFrom = createRequire(fileURLToPath(baseIdentifier));\n const target = Module.isBuiltin(specifier) ? specifier : resolveFrom.resolve(specifier);\n const cached = imports.get(target);\n if (cached) {\n return cached;\n }\n const mod = await import(target);\n const exportNames = Object.keys(mod);\n const imported = new SyntheticModule(\n exportNames,\n () => {\n exportNames.forEach((key) => imported.setExport(key, mod[key]));\n },\n { identifier: target, context: referencingModule.context },\n );\n\n imports.set(target, imported);\n return imported;\n });\n await script.evaluate();\n\n if (instance) {\n const reports = await instance.execute({\n ...executeOptions,\n [BENCHMARK_URL]: identifier,\n } as typeof executeOptions);\n switch (executeOptions.format) {\n case 'json':\n {\n printJSONReports(reports);\n }\n break;\n case 'pjson':\n {\n printJSONReports(reports, 2);\n }\n break;\n case 'table':\n {\n printTableReports(reports);\n }\n break;\n default:\n printSimpleReports(reports);\n }\n }\n }\n }\n });\n\ncommander.parse(process.argv);\n"],"names":["require","createRequire","name","description","version","BENCHMARK_URL","Symbol","for","commander","Command","argument","addOption","Option","choices","REPORT_TYPES","default","DEFAULT_REPORT_TYPES","DEFAULT_WORKERS","argParser","parseInt","parseFloat","action","patterns","executeOptions","files","Set","Promise","all","map","pattern","matches","glob","absolute","cwd","process","catch","forEach","file","add","stats","stat","isFile","content","readFile","identifier","pathToFileURL","href","code","transpile","instance","benchmark","args","Error","Benchmark","create","script","SourceTextModule","context","createContext","Buffer","console","initializeImportMeta","meta","url","importModuleDynamically","specifier","referencingModule","Module","isBuiltin","baseIdentifier","resolveFrom","fileURLToPath","resolved","resolve","imports","Map","link","target","cached","get","mod","exportNames","Object","keys","imported","SyntheticModule","key","setExport","set","evaluate","reports","execute","format","printJSONReports","printTableReports","printSimpleReports","parse","argv"],"mappings":"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"}
|
package/build/cli.js
CHANGED
|
@@ -16,7 +16,7 @@ commander.name(name).description(description).version(version).argument('<paths.
|
|
|
16
16
|
'json',
|
|
17
17
|
'pjson',
|
|
18
18
|
'table'
|
|
19
|
-
])).addOption(new Option('--abs-threshold [absThreshold]', 'absolute error threshold in nanoseconds').argParser(parseFloat)).addOption(new Option('--rel-threshold [relThreshold]', 'relative error threshold (fraction between 0 and 1)').argParser(parseFloat)).addOption(new Option('--warmup-cycles [warmupCycles]', 'number of warmup cycles before measuring').argParser(parseInt)).addOption(new Option('--max-cycles [maxCycles]', 'maximum measurement cycles per feed').argParser(parseInt)).addOption(new Option('--min-cycles [minCycles]', 'minimum measurement cycles per feed').argParser(parseInt)).addOption(new Option('--no-gc-observer', 'disable GC overlap detection')).action(async (patterns, executeOptions)=>{
|
|
19
|
+
])).addOption(new Option('--abs-threshold [absThreshold]', 'absolute error threshold in nanoseconds').argParser(parseFloat)).addOption(new Option('--rel-threshold [relThreshold]', 'relative error threshold (fraction between 0 and 1)').argParser(parseFloat)).addOption(new Option('--warmup-cycles [warmupCycles]', 'number of warmup cycles before measuring').argParser(parseInt)).addOption(new Option('--max-cycles [maxCycles]', 'maximum measurement cycles per feed').argParser(parseInt)).addOption(new Option('--min-cycles [minCycles]', 'minimum measurement cycles per feed').argParser(parseInt)).addOption(new Option('--no-gc-observer', 'disable GC overlap detection')).addOption(new Option('--progress', 'show progress bar during benchmark execution')).action(async (patterns, executeOptions)=>{
|
|
20
20
|
const files = new Set();
|
|
21
21
|
await Promise.all(patterns.map(async (pattern)=>{
|
|
22
22
|
const matches = await glob(pattern, {
|
package/build/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { createRequire, Module } from 'node:module';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\nimport { SyntheticModule, createContext, SourceTextModule } from 'node:vm';\nimport { stat, readFile } from 'node:fs/promises';\nimport { Command, Option } from 'commander';\nimport { glob } from 'glob';\nimport { Benchmark, printTableReports, printJSONReports, printSimpleReports, DEFAULT_REPORT_TYPES, DEFAULT_WORKERS } from './index.js';\nimport { transpile } from './utils.js';\nimport { REPORT_TYPES } from './types.js';\n\nconst require = createRequire(import.meta.url);\nconst { name, description, version } = require('../package.json');\nconst BENCHMARK_URL = Symbol.for('overtake.benchmarkUrl');\n\nconst commander = new Command();\n\ncommander\n .name(name)\n .description(description)\n .version(version)\n .argument('<paths...>', 'glob pattern to find benchmarks')\n .addOption(new Option('-r, --report-types [reportTypes...]', 'statistic types to include in the report').choices(REPORT_TYPES).default(DEFAULT_REPORT_TYPES))\n .addOption(new Option('-w, --workers [workers]', 'number of concurent workers').default(DEFAULT_WORKERS).argParser(parseInt))\n .addOption(new Option('-f, --format [format]', 'output format').default('simple').choices(['simple', 'json', 'pjson', 'table']))\n .addOption(new Option('--abs-threshold [absThreshold]', 'absolute error threshold in nanoseconds').argParser(parseFloat))\n .addOption(new Option('--rel-threshold [relThreshold]', 'relative error threshold (fraction between 0 and 1)').argParser(parseFloat))\n .addOption(new Option('--warmup-cycles [warmupCycles]', 'number of warmup cycles before measuring').argParser(parseInt))\n .addOption(new Option('--max-cycles [maxCycles]', 'maximum measurement cycles per feed').argParser(parseInt))\n .addOption(new Option('--min-cycles [minCycles]', 'minimum measurement cycles per feed').argParser(parseInt))\n .addOption(new Option('--no-gc-observer', 'disable GC overlap detection'))\n .action(async (patterns: string[], executeOptions) => {\n const files = new Set<string>();\n await Promise.all(\n patterns.map(async (pattern) => {\n const matches = await glob(pattern, { absolute: true, cwd: process.cwd() }).catch(() => []);\n matches.forEach((file) => files.add(file));\n }),\n );\n\n for (const file of files) {\n const stats = await stat(file).catch(() => false as const);\n if (stats && stats.isFile()) {\n const content = await readFile(file, 'utf8');\n const identifier = pathToFileURL(file).href;\n const code = await transpile(content);\n let instance: Benchmark<unknown> | undefined;\n const benchmark = (...args: Parameters<(typeof Benchmark)['create']>) => {\n if (instance) {\n throw new Error('Only one benchmark per file is supported');\n }\n instance = Benchmark.create(...args);\n return instance;\n };\n const script = new SourceTextModule(code, {\n identifier,\n context: createContext({\n benchmark,\n Buffer,\n console,\n }),\n initializeImportMeta(meta) {\n meta.url = identifier;\n },\n async importModuleDynamically(specifier, referencingModule) {\n if (Module.isBuiltin(specifier)) {\n return import(specifier);\n }\n const baseIdentifier = referencingModule.identifier ?? identifier;\n const resolveFrom = createRequire(fileURLToPath(baseIdentifier));\n const resolved = resolveFrom.resolve(specifier);\n return import(resolved);\n },\n });\n const imports = new Map<string, SyntheticModule>();\n await script.link(async (specifier: string, referencingModule) => {\n const baseIdentifier = referencingModule.identifier ?? identifier;\n const resolveFrom = createRequire(fileURLToPath(baseIdentifier));\n const target = Module.isBuiltin(specifier) ? specifier : resolveFrom.resolve(specifier);\n const cached = imports.get(target);\n if (cached) {\n return cached;\n }\n const mod = await import(target);\n const exportNames = Object.keys(mod);\n const imported = new SyntheticModule(\n exportNames,\n () => {\n exportNames.forEach((key) => imported.setExport(key, mod[key]));\n },\n { identifier: target, context: referencingModule.context },\n );\n\n imports.set(target, imported);\n return imported;\n });\n await script.evaluate();\n\n if (instance) {\n const reports = await instance.execute({\n ...executeOptions,\n [BENCHMARK_URL]: identifier,\n } as typeof executeOptions);\n switch (executeOptions.format) {\n case 'json':\n {\n printJSONReports(reports);\n }\n break;\n case 'pjson':\n {\n printJSONReports(reports, 2);\n }\n break;\n case 'table':\n {\n printTableReports(reports);\n }\n break;\n default:\n printSimpleReports(reports);\n }\n }\n }\n }\n });\n\ncommander.parse(process.argv);\n"],"names":["createRequire","Module","fileURLToPath","pathToFileURL","SyntheticModule","createContext","SourceTextModule","stat","readFile","Command","Option","glob","Benchmark","printTableReports","printJSONReports","printSimpleReports","DEFAULT_REPORT_TYPES","DEFAULT_WORKERS","transpile","REPORT_TYPES","require","url","name","description","version","BENCHMARK_URL","Symbol","for","commander","argument","addOption","choices","default","argParser","parseInt","parseFloat","action","patterns","executeOptions","files","Set","Promise","all","map","pattern","matches","absolute","cwd","process","catch","forEach","file","add","stats","isFile","content","identifier","href","code","instance","benchmark","args","Error","create","script","context","Buffer","console","initializeImportMeta","meta","importModuleDynamically","specifier","referencingModule","isBuiltin","baseIdentifier","resolveFrom","resolved","resolve","imports","Map","link","target","cached","get","mod","exportNames","Object","keys","imported","key","setExport","set","evaluate","reports","execute","format","parse","argv"],"mappings":"AAAA,SAASA,aAAa,EAAEC,MAAM,QAAQ,cAAc;AACpD,SAASC,aAAa,EAAEC,aAAa,QAAQ,WAAW;AACxD,SAASC,eAAe,EAAEC,aAAa,EAAEC,gBAAgB,QAAQ,UAAU;AAC3E,SAASC,IAAI,EAAEC,QAAQ,QAAQ,mBAAmB;AAClD,SAASC,OAAO,EAAEC,MAAM,QAAQ,YAAY;AAC5C,SAASC,IAAI,QAAQ,OAAO;AAC5B,SAASC,SAAS,EAAEC,iBAAiB,EAAEC,gBAAgB,EAAEC,kBAAkB,EAAEC,oBAAoB,EAAEC,eAAe,QAAQ,aAAa;AACvI,SAASC,SAAS,QAAQ,aAAa;AACvC,SAASC,YAAY,QAAQ,aAAa;AAE1C,MAAMC,UAAUpB,cAAc,YAAYqB,GAAG;AAC7C,MAAM,EAAEC,IAAI,EAAEC,WAAW,EAAEC,OAAO,EAAE,GAAGJ,QAAQ;AAC/C,MAAMK,gBAAgBC,OAAOC,GAAG,CAAC;AAEjC,MAAMC,YAAY,IAAInB;AAEtBmB,UACGN,IAAI,CAACA,MACLC,WAAW,CAACA,aACZC,OAAO,CAACA,SACRK,QAAQ,CAAC,cAAc,mCACvBC,SAAS,CAAC,IAAIpB,OAAO,uCAAuC,4CAA4CqB,OAAO,CAACZ,cAAca,OAAO,CAAChB,uBACtIc,SAAS,CAAC,IAAIpB,OAAO,2BAA2B,+BAA+BsB,OAAO,CAACf,iBAAiBgB,SAAS,CAACC,WAClHJ,SAAS,CAAC,IAAIpB,OAAO,yBAAyB,iBAAiBsB,OAAO,CAAC,UAAUD,OAAO,CAAC;IAAC;IAAU;IAAQ;IAAS;CAAQ,GAC7HD,SAAS,CAAC,IAAIpB,OAAO,kCAAkC,2CAA2CuB,SAAS,CAACE,aAC5GL,SAAS,CAAC,IAAIpB,OAAO,kCAAkC,uDAAuDuB,SAAS,CAACE,aACxHL,SAAS,CAAC,IAAIpB,OAAO,kCAAkC,4CAA4CuB,SAAS,CAACC,WAC7GJ,SAAS,CAAC,IAAIpB,OAAO,4BAA4B,uCAAuCuB,SAAS,CAACC,WAClGJ,SAAS,CAAC,IAAIpB,OAAO,4BAA4B,uCAAuCuB,SAAS,CAACC,WAClGJ,SAAS,CAAC,IAAIpB,OAAO,oBAAoB,
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { createRequire, Module } from 'node:module';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\nimport { SyntheticModule, createContext, SourceTextModule } from 'node:vm';\nimport { stat, readFile } from 'node:fs/promises';\nimport { Command, Option } from 'commander';\nimport { glob } from 'glob';\nimport { Benchmark, printTableReports, printJSONReports, printSimpleReports, DEFAULT_REPORT_TYPES, DEFAULT_WORKERS } from './index.js';\nimport { transpile } from './utils.js';\nimport { REPORT_TYPES } from './types.js';\n\nconst require = createRequire(import.meta.url);\nconst { name, description, version } = require('../package.json');\nconst BENCHMARK_URL = Symbol.for('overtake.benchmarkUrl');\n\nconst commander = new Command();\n\ncommander\n .name(name)\n .description(description)\n .version(version)\n .argument('<paths...>', 'glob pattern to find benchmarks')\n .addOption(new Option('-r, --report-types [reportTypes...]', 'statistic types to include in the report').choices(REPORT_TYPES).default(DEFAULT_REPORT_TYPES))\n .addOption(new Option('-w, --workers [workers]', 'number of concurent workers').default(DEFAULT_WORKERS).argParser(parseInt))\n .addOption(new Option('-f, --format [format]', 'output format').default('simple').choices(['simple', 'json', 'pjson', 'table']))\n .addOption(new Option('--abs-threshold [absThreshold]', 'absolute error threshold in nanoseconds').argParser(parseFloat))\n .addOption(new Option('--rel-threshold [relThreshold]', 'relative error threshold (fraction between 0 and 1)').argParser(parseFloat))\n .addOption(new Option('--warmup-cycles [warmupCycles]', 'number of warmup cycles before measuring').argParser(parseInt))\n .addOption(new Option('--max-cycles [maxCycles]', 'maximum measurement cycles per feed').argParser(parseInt))\n .addOption(new Option('--min-cycles [minCycles]', 'minimum measurement cycles per feed').argParser(parseInt))\n .addOption(new Option('--no-gc-observer', 'disable GC overlap detection'))\n .addOption(new Option('--progress', 'show progress bar during benchmark execution'))\n .action(async (patterns: string[], executeOptions) => {\n const files = new Set<string>();\n await Promise.all(\n patterns.map(async (pattern) => {\n const matches = await glob(pattern, { absolute: true, cwd: process.cwd() }).catch(() => []);\n matches.forEach((file) => files.add(file));\n }),\n );\n\n for (const file of files) {\n const stats = await stat(file).catch(() => false as const);\n if (stats && stats.isFile()) {\n const content = await readFile(file, 'utf8');\n const identifier = pathToFileURL(file).href;\n const code = await transpile(content);\n let instance: Benchmark<unknown> | undefined;\n const benchmark = (...args: Parameters<(typeof Benchmark)['create']>) => {\n if (instance) {\n throw new Error('Only one benchmark per file is supported');\n }\n instance = Benchmark.create(...args);\n return instance;\n };\n const script = new SourceTextModule(code, {\n identifier,\n context: createContext({\n benchmark,\n Buffer,\n console,\n }),\n initializeImportMeta(meta) {\n meta.url = identifier;\n },\n async importModuleDynamically(specifier, referencingModule) {\n if (Module.isBuiltin(specifier)) {\n return import(specifier);\n }\n const baseIdentifier = referencingModule.identifier ?? identifier;\n const resolveFrom = createRequire(fileURLToPath(baseIdentifier));\n const resolved = resolveFrom.resolve(specifier);\n return import(resolved);\n },\n });\n const imports = new Map<string, SyntheticModule>();\n await script.link(async (specifier: string, referencingModule) => {\n const baseIdentifier = referencingModule.identifier ?? identifier;\n const resolveFrom = createRequire(fileURLToPath(baseIdentifier));\n const target = Module.isBuiltin(specifier) ? specifier : resolveFrom.resolve(specifier);\n const cached = imports.get(target);\n if (cached) {\n return cached;\n }\n const mod = await import(target);\n const exportNames = Object.keys(mod);\n const imported = new SyntheticModule(\n exportNames,\n () => {\n exportNames.forEach((key) => imported.setExport(key, mod[key]));\n },\n { identifier: target, context: referencingModule.context },\n );\n\n imports.set(target, imported);\n return imported;\n });\n await script.evaluate();\n\n if (instance) {\n const reports = await instance.execute({\n ...executeOptions,\n [BENCHMARK_URL]: identifier,\n } as typeof executeOptions);\n switch (executeOptions.format) {\n case 'json':\n {\n printJSONReports(reports);\n }\n break;\n case 'pjson':\n {\n printJSONReports(reports, 2);\n }\n break;\n case 'table':\n {\n printTableReports(reports);\n }\n break;\n default:\n printSimpleReports(reports);\n }\n }\n }\n }\n });\n\ncommander.parse(process.argv);\n"],"names":["createRequire","Module","fileURLToPath","pathToFileURL","SyntheticModule","createContext","SourceTextModule","stat","readFile","Command","Option","glob","Benchmark","printTableReports","printJSONReports","printSimpleReports","DEFAULT_REPORT_TYPES","DEFAULT_WORKERS","transpile","REPORT_TYPES","require","url","name","description","version","BENCHMARK_URL","Symbol","for","commander","argument","addOption","choices","default","argParser","parseInt","parseFloat","action","patterns","executeOptions","files","Set","Promise","all","map","pattern","matches","absolute","cwd","process","catch","forEach","file","add","stats","isFile","content","identifier","href","code","instance","benchmark","args","Error","create","script","context","Buffer","console","initializeImportMeta","meta","importModuleDynamically","specifier","referencingModule","isBuiltin","baseIdentifier","resolveFrom","resolved","resolve","imports","Map","link","target","cached","get","mod","exportNames","Object","keys","imported","key","setExport","set","evaluate","reports","execute","format","parse","argv"],"mappings":"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"}
|
package/build/executor.cjs
CHANGED
|
@@ -17,10 +17,10 @@ const _utilscjs = require("./utils.cjs");
|
|
|
17
17
|
const _typescjs = require("./types.cjs");
|
|
18
18
|
const BENCHMARK_URL = Symbol.for('overtake.benchmarkUrl');
|
|
19
19
|
const createExecutor = (options)=>{
|
|
20
|
-
const { workers, warmupCycles, maxCycles, minCycles, absThreshold, relThreshold, gcObserver = true, reportTypes } = options;
|
|
20
|
+
const { workers, warmupCycles, maxCycles, minCycles, absThreshold, relThreshold, gcObserver = true, reportTypes, onProgress, progressInterval = 100 } = options;
|
|
21
21
|
const benchmarkUrl = options[BENCHMARK_URL];
|
|
22
22
|
const resolvedBenchmarkUrl = typeof benchmarkUrl === 'string' ? benchmarkUrl : (0, _nodeurl.pathToFileURL)(process.cwd()).href;
|
|
23
|
-
const executor = (0, _async.queue)(async ({ setup, teardown, pre, run, post, data })=>{
|
|
23
|
+
const executor = (0, _async.queue)(async ({ id, setup, teardown, pre, run, post, data })=>{
|
|
24
24
|
const setupCode = setup?.toString();
|
|
25
25
|
const teardownCode = teardown?.toString();
|
|
26
26
|
const preCode = pre?.toString();
|
|
@@ -48,11 +48,32 @@ const createExecutor = (options)=>{
|
|
|
48
48
|
const worker = new _nodeworker_threads.Worker(workerFile, {
|
|
49
49
|
workerData
|
|
50
50
|
});
|
|
51
|
-
const [exitCode] = await (0, _nodeevents.once)(worker, 'exit');
|
|
52
|
-
if (exitCode !== 0) {
|
|
53
|
-
throw new Error(`worker exited with code ${exitCode}`);
|
|
54
|
-
}
|
|
55
51
|
const control = new Int32Array(controlSAB);
|
|
52
|
+
let progressIntervalId;
|
|
53
|
+
if (onProgress && id) {
|
|
54
|
+
progressIntervalId = setInterval(()=>{
|
|
55
|
+
const progress = control[_typescjs.Control.PROGRESS] / _typescjs.COMPLETE_VALUE;
|
|
56
|
+
onProgress({
|
|
57
|
+
id,
|
|
58
|
+
progress
|
|
59
|
+
});
|
|
60
|
+
}, progressInterval);
|
|
61
|
+
}
|
|
62
|
+
const WORKER_TIMEOUT_MS = 300_000;
|
|
63
|
+
const exitPromise = (0, _nodeevents.once)(worker, 'exit');
|
|
64
|
+
const timeoutId = setTimeout(()=>worker.terminate(), WORKER_TIMEOUT_MS);
|
|
65
|
+
try {
|
|
66
|
+
const [exitCode] = await exitPromise;
|
|
67
|
+
clearTimeout(timeoutId);
|
|
68
|
+
if (progressIntervalId) clearInterval(progressIntervalId);
|
|
69
|
+
if (exitCode !== 0) {
|
|
70
|
+
throw new Error(`worker exited with code ${exitCode}`);
|
|
71
|
+
}
|
|
72
|
+
} catch (err) {
|
|
73
|
+
clearTimeout(timeoutId);
|
|
74
|
+
if (progressIntervalId) clearInterval(progressIntervalId);
|
|
75
|
+
throw err;
|
|
76
|
+
}
|
|
56
77
|
const count = control[_typescjs.Control.INDEX];
|
|
57
78
|
const durations = new BigUint64Array(durationsSAB).slice(0, count).sort(_utilscjs.cmp);
|
|
58
79
|
const report = reportTypes.map((type)=>[
|
package/build/executor.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/executor.ts"],"sourcesContent":["import { Worker } from 'node:worker_threads';\nimport { once } from 'node:events';\nimport { queue } from 'async';\nimport { pathToFileURL } from 'node:url';\nimport { createReport, Report } from './reporter.js';\nimport { cmp } from './utils.js';\nimport {
|
|
1
|
+
{"version":3,"sources":["../src/executor.ts"],"sourcesContent":["import { Worker } from 'node:worker_threads';\nimport { once } from 'node:events';\nimport { queue } from 'async';\nimport { pathToFileURL } from 'node:url';\nimport { createReport, Report } from './reporter.js';\nimport { cmp } from './utils.js';\nimport {\n ExecutorRunOptions,\n ReportOptions,\n WorkerOptions,\n BenchmarkOptions,\n Control,\n ReportType,\n ReportTypeList,\n CONTROL_SLOTS,\n COMPLETE_VALUE,\n ProgressCallback,\n} from './types.js';\n\nexport type ExecutorReport<R extends ReportTypeList> = Record<R[number], Report> & { count: number };\n\nexport interface ExecutorOptions<R extends ReportTypeList> extends BenchmarkOptions, ReportOptions<R> {\n workers?: number;\n maxCycles?: number;\n onProgress?: ProgressCallback;\n progressInterval?: number;\n}\n\nconst BENCHMARK_URL = Symbol.for('overtake.benchmarkUrl');\n\nexport const createExecutor = <TContext, TInput, R extends ReportTypeList>(options: Required<ExecutorOptions<R>>) => {\n const { workers, warmupCycles, maxCycles, minCycles, absThreshold, relThreshold, gcObserver = true, reportTypes, onProgress, progressInterval = 100 } = options;\n const benchmarkUrl = (options as Record<symbol, unknown>)[BENCHMARK_URL];\n const resolvedBenchmarkUrl = typeof benchmarkUrl === 'string' ? benchmarkUrl : pathToFileURL(process.cwd()).href;\n\n const executor = queue<ExecutorRunOptions<TContext, TInput>>(async ({ id, setup, teardown, pre, run, post, data }) => {\n const setupCode = setup?.toString();\n const teardownCode = teardown?.toString();\n const preCode = pre?.toString();\n const runCode = run.toString()!;\n const postCode = post?.toString();\n\n const controlSAB = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * CONTROL_SLOTS);\n const durationsSAB = new SharedArrayBuffer(BigUint64Array.BYTES_PER_ELEMENT * maxCycles);\n\n const workerFile = new URL('./worker.js', import.meta.url);\n const workerData: WorkerOptions = {\n benchmarkUrl: resolvedBenchmarkUrl,\n setupCode,\n teardownCode,\n preCode,\n runCode,\n postCode,\n data,\n\n warmupCycles,\n minCycles,\n absThreshold,\n relThreshold,\n gcObserver,\n\n controlSAB,\n durationsSAB,\n };\n\n const worker = new Worker(workerFile, {\n workerData,\n });\n\n const control = new Int32Array(controlSAB);\n let progressIntervalId: ReturnType<typeof setInterval> | undefined;\n if (onProgress && id) {\n progressIntervalId = setInterval(() => {\n const progress = control[Control.PROGRESS] / COMPLETE_VALUE;\n onProgress({ id, progress });\n }, progressInterval);\n }\n\n const WORKER_TIMEOUT_MS = 300_000;\n const exitPromise = once(worker, 'exit');\n const timeoutId = setTimeout(() => worker.terminate(), WORKER_TIMEOUT_MS);\n try {\n const [exitCode] = await exitPromise;\n clearTimeout(timeoutId);\n if (progressIntervalId) clearInterval(progressIntervalId);\n if (exitCode !== 0) {\n throw new Error(`worker exited with code ${exitCode}`);\n }\n } catch (err) {\n clearTimeout(timeoutId);\n if (progressIntervalId) clearInterval(progressIntervalId);\n throw err;\n }\n\n const count = control[Control.INDEX];\n const durations = new BigUint64Array(durationsSAB).slice(0, count).sort(cmp);\n\n const report = reportTypes.map<[string, unknown]>((type) => [type, createReport(durations, type)] as [ReportType, Report]).concat([['count', count]]);\n return Object.fromEntries(report);\n }, workers);\n\n executor.error((err) => {\n console.error(err);\n });\n\n return executor;\n};\n"],"names":["createExecutor","BENCHMARK_URL","Symbol","for","options","workers","warmupCycles","maxCycles","minCycles","absThreshold","relThreshold","gcObserver","reportTypes","onProgress","progressInterval","benchmarkUrl","resolvedBenchmarkUrl","pathToFileURL","process","cwd","href","executor","queue","id","setup","teardown","pre","run","post","data","setupCode","toString","teardownCode","preCode","runCode","postCode","controlSAB","SharedArrayBuffer","Int32Array","BYTES_PER_ELEMENT","CONTROL_SLOTS","durationsSAB","BigUint64Array","workerFile","URL","workerData","worker","Worker","control","progressIntervalId","setInterval","progress","Control","PROGRESS","COMPLETE_VALUE","WORKER_TIMEOUT_MS","exitPromise","once","timeoutId","setTimeout","terminate","exitCode","clearTimeout","clearInterval","Error","err","count","INDEX","durations","slice","sort","cmp","report","map","type","createReport","concat","Object","fromEntries","error","console"],"mappings":";;;;+BA8BaA;;;eAAAA;;;oCA9BU;4BACF;uBACC;yBACQ;6BACO;0BACjB;0BAYb;AAWP,MAAMC,gBAAgBC,OAAOC,GAAG,CAAC;AAE1B,MAAMH,iBAAiB,CAA6CI;IACzE,MAAM,EAAEC,OAAO,EAAEC,YAAY,EAAEC,SAAS,EAAEC,SAAS,EAAEC,YAAY,EAAEC,YAAY,EAAEC,aAAa,IAAI,EAAEC,WAAW,EAAEC,UAAU,EAAEC,mBAAmB,GAAG,EAAE,GAAGV;IACxJ,MAAMW,eAAe,AAACX,OAAmC,CAACH,cAAc;IACxE,MAAMe,uBAAuB,OAAOD,iBAAiB,WAAWA,eAAeE,IAAAA,sBAAa,EAACC,QAAQC,GAAG,IAAIC,IAAI;IAEhH,MAAMC,WAAWC,IAAAA,YAAK,EAAuC,OAAO,EAAEC,EAAE,EAAEC,KAAK,EAAEC,QAAQ,EAAEC,GAAG,EAAEC,GAAG,EAAEC,IAAI,EAAEC,IAAI,EAAE;QAC/G,MAAMC,YAAYN,OAAOO;QACzB,MAAMC,eAAeP,UAAUM;QAC/B,MAAME,UAAUP,KAAKK;QACrB,MAAMG,UAAUP,IAAII,QAAQ;QAC5B,MAAMI,WAAWP,MAAMG;QAEvB,MAAMK,aAAa,IAAIC,kBAAkBC,WAAWC,iBAAiB,GAAGC,uBAAa;QACrF,MAAMC,eAAe,IAAIJ,kBAAkBK,eAAeH,iBAAiB,GAAGhC;QAE9E,MAAMoC,aAAa,IAAIC,IAAI,eAAe;QAC1C,MAAMC,aAA4B;YAChC9B,cAAcC;YACdc;YACAE;YACAC;YACAC;YACAC;YACAN;YAEAvB;YACAE;YACAC;YACAC;YACAC;YAEAyB;YACAK;QACF;QAEA,MAAMK,SAAS,IAAIC,0BAAM,CAACJ,YAAY;YACpCE;QACF;QAEA,MAAMG,UAAU,IAAIV,WAAWF;QAC/B,IAAIa;QACJ,IAAIpC,cAAcU,IAAI;YACpB0B,qBAAqBC,YAAY;gBAC/B,MAAMC,WAAWH,OAAO,CAACI,iBAAO,CAACC,QAAQ,CAAC,GAAGC,wBAAc;gBAC3DzC,WAAW;oBAAEU;oBAAI4B;gBAAS;YAC5B,GAAGrC;QACL;QAEA,MAAMyC,oBAAoB;QAC1B,MAAMC,cAAcC,IAAAA,gBAAI,EAACX,QAAQ;QACjC,MAAMY,YAAYC,WAAW,IAAMb,OAAOc,SAAS,IAAIL;QACvD,IAAI;YACF,MAAM,CAACM,SAAS,GAAG,MAAML;YACzBM,aAAaJ;YACb,IAAIT,oBAAoBc,cAAcd;YACtC,IAAIY,aAAa,GAAG;gBAClB,MAAM,IAAIG,MAAM,CAAC,wBAAwB,EAAEH,UAAU;YACvD;QACF,EAAE,OAAOI,KAAK;YACZH,aAAaJ;YACb,IAAIT,oBAAoBc,cAAcd;YACtC,MAAMgB;QACR;QAEA,MAAMC,QAAQlB,OAAO,CAACI,iBAAO,CAACe,KAAK,CAAC;QACpC,MAAMC,YAAY,IAAI1B,eAAeD,cAAc4B,KAAK,CAAC,GAAGH,OAAOI,IAAI,CAACC,aAAG;QAE3E,MAAMC,SAAS5D,YAAY6D,GAAG,CAAoB,CAACC,OAAS;gBAACA;gBAAMC,IAAAA,yBAAY,EAACP,WAAWM;aAAM,EAA0BE,MAAM,CAAC;YAAC;gBAAC;gBAASV;aAAM;SAAC;QACpJ,OAAOW,OAAOC,WAAW,CAACN;IAC5B,GAAGnE;IAEHgB,SAAS0D,KAAK,CAAC,CAACd;QACde,QAAQD,KAAK,CAACd;IAChB;IAEA,OAAO5C;AACT"}
|
package/build/executor.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { Report } from './reporter.js';
|
|
2
|
-
import {
|
|
2
|
+
import { ExecutorRunOptions, ReportOptions, BenchmarkOptions, ReportTypeList, ProgressCallback } from './types.js';
|
|
3
3
|
export type ExecutorReport<R extends ReportTypeList> = Record<R[number], Report> & {
|
|
4
4
|
count: number;
|
|
5
5
|
};
|
|
6
6
|
export interface ExecutorOptions<R extends ReportTypeList> extends BenchmarkOptions, ReportOptions<R> {
|
|
7
7
|
workers?: number;
|
|
8
8
|
maxCycles?: number;
|
|
9
|
+
onProgress?: ProgressCallback;
|
|
10
|
+
progressInterval?: number;
|
|
9
11
|
}
|
|
10
|
-
export declare const createExecutor: <TContext, TInput, R extends ReportTypeList>(options: Required<ExecutorOptions<R>>) => import("async").QueueObject<
|
|
12
|
+
export declare const createExecutor: <TContext, TInput, R extends ReportTypeList>(options: Required<ExecutorOptions<R>>) => import("async").QueueObject<ExecutorRunOptions<TContext, TInput>>;
|
package/build/executor.js
CHANGED
|
@@ -4,13 +4,13 @@ import { queue } from 'async';
|
|
|
4
4
|
import { pathToFileURL } from 'node:url';
|
|
5
5
|
import { createReport } from "./reporter.js";
|
|
6
6
|
import { cmp } from "./utils.js";
|
|
7
|
-
import { Control, CONTROL_SLOTS } from "./types.js";
|
|
7
|
+
import { Control, CONTROL_SLOTS, COMPLETE_VALUE } from "./types.js";
|
|
8
8
|
const BENCHMARK_URL = Symbol.for('overtake.benchmarkUrl');
|
|
9
9
|
export const createExecutor = (options)=>{
|
|
10
|
-
const { workers, warmupCycles, maxCycles, minCycles, absThreshold, relThreshold, gcObserver = true, reportTypes } = options;
|
|
10
|
+
const { workers, warmupCycles, maxCycles, minCycles, absThreshold, relThreshold, gcObserver = true, reportTypes, onProgress, progressInterval = 100 } = options;
|
|
11
11
|
const benchmarkUrl = options[BENCHMARK_URL];
|
|
12
12
|
const resolvedBenchmarkUrl = typeof benchmarkUrl === 'string' ? benchmarkUrl : pathToFileURL(process.cwd()).href;
|
|
13
|
-
const executor = queue(async ({ setup, teardown, pre, run, post, data })=>{
|
|
13
|
+
const executor = queue(async ({ id, setup, teardown, pre, run, post, data })=>{
|
|
14
14
|
const setupCode = setup?.toString();
|
|
15
15
|
const teardownCode = teardown?.toString();
|
|
16
16
|
const preCode = pre?.toString();
|
|
@@ -38,11 +38,32 @@ export const createExecutor = (options)=>{
|
|
|
38
38
|
const worker = new Worker(workerFile, {
|
|
39
39
|
workerData
|
|
40
40
|
});
|
|
41
|
-
const [exitCode] = await once(worker, 'exit');
|
|
42
|
-
if (exitCode !== 0) {
|
|
43
|
-
throw new Error(`worker exited with code ${exitCode}`);
|
|
44
|
-
}
|
|
45
41
|
const control = new Int32Array(controlSAB);
|
|
42
|
+
let progressIntervalId;
|
|
43
|
+
if (onProgress && id) {
|
|
44
|
+
progressIntervalId = setInterval(()=>{
|
|
45
|
+
const progress = control[Control.PROGRESS] / COMPLETE_VALUE;
|
|
46
|
+
onProgress({
|
|
47
|
+
id,
|
|
48
|
+
progress
|
|
49
|
+
});
|
|
50
|
+
}, progressInterval);
|
|
51
|
+
}
|
|
52
|
+
const WORKER_TIMEOUT_MS = 300_000;
|
|
53
|
+
const exitPromise = once(worker, 'exit');
|
|
54
|
+
const timeoutId = setTimeout(()=>worker.terminate(), WORKER_TIMEOUT_MS);
|
|
55
|
+
try {
|
|
56
|
+
const [exitCode] = await exitPromise;
|
|
57
|
+
clearTimeout(timeoutId);
|
|
58
|
+
if (progressIntervalId) clearInterval(progressIntervalId);
|
|
59
|
+
if (exitCode !== 0) {
|
|
60
|
+
throw new Error(`worker exited with code ${exitCode}`);
|
|
61
|
+
}
|
|
62
|
+
} catch (err) {
|
|
63
|
+
clearTimeout(timeoutId);
|
|
64
|
+
if (progressIntervalId) clearInterval(progressIntervalId);
|
|
65
|
+
throw err;
|
|
66
|
+
}
|
|
46
67
|
const count = control[Control.INDEX];
|
|
47
68
|
const durations = new BigUint64Array(durationsSAB).slice(0, count).sort(cmp);
|
|
48
69
|
const report = reportTypes.map((type)=>[
|
package/build/executor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/executor.ts"],"sourcesContent":["import { Worker } from 'node:worker_threads';\nimport { once } from 'node:events';\nimport { queue } from 'async';\nimport { pathToFileURL } from 'node:url';\nimport { createReport, Report } from './reporter.js';\nimport { cmp } from './utils.js';\nimport {
|
|
1
|
+
{"version":3,"sources":["../src/executor.ts"],"sourcesContent":["import { Worker } from 'node:worker_threads';\nimport { once } from 'node:events';\nimport { queue } from 'async';\nimport { pathToFileURL } from 'node:url';\nimport { createReport, Report } from './reporter.js';\nimport { cmp } from './utils.js';\nimport {\n ExecutorRunOptions,\n ReportOptions,\n WorkerOptions,\n BenchmarkOptions,\n Control,\n ReportType,\n ReportTypeList,\n CONTROL_SLOTS,\n COMPLETE_VALUE,\n ProgressCallback,\n} from './types.js';\n\nexport type ExecutorReport<R extends ReportTypeList> = Record<R[number], Report> & { count: number };\n\nexport interface ExecutorOptions<R extends ReportTypeList> extends BenchmarkOptions, ReportOptions<R> {\n workers?: number;\n maxCycles?: number;\n onProgress?: ProgressCallback;\n progressInterval?: number;\n}\n\nconst BENCHMARK_URL = Symbol.for('overtake.benchmarkUrl');\n\nexport const createExecutor = <TContext, TInput, R extends ReportTypeList>(options: Required<ExecutorOptions<R>>) => {\n const { workers, warmupCycles, maxCycles, minCycles, absThreshold, relThreshold, gcObserver = true, reportTypes, onProgress, progressInterval = 100 } = options;\n const benchmarkUrl = (options as Record<symbol, unknown>)[BENCHMARK_URL];\n const resolvedBenchmarkUrl = typeof benchmarkUrl === 'string' ? benchmarkUrl : pathToFileURL(process.cwd()).href;\n\n const executor = queue<ExecutorRunOptions<TContext, TInput>>(async ({ id, setup, teardown, pre, run, post, data }) => {\n const setupCode = setup?.toString();\n const teardownCode = teardown?.toString();\n const preCode = pre?.toString();\n const runCode = run.toString()!;\n const postCode = post?.toString();\n\n const controlSAB = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * CONTROL_SLOTS);\n const durationsSAB = new SharedArrayBuffer(BigUint64Array.BYTES_PER_ELEMENT * maxCycles);\n\n const workerFile = new URL('./worker.js', import.meta.url);\n const workerData: WorkerOptions = {\n benchmarkUrl: resolvedBenchmarkUrl,\n setupCode,\n teardownCode,\n preCode,\n runCode,\n postCode,\n data,\n\n warmupCycles,\n minCycles,\n absThreshold,\n relThreshold,\n gcObserver,\n\n controlSAB,\n durationsSAB,\n };\n\n const worker = new Worker(workerFile, {\n workerData,\n });\n\n const control = new Int32Array(controlSAB);\n let progressIntervalId: ReturnType<typeof setInterval> | undefined;\n if (onProgress && id) {\n progressIntervalId = setInterval(() => {\n const progress = control[Control.PROGRESS] / COMPLETE_VALUE;\n onProgress({ id, progress });\n }, progressInterval);\n }\n\n const WORKER_TIMEOUT_MS = 300_000;\n const exitPromise = once(worker, 'exit');\n const timeoutId = setTimeout(() => worker.terminate(), WORKER_TIMEOUT_MS);\n try {\n const [exitCode] = await exitPromise;\n clearTimeout(timeoutId);\n if (progressIntervalId) clearInterval(progressIntervalId);\n if (exitCode !== 0) {\n throw new Error(`worker exited with code ${exitCode}`);\n }\n } catch (err) {\n clearTimeout(timeoutId);\n if (progressIntervalId) clearInterval(progressIntervalId);\n throw err;\n }\n\n const count = control[Control.INDEX];\n const durations = new BigUint64Array(durationsSAB).slice(0, count).sort(cmp);\n\n const report = reportTypes.map<[string, unknown]>((type) => [type, createReport(durations, type)] as [ReportType, Report]).concat([['count', count]]);\n return Object.fromEntries(report);\n }, workers);\n\n executor.error((err) => {\n console.error(err);\n });\n\n return executor;\n};\n"],"names":["Worker","once","queue","pathToFileURL","createReport","cmp","Control","CONTROL_SLOTS","COMPLETE_VALUE","BENCHMARK_URL","Symbol","for","createExecutor","options","workers","warmupCycles","maxCycles","minCycles","absThreshold","relThreshold","gcObserver","reportTypes","onProgress","progressInterval","benchmarkUrl","resolvedBenchmarkUrl","process","cwd","href","executor","id","setup","teardown","pre","run","post","data","setupCode","toString","teardownCode","preCode","runCode","postCode","controlSAB","SharedArrayBuffer","Int32Array","BYTES_PER_ELEMENT","durationsSAB","BigUint64Array","workerFile","URL","url","workerData","worker","control","progressIntervalId","setInterval","progress","PROGRESS","WORKER_TIMEOUT_MS","exitPromise","timeoutId","setTimeout","terminate","exitCode","clearTimeout","clearInterval","Error","err","count","INDEX","durations","slice","sort","report","map","type","concat","Object","fromEntries","error","console"],"mappings":"AAAA,SAASA,MAAM,QAAQ,sBAAsB;AAC7C,SAASC,IAAI,QAAQ,cAAc;AACnC,SAASC,KAAK,QAAQ,QAAQ;AAC9B,SAASC,aAAa,QAAQ,WAAW;AACzC,SAASC,YAAY,QAAgB,gBAAgB;AACrD,SAASC,GAAG,QAAQ,aAAa;AACjC,SAKEC,OAAO,EAGPC,aAAa,EACbC,cAAc,QAET,aAAa;AAWpB,MAAMC,gBAAgBC,OAAOC,GAAG,CAAC;AAEjC,OAAO,MAAMC,iBAAiB,CAA6CC;IACzE,MAAM,EAAEC,OAAO,EAAEC,YAAY,EAAEC,SAAS,EAAEC,SAAS,EAAEC,YAAY,EAAEC,YAAY,EAAEC,aAAa,IAAI,EAAEC,WAAW,EAAEC,UAAU,EAAEC,mBAAmB,GAAG,EAAE,GAAGV;IACxJ,MAAMW,eAAe,AAACX,OAAmC,CAACJ,cAAc;IACxE,MAAMgB,uBAAuB,OAAOD,iBAAiB,WAAWA,eAAerB,cAAcuB,QAAQC,GAAG,IAAIC,IAAI;IAEhH,MAAMC,WAAW3B,MAA4C,OAAO,EAAE4B,EAAE,EAAEC,KAAK,EAAEC,QAAQ,EAAEC,GAAG,EAAEC,GAAG,EAAEC,IAAI,EAAEC,IAAI,EAAE;QAC/G,MAAMC,YAAYN,OAAOO;QACzB,MAAMC,eAAeP,UAAUM;QAC/B,MAAME,UAAUP,KAAKK;QACrB,MAAMG,UAAUP,IAAII,QAAQ;QAC5B,MAAMI,WAAWP,MAAMG;QAEvB,MAAMK,aAAa,IAAIC,kBAAkBC,WAAWC,iBAAiB,GAAGvC;QACxE,MAAMwC,eAAe,IAAIH,kBAAkBI,eAAeF,iBAAiB,GAAG9B;QAE9E,MAAMiC,aAAa,IAAIC,IAAI,eAAe,YAAYC,GAAG;QACzD,MAAMC,aAA4B;YAChC5B,cAAcC;YACdY;YACAE;YACAC;YACAC;YACAC;YACAN;YAEArB;YACAE;YACAC;YACAC;YACAC;YAEAuB;YACAI;QACF;QAEA,MAAMM,SAAS,IAAIrD,OAAOiD,YAAY;YACpCG;QACF;QAEA,MAAME,UAAU,IAAIT,WAAWF;QAC/B,IAAIY;QACJ,IAAIjC,cAAcQ,IAAI;YACpByB,qBAAqBC,YAAY;gBAC/B,MAAMC,WAAWH,OAAO,CAAChD,QAAQoD,QAAQ,CAAC,GAAGlD;gBAC7Cc,WAAW;oBAAEQ;oBAAI2B;gBAAS;YAC5B,GAAGlC;QACL;QAEA,MAAMoC,oBAAoB;QAC1B,MAAMC,cAAc3D,KAAKoD,QAAQ;QACjC,MAAMQ,YAAYC,WAAW,IAAMT,OAAOU,SAAS,IAAIJ;QACvD,IAAI;YACF,MAAM,CAACK,SAAS,GAAG,MAAMJ;YACzBK,aAAaJ;YACb,IAAIN,oBAAoBW,cAAcX;YACtC,IAAIS,aAAa,GAAG;gBAClB,MAAM,IAAIG,MAAM,CAAC,wBAAwB,EAAEH,UAAU;YACvD;QACF,EAAE,OAAOI,KAAK;YACZH,aAAaJ;YACb,IAAIN,oBAAoBW,cAAcX;YACtC,MAAMa;QACR;QAEA,MAAMC,QAAQf,OAAO,CAAChD,QAAQgE,KAAK,CAAC;QACpC,MAAMC,YAAY,IAAIvB,eAAeD,cAAcyB,KAAK,CAAC,GAAGH,OAAOI,IAAI,CAACpE;QAExE,MAAMqE,SAASrD,YAAYsD,GAAG,CAAoB,CAACC,OAAS;gBAACA;gBAAMxE,aAAamE,WAAWK;aAAM,EAA0BC,MAAM,CAAC;YAAC;gBAAC;gBAASR;aAAM;SAAC;QACpJ,OAAOS,OAAOC,WAAW,CAACL;IAC5B,GAAG5D;IAEHe,SAASmD,KAAK,CAAC,CAACZ;QACda,QAAQD,KAAK,CAACZ;IAChB;IAEA,OAAOvC;AACT,EAAE"}
|
package/build/index.cjs
CHANGED
|
@@ -47,8 +47,14 @@ _export(exports, {
|
|
|
47
47
|
}
|
|
48
48
|
});
|
|
49
49
|
const _nodeos = require("node:os");
|
|
50
|
+
const _progress = /*#__PURE__*/ _interop_require_default(require("progress"));
|
|
50
51
|
const _executorcjs = require("./executor.cjs");
|
|
51
52
|
const _typescjs = require("./types.cjs");
|
|
53
|
+
function _interop_require_default(obj) {
|
|
54
|
+
return obj && obj.__esModule ? obj : {
|
|
55
|
+
default: obj
|
|
56
|
+
};
|
|
57
|
+
}
|
|
52
58
|
const DEFAULT_WORKERS = (0, _nodeos.cpus)().length;
|
|
53
59
|
const AsyncFunction = (async ()=>{}).constructor;
|
|
54
60
|
const BENCHMARK_URL = Symbol.for('overtake.benchmarkUrl');
|
|
@@ -141,12 +147,34 @@ class Benchmark {
|
|
|
141
147
|
return new Target(target);
|
|
142
148
|
}
|
|
143
149
|
async execute(options) {
|
|
144
|
-
const { workers = DEFAULT_WORKERS, warmupCycles = 20, maxCycles = _typescjs.DEFAULT_CYCLES, minCycles = 50, absThreshold = 1_000, relThreshold = 0.02, gcObserver = true, reportTypes = DEFAULT_REPORT_TYPES } = options;
|
|
150
|
+
const { workers = DEFAULT_WORKERS, warmupCycles = 20, maxCycles = _typescjs.DEFAULT_CYCLES, minCycles = 50, absThreshold = 1_000, relThreshold = 0.02, gcObserver = true, reportTypes = DEFAULT_REPORT_TYPES, progress = false, progressInterval = 100 } = options;
|
|
145
151
|
if (this.#executed) {
|
|
146
152
|
throw new Error("Benchmark is executed and can't be reused");
|
|
147
153
|
}
|
|
148
154
|
this.#executed = true;
|
|
149
155
|
const benchmarkUrl = options[BENCHMARK_URL];
|
|
156
|
+
const totalBenchmarks = this.#targets.reduce((acc, t)=>acc + t.measures.length * this.#feeds.length, 0);
|
|
157
|
+
const progressMap = new Map();
|
|
158
|
+
let completedBenchmarks = 0;
|
|
159
|
+
let bar = null;
|
|
160
|
+
if (progress && totalBenchmarks > 0) {
|
|
161
|
+
bar = new _progress.default(' [:bar] :percent :current/:total :label', {
|
|
162
|
+
total: totalBenchmarks * 100,
|
|
163
|
+
width: 30,
|
|
164
|
+
complete: '=',
|
|
165
|
+
incomplete: ' '
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
const onProgress = progress ? (info)=>{
|
|
169
|
+
progressMap.set(info.id, info.progress);
|
|
170
|
+
const totalProgress = (completedBenchmarks + [
|
|
171
|
+
...progressMap.values()
|
|
172
|
+
].reduce((a, b)=>a + b, 0)) * 100;
|
|
173
|
+
const label = info.id.length > 30 ? info.id.slice(0, 27) + '...' : info.id;
|
|
174
|
+
bar?.update(totalProgress / (totalBenchmarks * 100), {
|
|
175
|
+
label
|
|
176
|
+
});
|
|
177
|
+
} : undefined;
|
|
150
178
|
const executor = (0, _executorcjs.createExecutor)({
|
|
151
179
|
workers,
|
|
152
180
|
warmupCycles,
|
|
@@ -156,6 +184,8 @@ class Benchmark {
|
|
|
156
184
|
relThreshold,
|
|
157
185
|
gcObserver,
|
|
158
186
|
reportTypes,
|
|
187
|
+
onProgress,
|
|
188
|
+
progressInterval,
|
|
159
189
|
[BENCHMARK_URL]: benchmarkUrl
|
|
160
190
|
});
|
|
161
191
|
const reports = [];
|
|
@@ -170,8 +200,10 @@ class Benchmark {
|
|
|
170
200
|
feeds: []
|
|
171
201
|
};
|
|
172
202
|
for (const feed of this.#feeds){
|
|
203
|
+
const id = `${target.title}/${measure.title}/${feed.title}`;
|
|
173
204
|
const data = await feed.fn?.();
|
|
174
205
|
executor.push({
|
|
206
|
+
id,
|
|
175
207
|
setup: target.setup,
|
|
176
208
|
teardown: target.teardown,
|
|
177
209
|
pre: measure.pre,
|
|
@@ -179,6 +211,8 @@ class Benchmark {
|
|
|
179
211
|
post: measure.post,
|
|
180
212
|
data
|
|
181
213
|
}).then((data)=>{
|
|
214
|
+
progressMap.delete(id);
|
|
215
|
+
completedBenchmarks++;
|
|
182
216
|
measureReport.feeds.push({
|
|
183
217
|
feed: feed.title,
|
|
184
218
|
data
|
|
@@ -191,6 +225,12 @@ class Benchmark {
|
|
|
191
225
|
}
|
|
192
226
|
await executor.drain();
|
|
193
227
|
executor.kill();
|
|
228
|
+
if (bar) {
|
|
229
|
+
bar.update(1, {
|
|
230
|
+
label: 'done'
|
|
231
|
+
});
|
|
232
|
+
bar.terminate();
|
|
233
|
+
}
|
|
194
234
|
return reports;
|
|
195
235
|
}
|
|
196
236
|
}
|
package/build/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { cpus } from 'node:os';\nimport { createExecutor, ExecutorOptions, ExecutorReport } from './executor.js';\nimport { MaybePromise, StepFn, SetupFn, TeardownFn, FeedFn, ReportType, ReportTypeList, DEFAULT_CYCLES } from './types.js';\n\ndeclare global {\n const benchmark: typeof Benchmark.create;\n}\n\nexport const DEFAULT_WORKERS = cpus().length;\n\nexport const AsyncFunction = (async () => {}).constructor;\nconst BENCHMARK_URL = Symbol.for('overtake.benchmarkUrl');\n\nexport interface TargetReport<R extends ReportTypeList> {\n target: string;\n measures: MeasureReport<R>[];\n}\n\nexport interface MeasureReport<R extends ReportTypeList> {\n measure: string;\n feeds: FeedReport<R>[];\n}\n\nexport interface FeedReport<R extends ReportTypeList> {\n feed: string;\n data: ExecutorReport<R>;\n}\n\nexport const DEFAULT_REPORT_TYPES = ['ops'] as const;\nexport type DefaultReportTypes = (typeof DEFAULT_REPORT_TYPES)[number];\n\nexport class MeasureContext<TContext, TInput> {\n public pre?: StepFn<TContext, TInput>;\n public post?: StepFn<TContext, TInput>;\n\n constructor(\n public title: string,\n public run: StepFn<TContext, TInput>,\n ) {}\n}\n\nexport class Measure<TContext, TInput> {\n #ctx: MeasureContext<TContext, TInput>;\n\n constructor(ctx: MeasureContext<TContext, TInput>) {\n this.#ctx = ctx;\n }\n\n pre(fn: StepFn<TContext, TInput>): Measure<TContext, TInput> {\n this.#ctx.pre = fn;\n return this;\n }\n post(fn: StepFn<TContext, TInput>): Measure<TContext, TInput> {\n this.#ctx.post = fn;\n return this;\n }\n}\n\nexport class TargetContext<TContext, TInput> {\n public teardown?: TeardownFn<TContext>;\n public measures: MeasureContext<TContext, TInput>[] = [];\n\n constructor(\n readonly title: string,\n readonly setup?: SetupFn<MaybePromise<TContext>>,\n ) {}\n}\n\nexport class Target<TContext, TInput> {\n #ctx: TargetContext<TContext, TInput>;\n\n constructor(ctx: TargetContext<TContext, TInput>) {\n this.#ctx = ctx;\n }\n teardown(fn: TeardownFn<TContext>): Target<TContext, TInput> {\n this.#ctx.teardown = fn;\n\n return this;\n }\n measure(title: string, run: StepFn<TContext, TInput>): Measure<TContext, TInput> {\n const measure = new MeasureContext(title, run);\n this.#ctx.measures.push(measure);\n\n return new Measure(measure);\n }\n}\n\nexport class FeedContext<TInput> {\n constructor(\n readonly title: string,\n readonly fn?: FeedFn<TInput>,\n ) {}\n}\n\nexport class Benchmark<TInput> {\n #targets: TargetContext<unknown, TInput>[] = [];\n #feeds: FeedContext<TInput>[] = [];\n #executed = false;\n\n static create(title: string): Benchmark<void>;\n static create<I>(title: string, fn: FeedFn<I>): Benchmark<I>;\n static create<I>(title: string, fn?: FeedFn<I> | undefined): Benchmark<I> {\n if (fn) {\n return new Benchmark(title, fn);\n } else {\n return new Benchmark(title);\n }\n }\n\n constructor(title: string);\n constructor(title: string, fn: FeedFn<TInput>);\n constructor(title: string, fn?: FeedFn<TInput> | undefined) {\n if (fn) {\n this.feed(title, fn);\n } else {\n this.feed(title);\n }\n }\n\n feed(title: string): Benchmark<TInput | void>;\n feed<I>(title: string, fn: FeedFn<I>): Benchmark<TInput | I>;\n feed<I>(title: string, fn?: FeedFn<I> | undefined): Benchmark<TInput | I> {\n const self = this as Benchmark<TInput | I>;\n self.#feeds.push(fn ? new FeedContext(title, fn) : new FeedContext(title));\n\n return self;\n }\n\n target<TContext>(title: string): Target<void, TInput>;\n target<TContext>(title: string, setup: SetupFn<Awaited<TContext>>): Target<TContext, TInput>;\n target<TContext>(title: string, setup?: SetupFn<Awaited<TContext>> | undefined): Target<TContext, TInput> {\n const target = new TargetContext<TContext, TInput>(title, setup);\n this.#targets.push(target as TargetContext<unknown, TInput>);\n\n return new Target<TContext, TInput>(target);\n }\n\n async execute<R extends readonly ReportType[] = typeof DEFAULT_REPORT_TYPES>(options: ExecutorOptions<R>): Promise<TargetReport<R>[]> {\n const {\n workers = DEFAULT_WORKERS,\n warmupCycles = 20,\n maxCycles = DEFAULT_CYCLES,\n minCycles = 50,\n absThreshold = 1_000,\n relThreshold = 0.02,\n gcObserver = true,\n reportTypes = DEFAULT_REPORT_TYPES as unknown as R,\n } = options;\n if (this.#executed) {\n throw new Error(\"Benchmark is executed and can't be reused\");\n }\n this.#executed = true;\n const benchmarkUrl = (options as unknown as Record<symbol, unknown>)[BENCHMARK_URL];\n\n const executor = createExecutor<unknown, TInput, R>({\n workers,\n warmupCycles,\n maxCycles,\n minCycles,\n absThreshold,\n relThreshold,\n gcObserver,\n reportTypes,\n [BENCHMARK_URL]: benchmarkUrl,\n } as Required<ExecutorOptions<R>>);\n\n const reports: TargetReport<R>[] = [];\n for (const target of this.#targets) {\n const targetReport: TargetReport<R> = { target: target.title, measures: [] };\n for (const measure of target.measures) {\n const measureReport: MeasureReport<R> = { measure: measure.title, feeds: [] };\n for (const feed of this.#feeds) {\n const data = await feed.fn?.();\n executor\n .push<ExecutorReport<R>>({\n setup: target.setup,\n teardown: target.teardown,\n pre: measure.pre,\n run: measure.run,\n post: measure.post,\n data,\n })\n .then((data) => {\n measureReport.feeds.push({\n feed: feed.title,\n data,\n });\n });\n }\n targetReport.measures.push(measureReport);\n }\n reports.push(targetReport);\n }\n await executor.drain();\n executor.kill();\n\n return reports;\n }\n}\n\nexport const printSimpleReports = <R extends ReportTypeList>(reports: TargetReport<R>[]) => {\n for (const report of reports) {\n for (const { measure, feeds } of report.measures) {\n console.group('\\n', report.target, measure);\n for (const { feed, data } of feeds) {\n const output = Object.entries(data)\n .map(([key, report]) => `${key}: ${report.toString()}`)\n .join('; ');\n console.log(feed, output);\n }\n console.groupEnd();\n }\n }\n};\n\nexport const printTableReports = <R extends ReportTypeList>(reports: TargetReport<R>[]) => {\n for (const report of reports) {\n for (const { measure, feeds } of report.measures) {\n console.log('\\n', report.target, measure);\n const table: Record<string, unknown> = {};\n for (const { feed, data } of feeds) {\n table[feed] = Object.fromEntries(Object.entries(data).map(([key, report]) => [key, report.toString()]));\n }\n console.table(table);\n }\n }\n};\n\nexport const printJSONReports = <R extends ReportTypeList>(reports: TargetReport<R>[], padding?: number) => {\n const output = {} as Record<string, Record<string, Record<string, string>>>;\n for (const report of reports) {\n for (const { measure, feeds } of report.measures) {\n const row = {} as Record<string, Record<string, string>>;\n for (const { feed, data } of feeds) {\n row[feed] = Object.fromEntries(Object.entries(data).map(([key, report]) => [key, report.toString()]));\n }\n output[`${report.target} ${measure}`] = row;\n }\n }\n console.log(JSON.stringify(output, null, padding));\n};\n"],"names":["AsyncFunction","Benchmark","DEFAULT_REPORT_TYPES","DEFAULT_WORKERS","FeedContext","Measure","MeasureContext","Target","TargetContext","printJSONReports","printSimpleReports","printTableReports","cpus","length","BENCHMARK_URL","Symbol","for","pre","post","title","run","ctx","fn","teardown","measures","setup","measure","push","create","feed","self","target","execute","options","workers","warmupCycles","maxCycles","DEFAULT_CYCLES","minCycles","absThreshold","relThreshold","gcObserver","reportTypes","Error","benchmarkUrl","executor","createExecutor","reports","targetReport","measureReport","feeds","data","then","drain","kill","report","console","group","output","Object","entries","map","key","toString","join","log","groupEnd","table","fromEntries","padding","row","JSON","stringify"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { cpus } from 'node:os';\nimport Progress from 'progress';\nimport { createExecutor, ExecutorOptions, ExecutorReport } from './executor.js';\nimport { MaybePromise, StepFn, SetupFn, TeardownFn, FeedFn, ReportType, ReportTypeList, DEFAULT_CYCLES, ProgressInfo } from './types.js';\n\ndeclare global {\n const benchmark: typeof Benchmark.create;\n}\n\nexport const DEFAULT_WORKERS = cpus().length;\n\nexport const AsyncFunction = (async () => {}).constructor;\nconst BENCHMARK_URL = Symbol.for('overtake.benchmarkUrl');\n\nexport interface TargetReport<R extends ReportTypeList> {\n target: string;\n measures: MeasureReport<R>[];\n}\n\nexport interface MeasureReport<R extends ReportTypeList> {\n measure: string;\n feeds: FeedReport<R>[];\n}\n\nexport interface FeedReport<R extends ReportTypeList> {\n feed: string;\n data: ExecutorReport<R>;\n}\n\nexport const DEFAULT_REPORT_TYPES = ['ops'] as const;\nexport type DefaultReportTypes = (typeof DEFAULT_REPORT_TYPES)[number];\n\nexport class MeasureContext<TContext, TInput> {\n public pre?: StepFn<TContext, TInput>;\n public post?: StepFn<TContext, TInput>;\n\n constructor(\n public title: string,\n public run: StepFn<TContext, TInput>,\n ) {}\n}\n\nexport class Measure<TContext, TInput> {\n #ctx: MeasureContext<TContext, TInput>;\n\n constructor(ctx: MeasureContext<TContext, TInput>) {\n this.#ctx = ctx;\n }\n\n pre(fn: StepFn<TContext, TInput>): Measure<TContext, TInput> {\n this.#ctx.pre = fn;\n return this;\n }\n post(fn: StepFn<TContext, TInput>): Measure<TContext, TInput> {\n this.#ctx.post = fn;\n return this;\n }\n}\n\nexport class TargetContext<TContext, TInput> {\n public teardown?: TeardownFn<TContext>;\n public measures: MeasureContext<TContext, TInput>[] = [];\n\n constructor(\n readonly title: string,\n readonly setup?: SetupFn<MaybePromise<TContext>>,\n ) {}\n}\n\nexport class Target<TContext, TInput> {\n #ctx: TargetContext<TContext, TInput>;\n\n constructor(ctx: TargetContext<TContext, TInput>) {\n this.#ctx = ctx;\n }\n teardown(fn: TeardownFn<TContext>): Target<TContext, TInput> {\n this.#ctx.teardown = fn;\n\n return this;\n }\n measure(title: string, run: StepFn<TContext, TInput>): Measure<TContext, TInput> {\n const measure = new MeasureContext(title, run);\n this.#ctx.measures.push(measure);\n\n return new Measure(measure);\n }\n}\n\nexport class FeedContext<TInput> {\n constructor(\n readonly title: string,\n readonly fn?: FeedFn<TInput>,\n ) {}\n}\n\nexport class Benchmark<TInput> {\n #targets: TargetContext<unknown, TInput>[] = [];\n #feeds: FeedContext<TInput>[] = [];\n #executed = false;\n\n static create(title: string): Benchmark<void>;\n static create<I>(title: string, fn: FeedFn<I>): Benchmark<I>;\n static create<I>(title: string, fn?: FeedFn<I> | undefined): Benchmark<I> {\n if (fn) {\n return new Benchmark(title, fn);\n } else {\n return new Benchmark(title);\n }\n }\n\n constructor(title: string);\n constructor(title: string, fn: FeedFn<TInput>);\n constructor(title: string, fn?: FeedFn<TInput> | undefined) {\n if (fn) {\n this.feed(title, fn);\n } else {\n this.feed(title);\n }\n }\n\n feed(title: string): Benchmark<TInput | void>;\n feed<I>(title: string, fn: FeedFn<I>): Benchmark<TInput | I>;\n feed<I>(title: string, fn?: FeedFn<I> | undefined): Benchmark<TInput | I> {\n const self = this as Benchmark<TInput | I>;\n self.#feeds.push(fn ? new FeedContext(title, fn) : new FeedContext(title));\n\n return self;\n }\n\n target<TContext>(title: string): Target<void, TInput>;\n target<TContext>(title: string, setup: SetupFn<Awaited<TContext>>): Target<TContext, TInput>;\n target<TContext>(title: string, setup?: SetupFn<Awaited<TContext>> | undefined): Target<TContext, TInput> {\n const target = new TargetContext<TContext, TInput>(title, setup);\n this.#targets.push(target as TargetContext<unknown, TInput>);\n\n return new Target<TContext, TInput>(target);\n }\n\n async execute<R extends readonly ReportType[] = typeof DEFAULT_REPORT_TYPES>(options: ExecutorOptions<R> & { progress?: boolean }): Promise<TargetReport<R>[]> {\n const {\n workers = DEFAULT_WORKERS,\n warmupCycles = 20,\n maxCycles = DEFAULT_CYCLES,\n minCycles = 50,\n absThreshold = 1_000,\n relThreshold = 0.02,\n gcObserver = true,\n reportTypes = DEFAULT_REPORT_TYPES as unknown as R,\n progress = false,\n progressInterval = 100,\n } = options;\n if (this.#executed) {\n throw new Error(\"Benchmark is executed and can't be reused\");\n }\n this.#executed = true;\n const benchmarkUrl = (options as unknown as Record<symbol, unknown>)[BENCHMARK_URL];\n\n const totalBenchmarks = this.#targets.reduce((acc, t) => acc + t.measures.length * this.#feeds.length, 0);\n const progressMap = new Map<string, number>();\n let completedBenchmarks = 0;\n let bar: Progress | null = null;\n\n if (progress && totalBenchmarks > 0) {\n bar = new Progress(' [:bar] :percent :current/:total :label', {\n total: totalBenchmarks * 100,\n width: 30,\n complete: '=',\n incomplete: ' ',\n });\n }\n\n const onProgress = progress\n ? (info: ProgressInfo) => {\n progressMap.set(info.id, info.progress);\n const totalProgress = (completedBenchmarks + [...progressMap.values()].reduce((a, b) => a + b, 0)) * 100;\n const label = info.id.length > 30 ? info.id.slice(0, 27) + '...' : info.id;\n bar?.update(totalProgress / (totalBenchmarks * 100), { label });\n }\n : undefined;\n\n const executor = createExecutor<unknown, TInput, R>({\n workers,\n warmupCycles,\n maxCycles,\n minCycles,\n absThreshold,\n relThreshold,\n gcObserver,\n reportTypes,\n onProgress,\n progressInterval,\n [BENCHMARK_URL]: benchmarkUrl,\n } as Required<ExecutorOptions<R>>);\n\n const reports: TargetReport<R>[] = [];\n for (const target of this.#targets) {\n const targetReport: TargetReport<R> = { target: target.title, measures: [] };\n for (const measure of target.measures) {\n const measureReport: MeasureReport<R> = { measure: measure.title, feeds: [] };\n for (const feed of this.#feeds) {\n const id = `${target.title}/${measure.title}/${feed.title}`;\n const data = await feed.fn?.();\n executor\n .push<ExecutorReport<R>>({\n id,\n setup: target.setup,\n teardown: target.teardown,\n pre: measure.pre,\n run: measure.run,\n post: measure.post,\n data,\n })\n .then((data) => {\n progressMap.delete(id);\n completedBenchmarks++;\n measureReport.feeds.push({\n feed: feed.title,\n data,\n });\n });\n }\n targetReport.measures.push(measureReport);\n }\n reports.push(targetReport);\n }\n await executor.drain();\n executor.kill();\n\n if (bar) {\n bar.update(1, { label: 'done' });\n bar.terminate();\n }\n\n return reports;\n }\n}\n\nexport const printSimpleReports = <R extends ReportTypeList>(reports: TargetReport<R>[]) => {\n for (const report of reports) {\n for (const { measure, feeds } of report.measures) {\n console.group('\\n', report.target, measure);\n for (const { feed, data } of feeds) {\n const output = Object.entries(data)\n .map(([key, report]) => `${key}: ${report.toString()}`)\n .join('; ');\n console.log(feed, output);\n }\n console.groupEnd();\n }\n }\n};\n\nexport const printTableReports = <R extends ReportTypeList>(reports: TargetReport<R>[]) => {\n for (const report of reports) {\n for (const { measure, feeds } of report.measures) {\n console.log('\\n', report.target, measure);\n const table: Record<string, unknown> = {};\n for (const { feed, data } of feeds) {\n table[feed] = Object.fromEntries(Object.entries(data).map(([key, report]) => [key, report.toString()]));\n }\n console.table(table);\n }\n }\n};\n\nexport const printJSONReports = <R extends ReportTypeList>(reports: TargetReport<R>[], padding?: number) => {\n const output = {} as Record<string, Record<string, Record<string, string>>>;\n for (const report of reports) {\n for (const { measure, feeds } of report.measures) {\n const row = {} as Record<string, Record<string, string>>;\n for (const { feed, data } of feeds) {\n row[feed] = Object.fromEntries(Object.entries(data).map(([key, report]) => [key, report.toString()]));\n }\n output[`${report.target} ${measure}`] = row;\n }\n }\n console.log(JSON.stringify(output, null, padding));\n};\n"],"names":["AsyncFunction","Benchmark","DEFAULT_REPORT_TYPES","DEFAULT_WORKERS","FeedContext","Measure","MeasureContext","Target","TargetContext","printJSONReports","printSimpleReports","printTableReports","cpus","length","BENCHMARK_URL","Symbol","for","pre","post","title","run","ctx","fn","teardown","measures","setup","measure","push","create","feed","self","target","execute","options","workers","warmupCycles","maxCycles","DEFAULT_CYCLES","minCycles","absThreshold","relThreshold","gcObserver","reportTypes","progress","progressInterval","Error","benchmarkUrl","totalBenchmarks","reduce","acc","t","progressMap","Map","completedBenchmarks","bar","Progress","total","width","complete","incomplete","onProgress","info","set","id","totalProgress","values","a","b","label","slice","update","undefined","executor","createExecutor","reports","targetReport","measureReport","feeds","data","then","delete","drain","kill","terminate","report","console","group","output","Object","entries","map","key","toString","join","log","groupEnd","table","fromEntries","padding","row","JSON","stringify"],"mappings":"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"}
|
package/build/index.d.ts
CHANGED
|
@@ -60,7 +60,9 @@ export declare class Benchmark<TInput> {
|
|
|
60
60
|
feed<I>(title: string, fn: FeedFn<I>): Benchmark<TInput | I>;
|
|
61
61
|
target<TContext>(title: string): Target<void, TInput>;
|
|
62
62
|
target<TContext>(title: string, setup: SetupFn<Awaited<TContext>>): Target<TContext, TInput>;
|
|
63
|
-
execute<R extends readonly ReportType[] = typeof DEFAULT_REPORT_TYPES>(options: ExecutorOptions<R>
|
|
63
|
+
execute<R extends readonly ReportType[] = typeof DEFAULT_REPORT_TYPES>(options: ExecutorOptions<R> & {
|
|
64
|
+
progress?: boolean;
|
|
65
|
+
}): Promise<TargetReport<R>[]>;
|
|
64
66
|
}
|
|
65
67
|
export declare const printSimpleReports: <R extends ReportTypeList>(reports: TargetReport<R>[]) => void;
|
|
66
68
|
export declare const printTableReports: <R extends ReportTypeList>(reports: TargetReport<R>[]) => void;
|
package/build/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { cpus } from 'node:os';
|
|
2
|
+
import Progress from 'progress';
|
|
2
3
|
import { createExecutor } from "./executor.js";
|
|
3
4
|
import { DEFAULT_CYCLES } from "./types.js";
|
|
4
5
|
export const DEFAULT_WORKERS = cpus().length;
|
|
@@ -93,12 +94,34 @@ export class Benchmark {
|
|
|
93
94
|
return new Target(target);
|
|
94
95
|
}
|
|
95
96
|
async execute(options) {
|
|
96
|
-
const { workers = DEFAULT_WORKERS, warmupCycles = 20, maxCycles = DEFAULT_CYCLES, minCycles = 50, absThreshold = 1_000, relThreshold = 0.02, gcObserver = true, reportTypes = DEFAULT_REPORT_TYPES } = options;
|
|
97
|
+
const { workers = DEFAULT_WORKERS, warmupCycles = 20, maxCycles = DEFAULT_CYCLES, minCycles = 50, absThreshold = 1_000, relThreshold = 0.02, gcObserver = true, reportTypes = DEFAULT_REPORT_TYPES, progress = false, progressInterval = 100 } = options;
|
|
97
98
|
if (this.#executed) {
|
|
98
99
|
throw new Error("Benchmark is executed and can't be reused");
|
|
99
100
|
}
|
|
100
101
|
this.#executed = true;
|
|
101
102
|
const benchmarkUrl = options[BENCHMARK_URL];
|
|
103
|
+
const totalBenchmarks = this.#targets.reduce((acc, t)=>acc + t.measures.length * this.#feeds.length, 0);
|
|
104
|
+
const progressMap = new Map();
|
|
105
|
+
let completedBenchmarks = 0;
|
|
106
|
+
let bar = null;
|
|
107
|
+
if (progress && totalBenchmarks > 0) {
|
|
108
|
+
bar = new Progress(' [:bar] :percent :current/:total :label', {
|
|
109
|
+
total: totalBenchmarks * 100,
|
|
110
|
+
width: 30,
|
|
111
|
+
complete: '=',
|
|
112
|
+
incomplete: ' '
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
const onProgress = progress ? (info)=>{
|
|
116
|
+
progressMap.set(info.id, info.progress);
|
|
117
|
+
const totalProgress = (completedBenchmarks + [
|
|
118
|
+
...progressMap.values()
|
|
119
|
+
].reduce((a, b)=>a + b, 0)) * 100;
|
|
120
|
+
const label = info.id.length > 30 ? info.id.slice(0, 27) + '...' : info.id;
|
|
121
|
+
bar?.update(totalProgress / (totalBenchmarks * 100), {
|
|
122
|
+
label
|
|
123
|
+
});
|
|
124
|
+
} : undefined;
|
|
102
125
|
const executor = createExecutor({
|
|
103
126
|
workers,
|
|
104
127
|
warmupCycles,
|
|
@@ -108,6 +131,8 @@ export class Benchmark {
|
|
|
108
131
|
relThreshold,
|
|
109
132
|
gcObserver,
|
|
110
133
|
reportTypes,
|
|
134
|
+
onProgress,
|
|
135
|
+
progressInterval,
|
|
111
136
|
[BENCHMARK_URL]: benchmarkUrl
|
|
112
137
|
});
|
|
113
138
|
const reports = [];
|
|
@@ -122,8 +147,10 @@ export class Benchmark {
|
|
|
122
147
|
feeds: []
|
|
123
148
|
};
|
|
124
149
|
for (const feed of this.#feeds){
|
|
150
|
+
const id = `${target.title}/${measure.title}/${feed.title}`;
|
|
125
151
|
const data = await feed.fn?.();
|
|
126
152
|
executor.push({
|
|
153
|
+
id,
|
|
127
154
|
setup: target.setup,
|
|
128
155
|
teardown: target.teardown,
|
|
129
156
|
pre: measure.pre,
|
|
@@ -131,6 +158,8 @@ export class Benchmark {
|
|
|
131
158
|
post: measure.post,
|
|
132
159
|
data
|
|
133
160
|
}).then((data)=>{
|
|
161
|
+
progressMap.delete(id);
|
|
162
|
+
completedBenchmarks++;
|
|
134
163
|
measureReport.feeds.push({
|
|
135
164
|
feed: feed.title,
|
|
136
165
|
data
|
|
@@ -143,6 +172,12 @@ export class Benchmark {
|
|
|
143
172
|
}
|
|
144
173
|
await executor.drain();
|
|
145
174
|
executor.kill();
|
|
175
|
+
if (bar) {
|
|
176
|
+
bar.update(1, {
|
|
177
|
+
label: 'done'
|
|
178
|
+
});
|
|
179
|
+
bar.terminate();
|
|
180
|
+
}
|
|
146
181
|
return reports;
|
|
147
182
|
}
|
|
148
183
|
}
|