6. さらに並列度を上げるには?

gpuTranspose2カーネルはメモリバンド幅が制約になっているようであると指摘されているので、メモリバンド幅の解析を実行する。

gpuTranspose2カーネルはメモリバンド幅が性能を制約している可能性が高いという指摘であるので、メモリバンド幅の解析を行う

グローバルメモリをアクセスするアドレスのアライメント(128バイト境界に合っているか)やアクセスパターン(連続アドレスか飛び飛びか)などが利用できるメモリバンド幅に大きく影響する。58行目(ここでは58行目と言われても分からないが、 NVVPを動かしている場合は、指摘の行をクリックすると、この次の図のように、その付近のソースが表示される)のコードは、1回のL2キャッシュアクセスに32回のトランザクションが発生している。理想的な4トランザクション/アクセスに比べてトランザクション数が多いのが、メモリバンド幅が低い原因であるという指摘である。

58行目のコードで、1回のL2キャッシュのアクセスに32回のトランザクションが発生しているのが、メモリバンド幅が低い原因という指摘

指摘をクリックして58行目を表示すると、out[i * rows + j] = in[j * cols + i];という行である。このコードは、行方向にアクセスする場合は連続アドレスとなるが、列方向にアクセスする場合は、飛び飛びのアクセスとなってしまう。

58行目付近のソースコードを表示したところ

NVIDIAのGPUはSIMTという実行モデルを使っている。SIMTでは、グリッド単位で実行を行う。グリッドに含まれるすべてのスレッドは同じカーネルを実行するが、SMへの割り付けはスレッドブロック単位で行われる。

スレッドブロックの中の32スレッドをまとめたものをワープと呼ぶ。スレッドブロックの中ではスレッドに一連の番号が付けられており、番号順に32スレッドをまとめてワープにしている。この同一ワープの中の32スレッドは同じ命令を同時に実行する。

スレッドブロックの中のスレッドは、32スレッド単位にまとめられて並列に実行される。この32スレッドのまとまりをワープと呼ぶ

概念的なモデルとしては、ワープごとにプログラムカウンタがあり、次の命令が存在する。この次の命令は32個の実行ユニットに発行される。32個の実行ユニットは、それぞれが独立したレジスタセットを持ち、それぞれが異なるオペランドに対して、同一の演算を行う。そして、それぞれが演算結果を生成する。つまり、ワープに含まれる32スレッドは独立に実行される。

そして、すべてのスレッドで命令が実行されるまで、この操作を繰り返す。ただし、これは概念的なモデルであり、実際のハードウェアがこの通りに動いているとは限らない。

ワープごとにプログラムカウンタがあり、次々と命令を実行するモデル