From a9b73bd4163c499fe10c1184817c1121689c4436 Mon Sep 17 00:00:00 2001 From: Dan Vanderkam Date: Thu, 1 Feb 2024 14:54:52 -0500 Subject: [PATCH] perf: Add benchmark and speedup (#37) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #36 at least to some extent! Throwing a non-`Error` subclass makes the Fibonacci benchmark ~6x faster: -Time elapsed (ms): 60459 +Time elapsed (ms): 10152 The difference for the 40th Fibonacci number is even more dramatic, ~2000s → 200s. Still slower than jlox's 27 seconds, but at least within an order of magnitude. Thanks to https://github.com/davidhfriedman/jslox for the inspiration. --- bench/fib.lox | 10 ++++++++++ bench/fib33.lox | 10 ++++++++++ package.json | 1 + src/interpreter.ts | 6 ++++-- 4 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 bench/fib.lox create mode 100644 bench/fib33.lox diff --git a/bench/fib.lox b/bench/fib.lox new file mode 100644 index 0000000..b28655b --- /dev/null +++ b/bench/fib.lox @@ -0,0 +1,10 @@ +fun fib(n) { + if (n < 2) return n; + return fib(n - 1) + fib(n - 2); +} + +var before = clock(); +print fib(40); +var after = clock(); +print "Time elapsed (ms):"; +print after - before; \ No newline at end of file diff --git a/bench/fib33.lox b/bench/fib33.lox new file mode 100644 index 0000000..5174edd --- /dev/null +++ b/bench/fib33.lox @@ -0,0 +1,10 @@ +fun fib(n) { + if (n < 2) return n; + return fib(n - 1) + fib(n - 2); +} + +var before = clock(); +print fib(33); +var after = clock(); +print "Time elapsed (ms):"; +print after - before; diff --git a/package.json b/package.json index f5c440b..fd626df 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "README.md" ], "scripts": { + "benchmark": "pnpm --silent run repl bench/fib33.lox", "build": "tsup", "coverage": "pnpm test -- --coverage --no-watch", "format": "prettier \"**/*\" --ignore-unknown", diff --git a/src/interpreter.ts b/src/interpreter.ts index 4aab1b2..5415e6f 100644 --- a/src/interpreter.ts +++ b/src/interpreter.ts @@ -8,10 +8,9 @@ import { CurrencyValue, LoxValue, isCurrency } from "./lox-value.js"; import { runtimeError } from "./main.js"; import { Token } from "./token.js"; -export class ReturnCall extends Error { +export class ReturnCall { value: LoxValue; constructor(value: LoxValue) { - super(); this.value = value; } } @@ -286,6 +285,9 @@ export class Interpreter { case "return": { const value = stmt.value && this.evaluate(stmt.value); + // While it's bad practice to throw something other than an Error subclass, + // doing so here result in a ~5x speedup on the Fibonacci benchmark. + // eslint-disable-next-line @typescript-eslint/no-throw-literal throw new ReturnCall(value); }