缓存友好代码的示例

时间:2014-08-15 19:46:18

标签: c++ caching

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。

以上示例是否缓存友好代码?

3 个答案:

答案 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

如果您不仅abc,还有d - z,那么您的示例也会对缓存不友好aa - az,也许还有一些。 (你需要走多远取决于缓存的复杂程度 - 它有多少关联方式等等。)

你对Thomas Matthews&#39;码?

答案 2 :(得分:0)

您应该信任编译器优化工作(当然还能实现优化);它可能与CPU cache处理得很好(可能通过发布适当的prefetch instructions)。

有时您可以通过builtins或pragma提示编译器。例如,对于x86-64上的GCC,您可以 - 谨慎地使用__builtin_prefetch。通常不值得努力(如果你滥用它,性能会受到影响)。请参阅this answer相关问题。