gpt4 book ai didi

JavaScript 数组性能在 13k-16k 元素时下降

转载 作者:行者123 更新时间:2023-12-05 00:25:00 25 4
gpt4 key购买 nike

我正在对数组的创建和编辑性能进行一些性能测试,并注意到在大约 13k-16k 元素的数组周围有一些奇怪的特征。
下图显示了创建数组并从中读取每个元素所需的时间(在这种情况下,将其中的数字相加)。 capacitypush与创建数组的方式有关:

  • 容量 : const arr = new Array(length)然后 arr[i] = data
  • : const arr = [];然后 arr.push(data)

  • Time for creation of array based on length
    Time for operations on array based on length
    如您所见,在这两种情况下,创建一个数组并从中读取,与减少 1k 个元素的每个元素的性能相比,性能降低了大约 2-3 倍。
    使用 push 方法创建数组时,与预先使用正确容量创建数组相比,此跳转发生得更早一些。我认为发生这种情况是因为,当推送到已经处于最大容量的阵列时,添加的额外容量超过了实际需要的额外容量(以避免很快再次添加新容量),并且达到了较慢性能路径的阈值早些时候。
    如果您想查看代码或自己测试: github
    我的问题,为什么性能下降到 13k-16k 左右?
    对我来说,在 v8 中似乎对较大的数组进行了不同的处理,从大约 13k-16k 元素开始以提高它们的性能,但是截止点(至少在我的代码中)有点太早了,所以在优化之前性能下降了任何好处。
    您可以看到性能改进在大约 500 个元素后下降,并在下降后再次上升。
    可悲的是,我找不到任何有关此的信息。
    另外,如果您碰巧知道为什么在使用容量创建和通过推送求和时会出现这些峰值,请随时告诉我:)
    编辑:
    正如@ggorlen 所建议的那样,我在另一台机器上运行相同的测试以排除缓存作为所见行为的原因(使用不同的、较弱的 CPU 和更少的 RAM)。结果似乎非常相似。
    Time for creation of array based on length on a different machine
    Time for operations on array based on length on a different machine
    编辑:
    我使用 --allow-natives-syntax 运行节点使用 %DebugPrint(array); 调试记录创建的数组的标志,希望看到不同数组长度之间的差异,但除了长度和内存地址之外,它们看起来都一样。这是一个例子:

    // For array created with capacity
    DebugPrint: 000002CB8E1ACE19: [JSArray]
    - map: 0x035206283321 <Map(HOLEY_SMI_ELEMENTS)> [FastProperties]
    - prototype: 0x036b86245b19 <JSArray[0]>
    - elements: 0x02cb8e1ace39 <FixedArray[1]> [HOLEY_SMI_ELEMENTS]
    - length: 1
    - properties: 0x0114c5d01309 <FixedArray[0]>
    - All own properties (excluding elements): {
    00000114C5D04D41: [String] in ReadOnlySpace: #length: 0x03f907ac1189 <AccessorInfo> (const accessor descriptor), location: descriptor
    }

    0000035206283321: [Map]
    - type: JS_ARRAY_TYPE
    - instance size: 32
    - inobject properties: 0
    - elements kind: HOLEY_SMI_ELEMENTS
    - unused property fields: 0
    - enum length: invalid
    - back pointer: 0x035206283369 <Map(PACKED_SMI_ELEMENTS)>
    - prototype_validity cell: 0x03f907ac15e9 <Cell value= 1>
    - instance descriptors #1: 0x009994a6aa31 <DescriptorArray[1]>
    - transitions #1: 0x009994a6a9d1 <TransitionArray[4]>Transition array #1:
    0x0114c5d05949 <Symbol: (elements_transition_symbol)>: (transition to PACKED_DOUBLE_ELEMENTS) -> 0x0352062832d9 <Map(PACKED_DOUBLE_ELEMENTS)>

    - prototype: 0x036b86245b19 <JSArray[0]>
    - constructor: 0x031474c124e9 <JSFunction Array (sfi = 000003CECD93C3A9)>
    - dependent code: 0x0114c5d01239 <Other heap object (WEAK_FIXED_ARRAY_TYPE)>
    - construction counter: 0


    // For array created with push
    DebugPrint: 000003B09882CE19: [JSArray]
    - map: 0x02ff94f83369 <Map(PACKED_SMI_ELEMENTS)> [FastProperties]
    - prototype: 0x0329b3805b19 <JSArray[0]>
    - elements: 0x03b09882ce39 <FixedArray[17]> [PACKED_SMI_ELEMENTS]
    - length: 1
    - properties: 0x03167aa81309 <FixedArray[0]>
    - All own properties (excluding elements): {
    000003167AA84D41: [String] in ReadOnlySpace: #length: 0x02094f941189 <AccessorInfo> (const accessor descriptor), location: descriptor
    }

    000002FF94F83369: [Map]
    - type: JS_ARRAY_TYPE
    - instance size: 32
    - inobject properties: 0
    - elements kind: PACKED_SMI_ELEMENTS
    - unused property fields: 0
    - enum length: invalid
    - back pointer: 0x03167aa81599 <undefined>
    - prototype_validity cell: 0x02094f9415e9 <Cell value= 1>
    - instance descriptors #1: 0x00d25122aa31 <DescriptorArray[1]>
    - transitions #1: 0x00d25122aa01 <TransitionArray[4]>Transition array #1:
    0x03167aa85949 <Symbol: (elements_transition_symbol)>: (transition to HOLEY_SMI_ELEMENTS) -> 0x02ff94f83321 <Map(HOLEY_SMI_ELEMENTS)>

    - prototype: 0x0329b3805b19 <JSArray[0]>
    - constructor: 0x009ff8a524e9 <JSFunction Array (sfi = 0000025A84ABC3A9)>
    - dependent code: 0x03167aa81239 <Other heap object (WEAK_FIXED_ARRAY_TYPE)>
    - construction counter: 0

    编辑
    从大小为 13_994 的数组变为 13_995 时,求和的性能下降:
    enter image description here

    最佳答案

    (这里是 V8 开发人员。)
    TL;DR:这里没什么可看的,只是产生令人困惑的伪影的微基准。

    这里有两个单独的效果:

  • 在 16384 个元素处发生的情况是,后备存储被分配在“大对象空间”中,这是针对大对象优化的堆的特殊区域。在启用了指针压缩的 Chrome 中,发生这种情况的元素数量恰好是禁用指针压缩的 Node 中的两倍。其结果是分配本身不能再作为内联指令序列直接在优化代码中发生;相反,它是对 C++ 函数的调用;除了有一些调用开销之外,它还是一个更通用的实现,因此速度有点慢(可能有一些优化潜力,不确定)。所以这不是太早开始的优化。这只是巨大的物体所付出的代价。它只会在(微小的微基准测试?)分配许多大型数组然后对它们没有太多作用的情况下突出显示。
  • 在 13995 个元素处发生的是特定函数 sum ,那是优化编译器启动到“OSR”(堆栈上替换)函数的时候,即函数在运行时被优化代码替换。无论何时发生,这都是一定的一次性成本,并且很快就会收回成本。因此,将其视为特定时间的特定命中是典型的微基准测试工件,与实际使用无关。 (例如,如果您在同一进程中多次运行测试,则不会再看到 13995 处的步骤。如果您以多种尺寸运行它,则可能不需要 OSR(因为该函数可以下次调用时切换到优化代码)并且这种一次性成本根本不会发生。)
  • 关于JavaScript 数组性能在 13k-16k 元素时下降,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73015250/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com