そもそもGPGPUのテーマであるデータパラレルコンピューティングとはなんなのか。

従来のCPU向けのプログラムコードにおいて、大量のデータに対してある演算を施す場合、下図の左のようにあるインデックス変数を用意し、そのインデックスに対応したデータを取りだしては1つずつ演算を施し、Forループでインデックス変数を変移させていくような構造を取るのが一般的だ。

データパラレルコンピューティングの場合は下図の右のように、データに施す演算を「カーネル」として定義し、複数のデータに対し、同時多発的にこのカーネルを適用する。その「同時多発」の具合は、前述したCopmuteDeviceのポテンシャルに応じてスケーラブルに変わる。Processing Element×ComputeUnitの数が多ければ多いほど、より一度に「同時多発」が起こるのでパフォーマンスは上がる。GPUに当てはめて考えるならば、上位モデルのシェーダユニットの数が多いモデルの方が並列性が高くなるので、より短時間で処理を終えられる。

従来のスカラプログラムとデータパラレルプログラムとの構造の違い

GPGPU、データパラレルコンピューティングでキモとなるのは、この「同時多発」をどう管理するかという問題。CUDAもWARPという32スレッド単位が1つとの「同時多発」の目安としていたが、OpenCLにもそうした管理階層概念が存在する。

処理対象データの全体サイズをグローバルディメンション(Global Dimension)と呼び、処理対象データの最小単位をワークアイテム(Work Item)と呼ぶ。そしてワークアイテムのひとかたまりをワークグループ(Work Group)と呼び、このワークグループのサイズをローカルディメンション(Local Dimension)と呼ぶ。

たとえば1024×1024個のデータがあったとすると、これがグローバルディメンションとなる。そしてローカルディメンションを128×128で切るとワークグループは8×8になる。つまり1ワークグループ内のワークアイテム数は64個ということになる。

OpenCLの「同時多発」管理概念

OpenCLではこのワークグループ単位で同時多発的にワークアイテムに対してカーネルを実行していくことになる。なお、ワークグループ内では自由にワークアイテム間での同期取りが行え、メモリフェンス/メモリバリアといった同時多発的な同一メモリアドレスへのアクセス制御にも対応できる。しかし、ワークグループが異なるワークアイテム間ではこれはサポートされない。これは制限……というよりは、並列性を維持するための最低限のルールというイメージだ。

グローバルディメンションは最大3次元までがサポートされる。1Dデータは、たとえば音声データなど、2Dデータは画像など、3Dデータはボリュームレンダリング用のボクセルデータなどが代表例になるだろうか。

処理対象テーマとデータ"次元"の関係

26個で構成される1Dデータを2ワークグループで管理した場合の例

データパラレルコンピューティングでは主役はデータの方であり、プログラムの実体部ともいえるカーネルはデータによって駆動されるというイメージだ。カーネルは処理対象のデータが格納されているアドレス(インデックス)と共に呼び出される。

二乗を計算するカーネルに対しグローバルディメンションのID=10で呼び出された例