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 +4 -3
- package/build/loader-hook.d.ts +2 -0
- package/build/loader-hook.js +33 -0
- package/build/register-hook.js +1 -14
- package/build/utils.js +2 -15
- package/package.json +2 -2
- package/src/__tests__/fixtures/enum-bench.ts +17 -0
- package/src/__tests__/fixtures/param-property-bench.ts +14 -0
- package/src/__tests__/loader-hook.ts +33 -0
- package/src/executor.ts +3 -3
- package/src/loader-hook.ts +33 -0
- package/src/register-hook.ts +1 -13
- package/src/utils.ts +1 -13
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
|
|
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
|
-
|
|
125
|
+
if (workerError)
|
|
126
|
+
entries.push(['error', workerError]);
|
|
127
|
+
return Object.fromEntries(entries);
|
|
127
128
|
};
|
|
128
129
|
return {
|
|
129
130
|
pushAsync,
|
|
@@ -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
|
+
}
|
package/build/register-hook.js
CHANGED
|
@@ -1,15 +1,2 @@
|
|
|
1
1
|
import { register } from 'node:module';
|
|
2
|
-
|
|
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
|
-
|
|
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 =
|
|
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.
|
|
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": ">=
|
|
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
|
|
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
|
-
|
|
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
|
+
}
|
package/src/register-hook.ts
CHANGED
|
@@ -1,15 +1,3 @@
|
|
|
1
1
|
import { register } from 'node:module';
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
|
|
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');
|