[VM] Deopt code

const COUNT = Number.parseInt(process.argv[2] || "10");
console.log(`Running ${COUNT} iterations.`);

let value = 0;
export function benchA() {
  value = value === 0 ? 0 : 1;
}
export function benchB() {
  value = value === 0 ? 0 : 2;
}
export function benchC() {
  value = value === 0 ? 0 : 3;
}
export function benchD() {
  value = value === 0 ? 0 : 4;
}

//benchmark('-------------------------- IGNORE --------------------------', benchA);

if (require.main === module) {
  benchmark("A", benchA);
  benchmark("B", benchB);
  benchmark("C", benchC);
  benchmark("D", benchD);
}

/////////////////////

function benchmark(name: string, fn: () => void) {
  console.log("Starting:", name, "...");
  const start = performance.now();
  for (let i = 0; i < COUNT; i++) {
    fn();
  }
  const duration = performance.now() - start;
  console.log(
    "         ",
    name,
    Number((duration / COUNT) * 1000 * 1000).toFixed(3),
    "us"
  );
}

 

For the code above, we got result that benchmark("A", benchA);runs twice as faster than others.

The reason is that modern CPU and Javascript engines helps to optimize the code. It tries to do Branch predicition: it sees that value === 0 ? 0 : 1happens everytimes and it is easily predicatable. 

This allow CPU to inlnie the function to make it run faster

for (let i = 0; i < COUNT; i++) {
    // fn();  // before inline
    value = 0 // after inline
  }

 

But when it comes to run B,C, D benchmark, JS engine see the assumption it made before was wrong, now the has changed. So that it performe deopt operation :

for (let i = 0; i < COUNT; i++) {
    // value = 0 // inline
    fn();  // deopt
  }

that's why, in the end, benchmark A run faster than B,C & D.

 

Fix the deopt issue:

import { createBenchmark } from "./benchmark";
import { benchA, benchB, benchC, benchD } from "./deopt";
const benchmark = createBenchmark("example2");

let timeA = benchmark("A");
while (timeA()) {
  benchA();
}

let timeB = benchmark("B");
while (timeB()) {
  benchB();
}

let timeC = benchmark("C");
while (timeC()) {
  benchC();
}

let timeD = benchmark("D");
while (timeD()) {
  benchD();
}

benchmark.report();

Doing benchmark in four different while loop, so that each while loop can have its own inline function, each they are equaliy fast.

 

posted @ 2023-11-06 15:28  Zhentiw  阅读(13)  评论(0编辑  收藏  举报