2014年5月23日金曜日

OpenCLによるGPGPU入門①

OpleCLによるGPGPU 記事一覧

実際のコードは次の項目(OpenCLによるGPGPU入門②)を参照の事。

一応簡単な計算ができたので記事にまとめておく。
本当は本は使わない予定だったのだが、
結局図書館でOpenCLに関する本を借りてきた。
以下その二冊。

   OpenCL入門 - マルチコアCPU・GPUのための並列プログラミング
   http://www.fixstars.com/ja/news/books/opencl/
   サンプルのダウンロードページ
   amazon
   amazon(改訂版の方)
   借りてきたのは改訂前の古い版。

   OpenCL入門 GPU&マルチコアCPU 並列プログラミング
   http://www.shuwasystem.co.jp/products/7980html/2608.html
   サンプルのダウンロードページ
   amazon
   こちらの本の方が、説明が丁寧で入門者向きだとおもう。
   ただし、既に絶版。amazonではまだ買えそう。……どうしよう。


語句の確認
   GPGPUに関連する語句の説明(GPGPUがやりたい。①)
   GPGPUをする事の出来るプラットフォームはなにもOpenCLだけじゃない……と言う話。
開発環境のインストール
   開発環境の整え方および今回参考にした記事(GPGPUがやりたい。②)
   私の場合はAMDなので、
   AMD-APP-SDK-v2.9-Windows-64.exe
   をインストールした。

以下、OpenCL Cプログラミングの流れ。

1.プラットフォームのIDを取得する。
……「clGetPlatformIDs()」関数
要するに、どこのメーカーの出しているプラットフォームを使うかを選択する。
今回は、AMDのGPUを使うので、AMDの「OpenCL 1.1 AMD-APP-SDK-v2.4 (650.9)」を選択する。


2.デバイスのIDを取得する。
……「clGetDeviceIDs()」関数
[1.プラットフォームのIDを取得する。]で取得したプラットフォームのIDから、
アクセスできるデバイスを選択する。


3.コンテキストを作成する。
……「clCreateContext()」関数
このコンテキストに、OpenCLに必要な様々な情報を格納する。
噛み砕いて言えば、ファイル操作をするときのファイルポインタ(FILE*)のようなもの。
(あるいは、情報を格納する構造体。)


4.プログラムを文字列としてロードし、コンパイルする。
  「OpenCL C言語」 で記述された、GPUで計算させるための、"カーネル"
と呼ばれるプログラムをロードする。
(OpenCLでは、C++のコード中でコンパイルする必要がある。
これは様々なハードウェアとの互換性を確保するためでもある。
また、コンパイル済みのデータをロードし実行する事もできる。)

   <<4.1ソースコードからコンパイルして実行する。>>

   4.1.オンラインコンパイル
   ソースコードの状態のプログラムをロードする。
   4.1_1.プログラムを文字列としてロードし、プログラムオブジェクトを作成する。
   ……「clCreateProgramWithSource()」関数
   4.1_2.プログラムをビルドする。
   ……「clBuildProgram()」関数
   4.1_3.次回以降オフラインコンパイルを使用する場合は、ビルド済みのバイナリデータを保存する。
   (ただし、カーネルプログラム(GPU側のプログラム)を変更した場合は、再度オンラインコンパイルが必要。)
   詳細のメモ書きは、「GPGPUがやりたい。③」参照。
   ……「clGetProgramInfo()」関数



   <<4.2既にコンパイル済みのデータをロードして実行する。                         >>
       ( 先に[4.1]でコンパイルし、バイナリを保存している事が前提となる。 )

   4.2.オフラインコンパイル
   ビルドされた状態のバイナリファイルをロードする。(そのため、当然オンラインコンパイルよりもビルドに掛かる時間だけ高速。(だと予想しているが、確認はしていない。))
   4.2_1.プログラムをバイナリデータとしてロードし、プログラムオブジェクトを作成する。
   ……「clCreateProgramWithSource()」関数
   4.2_2.プログラムをビルドする。
   ……「clBuildProgram()」関数


5.カーネルオブジェクトを作成する。
……「clCreateKernel()」関数
おそらく、カーネルプログラムに記述した、GPU上で動作させる関数を実体化する作業。


6.メモリオブジェクトを作成する。
……「clCreateBuffer()」関数
おそらく、GPU上のメモリに、必要なメモリを確保する作業。
C言語を使ってCPU上で計算させる時に、「int Buffer;」などとしてメモリを確保するのと同じ。
この時に、一緒に計算させる値をGPU上のメモリに転送する。


7.カーネル関数の引数を設定。
……「clSetKernelArg()」関数
で確保したメモリを、カーネル関数の引数にセットする。


8.コマンドキューを作成する。
……「clCreateCommandQueue()」関数
GPUに計算命令を送るのに必要。


9.カーネルを実行する。(計算命令を、キュー(順番待ちの列)に入れる。順番が来ると勝手に実行される。)
……「clEnqueueNDRangeKernel()」関数


10.GPU上のメモリをコピーして、計算結果を取得する。
……「clEnqueueReadBuffer()」関数


11.リソースの解放。(実際には、使用しなくなったリソースは順次開放してよい。)
……「clReleaseCommandQueue()」関数
……「clReleaseMemObject()」関数
……「clReleaseKernel()」関数
……「clReleaseProgram()」関数
……「clReleaseContext()」関数
……「free()」関数(これは自分で確保したメモリ空間。)
一応取得した順番と逆順に解放して行くが、そうする必要性は無い。


実際のコードは次の項目(OpenCLによるGPGPU入門②)を参照の事。

ところで……
実は
「1.プラットフォームのIDを取得する。」
「2.デバイスのIDを取得する。」
辺りの処理は、今回(OpenCLによるGPGPU入門②では)決め打ちで書いていますが、
それは、
OpenCLによるGPGPU入門①_2
で示しているように、事前に自分の環境情報を取得しているからです……。

0 件のコメント:

コメントを投稿