読者です 読者をやめる 読者になる 読者になる

アラインされたstd::vector

SSEやAVXを利用して処理を高速化する際に、メモリ領域がアラインされている必要があります。

アラインされた領域を確保するだけであれば_mm_mallocで可能ですが、_mm_freeを自分で呼ぶ必要があります。

今回はstd::vectorでアラインされた領域を確保できるようにしたいと思います。

IsAligned

まず第一にメモリがアラインされているか確認する関数が必要です。

中身は至って簡単で、アドレス値がNで割り切れれば、NByteでアラインされています。

bool IsAligned(void* p, int n) 
{ 
    return (int)p % n == 0; 
}


AlignedAllocator

std::vectorには独自のアロケータを指定できます。

そこで、アラインされたメモリを確保するアロケータを定義します。

allocate、deallocate以外はほぼ定型文です。(テンプレート引数が型のみであれば、rebindは必要ありません)

template <class T, std::size_t N>
struct AlignedAllocator
{
    using value_type = T;
    AlignedAllocator() {}
    template<class U> AlignedAllocator(const AlignedAllocator<U, N>&) {}
    template<class U> bool operator == (const AlignedAllocator<U, N>&) { return true; }
    template<class U> bool operator != (const AlignedAllocator<U, N>&) { return false; }
    template<class U> struct rebind { using other = AlignedAllocator<U, N>; };

    T* allocate(const size_t n) 
    { 
        return (T*)_mm_malloc(n * sizeof(T), N); 
    }
    void deallocate(T* p, size_t) 
    { 
        _mm_free(p); 
    }
};


利用方法

下記のように利用すると、アラインされたstd::vectorが作成できます。

std::vector<T, AlignedAllocator<T, 16>> vector_aligned16(1);
IsAligned(vector_aligned16.data(), 16); // true

std::vector<T, AlignedAllocator<T, 128>> vector_aligned128(1);
IsAligned(vector_aligned128.data(), 128); // true