在缓存中加载时的数据对齐
Data Alignment while loading in Cache
假设 4 字节自然对齐。
struct Node
{
int data;
char c_data;
};
int main() {
int global = 10;
struct Node N;
for ( register int i = 0; i < 10; i++)
cout << global << N.data << endl; }
如果缓存行大小为 16 字节,并且如果我的程序正在循环访问这 2 个变量,那么这些变量将如何出现在缓存中?假设其他一切都是寄存器变量。
在同一缓存行上?
在不同的缓存行上?
如果缓存行相同,每个成员是否会从缓存中的 4 字节对齐地址开始?像全局变量将跨越 [0,3] 和 N 将跨越 [4,7].. 类似的东西?或者,如果结构只有一个字符,它甚至可以从缓存行中的 [5] 开始。
基本上,在缓存中加载数据时,是否根据结构的大小或它的第一个成员考虑对齐?
如何使用缓存主要取决于代码,即您在问题中提到但没有post 的理论循环。循环之前使用的其他变量可能优先,具体取决于分配在何处的变量。即使考虑到特定系统的详细源代码,也很难准确判断会发生什么。
在内存中相邻分配的变量是缓存友好的。基本上应该有一大块相邻分配的变量可以从 RAM 传输到缓存,以便缓存有效。如果您在完全不同的段中有变量,那将给出 "cache misses":也就是说,必须从缓存中丢弃某些内容,而必须从 RAM 中读取其他内容。
例如,如果您有一大块本地的、堆栈分配的变量,将它们全部存储在缓存中可能会有好处。
在你的例子中,global
分配在内存的.data
部分,N
分配在.bss
部分,所以它们根本不相邻并且不会因为这个原因被加载到同一个缓存行中。这意味着在您的情况下,整个缓存讨论甚至都不适用。
如果您改为编写 struct Node N = {1};
,那么可以合理地假设如果在代码中的相同位置使用变量,最终会在 .data
中像这样分配(我我在胡乱猜测):
4 bytes - global
4 bytes - N.data
4 bytes - N.c_data
调整对齐方式以适应 CPU。缓存将只是镜像 RAM,没有什么是 "moved around to suit alignment" - 当变量在 RAM 中分配时,对齐已经被处理了。
然后整个块可能会作为一个整体读入缓存。
假设 4 字节自然对齐。
struct Node
{
int data;
char c_data;
};
int main() {
int global = 10;
struct Node N;
for ( register int i = 0; i < 10; i++)
cout << global << N.data << endl; }
如果缓存行大小为 16 字节,并且如果我的程序正在循环访问这 2 个变量,那么这些变量将如何出现在缓存中?假设其他一切都是寄存器变量。
在同一缓存行上?
在不同的缓存行上?
如果缓存行相同,每个成员是否会从缓存中的 4 字节对齐地址开始?像全局变量将跨越 [0,3] 和 N 将跨越 [4,7].. 类似的东西?或者,如果结构只有一个字符,它甚至可以从缓存行中的 [5] 开始。
基本上,在缓存中加载数据时,是否根据结构的大小或它的第一个成员考虑对齐?
如何使用缓存主要取决于代码,即您在问题中提到但没有post 的理论循环。循环之前使用的其他变量可能优先,具体取决于分配在何处的变量。即使考虑到特定系统的详细源代码,也很难准确判断会发生什么。
在内存中相邻分配的变量是缓存友好的。基本上应该有一大块相邻分配的变量可以从 RAM 传输到缓存,以便缓存有效。如果您在完全不同的段中有变量,那将给出 "cache misses":也就是说,必须从缓存中丢弃某些内容,而必须从 RAM 中读取其他内容。
例如,如果您有一大块本地的、堆栈分配的变量,将它们全部存储在缓存中可能会有好处。
在你的例子中,global
分配在内存的.data
部分,N
分配在.bss
部分,所以它们根本不相邻并且不会因为这个原因被加载到同一个缓存行中。这意味着在您的情况下,整个缓存讨论甚至都不适用。
如果您改为编写 struct Node N = {1};
,那么可以合理地假设如果在代码中的相同位置使用变量,最终会在 .data
中像这样分配(我我在胡乱猜测):
4 bytes - global
4 bytes - N.data
4 bytes - N.c_data
调整对齐方式以适应 CPU。缓存将只是镜像 RAM,没有什么是 "moved around to suit alignment" - 当变量在 RAM 中分配时,对齐已经被处理了。
然后整个块可能会作为一个整体读入缓存。