Skip to content

Commit 07af153

Browse files
committed
feat: implement tinybench compatibility
1 parent d21054d commit 07af153

File tree

11 files changed

+241
-0
lines changed

11 files changed

+241
-0
lines changed

packages/core/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ The core Node library used to integrate with Codspeed runners
77

88
For now, this crate should not be used directly. Instead, use one of the integration crates:
99

10+
- `@codspeed/tinybench`
1011
- `@codspeed/benchmark.js`

packages/tinybench/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<div align="center">
2+
<h1><code>@codspeed/tinybench</code></h1>
3+
4+
tinybench compatibility layer for CodSpeed
5+
6+
</div>

packages/tinybench/benches/sample.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import Benchmark from "benchmark";
2+
import { withCodSpeed } from "../";
3+
4+
const suite = withCodSpeed(new Benchmark.Suite());
5+
6+
suite
7+
.add("RegExp#test", function () {
8+
/o/.test("Hello World!");
9+
})
10+
.add("String#indexOf", function () {
11+
"Hello World!".indexOf("o") > -1;
12+
})
13+
// add listeners
14+
.on("cycle", function (event: Benchmark.Event) {
15+
console.log(String(event.target));
16+
})
17+
// run async
18+
.run({ async: true });

packages/tinybench/jest.config.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/** @type {import('ts-jest').JestConfigWithTsJest} */
2+
module.exports = {
3+
preset: "ts-jest",
4+
testEnvironment: "node",
5+
transform: {
6+
"^.+\\.tsx?$": [
7+
"ts-jest",
8+
{
9+
tsconfig: "tsconfig.test.json",
10+
},
11+
],
12+
},
13+
};

packages/tinybench/package.json

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"name": "@codspeed/tinybench",
3+
"version": "0.0.0",
4+
"description": "",
5+
"keywords": [],
6+
"main": "dist/index.cjs.js",
7+
"module": "dist/index.es5.js",
8+
"types": "dist/index.d.ts",
9+
"files": [
10+
"dist"
11+
],
12+
"author": "--username-- <--usermail-->",
13+
"repository": {
14+
"type": "git",
15+
"url": ""
16+
},
17+
"license": "MIT",
18+
"devDependencies": {
19+
"@types/find-up": "^4.0.0",
20+
"@types/stack-trace": "^0.0.30",
21+
"jest-mock-extended": "^3.0.1"
22+
},
23+
"dependencies": {
24+
"@codspeed/core": "workspace:*",
25+
"find-up": "^6.3.0",
26+
"stack-trace": "1.0.0-pre1",
27+
"tinybench": "^2.3.1"
28+
}
29+
}

packages/tinybench/rollup.config.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { defineConfig } from "rollup";
2+
import pkg from "./package.json" assert { type: "json" };
3+
import { declarationsPlugin, jsPlugins } from "../../rollup.options";
4+
5+
const entrypoint = "src/index.ts";
6+
7+
export default defineConfig([
8+
{
9+
input: entrypoint,
10+
output: [
11+
{
12+
file: pkg.types,
13+
format: "es",
14+
sourcemap: true,
15+
},
16+
],
17+
plugins: declarationsPlugin,
18+
},
19+
{
20+
input: entrypoint,
21+
output: [
22+
{
23+
file: pkg.main,
24+
format: "cjs",
25+
sourcemap: true,
26+
},
27+
{ file: pkg.module, format: "es", sourcemap: true },
28+
],
29+
plugins: [...jsPlugins],
30+
external: ["@codspeed/core"],
31+
},
32+
]);

