diff options
author | Bartek IwaĆczuk <biwanczuk@gmail.com> | 2023-07-17 23:17:28 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-17 21:17:28 +0000 |
commit | 298e4149368b23fee573fa27f1a00e0c50828c8c (patch) | |
tree | 0c19422b12b3d04f944bddfb99c891b6d59c45b0 /cli | |
parent | 4ebe3bdb06a4d539cc8991e1241aa3150100f866 (diff) |
fix(bench): run warmup benchmark to break JIT bias (#19844)
Closes https://github.com/denoland/deno/issues/15277
This commit adds a single "warmup" run of empty function when running
`deno bench`.
This change will break so-called "JIT bias" which makes V8 optimize the
first function
and then bail out of optimization on second function. In essence the
"warmup" function
is getting optimized and then all user benches are bailed out of
optimization.
Diffstat (limited to 'cli')
-rw-r--r-- | cli/js/40_testing.js | 22 | ||||
-rw-r--r-- | cli/ops/bench.rs | 3 | ||||
-rw-r--r-- | cli/tools/bench.rs | 9 |
3 files changed, 34 insertions, 0 deletions
diff --git a/cli/js/40_testing.js b/cli/js/40_testing.js index 3058fcee3..740e950a3 100644 --- a/cli/js/40_testing.js +++ b/cli/js/40_testing.js @@ -685,6 +685,8 @@ function test( }); } +let registeredWarmupBench = false; + // Main bench function provided by Deno. function bench( nameOrFnOrOptions, @@ -695,6 +697,25 @@ function bench( return; } + if (!registeredWarmupBench) { + registeredWarmupBench = true; + const warmupBenchDesc = { + name: "<warmup>", + fn: function warmup() {}, + async: false, + ignore: false, + baseline: false, + only: false, + sanitizeExit: true, + permissions: null, + warmup: true, + }; + warmupBenchDesc.fn = wrapBenchmark(warmupBenchDesc); + const { id, origin } = ops.op_register_bench(warmupBenchDesc); + warmupBenchDesc.id = id; + warmupBenchDesc.origin = origin; + } + let benchDesc; const defaults = { ignore: false, @@ -777,6 +798,7 @@ function bench( const AsyncFunction = (async () => {}).constructor; benchDesc.async = AsyncFunction === benchDesc.fn.constructor; benchDesc.fn = wrapBenchmark(benchDesc); + benchDesc.warmup = false; const { id, origin } = ops.op_register_bench(benchDesc); benchDesc.id = id; diff --git a/cli/ops/bench.rs b/cli/ops/bench.rs index f569a8cbb..0f7509751 100644 --- a/cli/ops/bench.rs +++ b/cli/ops/bench.rs @@ -101,6 +101,8 @@ struct BenchInfo<'s> { group: Option<String>, ignore: bool, only: bool, + #[serde(default)] + warmup: bool, } #[derive(Debug, Serialize)] @@ -128,6 +130,7 @@ fn op_register_bench<'a>( group: info.group, ignore: info.ignore, only: info.only, + warmup: info.warmup, }; let function: v8::Local<v8::Function> = info.function.v8_value.try_into()?; let function = v8::Global::new(scope, function); diff --git a/cli/tools/bench.rs b/cli/tools/bench.rs index f926cec5a..fd686a938 100644 --- a/cli/tools/bench.rs +++ b/cli/tools/bench.rs @@ -95,6 +95,7 @@ pub struct BenchDescription { pub group: Option<String>, pub ignore: bool, pub only: bool, + pub warmup: bool, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -194,6 +195,10 @@ impl BenchReporter for JsonReporter { fn report_output(&mut self, _output: &str) {} fn report_result(&mut self, desc: &BenchDescription, result: &BenchResult) { + if desc.warmup { + return; + } + let maybe_bench = self.0.benches.iter_mut().find(|bench| { bench.origin == desc.origin && bench.group == desc.group @@ -326,6 +331,10 @@ impl BenchReporter for ConsoleReporter { } fn report_result(&mut self, desc: &BenchDescription, result: &BenchResult) { + if desc.warmup { + return; + } + let options = self.options.as_ref().unwrap(); match result { |