Skip to content

Commit 064d031

Browse files
committed
🧪 test(benchmark): Add benchmarking
1 parent 43cf012 commit 064d031

File tree

4 files changed

+120
-2
lines changed

4 files changed

+120
-2
lines changed

package-lock.json

Lines changed: 51 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@
2727
"module": "./index.js",
2828
"types": "./index.d.ts",
2929
"scripts": {
30+
"bench": "vitest bench --run",
31+
"bench:watch": "vitest bench",
3032
"prebuild": "npm run clean",
31-
"build": "tsc --emitDeclarationOnly -p tsconfig.build.json && sucrase src -d dist --transforms typescript && rimraf -g dist/*.{spec,proof}.js dist/types.{d.js,d.ts} && cpy src/**/*.{js,d.ts} dist && tsc-alias -p tsconfig.build.json && replace-in-file \"/^\\s*\\/\\/ eslint-disable-next-line .+$/mg\" \"\" dist/**/*.js --isRegex && replace-in-file \"/^\\s*\\/\\/ @ts-.+$/mg\" \"\" dist/**/*.js --isRegex && prettier --log-level=silent --print-width 80 --write dist/**/* --ignore-path !dist/**/* && cpy package.json dist && json -I -f dist/package.json -e \"delete this.private; delete this.scripts; delete this.devDependencies\" && cpy README.md dist && cpy screenshot.svg dist && cpy LICENSE dist",
33+
"build": "tsc --emitDeclarationOnly -p tsconfig.build.json && sucrase src -d dist --transforms typescript && rimraf -g dist/*.{proof,spec,bench}.js dist/types.{d.js,d.ts} && cpy src/**/*.{js,d.ts} dist && tsc-alias -p tsconfig.build.json && replace-in-file \"/^\\s*\\/\\/ eslint-disable-next-line .+$/mg\" \"\" dist/**/*.js --isRegex && replace-in-file \"/^\\s*\\/\\/ @ts-.+$/mg\" \"\" dist/**/*.js --isRegex && prettier --log-level=silent --print-width 80 --write dist/**/* --ignore-path !dist/**/* && cpy package.json dist && json -I -f dist/package.json -e \"delete this.private; delete this.scripts; delete this.devDependencies\" && cpy README.md dist && cpy screenshot.svg dist && cpy LICENSE dist",
3234
"clean": "rimraf dist",
3335
"format": "prettier --no-error-on-unmatched-pattern --write **/*.{js,ts,json,md} *.{cjs,mjs,cts,mts}",
3436
"lint": "eslint **/*.{js,ts} *.{cjs,mjs,cts,mts} --no-error-on-unmatched-pattern --report-unused-disable-directives-severity error --max-warnings 0",
@@ -50,6 +52,7 @@
5052
"@vitest/coverage-v8": "^2.1.4",
5153
"@vitest/ui": "^2.1.4",
5254
"cpy-cli": "^5.0.0",
55+
"effect": "^3.10.13",
5356
"eslint": "^8.57.1",
5457
"eslint-config-prettier": "^9.1.0",
5558
"eslint-import-resolver-typescript": "^3.6.3",

src/fib.bench.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* Benchmark for overhead of computationally expensive functions.
3+
*
4+
* Currently the effected version is around 100x (`fibPipe`) to 200x (`fibGen`) slower than the
5+
* non-effected version.
6+
*
7+
* Such overhead should be acceptable for most use-cases, as real-world applications are unlikely to
8+
* execute computationally expensive logic in an effected function.
9+
*
10+
* It is worth noting that tinyeffect’s version using generator syntax is around 20% faster than
11+
* Effect’s version using `Effect.gen`, but the one using pipeline syntax is around 30%~120% slower
12+
* than Effect’s version, which is quite surprising. A further investigation is needed to find out
13+
* why Effect’s version is faster than tinyeffect’s version using pipeline syntax.
14+
*/
15+
16+
import { Effect } from "effect";
17+
import { bench, describe } from "vitest";
18+
19+
import { Effected, effected } from ".";
20+
21+
const fib = (n: number): number => {
22+
if (n <= 1) return n;
23+
return fib(n - 1) + fib(n - 2);
24+
};
25+
26+
const fibGen = (n: number): Effected<never, number> =>
27+
effected(function* () {
28+
if (n <= 1) return n;
29+
return (yield* fibGen(n - 1)) + (yield* fibGen(n - 2));
30+
});
31+
32+
const fibPipe = (n: number): Effected<never, number> => {
33+
if (n <= 1) return Effected.of(n);
34+
return fibPipe(n - 1).map((a) => fibPipe(n - 2).map((b) => a + b));
35+
};
36+
37+
const fibEGen = (n: number): Effect.Effect<number, never, never> =>
38+
Effect.gen(function* () {
39+
if (n <= 1) return n;
40+
return (yield* fibEGen(n - 1)) + (yield* fibEGen(n - 2));
41+
});
42+
43+
const fibEPipe = (n: number): Effect.Effect<number, never, never> => {
44+
if (n <= 1) return Effect.succeed(n);
45+
return fibEPipe(n - 1).pipe(
46+
Effect.flatMap((a) => fibEPipe(n - 2).pipe(Effect.map((b) => a + b))),
47+
);
48+
};
49+
50+
describe("fib(20)", () => {
51+
bench("fib(20)", () => void fib(20));
52+
bench("fibGen(20)", () => void fibGen(20).runSync());
53+
bench("fibPipe(20)", () => void fibPipe(20).runSync());
54+
bench("fibEGen(20)", () => void Effect.runSync(fibEGen(20)));
55+
bench("fibEPipe(20)", () => void Effect.runSync(fibEPipe(20)));
56+
});
57+
58+
describe("fib(30)", () => {
59+
bench("fib(30)", () => void fib(30));
60+
bench("fibGen(30)", () => void fibGen(30).runSync());
61+
bench("fibPipe(30)", () => void fibPipe(30).runSync());
62+
bench("fibEGen(30)", () => void Effect.runSync(fibEGen(30)));
63+
bench("fibEPipe(30)", () => void Effect.runSync(fibEPipe(30)));
64+
});

tsconfig.build.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"outDir": "dist"
77
},
88
"include": ["src"],
9-
"exclude": ["src/**/*.spec.ts", "src/**/*.proof.ts"],
9+
"exclude": ["src/**/*.proof.ts", "src/**/*.spec.ts", "src/**/*.bench.ts"],
1010
"tsc-alias": {
1111
"resolveFullPaths": true
1212
}

0 commit comments

Comments
 (0)