独自のメモリ管理はアロケータ自作が便利
AVXを少しずつ触り始めたのだが、面倒だと感じていることの一つにアラインメントをそろえなければいけないこと。いや、必ずしも必要ないが揃っていないとloadやstoreが別命令になるので重くなるのは自明なので最初からそろえた方がいいに決まっている(そもそもSIMDを選択する時点で爪に火を灯す程の高速化が必要な状況なはず)
windowsなら_aligned_malloc、_aligned_freeというアラインメントをそろえて確保する命令があるのを知った。これを使えば万事OKなわけだが、vectorやスマポで慣れた私には今更メモリの自前管理なんてとても出来るわけもなく・・・。というわけで思いついたのがアロケータを自作すること。大変かなぁと思ったけどよくよく考えたら凄く簡単だった。デフォルトのアロケータ(newとdelete)をコピペしてallocateとdeallocateを少し書き換えるだけ。
template <class T, size_t alignment > class AlignedAllocator { //・・・省略 //メモリ確保 pointer allocate( size_type num, const void* /*p*/ ){ return allocate(num); } pointer allocate( size_type num ) { return (pointer)_aligned_malloc( num * sizeof(value_type), alignment ); } //メモリ開放 void deallocate(pointer p, size_type /*num*/ ) { _aligned_free( p ); } };
たったこれだけで済んだ。簡単で助かった。使い方は至って普通で、vectorの第二テンプレート引数に渡すだけ。あとは普通のvectorの様に扱えば特に意識する必要はない。
struct Float8{ float val[8]; }; std::vector< Float8, AlignedAllocator< Float8, 32 > > data;
これでAVX実装が捗る(^^)