Skip to content

Commit 60fc89b

Browse files
committed
feat!: update V8 flags and force optimization
1 parent c8110bd commit 60fc89b

File tree

7 files changed

+41
-35
lines changed

7 files changed

+41
-35
lines changed

packages/benchmark.js-plugin/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ async function runBenchmarks({
196196
if (isAsync) {
197197
await optimizeFunction(benchPayload);
198198
await mongoMeasurement.start(uri);
199+
global.gc?.();
199200
await (async function __codspeed_root_frame__() {
200201
Measurement.startInstrumentation();
201202
await benchPayload();

packages/core/src/introspection.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ export const getV8Flags = () => {
1212
"--predictable",
1313
"--predictable-gc-schedule",
1414
"--interpreted-frames-native-stack",
15+
"--allow-natives-syntax",
16+
"--expose-gc",
17+
"--no-concurrent-sweeping",
18+
"--max-old-space-size=4096",
1519
];
1620
if (nodeVersionMajor < 18) {
1721
flags.push("--no-randomize-hashes");

packages/core/src/optimization.ts

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,30 @@
1-
const skipOptimization = process.env.CODSPEED_FORCE_OPTIMIZATION !== "true";
2-
31
export const initOptimization = () => {
4-
if (!skipOptimization) {
5-
// eslint-disable-next-line @typescript-eslint/no-var-requires
6-
require("v8").setFlagsFromString("--allow-natives-syntax");
7-
}
2+
// eslint-disable-next-line @typescript-eslint/no-var-requires
3+
require("v8").setFlagsFromString("--allow-natives-syntax");
84
};
95

106
export const optimizeFunction = async (fn: CallableFunction) => {
11-
if (skipOptimization) {
12-
// warmup V8 symbols generation of the performance map
13-
await fn();
14-
return;
15-
}
167
// Source: https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#optimization-killers
17-
await fn(); //Fill type-info
18-
await fn(); // 2 calls are needed to go from uninitialized -> pre-monomorphic -> monomorphic
8+
// a total of 7 calls seems to be the sweet spot
9+
await fn();
10+
await fn();
11+
await fn();
12+
await fn();
13+
await fn();
14+
await fn();
1915
eval("%OptimizeFunctionOnNextCall(fn)");
2016
await fn(); // optimize
2117
};
2218

2319
export const optimizeFunctionSync = (fn: CallableFunction) => {
24-
if (skipOptimization) {
25-
// warmup V8 symbols generation of the performance map
26-
fn();
27-
return;
28-
}
2920
// Source: https://github.com/petkaantonov/bluebird/wiki/Optimization-killers#optimization-killers
30-
fn(); //Fill type-info
31-
fn(); // 2 calls are needed to go from uninitialized -> pre-monomorphic -> monomorphic
21+
// a total of 7 calls seems to be the sweet spot
22+
fn();
23+
fn();
24+
fn();
25+
fn();
26+
fn();
27+
fn();
3228
eval("%OptimizeFunctionOnNextCall(fn)");
3329
fn(); // optimize
3430
};

packages/tinybench-plugin/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ export function withCodSpeed(bench: Bench): Bench {
7070
await task.opts.beforeEach?.call(task);
7171

7272
await mongoMeasurement.start(uri);
73+
global.gc?.();
7374
await (async function __codspeed_root_frame__() {
7475
Measurement.startInstrumentation();
7576
await task.fn();

packages/vitest-plugin/src/__tests__/index.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ describe("codSpeedPlugin", () => {
8989
"--predictable",
9090
"--predictable-gc-schedule",
9191
"--interpreted-frames-native-stack",
92+
"--allow-natives-syntax",
93+
"--expose-gc",
94+
"--no-concurrent-sweeping",
95+
"--max-old-space-size=4096",
9296
"--no-scavenge-task",
9397
],
9498
},

packages/vitest-plugin/src/__tests__/runner.test.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,22 @@ const coreMocks = vi.hoisted(() => {
1818
};
1919
});
2020

21+
global.eval = vi.fn();
22+
2123
vi.mock("@codspeed/core", async (importOriginal) => {
2224
const mod = await importOriginal<typeof import("@codspeed/core")>();
2325
return { ...mod, ...coreMocks };
2426
});
2527

2628
console.log = vi.fn();
2729

28-
vi.mock("vitest/suite", () => ({
29-
getBenchFn: vi.fn(),
30-
// wrapping the value in vi.fn(...) here will not work for some reason
31-
getHooks: () => ({
32-
beforeAll: [],
33-
beforeEach: [],
34-
afterEach: [],
35-
afterAll: [],
36-
}),
37-
}));
30+
vi.mock("vitest/suite", async (importOriginal) => {
31+
const actual = await importOriginal<typeof import("vitest/suite")>();
32+
return {
33+
...actual,
34+
getBenchFn: vi.fn(),
35+
};
36+
});
3837
const mockedGetBenchFn = vi.mocked(getBenchFn);
3938

4039
describe("CodSpeedRunner", () => {
@@ -62,7 +61,7 @@ describe("CodSpeedRunner", () => {
6261
"packages/vitest-plugin/src/__tests__/runner.test.ts::test bench"
6362
);
6463
expect(coreMocks.Measurement.startInstrumentation).toHaveBeenCalledTimes(1);
65-
expect(benchFn).toHaveBeenCalledTimes(2);
64+
expect(benchFn).toHaveBeenCalledTimes(8);
6665
expect(coreMocks.Measurement.stopInstrumentation).toHaveBeenCalledTimes(1);
6766
expect(coreMocks.mongoMeasurement.stop).toHaveBeenCalledTimes(1);
6867
expect(console.log).toHaveBeenCalledWith(
@@ -116,7 +115,7 @@ describe("CodSpeedRunner", () => {
116115
"packages/vitest-plugin/src/__tests__/runner.test.ts::nested suite::test bench"
117116
);
118117
expect(coreMocks.Measurement.startInstrumentation).toHaveBeenCalledTimes(1);
119-
expect(benchFn).toHaveBeenCalledTimes(2);
118+
expect(benchFn).toHaveBeenCalledTimes(8);
120119
expect(coreMocks.Measurement.stopInstrumentation).toHaveBeenCalledTimes(1);
121120
expect(coreMocks.mongoMeasurement.stop).toHaveBeenCalledTimes(1);
122121
expect(console.log).toHaveBeenCalledWith(

packages/vitest-plugin/src/runner.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,23 @@ import { getBenchFn, getHooks } from "vitest/suite";
1515
type SuiteHooks = ReturnType<typeof getHooks>;
1616

1717
function getSuiteHooks(suite: Suite, name: keyof SuiteHooks) {
18-
return getHooks(suite)[name];
18+
return getHooks(suite)?.[name] ?? [];
1919
}
2020

2121
export async function callSuiteHook<T extends keyof SuiteHooks>(
2222
suite: Suite,
2323
currentTask: Task,
2424
name: T
2525
): Promise<void> {
26-
if (name === "beforeEach" && suite.suite) {
26+
if (name === "beforeEach" && suite?.suite) {
2727
await callSuiteHook(suite.suite, currentTask, name);
2828
}
2929

3030
const hooks = getSuiteHooks(suite, name);
3131

3232
await Promise.all(hooks.map((fn) => fn()));
3333

34-
if (name === "afterEach" && suite.suite) {
34+
if (name === "afterEach" && suite?.suite) {
3535
await callSuiteHook(suite.suite, currentTask, name);
3636
}
3737
}
@@ -69,6 +69,7 @@ async function runBench(benchmark: Benchmark, currentSuiteName: string) {
6969

7070
await callSuiteHook(benchmark.suite, benchmark, "beforeEach");
7171
await mongoMeasurement.start(uri);
72+
global.gc?.();
7273
await (async function __codspeed_root_frame__() {
7374
Measurement.startInstrumentation();
7475
// @ts-expect-error we do not need to bind the function to an instance of tinybench's Bench

0 commit comments

Comments
 (0)