大数据结构上的缓存行检索和性能
cache line retrieval and performance on large data structure
假设我有一个非常大的数据结构,它比我的硬件缓存行大得多(请参见下面的示例)。假设我想
- 读写
memb_one_
位于第一个缓存行
- 然后我想读写
memb_forty_
位于2缓存行之后。
- 现在我可能还想读取和写入位于第二个缓存行中的成员,即中间行中的成员
memb_ten_
。这并不总是发生。
所以我需要经常执行第 1 步和第 2 步,但并不总是执行第 3 步。不幸的是我无法更改结构的布局。
我的问题如下:在第 1 步和第 2 步之后,第二个缓存行(即中间的那个)是否完全从内存中检索到 L1?
据我所知,在 L1 中检索到的缓存行只是 'touched' by reading/writing 位于其中的结构成员。这基本上意味着 L1 中只有结构实例的一部分可用。
如果我的理解是正确的,有没有强制要求所有3个缓存行的请求?我想通过在需要时写入第二个缓存行来避免缓存未命中。
如果没有这样的机制,您认为我可以从使用共享同一缓存的后台线程并频繁读取这些实例以保持缓存行中受益吗'hot'?此线程永远不会写入以避免错误的共享效果或过多的数据总线流量。
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
。
不,在您触摸第一行和第三行之后,第二个缓存行不能保证在 L1 缓存中。但它可能存在,如果访问频率足够高的话。
如果后台线程与主线程在同一物理内核中运行,它可能只会帮助将数据放入 L1 缓存。您可以为您的线程设置 CPU affinity 以实现此效果。
在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 架构。 ]
假设我有一个非常大的数据结构,它比我的硬件缓存行大得多(请参见下面的示例)。假设我想
- 读写
memb_one_
位于第一个缓存行 - 然后我想读写
memb_forty_
位于2缓存行之后。 - 现在我可能还想读取和写入位于第二个缓存行中的成员,即中间行中的成员
memb_ten_
。这并不总是发生。
所以我需要经常执行第 1 步和第 2 步,但并不总是执行第 3 步。不幸的是我无法更改结构的布局。
我的问题如下:在第 1 步和第 2 步之后,第二个缓存行(即中间的那个)是否完全从内存中检索到 L1?
据我所知,在 L1 中检索到的缓存行只是 'touched' by reading/writing 位于其中的结构成员。这基本上意味着 L1 中只有结构实例的一部分可用。
如果我的理解是正确的,有没有强制要求所有3个缓存行的请求?我想通过在需要时写入第二个缓存行来避免缓存未命中。
如果没有这样的机制,您认为我可以从使用共享同一缓存的后台线程并频繁读取这些实例以保持缓存行中受益吗'hot'?此线程永远不会写入以避免错误的共享效果或过多的数据总线流量。
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
。
不,在您触摸第一行和第三行之后,第二个缓存行不能保证在 L1 缓存中。但它可能存在,如果访问频率足够高的话。
如果后台线程与主线程在同一物理内核中运行,它可能只会帮助将数据放入 L1 缓存。您可以为您的线程设置 CPU affinity 以实现此效果。
在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 架构。 ]