2015-03-30 62 views
0

假设我有一个非常大的数据结构,它比我硬件的缓存行(见下面的示例)大得多。让我们假设我想在大数据结构上缓存行检索和性能

  1. 读写memb_one_位于第一高速缓存行
  2. 然后我想读,写后位于memb_forty_ 2高速缓存行。
  3. 现在我可能还想读写位于第二缓存行中的成员,即中间行memb_ten_中的成员。这并不总是发生。

所以我需要经常执行第1步和第2步,但不总是第3步。不幸的是,我无法更改结构的布局。

我的问题如下:在步骤1和步骤2之后,是第二个缓存行,即中间的一个从内存中检索到L1?

据我所知,在L1中检索到的缓存行只是通过读/写位于其中的结构成员而“感动”的。这实际上意味着只有一部分结构的实例可以在L1中获得。

如果我的理解是正确的,有没有办法强制所有3个缓存行的请求?我想避免在需要时通过写入第二个缓存行来获取缓存缺失。

如果没有这样的机制,您认为我可以从共享相同缓存的后台线程中受益,并频繁阅读这些实例以保持缓存行“热”吗?该线程永远不会写入,以避免错误的共享效应或过多的数据总线流量。

struct VeryBigStruct 
{ 
    // first cahce line.. 
    int memb_one_; 
    ... 

    // second cahce line.. 
    int memb_ten_; 
    ... 

    // third cache line 
    int memb_forty_; 
    ... 
} 

我在Linux上使用g++ 4.7 and 4.9

回答

1

不,第二个缓存行不能保证在第一个和第三个第一个缓存中。但如果访问频率足够高,它可能就在那里。

如果后台线程运行在与主线程相同的物理内核中,那么后台线程可能只能帮助您将数据存入L1缓存。你可以为你的线程设置CPU亲和力来达到这个效果。

在GCC有一个内置函数预取的内存地址缓存, 它被称为是这样的:

__builtin_prefetch(&your_struct_ptr->memb_ten_, 1, 3); 

或者你可以这样做:

#include <xmmintrin.h> 
... 
_mm_prefetch(&your_struct_ptr->memb_ten_, _MM_HINT_ET0); 

在这里看到:https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html 和这里:https://software.intel.com/en-us/node/524263

[我认为你使用x86或x86-64架构。 ]

+0

@Alexey:非常感谢!我在想,我晚上把这个调用放在一个现有的线程中(在同一个核心上),它试图通过'try_lock'来获取互斥锁。如果try_lock没有成功,它会调用__builtin_prefetch – 2015-03-31 07:27:51

+0

如果先调用Prefetch,那么Prefetch的效果最好,然后在其他某些东西上花费几个CPU周期,让CPU有时间在后台执行请求,然后再回到真正的使用预取数据。 – 2015-03-31 10:19:15

+0

@Akexet:酷信息!非常感谢! – 2015-03-31 10:45:08