首页 > 其他分享 >[V8] Object Shapes & Inline Caching

[V8] Object Shapes & Inline Caching

时间:2023-11-11 21:12:37浏览次数:36  
标签:const age Object value Shapes person V8 HC array

Benchmark:

查看代码
import {createBenchmark} from './benchmark';

const ARRAY_SIZE = 10000;
const array1 = [];  // {value,prop_0}, {value,prop_0}, {value,prop_0}, {value,prop_0},
const array2 = [];  // {value,prop_0}, {value,prop_1}, {value,prop_0}, {value,prop_1},
const array3 = [];  // {value,prop_0}, {value,prop_1}, {value,prop_2}, {value,prop_0},
const array4 = [];  // {value,prop_0}, {value,prop_1}, {value,prop_2}, {value,prop_3},
const array5 = [];
const array6 = [];
const array7 = [];
const array10 = [];
const array100 = [];
const array1000 = [];
const array10000 = [];

for (let i = 0; i < ARRAY_SIZE; i++) {
  array1.push({value: 0, [uniqueName(i, 1)]: false});
  array2.push({value: 0, [uniqueName(i, 2)]: false});
  array3.push({value: 0, [uniqueName(i, 3)]: false});
  array4.push({value: 0, [uniqueName(i, 4)]: false});
  array5.push({value: 0, [uniqueName(i, 5)]: false});
  array6.push({value: 0, [uniqueName(i, 6)]: false});
  array7.push({value: 0, [uniqueName(i, 7)]: false});
  array10.push({value: 0, [uniqueName(i, 10)]: false});
  array100.push({value: 0, [uniqueName(i, 100)]: false});
  array1000.push({value: 0, [uniqueName(i, 1000)]: false});
  array10000.push({value: 0, [uniqueName(i, 10000)]: false});
}
function uniqueName(index: number, shapesCount: number): string {
  return 'prop_' + (index % shapesCount);
}

(function doBenchmarks(benchmark) {
  let sum = 0;
  (function benchmark1(array, timer) {
    while (timer()) {
      for (let i = 0; i < array.length; i++) {
        sum += array[i].value;
      }
    }
  })(array1, benchmark('1'));

  (function benchmark2(array, timer) {
    while (timer()) {
      for (let i = 0; i < array.length; i++) {
        sum += array[i].value;
      }
    }
  })(array2, benchmark('2'));

  (function benchmark3(array, timer) {
    while (timer()) {
      for (let i = 0; i < array.length; i++) {
        sum += array[i].value;
      }
    }
  })(array3, benchmark('3'));

  (function benchmark4(array, timer) {
    while (timer()) {
      for (let i = 0; i < array.length; i++) {
        sum += array[i].value;
      }
    }
  })(array4, benchmark('4'));

  (function benchmark5(array, timer) {
    while (timer()) {
      for (let i = 0; i < array.length; i++) {
        sum += array[i].value;
      }
    }
  })(array5, benchmark('5'));

  (function benchmark6(array, timer) {
    while (timer()) {
      for (let i = 0; i < array.length; i++) {
        sum += array[i].value;
      }
    }
  })(array6, benchmark('6'));

  (function benchmark7(array, timer) {
    while (timer()) {
      for (let i = 0; i < array.length; i++) {
        sum += array[i].value;
      }
    }
  })(array7, benchmark('7'));

  (function benchmark10(array, timer) {
    while (timer()) {
      for (let i = 0; i < array.length; i++) {
        sum += array[i].value;
      }
    }
  })(array10, benchmark('10'));

  (function benchmark100(array, timer) {
    while (timer()) {
      for (let i = 0; i < array.length; i++) {
        sum += array[i].value;
      }
    }
  })(array100, benchmark('100'));

  (function benchmark1000(array, timer) {
    while (timer()) {
      for (let i = 0; i < array.length; i++) {
        sum += array[i].value;
      }
    }
  })(array1000, benchmark('1000'));

  (function benchmark10000(array, timer) {
    while (timer()) {
      for (let i = 0; i < array.length; i++) {
        sum += array[i].value;
      }
    }
  })(array10000, benchmark('10000'));

  benchmark.report();
})(createBenchmark('example3'));

 

All we did in benchmark function is create branch of array, for each array, the number array1array2 means how many object shape inside array:

const array1 = [];  // {value,prop_0}, {value,prop_0}, {value,prop_0}, {value,prop_0},
const array2 = [];  // {value,prop_0}, {value,prop_1}, {value,prop_0}, {value,prop_1},
const array3 = [];  // {value,prop_0}, {value,prop_1}, {value,prop_2}, {value,prop_0},
const array4 = [];  // {value,prop_0}, {value,prop_1}, {value,prop_2}, {value,prop_3},

 

