1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-30 16:40:57 -05:00

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.
This commit is contained in:
Bartek Iwańczuk 2023-07-17 23:17:28 +02:00
parent bbaab3b21c
commit d267eaa3b9
No known key found for this signature in database
GPG key ID: 0C6BCDDC3B3AD750
3 changed files with 34 additions and 0 deletions

View file

@ -685,6 +685,8 @@ function test(
}); });
} }
let registeredWarmupBench = false;
// Main bench function provided by Deno. // Main bench function provided by Deno.
function bench( function bench(
nameOrFnOrOptions, nameOrFnOrOptions,
@ -695,6 +697,25 @@ function bench(
return; 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; let benchDesc;
const defaults = { const defaults = {
ignore: false, ignore: false,
@ -777,6 +798,7 @@ function bench(
const AsyncFunction = (async () => {}).constructor; const AsyncFunction = (async () => {}).constructor;
benchDesc.async = AsyncFunction === benchDesc.fn.constructor; benchDesc.async = AsyncFunction === benchDesc.fn.constructor;
benchDesc.fn = wrapBenchmark(benchDesc); benchDesc.fn = wrapBenchmark(benchDesc);
benchDesc.warmup = false;
const { id, origin } = ops.op_register_bench(benchDesc); const { id, origin } = ops.op_register_bench(benchDesc);
benchDesc.id = id; benchDesc.id = id;

View file

@ -101,6 +101,8 @@ struct BenchInfo<'s> {
group: Option<String>, group: Option<String>,
ignore: bool, ignore: bool,
only: bool, only: bool,
#[serde(default)]
warmup: bool,
} }
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
@ -128,6 +130,7 @@ fn op_register_bench<'a>(
group: info.group, group: info.group,
ignore: info.ignore, ignore: info.ignore,
only: info.only, only: info.only,
warmup: info.warmup,
}; };
let function: v8::Local<v8::Function> = info.function.v8_value.try_into()?; let function: v8::Local<v8::Function> = info.function.v8_value.try_into()?;
let function = v8::Global::new(scope, function); let function = v8::Global::new(scope, function);

View file

@ -95,6 +95,7 @@ pub struct BenchDescription {
pub group: Option<String>, pub group: Option<String>,
pub ignore: bool, pub ignore: bool,
pub only: bool, pub only: bool,
pub warmup: bool,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@ -194,6 +195,10 @@ impl BenchReporter for JsonReporter {
fn report_output(&mut self, _output: &str) {} fn report_output(&mut self, _output: &str) {}
fn report_result(&mut self, desc: &BenchDescription, result: &BenchResult) { fn report_result(&mut self, desc: &BenchDescription, result: &BenchResult) {
if desc.warmup {
return;
}
let maybe_bench = self.0.benches.iter_mut().find(|bench| { let maybe_bench = self.0.benches.iter_mut().find(|bench| {
bench.origin == desc.origin bench.origin == desc.origin
&& bench.group == desc.group && bench.group == desc.group
@ -326,6 +331,10 @@ impl BenchReporter for ConsoleReporter {
} }
fn report_result(&mut self, desc: &BenchDescription, result: &BenchResult) { fn report_result(&mut self, desc: &BenchDescription, result: &BenchResult) {
if desc.warmup {
return;
}
let options = self.options.as_ref().unwrap(); let options = self.options.as_ref().unwrap();
match result { match result {