なぜ、nBlocksとnThreadsがあるのか

このようにシェブロン表記を使えば、GPUで動作するN×N個の多数のスレッドを簡単に作ることができる。単に多数のスレッドを生成するだけなら、「nBlocks」と「nThreads」と2つの変数を使わなくても良いと思われるかも知れないが、実はnBlocksとnThreadsには大きな違いがある。1つのブロックに含まれるnThreads本のスレッドは同じSMで実行される。したがって、1つのブロックに含まれるスレッド間では、シェアードメモリ(GPUチップに内蔵され、アクセス時間が短い)を使ってデータのやり取りをしたり、同期をとったりすることができる。一方、別のブロックは別のSMで実行されるように割り付けられるのが一般的であり、異なるブロックに属するスレッド間ではシェアードメモリを使った通信やアトミックアクセスを使って同期をとることはできず、デバイスメモリ(GDDR5 DRAMで構成され、GPUボード上に搭載される)を使う必要があるという違いがある。

スレッド、ブロック、グリッドといった実行の階層とメモリ階層の対応を図3-35に示す。ここで、同じメモリを使っているグループに属するスレッドの間では、そのメモリを使った通信が可能である。

図3-35 スレッド、ブロック、グリッドとメモリの対応 (出典:J.Nicholls、W.Dally、"GPU Computing Era"、 IEEE Micro、Mar/Apr. 2010)

NVIDIA Kepler GPUのハードウェア構成

図3-36は、NVIDIAのKepler GPUのSM(Streaming Multiprocessor)のブロック図である。図の一番上に1次命令キャッシュがあり、そこからワープの命令を読み出して実行をスケジュールする4台のWarp Schedulerがある。ワープバッファからオペランドが揃い実行準備が整ったワープの命令をWarp Schedulerが取り出し、命令を演算器群に投入するDispatcherに送る。Dispatcherは各Warp Schedulerに2台あり、連続した命令の場合は、命令nを左のDispatcher、命令n+1を右のDispatcherという風に、連続した2命令を同時に発行することができるようになっている。

そして、発行する命令が必要とするオペランドをレジスタファイルから読み出して、命令と一緒に、レジスタファイルの下に描かれている演算器群に発行する。

図3-36 NVIDIAのKepler GPUのSMのブロック図

Coreと書かれた小さな箱は単精度浮動小数点演算や整数演算を行うブロック、DP Unitと書かれた大き目の箱は倍精度浮動小数点演算を行うブロック、LD/STと書かれた箱はロード、ストアを行うブロックで、SFU(Special Function Unit)は逆数や三角関数、対数などの複雑な関数の計算を行なうブロックである。Kepler GPUでは、図3-36に見られるように、Coreは192個、DP Unitは64個、LD/STとSFUは32個搭載されている。

そして、演算器群の下には演算器とメモリを相互接続するインタコネクトネットワークがあり、L1Dキャッシュ/シェアードメモリ、48KBのリードオンリーデータキャッシュ、テクスチャユニットが描かれている。

図3-37に示すように、GK110チップには15個のSMが搭載されている。そして、図の上辺にはPCI Express 3.0のホストCPUインタフェース、全体の並列実行を司るGiga Thread Engineが描かれ、中央にはL2キャッシュ、左右の辺には合計6個のメモリコントローラが描かれている。各メモリコントローラは2個のGDDR5 DRAMをサポートするので、全体では12個のGDDR5 DRAMが接続されることになる。

図3-37 GK110チップには15個のSMとL2キャッシュ、6個のメモリコントローラなどが搭載されている

つまり、チップ全体では、192×15=2880個の単精度浮動小数点演算器と64×15=960個の倍精度浮動小数点演算器を集積している。これらの演算器は、毎サイクルA×B+Cという積和演算を行うことができるので、最大2演算/サイクルの計算を行なうことができる。そして、GK110チップを使うTesla K40ボードのGPUクロックは745MHzであるので、ピークでは単精度で4.29TFlops、倍精度では1.43TFlopsのピーク演算性能を持つことになる。なお、熱的に余裕がある場合は、ターボ動作でクロックを引き上げることができ、それぞれ、5TFlopsと1.66TFlopsになる。

しかし、このピーク性能が出せるのは、全部のCoreあるいはDP Unitが毎サイクル積和演算を連続して行っている場合で、積和演算ではなく積だけ、和だけの演算を行うと演算数は半減してしまうし、メモリアクセス待ちなどで連続して演算できないとその分、性能は下がってしまう。