@soroush.tech/bench 0.1.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/Dockerfile +10 -0
- package/LICENSE +21 -0
- package/README.md +143 -0
- package/dist/bin.mjs +147 -0
- package/dist/harness.mjs +1730 -0
- package/dist/index.cjs +17 -0
- package/dist/index.d.cts +37 -0
- package/dist/index.d.mts +37 -0
- package/dist/index.mjs +17 -0
- package/package.json +76 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/index.ts
|
|
2
|
+
/**
|
|
3
|
+
* Validates and freezes a benchmark definition. Authored in a `*.bench.ts`
|
|
4
|
+
* file and `export default`-ed; the `bench` CLI loads that default export
|
|
5
|
+
* inside the pinned container.
|
|
6
|
+
*/
|
|
7
|
+
function defineBench(config) {
|
|
8
|
+
if (typeof config.name !== "string" || config.name.trim() === "") throw new TypeError("defineBench: `name` must be a non-empty string");
|
|
9
|
+
const caseEntries = Object.entries(config.cases ?? {});
|
|
10
|
+
if (caseEntries.length < 2) throw new TypeError("defineBench: `cases` must define at least two cases to compare");
|
|
11
|
+
for (const [key, fn] of caseEntries) if (typeof fn !== "function") throw new TypeError(`defineBench: case "${key}" must be a function`);
|
|
12
|
+
for (const [alias, spec] of Object.entries(config.packages ?? {})) if (typeof spec !== "string" || spec.trim() === "") throw new TypeError(`defineBench: package "${alias}" must map to a non-empty install spec`);
|
|
13
|
+
if (config.warmup !== void 0 && (!Number.isInteger(config.warmup) || config.warmup < 0)) throw new TypeError("defineBench: `warmup` must be a non-negative integer");
|
|
14
|
+
return Object.freeze({ ...config });
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
module.exports = defineBench;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//#region src/index.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The context handed to every benchmark case at call time.
|
|
4
|
+
*
|
|
5
|
+
* `modules` maps each alias declared in {@link BenchConfig.packages} to its
|
|
6
|
+
* resolved module namespace. Comparing two versions of the same package is the
|
|
7
|
+
* reason cases receive their modules here rather than importing at the top
|
|
8
|
+
* level: Node cannot hold two versions of one bare specifier in a single graph,
|
|
9
|
+
* so the harness installs each under its alias and injects them.
|
|
10
|
+
*/
|
|
11
|
+
interface BenchContext {
|
|
12
|
+
modules: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
/** A single function under test. Receives the {@link BenchContext}. */
|
|
15
|
+
type BenchCase = (ctx: BenchContext) => unknown | Promise<unknown>;
|
|
16
|
+
interface BenchConfig {
|
|
17
|
+
/** Human label for the comparison; prefixes every case in the report. */
|
|
18
|
+
name: string;
|
|
19
|
+
/**
|
|
20
|
+
* Optional `alias -> npm install spec` map (e.g. `{ v4: 'lodash@4.17.21' }`).
|
|
21
|
+
* The harness installs each under its alias and exposes it on
|
|
22
|
+
* `ctx.modules[alias]`, enabling two-or-more-versions-of-one-package runs.
|
|
23
|
+
*/
|
|
24
|
+
packages?: Record<string, string>;
|
|
25
|
+
/** The named versions to compare. At least two are required. */
|
|
26
|
+
cases: Record<string, BenchCase>;
|
|
27
|
+
/** Warmup iterations before measuring. Defaults to the runner's default. */
|
|
28
|
+
warmup?: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Validates and freezes a benchmark definition. Authored in a `*.bench.ts`
|
|
32
|
+
* file and `export default`-ed; the `bench` CLI loads that default export
|
|
33
|
+
* inside the pinned container.
|
|
34
|
+
*/
|
|
35
|
+
declare function defineBench(config: BenchConfig): Readonly<BenchConfig>;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { BenchCase, BenchConfig, BenchContext, defineBench as default };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//#region src/index.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The context handed to every benchmark case at call time.
|
|
4
|
+
*
|
|
5
|
+
* `modules` maps each alias declared in {@link BenchConfig.packages} to its
|
|
6
|
+
* resolved module namespace. Comparing two versions of the same package is the
|
|
7
|
+
* reason cases receive their modules here rather than importing at the top
|
|
8
|
+
* level: Node cannot hold two versions of one bare specifier in a single graph,
|
|
9
|
+
* so the harness installs each under its alias and injects them.
|
|
10
|
+
*/
|
|
11
|
+
interface BenchContext {
|
|
12
|
+
modules: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
/** A single function under test. Receives the {@link BenchContext}. */
|
|
15
|
+
type BenchCase = (ctx: BenchContext) => unknown | Promise<unknown>;
|
|
16
|
+
interface BenchConfig {
|
|
17
|
+
/** Human label for the comparison; prefixes every case in the report. */
|
|
18
|
+
name: string;
|
|
19
|
+
/**
|
|
20
|
+
* Optional `alias -> npm install spec` map (e.g. `{ v4: 'lodash@4.17.21' }`).
|
|
21
|
+
* The harness installs each under its alias and exposes it on
|
|
22
|
+
* `ctx.modules[alias]`, enabling two-or-more-versions-of-one-package runs.
|
|
23
|
+
*/
|
|
24
|
+
packages?: Record<string, string>;
|
|
25
|
+
/** The named versions to compare. At least two are required. */
|
|
26
|
+
cases: Record<string, BenchCase>;
|
|
27
|
+
/** Warmup iterations before measuring. Defaults to the runner's default. */
|
|
28
|
+
warmup?: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Validates and freezes a benchmark definition. Authored in a `*.bench.ts`
|
|
32
|
+
* file and `export default`-ed; the `bench` CLI loads that default export
|
|
33
|
+
* inside the pinned container.
|
|
34
|
+
*/
|
|
35
|
+
declare function defineBench(config: BenchConfig): Readonly<BenchConfig>;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { BenchCase, BenchConfig, BenchContext, defineBench as default };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/index.ts
|
|
2
|
+
/**
|
|
3
|
+
* Validates and freezes a benchmark definition. Authored in a `*.bench.ts`
|
|
4
|
+
* file and `export default`-ed; the `bench` CLI loads that default export
|
|
5
|
+
* inside the pinned container.
|
|
6
|
+
*/
|
|
7
|
+
function defineBench(config) {
|
|
8
|
+
if (typeof config.name !== "string" || config.name.trim() === "") throw new TypeError("defineBench: `name` must be a non-empty string");
|
|
9
|
+
const caseEntries = Object.entries(config.cases ?? {});
|
|
10
|
+
if (caseEntries.length < 2) throw new TypeError("defineBench: `cases` must define at least two cases to compare");
|
|
11
|
+
for (const [key, fn] of caseEntries) if (typeof fn !== "function") throw new TypeError(`defineBench: case "${key}" must be a function`);
|
|
12
|
+
for (const [alias, spec] of Object.entries(config.packages ?? {})) if (typeof spec !== "string" || spec.trim() === "") throw new TypeError(`defineBench: package "${alias}" must map to a non-empty install spec`);
|
|
13
|
+
if (config.warmup !== void 0 && (!Number.isInteger(config.warmup) || config.warmup < 0)) throw new TypeError("defineBench: `warmup` must be a non-negative integer");
|
|
14
|
+
return Object.freeze({ ...config });
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { defineBench as default };
|
package/package.json
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@soroush.tech/bench",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Run A/B function and package-version benchmarks inside a CPU/RAM-pinned Docker sandbox for stable, low-noise numbers. Built on mitata.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"benchmark",
|
|
7
|
+
"benchmarking",
|
|
8
|
+
"mitata",
|
|
9
|
+
"performance",
|
|
10
|
+
"docker",
|
|
11
|
+
"sandbox",
|
|
12
|
+
"cpu-pinning",
|
|
13
|
+
"typescript"
|
|
14
|
+
],
|
|
15
|
+
"author": "Masoud Soroush <masoud@soroush.tech>",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"homepage": "https://github.com/soroush-tech/soroush.tech/tree/main/packages/bench#readme",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/soroush-tech/soroush.tech.git",
|
|
21
|
+
"directory": "packages/bench"
|
|
22
|
+
},
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/soroush-tech/soroush.tech/issues"
|
|
25
|
+
},
|
|
26
|
+
"type": "module",
|
|
27
|
+
"sideEffects": false,
|
|
28
|
+
"bin": {
|
|
29
|
+
"bench": "./dist/bin.mjs"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist",
|
|
33
|
+
"Dockerfile"
|
|
34
|
+
],
|
|
35
|
+
"exports": {
|
|
36
|
+
".": "./src/index.ts"
|
|
37
|
+
},
|
|
38
|
+
"types": "./src/index.ts",
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public",
|
|
41
|
+
"exports": {
|
|
42
|
+
".": {
|
|
43
|
+
"import": {
|
|
44
|
+
"types": "./dist/index.d.mts",
|
|
45
|
+
"default": "./dist/index.mjs"
|
|
46
|
+
},
|
|
47
|
+
"require": {
|
|
48
|
+
"types": "./dist/index.d.cts",
|
|
49
|
+
"default": "./dist/index.cjs"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"main": "./dist/index.cjs",
|
|
54
|
+
"module": "./dist/index.mjs",
|
|
55
|
+
"types": "./dist/index.d.mts"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"build": "tsdown",
|
|
59
|
+
"lint": "eslint . --max-warnings 0",
|
|
60
|
+
"typecheck": "tsc --noEmit",
|
|
61
|
+
"test": "vitest run",
|
|
62
|
+
"test:coverage": "vitest run --coverage",
|
|
63
|
+
"prepublishOnly": "pnpm build"
|
|
64
|
+
},
|
|
65
|
+
"devDependencies": {
|
|
66
|
+
"@soroush.tech/eslint-config": "workspace:*",
|
|
67
|
+
"@types/node": "^24.13.2",
|
|
68
|
+
"@vitest/coverage-v8": "^4.1.9",
|
|
69
|
+
"eslint": "^10.5.0",
|
|
70
|
+
"globals": "^17.7.0",
|
|
71
|
+
"mitata": "^1.0.34",
|
|
72
|
+
"tsdown": "^0.22.3",
|
|
73
|
+
"typescript": "~6.0.3",
|
|
74
|
+
"vitest": "^4.1.9"
|
|
75
|
+
}
|
|
76
|
+
}
|