このコードは
OpenCL入門―GPU&マルチコアCPU並列プログラミング for MacOS Windows LinuxのChapter 3を参考に、作成した
{
#include <stdio.h>
#include <time.h>
#include <CL/cl.h>
static void printPlatformInfo(const cl_platform_id platform_id);
/*---------------------------------------------------------------------------
*
*/
int main(int argc, char * const argv[])
{
//時間計測
clock_t t1, t2;
t1= clock();
// プラットフォームIDを取得する
cl_platform_id platforms[10];
cl_uint num_platforms;
cl_int status;
status = clGetPlatformIDs(sizeof(platforms) / sizeof(*platforms),
platforms,
&num_platforms);
if (status != CL_SUCCESS) {
fprintf(stderr, "clGetPlatformIds failed with status %d\n", status);
return 1;
}
printf("Number of platform(s) : %d\n", num_platforms);
for (int i = 0; i < (int)num_platforms; i++) {
// プラットフォームIDについての情報を表示する
printPlatformInfo(platforms[i]);
}
t2 = clock();
printf("time = %f\n", (double)(t2 - t1) / CLOCKS_PER_SEC);
return 0;
}
/*---------------------------------------------------------------------------
* 引数で与えられたプラットフォームの情報を表示する
* platfomrm_id: 情報を表示するプラットフォームのID
*/
static void
printPlatformInfo(const cl_platform_id platform_id)
{
char buffer[1024];
size_t actual_size;
cl_int status;
// プロファイル
status = clGetPlatformInfo(platform_id, CL_PLATFORM_PROFILE,
sizeof(buffer) - 1, buffer, &actual_size);
printf("Platform profile : ");
if (status == CL_SUCCESS) {
buffer[actual_size] = '\0';
printf("%s\n", buffer);
} else {
printf("Error: clGetPlatformInfo failed with status %d\n", status);
}
// バージョン
status = clGetPlatformInfo(platform_id, CL_PLATFORM_VERSION,
sizeof(buffer) - 1, buffer, &actual_size);
printf("Platform version : ");
if (status == CL_SUCCESS) {
buffer[actual_size] = '\0';
printf("%s\n", buffer);
} else {
printf("Error: clGetPlatformInfo failed with status %d\n", status);
}
// 名前
status = clGetPlatformInfo(platform_id, CL_PLATFORM_NAME,
sizeof(buffer) - 1, buffer, &actual_size);
printf("Platform name : ");
if (status == CL_SUCCESS) {
buffer[actual_size] = '\0';
printf("%s\n", buffer);
} else {
printf("Error: clGetPlatformInfo failed with status %d\n", status);
}
// ベンダー
status = clGetPlatformInfo(platform_id, CL_PLATFORM_VENDOR,
sizeof(buffer) - 1, buffer, &actual_size);
printf("Platform vendor : ");
if (status == CL_SUCCESS) {
buffer[actual_size] = '\0';
printf("%s\n", buffer);
} else {
printf("Error: clGetPlatformInfo failed with status %d\n", status);
}
// 機能拡張
status = clGetPlatformInfo(platform_id, CL_PLATFORM_EXTENSIONS,
sizeof(buffer) - 1, buffer, &actual_size);
printf("Platform extensions: ");
if (status == CL_SUCCESS) {
buffer[actual_size] = '\0';
printf("%s\n", buffer);
} else {
printf("Error: clGetPlatformInfo failed with status %d\n", status);
}
}
このプログラム自体はOpenCLデバイスで計算はしていない。OpenCL APIをつかった単なるC++のプログラム。OpenCLデバイスで計算させるためには、OpenCLにデータを飛ばさなければならないため一気に記述する量が多くになる。
それが以下のような一般的なOpenCLプログラムの流れである。
1.コンテキストの作成(clCreateContext)
2.コンテキストに含まれるデバイス取得(clGetContextInfo)
3.コマンドキューの作成(clCreateCommandQueue)
4.プログラムオブジェクトの作成(clCreateProgramWithSource)
5.カーネルプログラムのビルド(clBuildProgram)
6.カーネルオブジェクトの作成(clCreateKernel)
7.メモリオブジェクトの作成(clCreateBuffer)
8.カーネル引数の設定(clSetKernelArg)、実行(clEnqueueTask)
9.メモリバッファから結果取得(clEnqueueReadBuffer)、表示
後ろに括弧で書いておるのがAPIである。このような様々なAPIを利用し、OpenCLデバイスデータを飛ばし計算させデータを取ってくる。僕自身のイメージとして基本的にOpenCLデバイスは本当に計算しかできない。だから、手取り足取りメモリを確保することからカーネルオブジェクトの作成、計算の結果の取得まですべてホストプログラム(CPU)がやれなければならない。
また、OpenCL独特のオンラインコンパイルについて記述する。その前にオフラインコンパイラについての説明から。
オフラインコンパイル方式では,カーネルプログラムをOpenCLコンパイラによって予めコンパイルしておき,ホストプログラム中でOpenCL APIを用いて読み込む方式である.プログラム中でコンパイルを行う必要がなく,カーネルプログラムの起動で生じるラグが少ないことが利点である.しかし,移植性を高めたい場合には,様々なアーキテクチャに対応させたカーネルプログラムにしなければならないため,必然的にプログラムサイズが大きくなる.多くのデバイスのメモリ容量は少ないことが多いので,この点でオフライン方式は不利となる.また,現状ではオンラインコンパイルのみをサポートし,オフラインコンパイルをサポートしていない実装がいくつかある.(http://www.is.doshisha.ac.jp/report/2010/9/17/2010030001/index.htmlより引用)
つまり、これが普通のコンパイル。ホストプログラムもカーネルプログラムも全部コンパイルして実行ファイルを作ってしまう。そしたら楽なんだけど、移植性は低くなっちゃうよねって話。
それとは反対のオンラインコンパイル
オフラインコンパイル方式とは反対に,プログラム実行時にカーネルプログラムをコンパイルする方式がオンラインコンパイル方式である.デバイスのアーキテクチャに依存することなく,環境に応じて適応的にコンパイルできる点がオンライン方式の利点である.しかし,リアルタイム性が要求される組み込み用途,ソースコードを非公開にしたい場合などにはコンパイル分のオーバーヘッドが付くのでこの方式は適していない.現存のすべての実装で,この方式をサポートしている.(http://www.is.doshisha.ac.jp/report/2010/9/17/2010030001/index.htmlより引用)
つまり、これがOpenCL独特のコンパイル方式。予めコンパイルしておくのはホストプログラムだけ。ホストプログラムだけから作った実行ファイルを実行時に、その実行環境にあった並列処理(?)でカーネルプログラムを処理してくれるというもの。計算量が莫大になればなるほどおそらく逐次より早く動くものと思われる。