g++ 如何对齐内存以确保对齐从缓存行的开头开始?

How does g++ align memory to make sure the alignment starts at the beginning of a cacheline?

本文关键字:对齐 缓存 开始 开头 确保 何对齐 内存 g++      更新时间:2023-10-16

我在 g++ 中读到我们可以做到:

struct foo {
int a, b, c;
} __attribute__((__aligned__(64)));

因此结构 foo 的大小为 64 ---通常是缓存行的大小。 当我们需要访问此缓存行时,CPU 可以一次性加载 Foo。

这是否意味着 CPU 可以在任何内存地址---不一定是整数 64 的内存地址从 L2 加载 foo?

想象 foo 在内存中的地址类似于 0xFFFF3,CPU 是否需要读取两个缓存行来加载 foo?

谁能为我澄清这一点?

PS:我在 CentOS 6.2 上使用 g++ 64 位

对齐与内存中结构地址的起始位置有关。如果结构的大小小于或等于 64 字节,那么您是对的,您的结构将适合一行缓存,但如果结构大于 64 字节,则始终为 false。

对齐仅与该类型的局部或全局变量的起始位置相关。当您编写试图爆发处理器功率的算法时,请优化与 64 字节对齐的数据访问,以便您可以处理 64 个连续字节而不会出现任何缓存错误。顺便说一下,当数据对齐到 64 个字节时,编译器的优化器会创建更优化的代码。

一个快速测试是创建一个小程序,并生成对齐和未对齐的汇编程序代码,并比较您获得的汇编程序。(例如访问局部向量的小循环),启用优化器(-O2 或 -O3)。

PS:使用堆时,您可以自己分配

struct foo *myFoo = (malloc(size(struct foo)+15) + 15) & (~ 0x0f);

似乎有两个问题被掩盖为一个问题。我会尽力回答他们。

首先,对齐问题。一般来说,C++编译器对缓存行等一无所知(或假装一无所知)。相反,它只是确保此类型的所有对象都与 64 字节边界对齐(前提是它们本身更小或大小等于 64)。这是编译器作业完成的地方。

现在,我们需要关注 CPU 行为。由于缓存行大小为 64 字节,当对象在 64 字节边界上对齐时,我们确定加载整个对象时将位于缓存中。因此,对对象成员的访问保证由 L1 缓存提供,而不是更昂贵的方式(例如 L2)。

由于 L2是一个大得多的缓存,因此没有理由尝试对齐代码以遵守 L2 边界。