CUDA #pragma unrollについてのtips
消えたCUDA関連の旧ブログ記事を復元するひとり Advent Calendar 2024の記事です。
pragma unrollと本記事の内容について
CUDAの最適化の一つとしてfor文のunrollがあると思うのですが,単に
#pragma unroll
for (unsigned i = 0; i < 32; i++) {
// iroiro
}
色々できるよunrolling
そもそもCUDAではnvccがunrollしたほうが良さそうと判断した場合には自動でunrollされます.
これはこれで困る場合もあるかもしれません(本当に?).
こんなときは
#pragma unroll 1
for (unsigned i = 0; i < 32; i++) {
// iroiro
}
この1は何かと言うと,unrollの展開数です.
つまり
#pragma unroll 4
for (unsigned i = 0; i < 32; i++) {
// iroiro
}
この様にunrollは展開数を指定することができます.
forの回数が段数で割り切れなかった場合はPTXになる段階でうまい具合に調整されます(余りの文を最初処理し,残りをループ処理します).
このunrollの展開数ですが,こんな感じでコンパイル時に値が判明している定数でも指定することができます.
void func ( ... ) {
// iroiro
#pragma unroll N
for (unsigned i = 0; i < 32; i++) {
// iroiro
}
// iroiro
}
void func ( ... ) {
// iroiro
#pragma unroll (N + 4)
for (unsigned i = 0; i < 32; i++) {
// iroiro
}
// iroiro
}
おまけ
pragma unrollはコンパイル時にループ回数が分かっていないループにも少し使えます.
そもそもループ回数がコンパイル時に分かっていない場合も少し展開され,デフォルトでの展開のされ方は上の展開方法の展開数4の場合と似ています.
はじめにループ回数を4で割ったあまりを求め,この回数だけfor内の処理を行います.
あとは展開数4のループを回す感じです.
そこでこのコンパイル時にループ回数が分かっていないfor文に対してpragma unrollをすると,同じ様に展開数を指定できたりします(こちらでは端数処理は最後に行われるようです).