template<size_t size>
class Objects{
std::array<int,size> a;
std::array<int,size> b;
std::array<int,size> c;
void update(){
for (size_t i = 0; i < size; ++i){
c[i] = a[i] + b[i];
}
}
};
我正在收集有关如何编写缓存友好代码的信息,因为我读了几篇文章,但我仍然不了解基础知识。
我在大多数示例中都使用了上面编写的代码,但对我来说,这根本不是缓存友好的。
对我来说,内存布局应如下所示
aaaabbbbcccc
并在第一个循环中访问
[a]aaa[b]bbb[c]ccc
如果我理解正确,cpu会预取内存附近的元素。我不确定这种方法有多聪明,但我认为它是原始的,只是取出了第n个最近的元素。
问题是[a]aaa[b]bbb[c]ccc
根本不会按顺序访问元素。所以它可能会获取下一个&#39; 3&#39;元素a[aaa]bbbbcccc
这对下一个很好,因为它将是缓存命中但不是b。
以上示例是否缓存友好代码?
答案 0 :(得分:2)
我建议你使用一系列结构:
struct Cache_Item
{
int a;
int b;
int c;
};
Cache_Item cache_line[size];
for (unsigned int i = 0; i < size; ++i)
{
cache_line[i].c = cache_line[i].a + cache_line[i].b;
}
结构安排允许所有使用的变量在高速缓存行中彼此相邻或非常接近。
在你的数组方法中,元素b [0]理想地位于[size]的位置,因此它们是size
个项目。这可能意味着它们位于不同的缓存行上。结果位置c [0]位于[size + size],这意味着它可能是2个缓存行。
答案 1 :(得分:1)
您的代码并不是特别不友好。它一次需要三个活动缓存行而不是一个,但这并不是太多问题。如果不是
,你的代码将更加缓存不友好std::array<int,size> a;
你有
std::array<struct { int x; char description[5000]; }, size> a;
因为那时CPU必须从x
的数千个字节(你的循环从不使用)中挑选出单独的description
。
如果您不仅a
,b
和c
,还有d
- z
,那么您的示例也会对缓存不友好aa
- az
,也许还有一些。 (你需要走多远取决于缓存的复杂程度 - 它有多少关联方式等等。)
你对Thomas Matthews&#39;码?
答案 2 :(得分:0)
您应该信任编译器优化工作(当然还能实现优化);它可能与CPU cache处理得很好(可能通过发布适当的prefetch instructions)。
有时您可以通过builtins或pragma提示编译器。例如,对于x86-64上的GCC,您可以 - 谨慎地使用__builtin_prefetch。通常不值得努力(如果你滥用它,性能会受到影响)。请参阅this answer相关问题。