packages/tinybench/src/index.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import measurement from "@codspeed/core";
2+
import { get as getStackTrace } from "stack-trace";
3+
import path, { dirname } from "path";
4+
import { findUpSync, Options } from "find-up";
5+
import { Bench } from "tinybench";
6+
7+
export function withCodSpeed(bench: Bench): Bench {
8+
if (!measurement.isInstrumented()) {
9+
return bench;
10+
}
11+
const callingFile = getCallingFile();
12+
bench.run = async () => {
13+
for (const task of bench.tasks) {
14+
const uri = callingFile + "::" + task.name;
15+
measurement.startMeasurement();
16+
await task.fn();
17+
measurement.stopMeasurement(uri);
18+
}
19+
return bench.tasks;
20+
};
21+
return bench;
22+
}
23+
24+
function getCallingFile(): string {
25+
const stack = getStackTrace();
26+
const callingFile = stack[2].getFileName(); // [here, withCodSpeed, actual caller]
27+
const gitDir = getGitDir(callingFile);
28+
if (gitDir === undefined) {
29+
throw new Error("Could not find a git repository");
30+
}
31+
return path.relative(gitDir, callingFile);
32+
}
33+
34+
function getGitDir(path: string): string | undefined {
35+
const dotGitPath = findUpSync(".git", {
36+
cwd: path,
37+
type: "directory",
38+
} as Options);
39+
return dotGitPath ? dirname(dotGitPath) : undefined;
40+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { mockDeep, mockReset } from "jest-mock-extended";
2+
const mockCore = mockDeep<Measurement>();
3+
4+
import { Bench } from "tinybench";
5+
import { withCodSpeed } from "..";
6+
import type { Measurement } from "@codspeed/core";
7+
8+
jest.mock("@codspeed/core", () => mockCore);
9+
10+
beforeEach(() => {
11+
mockReset(mockCore);
12+
});
13+
14+
describe("Benchmark.Suite", () => {
15+
it("simple suite", async () => {
16+
mockCore.isInstrumented.mockReturnValue(false);
17+
const bench = withCodSpeed(new Bench({ time: 100 }));
18+
const onComplete = jest.fn();
19+
bench.add("RegExp", function () {
20+
/o/.test("Hello World!");
21+
});
22+
bench.getTask("RegExp")?.addEventListener("complete", onComplete);
23+
await bench.run();
24+
25+
expect(onComplete).toHaveBeenCalled();
26+
expect(mockCore.startMeasurement).not.toHaveBeenCalled();
27+
expect(mockCore.stopMeasurement).not.toHaveBeenCalled();
28+
});
29+
it("check core methods are called", async () => {
30+
mockCore.isInstrumented.mockReturnValue(true);
31+
await withCodSpeed(new Bench())
32+
.add("RegExp", function () {
33+
/o/.test("Hello World!");
34+
})
35+
.run();
36+
expect(mockCore.startMeasurement).toHaveBeenCalled();
37+
expect(mockCore.stopMeasurement).toHaveBeenCalledWith(
38+
"packages/tinybench/test/library.test.ts::RegExp"
39+
);
40+
});
41+
it("check suite name is in the uri", async () => {
42+
mockCore.isInstrumented.mockReturnValue(true);
43+
await withCodSpeed(new Bench())
44+
.add("RegExp", function () {
45+
/o/.test("Hello World!");
46+
})
47+
.add("RegExp2", () => {
48+
/o/.test("Hello World!");
49+
})
50+
.run();
51+
expect(mockCore.stopMeasurement).toHaveBeenCalledWith(
52+
"packages/tinybench/test/library.test.ts::RegExp"
53+
);
54+
expect(mockCore.stopMeasurement).toHaveBeenCalledWith(
55+
"packages/tinybench/test/library.test.ts::RegExp2"
56+
);
57+
});
58+
});

packages/tinybench/tsconfig.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"extends": "../../tsconfig.base.json",
3+
"compilerOptions": {
4+
"outDir": "dist",
5+
"rootDir": "src",
6+
"typeRoots": [
7+
"node_modules/@types",
8+
"../../node_modules/@types"
9+
]
10+
},
11+
"include": [
12+
"src/**/*.ts"
13+
]
14+
}

packages/tinybench/tsconfig.test.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"extends": "./tsconfig.json",
3+
"compilerOptions": {
4+
"types": ["jest", "node"]
5+
},
6+
"include": ["test/**/*.ts", "benches/**/*.ts", "jest.config.ts"]
7+
}

0 commit comments

Comments
 (0)