我有以下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高速缓存未命中如何从根本上影响性能,因此我尝试按顺序访问这两个阵列。但是我的问题是:
CellData[index]
之后,我使用其Hash
访问Dictionary<Hash, ItemClass>
,会进一步使循环本身的性能复杂化吗?byte[]
而不是Pointer[]
),因为网格可能很大并且可能稀疏,这是否公平?权衡?答案 0 :(得分:0)
如果重复速度足够快(即“更多工作”不会破坏缓存),则同一64B行中的元素仍将具有缓存优势。
如果数组位于不同的页面上,则跨行的元素仍应享有硬件预取的好处。
使用Hash字段将创建数据依赖关系,并且当然会受到惩罚。这是一个常见的A[B[i]]
问题,有一些学术上的预取者可以解决(例如IMP),但据我所知,在商用CPU中什么也没有。如果现有的“顺序”硬件预取能够在实际运行之前运行得足够长,从而可以预取哈希数据足够的迭代次数,则可以缓解其中的大部分情况,在这种情况下,代价将减少为两个背对背的L1访问(或任何高速缓存)级别会实现该预取器-通常L1应该有一个。
请注意,对性能的影响不是直接的,因为不同的迭代是独立的,但是一旦使未处理的缓冲区饱和,内存延迟将转化为内存带宽限制。