昨日の記事でx86用のコードでheapから(newで)確保されたメモリのアライメントが16バイト境界になってなくて大変だという話を書いたのだが、その続き。
std::stack<StateInfo>である。StateInfoはstructで、alignas(16)がついている(or メンバーの定義にalignas(16)がついているものがある)とする。
ここにpush()ときに内部的にヒープからメモリが割り当てられるようで、これもalignasを無視しやがるので、どうにかしたい。
しかし、std::stackのカスタムアロケーターを書くの、難しくてさっぱりわからん。std::stackって、内部的にはstd::dequeなんだっけ?てか、こんなalignasを無視するような糞コンテナ要らないんだけど…。調べる気にもならん…。
push()とtop()さえあればいいので、とりあえず以下のようにしておいたのだが…。
1 2 3 4 5 6 7 |
template void push(const T& t) { auto ptr = (T*)_mm_malloc(sizeof(T), alignof(T)); *ptr = t; container.push(ptr); } T& top() const { return *container.top(); } ~aligned_stack() { while (container.size()) { auto ptr = container.top(); _mm_free(ptr); container.pop(); } } private: std::stack }; |
「それ、XXX使えば1行で書けるよ!」というようなエクセレントなコメント、お待ちしております。
追記 2020/05/30
C++17では、newのときにメンバ変数のクラス定義につけてるalignasが考慮されるようになったので、本記事の処理は、不要になりました。
Boost.Alignを使いますが、
http://www.boost.org/doc/libs/1_60_0/doc/html/align/tutorial.html#align.tutorial.aligned_allocator
こんな感じに書けます。
http://melpon.org/wandbox/permlink/B9O8ZOp07dLkxyAy
Σ(゚∀゚ノ)ノキャー かっちょいい!!
でもこのためだけにBoostを使いたくないので、他に方法があれば…。
現段階で適用可能な方法では無いですが、
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0035r0.html この辺がいい感じに解決していつの日か標準に入るかもしれません。。。しばらく先になりそうですが。
カスタムアロケータの実装例が以下にあります。
http://stackoverflow.com/questions/12942548/making-stdvector-allocate-aligned-memory
posix_memalign, free 関数の代わりに _mm_malloc, _mm_free を使えば御所望のものになります。
コードの行数は増えちゃいますが…
std::stack<StateInfo, std::deque > state_info;
と使えます。
おお!ありがとうございます。custom allocatorの書き方わからなかったので参考になりました。しかし行数結構長くなりますねー。std::allocator継承してallocateのところだけ書き換えるようなことは出来そうもないし…。困ったもんです。
カスタムアロケータ(とカスタムイテレータ)は要求される typedef, メンバ関数、比較演算子などを全て用意しないといけないのでどうしても長くなってしまうんですよね。
標準で個別のメンバのみカスタム可能なアロケータが入ってくれると嬉しいのですが…
すいません、使用例の部分がエスケープされてしまいました。
redboltz さんがhttp://melpon.org/wandbox/permlink/B9O8ZOp07dLkxyAy
で紹介されているコードのアロケータの部分を置き変えるだけです。
x86を切り捨ててx64に決め打ちするのはダメなんですか?
一開発者としてはx64、AVX512のみを開発対象としたいのは山々ですが、動かない人が出てくるのも残念ですし…。