最もシンプルなOpenCLによる演算の実行 - 3
About
「最もシンプルなOpenCLによる演算の実行 - 1」、「最もシンプルなOpenCLによる演算の実行 - 2」から続く内容です。サンプルプロジェクトは前のページのものと同じものです。
OpenCL コマンドキューの生成
OpenCL カーネルに処理を実行させるには、コマンドキュー(command_queue)を用意する必要があります。分かりにくい場合は、単純に、命令を実行させるもの、あるいは命令そのもの、と覚えておけばよいと思います。
コマンドキューの生成には clCreateCommandQueue 関数を利用します。引数には OpenCL コンテキストやデバイスなどを指定します。今回のようなプログラムでは、特に難しい設定はありません。
- 引数やその他の詳細などはサンプルプロジェクトないし公式から確認してください。
//コマンドの生成 IntPtr commandQueue = clCreateCommandQueue (context, devices[0], 0, out errcode); if (errcode != CL_SUCCESS) throw new Exception("Error at clCreateCommandQueue : " + errcode);
カーネルによる処理の実行
処理を実行させるためのプラットフォームとデバイス、実行する処理内容、必要な引数と領域、実行させるための命令が用意できたので、カーネルに対し処理を実行させます。処理を実行させるには、clEnqueueTask 関数を利用します。引数には実行命令であるコマンドキューと、用意したカーネルなどを指定します。
- 引数やその他の詳細などはサンプルプロジェクトないし公式から確認してください。
//カーネルに実行するように指示をする errcode = clEnqueueTask(commandQueue, kernel, 0, null, IntPtr.Zero); if (errcode != CL_SUCCESS) throw new Exception("Error at clEnqueueTask : " + errcode);
処理結果の取得
OpenCL によって実行された処理の結果を取得します。OpenCL の処理結果は、前処理で用意したバッファ領域から読み取ることになります。このサンプルプログラムの処理結果(すなわち乗算の結果)は、rDataArray[] のバッファに与えられます。
ここでバッファ (OpenCL のメモリ領域) から、実行中のプログラムが利用するメモリ領域に処理結果を読み込むときには、バッファを用意したときと同様に、メモリ領域を固定する必要があります。ガベージコレクターによってメモリ領域が移動される可能性があるためです。
バッファからデータを読み取るには clEnqueueReadBuffer 関数を利用します。読み込むバッファと、読み込むデータの大きさなどを指定します。
- 引数やその他の詳細などはサンプルプロジェクトないし公式から確認してください。
//実行結果の取得 errcode = clEnqueueReadBuffer (commandQueue, buffer_rData, CL_TRUE, 0, (uint)(Marshal.SizeOf(rDataArray[0]) * rDataArray.Length), gcHandle.AddrOfPinnedObject(), 0, null, IntPtr.Zero); gcHandle.Free(); if (errcode != CL_SUCCESS) throw new Exception("Error at clEnqueueReadBuffer : " + errcode);
処理が確かに実行されているか確認します。サンプルプログラムでは 1920 * 1080 回演算していますが、処理内容は何れも同じなので 100 回分も確認すれば十分でしょう。
//計算結果の出力 for (int i = 0; i < 100; i++) Console.WriteLine(rDataArray[i]);
出力結果は次のようになるハズです。
9.869022 9.869022 9.869022 9.869022 …
OpenCL リソースの解放
OpenCL による処理の実行が完了し、利用していたリソースをこれ以上は参照しないとき、リソースはすべて解放してく必要があります。解放するために用いる関数は、解放するリソースによって異なります。特に複雑な手順を踏む必要がないので、サンプルプログラムを参考にしてください。
clReleaseMemObject(buffer_rData); clReleaseMemObject(buffer_yData); clReleaseMemObject(buffer_xData); clReleaseKernel(kernel); clReleaseProgram(program); clReleaseCommandQueue(commandQueue); clReleaseContext(context);
ここまでのまとめ
- OpenCL を利用して並列処理を実行するための、プラットフォームとデバイスを用意する。
- OpenCL コンテキストを用意する。
- OpenCLC で書かれたプログラムを用意して、読み込んで、ビルドする。
- OpenCL による処理を実行するためのカーネルの用意する。
- OpenCL によって利用されるメモリ領域=バッファの用意する。
- 用意したOpenCLカーネルに引数を設定する。
- OpenCLカーネルに処理を実行させるためのコマンドキューを生成する。
- OpenCLカーネルに処理を実行させる。
- 実行結果を取得する。
- OpenCL で利用した全てのリソースを解放する。