数据对齐以实现矢量化/高效缓存访问
Data alignment to enable vectorization / efficient cache access
This 书上是这样说的:
For Knights Landing, memory movement is optimal when the data starting
address lies on 64-byte boundaries.
Q1。有没有一种方法可以动态查询 C++ 代码中的处理器,以了解此最佳 n
字节边界对于当前应用程序 运行 所在的处理器而言是什么?这样,代码将是可移植的。
该书进一步指出:
As programmers, we end up with two jobs: (1)align our data and (2)make
sure the compiler knows it is aligned.
(假设我们知道我们的处理器最好让数据从 64 字节边界开始。)
这 "data" 到底是什么?
假设我有一个 class 这样:
class Class1_{
private:
int a;//4 bytes
double b;//8 bytes
std::vector<int> potentially_longish_vector_int;
std::vector<double> potentially_longish_vector_double;
double * potentially_longish_heap_array_double;
public:
//--stuff---//
double * return_heap_array_address() {return potentially_longish_heap_array_double;}
}
假设我也有这样原型的函数:
void func1(Class1_& obj_class1);
void func2(double* array);
即func1
引用了Class1_
的一个对象,func2
被调用为func2(obj_class1.return_heap_array_address());
为了与数据应适当边界对齐的建议保持一致,obj_class1
本身是否应为 64 字节边界对齐以实现 func1()
的高效运行? potentially_longish_heap_array_double
是否应为 64 字节边界对齐以实现 func2()
的高效运行?
对于作为 STL 容器的 class 的其他数据成员的对齐,线程 here 建议如何完成所需的对齐。
Q2。那么,对象本身以及其中的所有数据成员是否需要适当对齐?
一般来说,当您在高速缓存行边界上对齐阵列时,可以最大限度地提高高速缓存利用率,并且还可以使阵列适合任何 SIMD 指令对齐。这是因为 RAM 和 CPU 缓存之间的传输单位是一个缓存行,在现代英特尔 CPUs 上是 64 字节。
但是,增加对齐也可能会浪费内存并降低缓存利用率。通常只有应用程序的关键快速路径上的数据结构可能需要指定增加的对齐方式。
按 {hotness, size} 顺序排列 类 的成员是有意义的,这样最常访问的成员或一起访问的成员位于同一缓存行。
此处的优化objective 是为了减少高速缓存和 TLB 未命中(或者,减少每条指令的周期数/增加每条周期的指令数)。使用大页面可以减少 TLB 未命中。
This 书上是这样说的:
For Knights Landing, memory movement is optimal when the data starting address lies on 64-byte boundaries.
Q1。有没有一种方法可以动态查询 C++ 代码中的处理器,以了解此最佳 n
字节边界对于当前应用程序 运行 所在的处理器而言是什么?这样,代码将是可移植的。
该书进一步指出:
As programmers, we end up with two jobs: (1)align our data and (2)make sure the compiler knows it is aligned.
(假设我们知道我们的处理器最好让数据从 64 字节边界开始。)
这 "data" 到底是什么?
假设我有一个 class 这样:
class Class1_{
private:
int a;//4 bytes
double b;//8 bytes
std::vector<int> potentially_longish_vector_int;
std::vector<double> potentially_longish_vector_double;
double * potentially_longish_heap_array_double;
public:
//--stuff---//
double * return_heap_array_address() {return potentially_longish_heap_array_double;}
}
假设我也有这样原型的函数:
void func1(Class1_& obj_class1);
void func2(double* array);
即func1
引用了Class1_
的一个对象,func2
被调用为func2(obj_class1.return_heap_array_address());
为了与数据应适当边界对齐的建议保持一致,obj_class1
本身是否应为 64 字节边界对齐以实现 func1()
的高效运行? potentially_longish_heap_array_double
是否应为 64 字节边界对齐以实现 func2()
的高效运行?
对于作为 STL 容器的 class 的其他数据成员的对齐,线程 here 建议如何完成所需的对齐。
Q2。那么,对象本身以及其中的所有数据成员是否需要适当对齐?
一般来说,当您在高速缓存行边界上对齐阵列时,可以最大限度地提高高速缓存利用率,并且还可以使阵列适合任何 SIMD 指令对齐。这是因为 RAM 和 CPU 缓存之间的传输单位是一个缓存行,在现代英特尔 CPUs 上是 64 字节。
但是,增加对齐也可能会浪费内存并降低缓存利用率。通常只有应用程序的关键快速路径上的数据结构可能需要指定增加的对齐方式。
按 {hotness, size} 顺序排列 类 的成员是有意义的,这样最常访问的成员或一起访问的成员位于同一缓存行。
此处的优化objective 是为了减少高速缓存和 TLB 未命中(或者,减少每条指令的周期数/增加每条周期的指令数)。使用大页面可以减少 TLB 未命中。