首页 > 解决方案 > 在循环中有效地访问 2 个结构数组

问题描述

我有以下 2 个结构数组和一个容器类:

[Serializable]
public struct Pointer {

    public byte State;

}

[Serializable]
public struct Data {

    public uint Hash;
    public byte SomeIndex;
    public byte SomeMoreIndex;
    public byte SomeFurtherIndex;

}

[Serializable]
public class Grid {

    public Pointer[] Cells;
    public Data[] CellData;

}

我打算将它们循环如下:

int index = 0;
for (var i = 0; i < Cells.Length; i++) {
    if (Cells[i] != 0) {
        // access CellData[index], and do more work
        index++;
    }
}

我知道 CPU 缓存未命中如何影响基本级别的性能,因此我尝试按顺序访问这两个数组。但我的问题是:

标签: c#unity3dcpu-cache

解决方案


如果重复速度足够快(即“更多工作”不会破坏缓存),同一 64B 行中的元素仍将具有缓存优势。

如果数组位于不同的页面上,跨行的元素仍应享受硬件预取的好处。

使用 Hash 字段会产生数据依赖性,当然会受到惩罚。这是一个常见A[B[i]]问题,并且有一些学术预取器解决了它(例如,IMP),但据我所知,在商业 CPU 中没有任何问题。如果现有的“顺序”硬件预取在实际使用之前运行得足够远以预取哈希数据足够多的迭代,则应该可以减轻大部分问题,在这种情况下,惩罚将减少为两个背靠背的 L1 访问(或任何缓存级别实现该预取器 - 通常 L1 应该有一个)。请注意,对性能的影响不是直接的,因为不同的迭代是独立的,但是一旦您的未处理缓冲区饱和,内存延迟将转化为内存 BW 限制。


推荐阅读