____cacheline_aligned_in_smp
宏?它有助于在访问结构时提高性能吗?如果是,那么如何实现的?____cacheline_aligned_in_smp
宏?它有助于在访问结构时提高性能吗?如果是,那么如何实现的?____cacheline_aligned
指示编译器在特定架构下,将结构体或变量实例化到对应L1缓存行的开头地址,即使其L1缓存行对齐。____cacheline_aligned_in_smp
类似,但只有在内核以SMP配置(即使用选项CONFIG_SMP
)编译时才会实际进行L1缓存行对齐。这些定义在文件include/linux/cache.h中。
这些定义对于不通过某个分配器动态分配的变量(和数据结构)而是全局编译器分配的变量非常有用(使用动态内存分配器可以实现特定对齐内存的分配)。
将变量对齐到缓存线的原因是在SMP系统中通过硬件缓存一致性机制管理这些变量的缓存到缓存传输,以便它们的移动不会隐含地发生在其他变量移动时。这适用于性能关键代码,其中一个人预计多个CPU(核心)访问变量时会产生争用。在这种情况下,通常要避免的问题是虚假共享。
变量从缓存线的起始位置开始的内存是实现此目的的一半;还需要“仅”将应一起移动的变量“打包”在一起。一个例子是变量数组,其中数组的每个元素只由一个CPU(核心)访问:
struct my_data {
long int a;
int b;
} ____cacheline_aligned_in_smp cpu_data[ NR_CPUS ];
这种定义将要求编译器(在内核的SMP配置中)使每个CPU的结构体从缓存行边界开始。编译器将会隐式地在每个CPU的结构体后面分配额外的空间,以便下一个CPU的结构体也能从缓存行边界开始。
另一种方法是用缓存行大小的虚拟、未使用的字节填充数据结构:
struct my_data {
long int a;
int b;
char dummy[L1_CACHE_BYTES];
} cpu_data[ NR_CPUS ];
在这种情况下,只有虚拟的、未使用的数据会被无意地移动,而每个 CPU 实际访问的数据仅会因为缓存容量不足而在缓存和内存之间移动。
在任何缓存(dcache或icache)中,每个缓存行都是64字节(在x86架构中)。需要进行缓存对齐以避免缓存行的虚假共享。如果缓存行在全局变量之间共享(在内核中更常见),如果其中一个处理器在其缓存中更改了一个全局变量,则将该缓存行标记为脏。在剩余的CPU缓存行中,它变成了陈旧的条目,需要从内存中刷新并重新获取。这可能导致缓存行未命中,需要更多的CPU周期。这会降低系统的性能。请记住,这适用于全局变量。大多数内核数据结构使用此方法以避免缓存行未命中。
L1_CACHE_BYTES
,它由每个体系结构定义。