This is the result of benchmark:

Somehow we can see that the first array1runs 13.589us, but array10000runs 75071.458us, there is 55 times difference.

What's going on? why is so?

 

As we can see that each array has different shape, but the value of props are the same. So why the object shape has such big impact of the performance?

We can see that No4 & 5 is one big jump of number

also, 1000 & 10000 is another huge jump, what's the reason behind it?

 

Hidden class

(() => {
  interface Person {
    name: string;
    age: number;
  }

  type HiddenClass = any[];
  //const person: Person = { name: "Jack", age: 32 };
  const person_hc_0 = [null, "name", "age"];
  const person: [HiddenClass, ...any] = [person_hc_0, "Jack", 32];

  // console.log("Name:", person.name, "age:", person.age);
  const person_HC = person[0];
  const person_name = person[person_HC.indexOf("name")];
  const person_age = person[person_HC.indexOf("age")];
  console.log("Name:", person_name, "age:", person_age);
})();

When we try to access object prop, VM will create hidden class, and get hash index of the prop, in order to read the value.

 

Now let's analysis the follow code:

(() => {
  interface Person {
    name: string;
    age: number;
  }

  const people: Person[] = [
    { name: "Jack", age: 32 },
    { name: "Mary", age: 30 },
  ];

  let avgAge: number = 0;

  for (let i = 0; i < people.length; i++) {
    avgAge += people[i].age;
  }

  avgAge /= people.length;

  console.log("Average age:", avgAge);
})();

When we try to sum up age in the for loop, what is actually happening in VM

 

Inline cache

(() => {
  interface Person {
    name: string;
    age: number;
  }

  type HiddenClass = any[];

  const person_HC_0 = [null, "name", "age"];
  // const people: Person[] = [
  //   { name: "Jack", age: 32 },
  //   { name: "Mary", age: 30 },
  // ];
  const people: [HiddenClass, ...any][] = [
    [person_HC_0, "Jack", 32],
    [person_HC_0, "Mary", 30],
  ];

  let avgAge: number = 0;

  for (let i = 0; i < people.length; i++) {
    // avgAge += people[i].age;
    const person = people[i];
    const person_HC = person[0];
    const person_age = person[person_HC.indexOf("age")];
    avgAge += person_age;
  }

  avgAge /= people.length;

  console.log("Average age:", avgAge);
})();

For this code, compiler will always see the same inline cache, therefore the performance it good.

 

For the following code:

(() => {
  interface Person {
    name: string;
    age: number;
  }

  type HiddenClass = any[];

  const person_HC_0 = [null, "name", "age"];
  const person_HC_1 = [null, "name", "age", "school"];
  const person_HC_2 = [null, "age", "name"];
  // const people: Person[] = [
  //   { name: "Jack", age: 32 },
  //   { name: "Mary", age: 30, school: 'MIT'},
  //   { age: 31, name: "Jain"},
  // ];
  const people: [HiddenClass, ...any][] = [
    [person_HC_0, "Jack", 32],
    [person_HC_1, "Mary", 30, "MIT"],
    [person_HC_2, 30, "Jain"],
  ];

  let avgAge: number = 0;

  for (let i = 0; i < people.length; i++) {
    // avgAge += people[i].age;
    const person = people[i];
    const person_HC = person[0];
    const person_age = person[person_HC.indexOf("age")];
    avgAge += person_age;
  }

  avgAge /= people.length;

  console.log("Average age:", avgAge);
})();

Although we have three different hidden class, but everytime we only use one of the hidden class, so the performance is also good.

 

Now if inside for loop, everytime we use a different hidden class as following:

(() => {
  interface Person {
    name: string;
    age: number;
  }

  type HiddenClass = any[];

  const person_HC_0 = [null, "name", "age"];
  const person_HC_1 = [null, "name", "age", "school"];
  const person_HC_2 = [null, "age", "name"];
  // const people: Person[] = [
  //   { name: "Jack", age: 32 },
  //   { name: "Mary", age: 30, school: 'MIT'},
  //   { age: 31, name: "Jain"},
  // ];
  const people: [HiddenClass, ...any][] = [
    [person_HC_0, "Jack", 32],
    [person_HC_1, "Mary", 30, "MIT"],
    [person_HC_2, 30, "Jain"],
  ];

  let avgAge: number = 0;

  for (let i = 0; i < people.length; i++) {
    // avgAge += people[i].age;
    const person = people[i];
    const person_HC = person[0];
    const person_age =
      person[
        person_HC == person_HC_0
          ? 2
          : person_HC == person_HC_1
          ? 2
          : person_HC == person_HC_2
          ? 1
          : person_HC.indexOf("age")
      ];
    avgAge += person_age;
  }

  avgAge /= people.length;

  console.log("Average age:", avgAge);
})();

 

