rom*_*ric 11 c++ sse memory-alignment avx c++11
我在使用时遇到对齐问题 ymm寄存器,一些代码片段对我来说似乎很好.这是一个最小的工作示例:
#include <iostream>
#include <immintrin.h>
inline void ones(float *a)
{
__m256 out_aligned = _mm256_set1_ps(1.0f);
_mm256_store_ps(a,out_aligned);
}
int main()
{
size_t ss = 8;
float *a = new float[ss];
ones(a);
delete [] a;
std::cout << "All Good!" << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当然,sizeof(float)是4在我的架构(英特尔(R)至强(R)CPU E5-2650 V2 @ 2.60GHz),我与编译gcc使用-O3 -march=native标志.当然,错误会随着未对齐的内存访问而消失,即指定_mm256_storeu_ps.我在xmm寄存器上也没有这个问题,即
inline void ones_sse(float *a)
{
__m128 out_aligned = _mm_set1_ps(1.0f);
_mm_store_ps(a,out_aligned);
}
Run Code Online (Sandbox Code Playgroud)
我做了什么愚蠢的事吗?解决这个问题的方法是什么?
Pet*_*des 14
标准分配器通常仅对齐alignof(max_align_t),通常为16B,例如long double在x86-64 System V ABI中.但是在一些32位ABI中它只有8B,所以它甚至不足以动态分配对齐的__m128向量,你需要超越简单的调用new或malloc.
静态和自动存储很容易:使用 alignas(32) float arr[N];
C++ 17提供了对齐new的协调动态分配,与delete以下
内容兼容:请参阅/和的文档
float * arr = new (std::align_val_t(32)) float[numSteps];newnew[]std::align_val_t
动态分配的其他选项大多与malloc/ 兼容free,而不是 new /delete:
std::aligned_alloc:ISO C++ 17. 主要缺点:尺寸必须是对齐的倍数.例如,这种脑魄要求使得不适合分配未知数量的floats 的64B高速缓存行对齐数组.或者尤其是2M对齐的阵列,以利用透明的大页面.
C版本aligned_alloc已在ISO C11中添加.它可以在一些但不是所有的C++编译器中使用.如cppreference页面所述,当大小不是对齐的倍数(它是未定义的行为)时,C11版本不需要失败,因此许多实现提供了明显的期望行为作为"扩展". 正在讨论解决这个问题,但是现在我不能真正推荐aligned_alloc作为一种可移植的方式来分配任意大小的数组.
此外,评论者报告它在MSVC++中不可用.查看最佳跨平台方法,以获得对齐内存以实现适用#ifdef于Windows的内存.但AFAIK没有Windows对齐分配函数,可以生成与标准兼容的指针free.
posix_memalign:POSIX 2001的一部分,而不是任何ISO C或C++标准.笨重的原型/界面相比aligned_alloc.我已经看到gcc生成指针的重载,因为它不确定缓冲区中的存储没有修改指针.(因为posix_memalign传递了指针的地址.)因此,如果使用它,将指针复制到另一个C++变量中,该变量的地址没有传递到函数外部.
#include <stdlib.h>
int posix_memalign(void **memptr, size_t alignment, size_t size); // POSIX 2001
void *aligned_alloc(size_t alignment, size_t size); // C11 (and ISO C++17)
Run Code Online (Sandbox Code Playgroud)
_mm_malloc:可在任何可用的平台上_mm_whatever_ps使用,但您无法将指针传递给它free.在许多C和C++实现上_mm_free并且free是兼容的,但不保证它是可移植的.(与其他两个不同,它将在运行时失败,而不是编译时.)在Windows上的MSVC上,_mm_malloc使用_aligned_malloc,与之不兼容free; 它在实践中崩溃了.在C++ 11及更高版本中:使用alignas(32) float avx_array[1234]作为struct/class成员的第一个成员(或直接在plain数组上),因此该类型的静态和自动存储对象将具有32B对齐.std::aligned_storage文档中有一个这种技术的例子来解释std::aligned_storage它的作用.
这实际上不适用于动态分配的存储(如a std::vector<my_class_with_aligned_member_array>),请参阅使std :: vector分配对齐的内存.
在C++ 17中,可能有一种方法可以使用对齐的new std::vector.TODO:了解具体方法.
最后,最后一个选项非常糟糕,它甚至不是列表的一部分:分配一个更大的缓冲区并添加p+=31; p&=~31ULL适当的转换.太多的缺点(难以释放,浪费内存)值得讨论,因为在支持Intel _mm256内在函数的每个平台上都可以使用对齐分配功能.但是,甚至有一些图书馆功能可以帮助你做到这一点,IIRC.
使用这种技术可能需要使用_mm_free而不是free可能存在于_mm_malloc普通老年人之上的可能性malloc.
内存管理有两种内在函数._mm_malloc像标准malloc一样运行,但它需要一个额外的参数来指定所需的对齐方式.在这种情况下,32字节对齐.使用此分配方法时,必须通过相应的_mm_free调用释放内存.
float *a = static_cast<float*>(_mm_malloc(sizeof(float) * ss , 32));
...
_mm_free(a);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4468 次 |
| 最近记录: |