overtake 2.0.2 → 2.0.3

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/executor.js CHANGED
@@ -115,15 +115,16 @@ export const createExecutor = (options) => {
115
115
  }
116
116
  }
117
117
  const stats = count > 0 ? computeStats(durations) : undefined;
118
- const report = reportTypes
118
+ const entries = reportTypes
119
119
  .map((type) => [type, createReport(durations, type, stats)])
120
120
  .concat([
121
121
  ['count', count],
122
122
  ['heapUsedKB', heapUsedKB],
123
123
  ['dceWarning', dceWarning],
124
- ['error', workerError],
125
124
  ]);
126
- return Object.fromEntries(report);
125
+ if (workerError)
126
+ entries.push(['error', workerError]);
127
+ return Object.fromEntries(entries);
127
128
  };
128
129
  return {
129
130
  pushAsync,
@@ -0,0 +1,2 @@
1
+ export declare function resolve(specifier: string, context: unknown, nextResolve: (...args: unknown[]) => unknown): Promise<unknown>;
2
+ export declare function load(url: string, context: unknown, nextLoad: (...args: unknown[]) => unknown): Promise<unknown>;
@@ -0,0 +1,33 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { transformSync } from '@swc/core';
4
+ export async function resolve(specifier, context, nextResolve) {
5
+ try {
6
+ return await nextResolve(specifier, context);
7
+ }
8
+ catch (e) {
9
+ if (specifier.endsWith('.js'))
10
+ try {
11
+ return await nextResolve(specifier.slice(0, -3) + '.ts', context);
12
+ }
13
+ catch { }
14
+ throw e;
15
+ }
16
+ }
17
+ export async function load(url, context, nextLoad) {
18
+ if (!url.endsWith('.ts') && !url.endsWith('.mts')) {
19
+ return nextLoad(url, context);
20
+ }
21
+ const filePath = fileURLToPath(url);
22
+ const rawSource = await readFile(filePath, 'utf-8');
23
+ const { code } = transformSync(rawSource, {
24
+ filename: filePath,
25
+ jsc: {
26
+ parser: { syntax: 'typescript' },
27
+ target: 'esnext',
28
+ },
29
+ module: { type: 'es6' },
30
+ sourceMaps: false,
31
+ });
32
+ return { format: 'module', source: code, shortCircuit: true };
33
+ }
@@ -1,15 +1,2 @@
1
1
  import { register } from 'node:module';
2
- async function resolve(s, c, n) {
3
- try {
4
- return await n(s, c);
5
- }
6
- catch (e) {
7
- if (s.endsWith('.js'))
8
- try {
9
- return await n(s.slice(0, -3) + '.ts', c);
10
- }
11
- catch { }
12
- throw e;
13
- }
14
- }
15
- register('data:text/javascript,' + encodeURIComponent(`export ${resolve.toString()}`));
2
+ register(new URL('../build/loader-hook.js', import.meta.url).href);
package/build/utils.js CHANGED
@@ -1,18 +1,5 @@
1
1
  import { parseSync } from '@swc/core';
2
- async function resolve(s, c, n) {
3
- try {
4
- return await n(s, c);
5
- }
6
- catch (e) {
7
- if (s.endsWith('.js'))
8
- try {
9
- return await n(s.slice(0, -3) + '.ts', c);
10
- }
11
- catch { }
12
- throw e;
13
- }
14
- }
15
- export const resolveHookUrl = 'data:text/javascript,' + encodeURIComponent(`export ${resolve.toString()}`);
2
+ export const resolveHookUrl = new URL('./loader-hook.js', import.meta.url).href;
16
3
  export const isqrt = (n) => {
17
4
  if (n < 0n)
18
5
  throw new RangeError('Square root of negative');
@@ -44,7 +31,7 @@ export const max = (a, b) => {
44
31
  export function div(a, b, decimals = 2) {
45
32
  if (b === 0n)
46
33
  throw new RangeError('Division by zero');
47
- const neg = (a < 0n) !== (b < 0n);
34
+ const neg = a < 0n !== b < 0n;
48
35
  const absA = a < 0n ? -a : a;
49
36
  const absB = b < 0n ? -b : b;
50
37
  const scale = 10n ** BigInt(decimals);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overtake",
3
- "version": "2.0.2",
3
+ "version": "2.0.3",
4
4
  "description": "NodeJS performance benchmark",
5
5
  "type": "module",
6
6
  "types": "build/index.d.ts",
@@ -12,7 +12,7 @@
12
12
  "overtake": "bin/overtake.js"
13
13
  },
14
14
  "engines": {
15
- "node": ">=24"
15
+ "node": ">=22"
16
16
  },
17
17
  "repository": {
18
18
  "type": "git",
@@ -0,0 +1,17 @@
1
+ import 'overtake';
2
+
3
+ const suite = benchmark('ops', () => null);
4
+
5
+ const target = suite.target('enum', () => {
6
+ enum Direction {
7
+ Up,
8
+ Down,
9
+ Left,
10
+ Right,
11
+ }
12
+ return { Direction };
13
+ });
14
+
15
+ target.measure('access', ({ Direction }) => {
16
+ return Direction.Up + Direction.Right;
17
+ });
@@ -0,0 +1,14 @@
1
+ import 'overtake';
2
+
3
+ const suite = benchmark('ops', () => null);
4
+
5
+ const target = suite.target('param-property', () => {
6
+ class Container {
7
+ constructor(public value: number) {}
8
+ }
9
+ return { Container };
10
+ });
11
+
12
+ target.measure('create', ({ Container }) => {
13
+ return new Container(42);
14
+ });
@@ -0,0 +1,33 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { execFile } from 'node:child_process';
4
+ import { promisify } from 'node:util';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ const exec = promisify(execFile);
8
+ const overtakeBin = fileURLToPath(new URL('../../bin/overtake.js', import.meta.url));
9
+ const nodeFlags = ['--experimental-vm-modules', '--no-warnings', '--expose-gc'];
10
+
11
+ const runBench = async (fixture: string) => {
12
+ const { stdout } = await exec(process.execPath, [...nodeFlags, overtakeBin, '-f', 'json', '--max-cycles', '50', '--min-cycles', '10', '--warmup-cycles', '5', fixture], {
13
+ timeout: 30_000,
14
+ });
15
+
16
+ const result = JSON.parse(stdout);
17
+ const key = Object.keys(result)[0];
18
+ assert.ok(key, 'should have at least one benchmark result');
19
+ const feeds = result[key];
20
+ const feed = Object.keys(feeds)[0];
21
+ assert.ok(feeds[feed].ops, 'should have ops metric');
22
+ assert.ok(!feeds[feed].error, 'should not have an error');
23
+ };
24
+
25
+ describe('loader-hook', () => {
26
+ it('loads benchmark files using parameter properties', async () => {
27
+ await runBench(fileURLToPath(new URL('fixtures/param-property-bench.ts', import.meta.url)));
28
+ });
29
+
30
+ it('loads benchmark files using enums', async () => {
31
+ await runBench(fileURLToPath(new URL('fixtures/enum-bench.ts', import.meta.url)));
32
+ });
33
+ });
package/src/executor.ts CHANGED
@@ -153,15 +153,15 @@ export const createExecutor = <TContext, TInput, R extends ReportTypeList>(optio
153
153
  }
154
154
 
155
155
  const stats = count > 0 ? computeStats(durations) : undefined;
156
- const report = reportTypes
156
+ const entries: [string, unknown][] = reportTypes
157
157
  .map<[string, unknown]>((type) => [type, createReport(durations, type, stats)] as [ReportType, Report])
158
158
  .concat([
159
159
  ['count', count],
160
160
  ['heapUsedKB', heapUsedKB],
161
161
  ['dceWarning', dceWarning],
162
- ['error', workerError],
163
162
  ]);
164
- return Object.fromEntries(report);
163
+ if (workerError) entries.push(['error', workerError]);
164
+ return Object.fromEntries(entries);
165
165
  };
166
166
 
167
167
  return {
@@ -0,0 +1,33 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { transformSync } from '@swc/core';
4
+
5
+ export async function resolve(specifier: string, context: unknown, nextResolve: (...args: unknown[]) => unknown) {
6
+ try {
7
+ return await nextResolve(specifier, context);
8
+ } catch (e) {
9
+ if (specifier.endsWith('.js'))
10
+ try {
11
+ return await nextResolve(specifier.slice(0, -3) + '.ts', context);
12
+ } catch {}
13
+ throw e;
14
+ }
15
+ }
16
+
17
+ export async function load(url: string, context: unknown, nextLoad: (...args: unknown[]) => unknown) {
18
+ if (!url.endsWith('.ts') && !url.endsWith('.mts')) {
19
+ return nextLoad(url, context);
20
+ }
21
+ const filePath = fileURLToPath(url);
22
+ const rawSource = await readFile(filePath, 'utf-8');
23
+ const { code } = transformSync(rawSource, {
24
+ filename: filePath,
25
+ jsc: {
26
+ parser: { syntax: 'typescript' },
27
+ target: 'esnext',
28
+ },
29
+ module: { type: 'es6' },
30
+ sourceMaps: false,
31
+ });
32
+ return { format: 'module', source: code, shortCircuit: true };
33
+ }
@@ -1,15 +1,3 @@
1
1
  import { register } from 'node:module';
2
2
 
3
- async function resolve(s: string, c: unknown, n: (...args: unknown[]) => unknown) {
4
- try {
5
- return await n(s, c);
6
- } catch (e) {
7
- if (s.endsWith('.js'))
8
- try {
9
- return await n(s.slice(0, -3) + '.ts', c);
10
- } catch {}
11
- throw e;
12
- }
13
- }
14
-
15
- register('data:text/javascript,' + encodeURIComponent(`export ${resolve.toString()}`));
3
+ register(new URL('../build/loader-hook.js', import.meta.url).href);
package/src/utils.ts CHANGED
@@ -1,18 +1,6 @@
1
1
  import { parseSync } from '@swc/core';
2
2
 
3
- async function resolve(s: string, c: unknown, n: (...args: unknown[]) => unknown) {
4
- try {
5
- return await n(s, c);
6
- } catch (e) {
7
- if (s.endsWith('.js'))
8
- try {
9
- return await n(s.slice(0, -3) + '.ts', c);
10
- } catch {}
11
- throw e;
12
- }
13
- }
14
-
15
- export const resolveHookUrl = 'data:text/javascript,' + encodeURIComponent(`export ${resolve.toString()}`);
3
+ export const resolveHookUrl = new URL('./loader-hook.js', import.meta.url).href;
16
4
 
17
5
  export const isqrt = (n: bigint): bigint => {
18
6
  if (n < 0n) throw new RangeError('Square root of negative');