You can see the lookup condiiton here:

      person[
        person_HC == person_HC_0
          ? 2
          : person_HC == person_HC_1
          ? 2
          : person_HC == person_HC_2
          ? 1
          : person_HC.indexOf("age")
      ];

It turn out that compiler willing to do this up to 4 times. That's why up to 4 times, it was fast, but the 5th, it becomes slow.

 

But why 1000 & 10000 has such big differece?

It is because, then doing prop lookup person_HC.indexOf("age"), VM using has map, the lenght is upto 1024, if it's over this length, then no optimization can be done.

 

标签:const,age,Object,value,Shapes,person,V8,HC,array
From: https://www.cnblogs.com/Answer1215/p/17824381.html

相关文章

  • 对象定义 Object.create Object.defineProperty
    <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="width=device-......
  • webgoat _v8.1全流程通关
    1.1(A1)SQLInjection(intro)概念 本课程介绍了什么是结构化查询语言(SQL),以及如何操纵它以执行开发人员原始意图之外的任务。 目标 用户将对SQL的工作原理和用途有基本的了解。 用户将对SQL注入有基本的了解,以及它们的工作原理。 用户将展示对以下内容的知识: ......
  • 在Objective-C中,我如何测试对象的类型?
    内容来自DOChttps://q.houxu6.top/?s=在Objective-C中,我如何测试对象的类型?我需要测试对象是否是NSString或UIImageView类型。我该如何实现?是否有一种类似于“isoftype”的方法可以使用?如果你的对象是myObject,并且你想测试它是否为NSString类型,代码如下:[myObjecti......
  • typeof只能检测数据类型,而不能检测从数据类型中派生的其他类型,数组为object派生对象,所
    typeof[]返回值为objecttypeof只能检测数据类型,而不能检测从数据类型中派生的其他类型,数组为object派生对象,所以依然返回objecttypeof判断引用类型数据,除了function以外都会判断成为objectfunctionfn(){console.log(1);}conso......
  • JavaSE(十二)-Object类
    文章目录1.Object类2.Object类常用方法2.1.equals方法3.==和equals的区别3.1.==3.2.equals()方法的使用4.toString方法5.hashCode()方法1.Object类在JDK中提供一个Object类,它是类层次结构的根类,每个类都直接或间接基础自该类,所有对象(包括数组)都实现了这个类的方法。如果......
  • Object类
          ......
  • EF报错:Unable to create an object of type 'XXXXXXX'. For the different patterns s
    这个是在EF迁移的时候报错: 解决方案:修改你的MyDbcontext:  代码如下:publicclassStoreDbContexttFactory:IDesignTimeDbContextFactory<‘你的类名’>{public‘你的类名’CreateDbContext(string[]args){varoptionsBuilder=newDbContextOptionsBuilder<‘......
  • FS2957 降压恒压芯片内置120V功率管36V48V60V72V80v降压5V
    随着科技的不断进步,电子设备在我们的生活中越来越普及,而电源管理芯片作为电子设备中的重要组成部分,也得到了广泛的应用。今天,我们要介绍的是一款具有高性价比的FS2957降压恒压芯片,它内置120V功率管,适用于36V、48V、60V、72V、80V的降压5V输出。FS2957降压恒压芯片采用专利的电流模......
  • NodeJS系列(15)- TypeScript (二) | 对象类型 (Object Types)
    在“NodeJS系列(14)-TypeScript(一)|安装TypeScript、常用类型”里,我们简单介绍了TypeScript的安装配置,讲解和演示了TypeScript常用类型。本文继续介绍TypeScript对象类型(ObjectTypes)。TypeScript:https://www.typescriptlang.org/(中文版:https://ts.nodejs.cn/)Micro......
  • Windows ObjectType Hook 之 SecurityProcedure
    1、背景  ObjectTypeHook是基于ObjectType的一种深入的Hook,比起常用的SSDTHook更为深入。  有关ObjectType的分析见文章《Windows驱动开发学习记录-ObjectTypeHook之ObjectType结构相关分析》。  这里进行的Hook为其中之一的SecurityProcedure。文章实......