数据对齐以实现矢量化/高效缓存访问

Posted

技术标签:

【中文标题】数据对齐以实现矢量化/高效缓存访问【英文标题】:Data alignment to enable vectorization / efficient cache access 【发布时间】:2018-11-23 16:39:39 【问题描述】:

This book 说:

对于 Knights Landing,内存移动在数据开始时是最佳的 地址位于 64 字节边界上。

第一季度。有没有办法在 C++ 代码中动态查询处理器,以了解当前运行应用程序的处理器的最佳n-byte 边界是多少?这样,代码就可以移植了。

这本书进一步指出:

作为程序员,我们最终要完成两项工作:(1) 对齐数据和 (2) 制作 确保编译器知道它是对齐的。

(假设对于下面的问题,我们知道我们的处理器让数据从 64 字节边界开始是最优的。)

这个“数据”到底是什么?

假设我有这样的课程:

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 容器的类的其他数据成员的对齐,线程 here 建议如何完成所需的对齐。

第二季度。那么,对象本身以及其中的所有数据成员是否需要适当对齐?

【问题讨论】:

检查对齐要求的常用方法是做 cpuid + table 检查对齐....非常手动。 对于对齐问题,我认为(因为它是数据对齐)主要用于向量操作,您希望它们以没有“剥离”开头,因此您希望数组为 64 字节(或位??)对齐。 显示你想要向量化的算法。 至于 Q1:根据评论,这似乎是在谈论缓存行大小。在那种情况下相关:***.com/questions/39680206/… @Tryer 不,这不是一个好主意,因为这样每个变量将占用整个缓存行,并且一次只能缓存其中的几个,所以实际上你的内存要多得多访问会导致缓存未命中。 【参考方案1】:

一般来说,当您在缓存行边界上对齐阵列时,可以最大限度地提高缓存利用率,并且也使阵列适合任何 SIMD 指令对齐。这是因为 RAM 和 CPU 高速缓存之间的传输单位是高速缓存行,在现代 Intel CPU 上是 64 字节。

但是,增加对齐也可能会浪费内存并降低缓存利用率。通常,只有应用程序的关键快速路径上的数据结构可能需要指定增加的对齐方式。

按照 hotness, size 顺序排列类的成员是有意义的,以便最常访问的成员或一起访问的成员驻留在同一缓存行上。

此处的优化目标是减少高速缓存和 TLB 未命中(或减少每指令周期数/增加每周期指令数)。使用大页面可以减少 TLB 未命中。

【讨论】:

是的。那么,在 64 字节边界上启动一个对象以及其中的每个数据成员是否更好?有些函数可能要访问int adouble b 有些函数可能要访问堆分配的数组。 @Tryer 这取决于对象及其成员的使用方式。 是的,如果有太多“空洞”,关于缓存利用率的好处。

以上是关于数据对齐以实现矢量化/高效缓存访问的主要内容,如果未能解决你的问题,请参考以下文章

干货,使用布隆过滤器实现高效缓存!

如何高效地玩转多级缓存

Java 高效并发

lamp架构nginx高效缓存

lamp架构nginx高效缓存

lamp架构nginx高效缓存