c++ - 使用 std::vector<Vec8d> 是好是坏(性能方面)

标签 c++ simd vector-class-library

我正在使用 Agner Fog 的 vector 类库在我的应用程序中使用 SIMD 指令(特别是 AVX)。由于最好使用数组结构数据结构来轻松使用 SIMD,因此我经常使用:

std::vector<Vec8d> some_var;

甚至

struct some_struct {
    std::vector<Vec8d> a;
    std::vector<Vec8d> b;
}

考虑到 std::vector 内部 Vec8d* 数组实际上可能未对齐,我想知道这是否不好(性能方面甚至完全错误?)?

最佳答案

我通常会使用 vector<double>和标准 SIMD 加载/存储内在函数来访问数据。这避免将接口(interface)和接触它的所有代码绑定(bind)到特定的 SIMD vector 宽度和包装器库。您仍然可以将大小填充为 8 double 的倍数,这样您就不必在循环中包含清理处理。

但是,您可能希望为该 vector<double> 使用自定义分配器所以你可以让它对齐你的 double 。不幸的是,即使该分配器的底层内存分配与 new/delete 兼容,它也将具有与 vector<double> 不同的 C++ 类型。所以如果你在其他地方使用它,你不能自由地将它分配/移动到这样的容器。

我担心如果您确实想要访问个人 double你的 vector 元素,做Vec8vec[i][j]可能会导致比 operator[] 更糟糕的 asm(例如,加载 SIMD,然后从 VCL 的 vecdouble[i*8 + j] 进行洗牌或存储/重新加载) (可能只是一个 vmovsd ),特别是如果这意味着您需要编写一个嵌套循环,否则您将不需要它。

avec.load (&doublevec[8]);应该生成(几乎或完全)与 avec = Vec8vec[1]; 相同的 asm .如果数据在内存中,编译器将需要使用加载指令来加载它。它有什么“类型”并不重要;类型是 C++ 的东西,而不是 asm 的东西; SIMD vector 只是对内存中某些字节的重新解释。


但如果这是说服 C++17 编译器按 64 位对齐动态数组的最简单方法,那么它可能值得考虑。如果/当移植到 ARM NEON 或 SVE 时仍然令人讨厌并且会导致 future 的痛苦,因为我上次检查时 Agner 的 VCL 仅包装 x86 SIMD。甚至移植到 AVX2 也很糟糕。

更好的方法可能是自定义分配器(我认为 Boost 已经编写了一些),您可以将其用作 std::vector<double, aligned_allocator<64>> 之类的第二个模板参数。 .这也与 std::vector<double> 类型不兼容如果你想传递它并将它分配给其他vector<> s,但至少它没有专门绑定(bind)到 AVX512。

如果您使用 C++17 编译器(因此 std::vector 不遵守 alignof(T) > alignof(max_align_t) 即 16),那么甚至不要考虑一下;当像 GCC 和 Clang 这样的编译器使用 vmovapd 时它会出错(需要对齐)存储 __m512d .

您需要使数据保持一致;与当前 AVX512 CPU (Skylake-X) 上的 AVX2 相比,64 字节对齐对 AVX512 的影响更大。

MSVC(我认为是 ICC)出于某种原因选择始终使用未对齐的加载/存储指令(除了将加载折叠到内存源操作数中,即使使用遗留的 SSE 指令,因此需要 16 字节对齐),即使在编译时对齐时也是如此保证存在。我想这就是它恰好适合您的原因。

对于 SoA 数据布局,您可能希望所有数组共享一个通用大小,并使用 aligned_alloc (与 free 兼容,而不是 delete )或类似管理 double * 尺寸的东西成员。不幸的是,没有支持 aligned_realloc 的标准对齐分配器,所以你总是必须复制,即使你的数组​​后面有空闲的虚拟地址空间,一个不糟糕的 API 可以让你的数组在不复制的情况下增长。谢谢,C++。

关于c++ - 使用 std::vector<Vec8d> 是好是坏(性能方面),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66062171/

相关文章:

c - SSE加载和添加

c++ - SIMD 与否 SIMD - 跨平台

simd - SIMD 内在函数的引用手册/教程?

c++ - 使用 Agner 的 vector 类库编译多架构代码

c++ - OpenGL NURBS 曲面

c++ - 如何根据对的第二个元素对对的 vector 进行排序?

c++ - 我是否需要在 C++ 线程中使用整数锁定

c++ - 如何让我的类(class)免受 C++ 中的 "auto value = copy of proxy"地雷的影响?