[VM] Deopt code

发布时间 2023-11-06 15:33:42作者: Zhentiw
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.