矢量数据如何对齐?

fre*_*low 40 c++ sse vector alignment allocator

如果我想std::vector用SSE 处理数据,我需要16字节对齐.我怎样才能做到这一点?我需要编写自己的分配器吗?或者默认分配器是否已经与16字节边界对齐?

use*_*136 25

您应该使用带std::容器的自定义分配器,例如vector.不记得是谁写了下面的那个,但我用了一段时间它似乎工作(你可能需要_aligned_malloc改为_mm_malloc,取决于编译器/平台):

#ifndef ALIGNMENT_ALLOCATOR_H
#define ALIGNMENT_ALLOCATOR_H

#include <stdlib.h>
#include <malloc.h>

template <typename T, std::size_t N = 16>
class AlignmentAllocator {
public:
  typedef T value_type;
  typedef std::size_t size_type;
  typedef std::ptrdiff_t difference_type;

  typedef T * pointer;
  typedef const T * const_pointer;

  typedef T & reference;
  typedef const T & const_reference;

  public:
  inline AlignmentAllocator () throw () { }

  template <typename T2>
  inline AlignmentAllocator (const AlignmentAllocator<T2, N> &) throw () { }

  inline ~AlignmentAllocator () throw () { }

  inline pointer adress (reference r) {
    return &r;
  }

  inline const_pointer adress (const_reference r) const {
    return &r;
  }

  inline pointer allocate (size_type n) {
     return (pointer)_aligned_malloc(n*sizeof(value_type), N);
  }

  inline void deallocate (pointer p, size_type) {
    _aligned_free (p);
  }

  inline void construct (pointer p, const value_type & wert) {
     new (p) value_type (wert);
  }

  inline void destroy (pointer p) {
    p->~value_type ();
  }

  inline size_type max_size () const throw () {
    return size_type (-1) / sizeof (value_type);
  }

  template <typename T2>
  struct rebind {
    typedef AlignmentAllocator<T2, N> other;
  };

  bool operator!=(const AlignmentAllocator<T,N>& other) const  {
    return !(*this == other);
  }

  // Returns true if and only if storage allocated from *this
  // can be deallocated from other, and vice versa.
  // Always returns true for stateless allocators.
  bool operator==(const AlignmentAllocator<T,N>& other) const {
    return true;
  }
};

#endif
Run Code Online (Sandbox Code Playgroud)

像这样使用它(如果需要,将16改为另一个对齐):

std::vector<T, AlignmentAllocator<T, 16> > bla;
Run Code Online (Sandbox Code Playgroud)

但是,这只能确保内存块std::vector使用的是16字节对齐.如果sizeof(T)不是16的倍数,则某些元素将不会对齐.根据您的数据类型,这可能不是问题.如果Tint(4个字节),则只加载索引为4的倍数的元素.如果是double(8个字节),则只有2的倍数,等等.

真正的问题是如果你使用类T,在这种情况下你必须在类本身中指定你的对齐要求(同样,取决于编译器,这可能是不同的;示例是针对GCC):

class __attribute__ ((aligned (16))) Foo {
    __attribute__ ((aligned (16))) double u[2];
};
Run Code Online (Sandbox Code Playgroud)

我们差不多完成了!如果您使用Visual C++(至少是版本2010),您将无法使用std::vector您指定其对齐的类,因为std::vector::resize.

编译时,如果收到以下错误:

C:\Program Files\Microsoft Visual Studio 10.0\VC\include\vector(870):
error C2719: '_Val': formal parameter with __declspec(align('16')) won't be aligned
Run Code Online (Sandbox Code Playgroud)

您将不得不破解您的stl::vector header文件:

  1. 找到vector头文件[C:\ Program Files\Microsoft Visual Studio 10.0\VC\include\vector]
  2. 找到void resize( _Ty _Val )方法[VC2010上的第870行]
  3. 将其更改为void resize( const _Ty& _Val ).


Max*_*kin 21

C++标准要求分配函数(malloc()operator new())为任何标准类型分配适当对齐的内存.由于这些函数没有作为参数接收对齐要求,因此在实践中它意味着所有分配的对齐是相同的,并且是标准类型与最大对齐要求的对齐,这通常是long double和/或long long(参见boost max_align union).

与标准C++分配函数相比,向量指令(如SSE和AVX)具有更强的对齐要求(对于128位访问是16字节对齐,对于256位访问是32字节对齐).posix_memalign()或者memalign()可用于满足具有更强对齐要求的此类分配.


Dev*_*ull 11

如前所述,您可以使用boost::alignment::aligned_allocator以下内容而不是编写自己的分配器std::vector:

#include <vector>
#include <boost/align/aligned_allocator.hpp>

template <typename T>
using aligned_vector = std::vector<T, boost::alignment::aligned_allocator<T, 16>>;
Run Code Online (Sandbox Code Playgroud)