カテゴリー別アーカイブ: OpenCL

新年早々卒論

新年あけましておめでとうございます。

卒論がやばいす。雑多。

一応卒論でやりたかったプログラムの作成が終了した。ここまで整理。OpenCLのプログラムを作成していくうちにやはり多くの制限があって、結局すべて仕様ということにして終わらせることにするしかない。今後の課題とか。

ぼくがしたかったのは結局「OpenCLによるヘテロジニアス環境の自動並列化」。ライブラリの次元を超えていたらしい。一行でOpenCLを使えちゃうというのはライブラリ開発というより自動並列化プログラムになるらしい。

で、計算機の情報を自動的に取得し、複数デバイス用に並列化をするところまではできたが、プログラムを作成していくうちにデバイス内も並列化する必要があるということがわかった。これは完全に自分の知識不足なのだが、勝手にOpenCLでデバイス内も並列化してくれているものだと思った。あほ。デバイス内も並列化するためにはソースコードの中にglobalidを含めなければならない。つまり、ソースコードを大幅に改変する必要があった(普通に考えれば至極当然のこと)。

具体的に何が問題かというと、ぼくがしたかったのはユーザーが普通に計算処理を書いて(行列和なら2重ループ、行列積なら3重ループみたいな)、それを自動的に並列化してくれるというものなんだが、この処理を並列化しようとしたら2つの並列化が考えられる。複数デバイスにデータを分けて並列化。または1つのデバイスに対する並列化(主にGPU等で使われる並列化)。で、ぼくは1つのデバイスに対する並列化はOpenCLが自動的に並列化してくれると思っていたため、一生懸命複数デバイスで並列化できるように頑張っていたが、実は更にそこから複数デバイス各々で並列化をすることが必要だった。つまり並列化したデバイス内を更に並列化。あほ。今月末の卒論提出なので時間ないけどもう少し頑張ってそこまでやろうかと思ったけど、そのためには、ユーザーが書いた計算処理の部分のソースを読み込んでforを解析しなければならず、さすがにそこまではできないから複数デバイスの並列化までにとどめた。
おそらく、この研究を最後までしつづけると、ユーザー側が計算したい部分を上にOpenMPみたいに一行ちょろっと書いてヘテロジニアスな環境での自動並列化になるんだと思う。

とは言っても複数デバイスの並列化も行列和程度しかできない。これも仕様。配列の簡単な計算しかできない。まぁしょうがない。プログラムが完成したが、いまから月末まではまとめる作業。
データもまだすべてとれてないし、結論をどうまとめるかも考え中。仕様もどこまで書くかも決まっていない。やばす。

新年早々、卒論の記事になってしまったがこんなときもある。毎年今年のまとめと来年の抱負も書いてたのに忘れてしまった。ぐぬ〜。また時間があれば書きます。

卒論提出まであと少し

一応卒論の提出日が12月15日に決まった。それまでにある程度卒論を完成させなければならない。毎日2ページくらいのペースで書かないと間に合わない。。。

まだ全部実験も終わってない状態で書き始めてる。

これからすること。(ここから思考垂れ流し)
APIまで完成しているので、あとは最適化するだけ。ただこれが一番のメイン。どんな用途向けに最適化するか。
あくまでもだれでも簡単に使えるOpenCLが目的。ちょっと前にクロノスから発表されたCLUの考え方にに非常に近くなってしまうがしょうがない。

プロトタイプ向けに手軽にOpenCLを使えるためライブラリ開発、そして最適化は実行時間予測するために行う。これによってCPUとGPUのリソースどちらをどれだけ使ったほうがそのプログラムは高速化するかの予測ができることは実用性にもつながるはず、、、

今からやらなければならないことを整理すると、どんなプログラムも使えるような汎用的な最適化プログラムを組む。具体的には、CPUとGPUのプロセッサの特徴をブラシュアップして、この処理はCPUに、この処理はGPUというように分ける。それを.clファイルに対して考えなければならない。

ん?.clファイルに対してどのようにプログラミングすれば良いんだ?
ホストプログラムの処理はもちろんCPUが行う。この処理をGPUに回すことはない。となると最適化を考えた場合やはり.clファイルに対してリソース分配を考えなければならない。またマルチGPUについても考えなければならない。CPUとGPUの特徴の違いをまだ全部解析できていないが、例えば、CPUにはif文の処理、GPUにはfor文の処理というようにソースを読み込んだ段階でプログラムオブジェクトを分ける。そんなことをが果たして出来るのか?これは利用者がヘテロジニアスな環境を使う前提での研究だが、とりあえず家中に転がっていたCPUやらGPUを一つのパソコンに突っ込んでヘテロジニアスな環境ができたみたいな状況で、このパソコンでプログラムを動かしたい!みたいな。そのとき、「ほら、ぼくの研究役立つでしょ?」みたいな感じ。

そんでまずぼくのプログラムがするべきことっていうのは、まず環境情報をとってくる。どんなデバイスがあるのか。それがもし、CPUだけだったりしたら問題ない?いやそんなことない。OpenMPみたいにスレッドをたくさん立てて並列化するべきだ。またGPUが刺さっていたらもちろんCPUとGPUの並列化になるんだけど、一番難しいのはおそらくここのリソースの分け方。.clファイルを全部GPUに投げちゃえば楽なんだけどそれじゃ意味が無い。ここをさっき言ってたifとかforの関数ごとに分ける。本当にそんなんできんの?できて、CPUだけとGPUだけ処理してどっちが早いぐらいじゃねとも思う。もちろん変数なんて共有しているわけだからそれを別々のデバイスで計算したらわけわからんことになる気がする。そう考えると.clファイルの処理を分けるなんて無理じゃね?てか意味なくね?うーん。。。そんな複雑なプログラムなんてサンプルを考えるだけでも大変な気がする。んー例えばゲーム開発を想定して、分岐をCPU、グラフィック処理をGPUに振り分けるように、、、いやそれだったらホストプログラムの方で処理すればよいだけだ。そもそもCPUだけだったら.clファイルを作成する意味ってなくね?ホストプログラムで処理すればいいんだもん。。。先輩のCUDAでのやつもホストプログラムで処理させるようにしてるんだっけか????そうすると、ソースプログラムを読み込んだ段階でCPUとGPUで処理させてやって早く終わった方だけ結果返して表示させればいいんじゃね?でもそれってリソース分配になってない。。。

.clファイルが一つだけだと思っているからダメなのかもしれない。複数の.clファイルがあったとしてその.clファイルごとに「この.clファイルはCPUで処理するべきだ!この.clファイルはGPUで処理するべきだ!」ってなれば十分研究の価値はあるはず。.clファイルがいくつもあるプログラムってあるよね?.clファイルって結局計算してホストプログラムに結果返すんだから、.clファイルは十分機能ごとにわける可能性はあるよね。。。

今人に聞いたら単純に並列化すれば良いって話になった。適材適所って言うことを考えるんじゃなくて、少しでも高速化すれば良い。GPUがしてる処理をほんの少しでもCPUが負担してあげればそれはちゃんとした研究になる。そのためには、入力データを単純に分割する。その割合は少し考えなければいけない。ん?でもその割合って計算量によって変わる?そこらへんも考えなくちゃいけない。最初は単純にデータ量をデバイス数で割って割り当てれば良いか。

とりあえず今やらなければならないこと。CPUとGPUの並列化をできるようにする。非同期コマンドキュー。タスク並列化かデータ並列どっちが良いか考え、データの割り方を考える。色々試してみて、簡単でもいいから早いアルゴリズムを構築する。以上。

ヾ(*`Д´*)ノ”

OpenCLの行列和のC++化

OpenCLのライブラリを作成する前段階として、昔書いたOpenCLの行列和のプログラムのC++化を行った。まだ完全ではないがとりあえず動くのであげておく。

[cpp]
/*
* main.h
*
*/

#ifndef MAIN_H_
#define MAIN_H_

#include<iostream>
#include<cstdlib>
#include<string>
#include<cstdio>
#include"clapi.h"

#ifdef __APPLE__
#include<OpenCL/opencl.h>
#else
#include<CL/cl.h>
#endif //__APPLE

#define MAX_SOURCE_SIZE (0x100000)

#endif /* MAIN_H_ */
[/cpp]

[cpp]
/*
* main.cpp
*
*/
#include"main.h"

using namespace std;
int main(){
int fvar=4096, fwid=4096, lvar=4096, lwid=4096;
double *mtrx1,*mtrx2,*Out;
FILE *fp;
if ((fp = fopen("inputD.txt","r")) == NULL)
{
printf("file open error!!n");
exit(EXIT_FAILURE);
}
int size;
fscanf(fp, "%d", &size);

mtrx1 = (double*) malloc(size * size * sizeof(double));
mtrx2 = (double*) malloc(size * size * sizeof(double));
Out = (double*) malloc(size * size * sizeof(double));

if(mtrx1==NULL) return 1;
if(mtrx2==NULL) return 1;
if(Out==NULL) return 1;

int i, j;
for(i = 0; i < size; i++)
{
for(j = 0; j < size; j++)
{
Out[i * size + j] = 0;
fscanf(fp, "%lf", &mtrx1[i * size + j]);
}
}

for(i = 0; i < size; i++)
{
for(j = 0; j < size; j++)
{
fscanf(fp,"%lf", &mtrx2[i * size + j]);
}
}

fclose(fp);

//kotake
//1.カーネルプログラム指定
string filename="test.cl";
//2.オブジェクト生成???
clapi cl(filename);
//3.メンバ関数実行
//cl.auto(入力数, データ1のdouble型配列の個数, データ1の配列のアドレス, データ2の配列の個数, データ2の配列のアドレス, ….)

if(!cl.clauto(2, size*size, mtrx1, size*size, mtrx2))return -1;
//cl.doOpenCL();
// iif(cl.hikisu != true || doOpenCL != true) return 0;

Out = cl.getOut();

//結果表示
cout<<"加算結果"<<endl;
for(int i = 0 ; i < fvar ; i++){
for(int j = 0 ; j < fwid ; j++){
cout<< Out[i*fwid+j] << " " ;
}
cout << endl;
}

free(mtrx1);
free(mtrx2);
free(Out);
}
[/cpp]

[cpp]
/*
* clapi.h
*
*/

#ifndef CLAPI_H_
#define CLAPI_H_

#ifdef __APPLE__
#include<OpenCL/opencl.h>
#else
#include<CL/cl.h>
#endif //__APPLE

#include<stdarg.h>
#include<string>
#include<cstdio>
#include<iostream>

#define MAX_SOURCE_SIZE (0x100000)

using namespace std;

class clapi {
public:
clapi();
clapi(string);
~clapi();
bool clauto(int , …);
bool doOpenCL();
double* getOut();
cl_device_id device_list[4];
private:
void builderr();
cl_int status;
cl_platform_id platforms[2];
cl_uint num_platforms;
cl_context context;
//cl_device_id device_list[4]; //なぜか2じゃできない
cl_uint num_device;
cl_context_properties properties[3];
cl_command_queue queue;
cl_program program;
cl_uint pro_info;
cl_kernel kernel;
cl_mem memIn[10];
cl_mem memOut;
string filename;
double* s[10];
int size[10];
int num_hikisu;
double* Out;
};

#endif /* CLAPI_H_ */
[/cpp]

[cpp]
/*
* clapi.cpp
*
*/

#include "clapi.h"

using namespace std;

clapi::clapi() {

}

clapi::clapi(string tmp){
filename = tmp;
}

clapi::~clapi(){
clReleaseMemObject(memOut);
for(int i = 0; i < num_hikisu; i++) clReleaseMemObject(memIn[i]);
clReleaseKernel(kernel);
clReleaseProgram(program);
clReleaseCommandQueue(queue);
clReleaseContext(context);
}

bool clapi::clauto(int n, …) {
num_hikisu = n;
va_list args;
va_start(args, n);

for (int t = 0; t < n ; t++) { //forでループさせ渡された引数1個ずつについて処理する。すべてsに+=していく。
size[t] = va_arg(args,int);//double型配列の個数
s[t] = va_arg(args,double*); //可変長引数を取り出す. 第一引数はva_list型の変数。第二引数には取り出す型。
}
va_end(args);

doOpenCL();

return true;
}

bool clapi::doOpenCL() {
status = clGetPlatformIDs(2, platforms, &num_platforms);
if (status != CL_SUCCESS || num_platforms <= 0) {
fprintf(stdout, "clGetPlatformIDs failed.n");
printf("%dn", status);
return false;
}
// 最初の要素として返されたプラットフォームIDを、プロパティにセットする
properties[0] = CL_CONTEXT_PLATFORM;
properties[1] = (cl_context_properties)platforms[1];
properties[2] = 0;

//1.デバイスの取得
status = clGetDeviceIDs(platforms[1], CL_DEVICE_TYPE_GPU, 4, &device_list[0], &num_device);
if (status != CL_SUCCESS || num_device <= 0) {
fprintf(stdout, "clGetDeviceIDs failed.n");
printf("%dn", status);
return false;
}

context = clCreateContext(properties, num_device, &device_list[0], NULL,NULL, &status);
if (status != CL_SUCCESS) {
cout << "clCreateContext failednError Code: " << status << endl;
return false;
}

//3.コマンドキューの作成
queue = clCreateCommandQueue(context, device_list[0], 0, &status);
if (status != CL_SUCCESS) {
cout << "clCreateCommandQueue failednError Code: " << status << endl;
return false;
}
//4.プログラムオブジェクトの作成
FILE *fp;
size_t source_size;
char *source_str;

fp = fopen(filename.c_str(), "r");
if (!fp) {
fprintf(stderr, "Failed to leas kernel.n");
return false;
}
source_str = (char *) malloc(MAX_SOURCE_SIZE);
source_size = fread(source_str, 1, MAX_SOURCE_SIZE, fp);
fclose(fp);

program = clCreateProgramWithSource(context, 1, (const char**) &(source_str), &source_size, &status);
if (status != CL_SUCCESS) {
cout << "clCreateProgramWithSource failednError Code: " << status << endl;
return false;
}

//5.プログラムのビルド
status = clBuildProgram(program, num_device, &device_list[0], NULL, NULL, NULL);
if (status != CL_SUCCESS) {
cout << "clBuildProgram failed nError Code: "<< status << endl;
builderr();
return false;
}

//6.カーネルの作成
kernel = clCreateKernel(program, "calc", &status);
if (status != CL_SUCCESS) {
cout << "clCreateKernel failednError Code: " << status << endl;
return false;
}

//7メモリオブジェクトの作成
for(int i = 0 ; i<num_hikisu ; i++)
{
memIn[i] = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(double)*size[i], (void*) s[i], &status);
if (status != CL_SUCCESS) {
cout << "clCreateBuffer failednError Code: " << status << endl;
return false;
}

}
memOut = clCreateBuffer(context, CL_MEM_WRITE_ONLY, sizeof(double)*size[1] , NULL, &status);
if (status != CL_SUCCESS) {
cout << "clCreateBuffer failednError Code: " << status << endl;
return false;
}

//8.カーネルに渡す引数の設定
status = clSetKernelArg(kernel, 2, sizeof(cl_mem), (void *) &memOut);
if (status != CL_SUCCESS) {
cout << "clSetKernelArg failednError Code: " << status << endl;
return false;
}

for(int i = 0; i< num_hikisu; i++)
{
status = clSetKernelArg(kernel,i,sizeof(cl_mem),(void *) &memIn[i]);
if (status != CL_SUCCESS) {
cout << "clSetKernelArg failednError Code: " << status << endl;
return false;
}
}

//9.カーネルの実行
size_t globalsize[] = { size[0] };
status = clEnqueueNDRangeKernel(queue, kernel, 1, NULL, globalsize, NULL, 0, NULL, NULL);
if (status != CL_SUCCESS) {
cout << "clEnqueueNDRangeKernel failednError Code: " << status << endl;
return false;
}

//10.結果の取得
Out = (double*) malloc(size[0] * sizeof(double));
status = clEnqueueReadBuffer(queue, memOut, CL_TRUE, 0, sizeof(double)*size[1], Out, 0, NULL, NULL);
if (status != CL_SUCCESS) {
cout << "clEnqueueReadBuffer failednError Code: " << status << endl;
return false;
}

return true;
}

double* clapi::getOut(){
return Out;
}

void clapi::builderr() {
size_t logsize;
status = clGetProgramBuildInfo(program, device_list[0], CL_PROGRAM_BUILD_LOG, 0, NULL, &logsize);
if (status == CL_SUCCESS) {
//ログを格納するためのバッファをアロケートする
char *logbuffer;
logbuffer = new char[logsize + 1];
if (logbuffer == NULL) {
printf("memory allocation failed.n");
return;
}

status = clGetProgramBuildInfo(program, device_list[0], CL_PROGRAM_BUILD_LOG, logsize, logbuffer, NULL);
cout << status << endl;
if (status == CL_SUCCESS) {
logbuffer[logsize] = ‘\0’;
cout << "build log" << endl;
cout << logbuffer << endl;
}
delete[] logbuffer;
}
else {
cout << "clGetProgramBuildInfo failed" << endl;
}
}
[/cpp]

[cpp]
/*
* test.cl
*
*/

#pragma OPENCL EXTENSION cl_khr_fp64: enable

__kernel void
calc(
__global const double *in1,
__global const double *in2,
__global double *out)

{
int index = get_global_id(0);
out[index] = in1[index]+in2[index];
}
[/cpp]

ライブラリ作成

ライブラリ作成途中経過。とりあえずやり方だけ。

$ g++ -g -Wall -fPIC -c test.c
$ g++ -shared -o lib.so test.o
$ g++ -o main main.c ./lib.so
$ ./main

以下オプションの説明。

-Wall
すべての警告を出す

-fPIC
このオプションがターゲットマシンでサポートされていれば、位置独立なコードを出力します。このオプションはダイナミックリンクに適しており、分岐において大きなディスプレースメントを要求する場合にも適応します

-shared
他のオブジェクトとリンクして実行可能プログラムを形成し得る共有オブジェクトを生成します。ごく少数のシステムでのみ、このオプションはサポートされています。

libxxx.so(xxxがライブラリ名)
共有ファイルとは、プログラムが実行するときに呼び出す。そのため、静的ライブラリに比べ実行速度が遅くなる。しかし、その反面、以下のようなメリット、特長がある。

OpenCLで使い時は、1行目と3行目に-lOpenCLのオプションを追加する。

なんか色々書いたけど上のやり方じゃなくても、コンちゃんいわくそんな面倒いことしなくても1行でいけるらしい。。。

$ g++ test.c main.c -o main -lOpenCL
$ ./main

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
そんで、Makefileも少し勉強して簡単なやつだけど作ってみた。

main: main.cpp lib.so
      g++ -o main main.cpp ./lib.so -lOpenCL
lib.so: api.o
        g++ -shared -o lib.so api.o
api.o: api.cpp
       g++ -g -Wall -fPIC -c api.cpp -lOpenCL
clean:; rm main *.o *.lib

参考URL
http://blog.livedoor.jp/ha_yshr/archives/51793675.html
http://blog.livedoor.jp/vavacco/archives/665039.html
http://www.am.sanken.osaka-u.ac.jp/~mukaigaw/misc/Makefile.html

OpenCLここまで整理

最近このサーバが死ぬほど重い。。。リクエストを送っても返ってくるまで5秒以上かかる。キャッシュ使って早くしようとしたけどうまく設定できなく断念。また時間のあるときに設定しようと思う。

さてさて、10月ももう終わろうとしており、卒論を本格的に書き始めなければならない。とりあえず、OpenCLについてここまで整理、

現段階の目標は、複数枚のGPUを動かすこと。いろいろ試行錯誤した結果、当初僕がイメージしていた実装ではできないっぽいことが判明。OpenCLは、まず最初にコンテキストを作成しなければならないが、そのコンテキストに複数のデバイス情報を入れることでそのコンテキスト情報をカーネルに送ってマルチデバイスで計算するものだと思っていた。ただ実際はそうではなく、コンテキストがベンダーごとに作ってあげなければいけないらしい。device_idはベンダーごとのデバイスリストであるが、そのデバイスリストをコンテキストを作成するために必要なpropertiesに含めることができないみたい。
普通はこう書く。
[cpp]
cl_context_properties properties_gpu[] = {CL_CONTEXT_PLATFORM, (cl_context_properties)id[1], 0};
[/cpp]
だけどぼくは
[cpp]
cl_context_properties properties_cpugpu[] = {CL_CONTEXT_PLATFORM, (cl_context_properties)id[0],(cl_context_properties)id[1], 0};[/cpp]
[cpp]
cl_context_properties properties_cpugpu[] = {CL_CONTEXT_PLATFORM, (cl_context_properties)id[0],CL_CONTEXT_PLATFORM, (cl_context_properties)id[1], 0};[/cpp]
こんな感じでpropertiesに複数のデバイスCPUとGPUを含めることができると思ったができないっぽい。残念。

じゃあどのようにすればよいか。おそらく、二つのプラットホームを作らなければならない。CPUとGPUの二つのプラットフォームを作り、そのプラットフォームにそれぞれ処理を割り振って、カーネルプログラムで処理させるという流れになるだろう。そのためにはカーネルプログラム事態を二つに分けなければいけないのかや、カーネルプログラムのなかに二つのプラットホームを含めることができるのかも検証しなければならない。

でもおそらく、カーネルプログラムを実行する段階でデバイスリストを渡しているため、複数のデバイスでに自動的に処理が割り振られているかもしれない。ここもまだ検証中。

ここの問題を解消できれば、あとはライブラリ開発したり、割り振るアルゴリズムを考えるだけなので比較的簡単にできそう。はやく解決して12月中には、卒論の第一稿を提出したい。

卒論の方向性について

おおよそ論文の方向性がやっと明確になってきた。

 最終的な目的は「環境を考慮したOpenCLの負荷分散手法」である。ただこれもどの計算を対象にするか、それともとりあえず汎用的にどのプログラムでもそれなりの負荷分散できるような方法を提案するかを考える必要がある。
 そしてその過程として、「OpenCLの環境の情報をとってきて誰もが簡単に使えるライブラリ開発」を一つの目的にする。これはGPUが複数枚刺さっている環境、またCPUとGPUを開発者がOpenMPのようにコメント一つで簡単に使えるライブラリを開発するということ。
 今自分がやることは、複数枚GPUが刺さっている環境でOpenCLを動かすこと。そして動かせたら、それを引数を与えるだけで使える関数を作る。次にライブラリ化を考える。

今月中には4枚のGPUで動かせるようにしたい。そこまでいけばおそらくライブラリ作成はさぼど難しくはないず。
できるだけ12月中には論文を完成させたい。

OpenCLのマンデルブロ集合(1次元配列版)

[cpp]
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<CL/cl.h>
#include<string>
#include<time.h>

#define MAX_SOURCE_SIZE (0x100000)
#define MEM_SIZE (CL_DEVICE_MAX_WORK_ITEM_SIZES)

using namespace std;

//test
int main()
{
//char string[MEM_SIZE];

FILE *fp;
char fileName[] = "./calc.cl";
char *source_str;
size_t source_size;

fp = fopen(fileName, "r");
if(!fp)
{
cout << "file failed" <<endl;
exit(1);
}
source_str = (char *)malloc(MAX_SOURCE_SIZE);
source_size = fread(source_str,1,MAX_SOURCE_SIZE,fp);
fclose(fp);

cl_int status;
cl_platform_id platforms[2];
cl_uint num_platforms;
status = clGetPlatformIDs(2, platforms, &num_platforms);
//cout << status << endl;

cl_device_id devices;
cl_uint num_devices;
cl_context context;
status = clGetDeviceIDs(platforms[1], CL_DEVICE_TYPE_GPU, 4, &devices, &num_devices);
//cout << status << endl;

context = clCreateContext(NULL, 4, &devices, NULL, NULL, &status);
//cout << status << endl;

cl_command_queue queue;
queue = clCreateCommandQueue(context, devices, 0, &status);
//cout <<"queue:"<<status << endl;

cl_program program;
program = clCreateProgramWithSource(context, 1, (const char**)&source_str, &source_size, &status);
//cout << status << endl;

status = clBuildProgram(program, num_devices, &devices, NULL, NULL, NULL);
cout << status << endl;

//*////////////////////////

size_t logsize;
status = clGetProgramBuildInfo(program,devices,CL_PROGRAM_BUILD_LOG,0,NULL,&logsize);
if(status == CL_SUCCESS)
{
char *logbuffer;
logbuffer = new char[logsize + 1];
if(logbuffer == NULL)
{
cout << "memory allocation failed."<<endl;
//return;
}

status = clGetProgramBuildInfo(program,devices,CL_PROGRAM_BUILD_LOG,logsize,logbuffer,NULL);
if(status == CL_SUCCESS)
{
logbuffer[logsize]=’\0’;
cout << "build log" << endl;
cout << logbuffer << endl;
}
delete [] logbuffer;
}

//*////////////////////////

cl_kernel kernel;
kernel = clCreateKernel(program, "calc", &status);
//cout << status << endl;

float Outx[MEM_SIZE];
float Outy[MEM_SIZE];
//bool OutCheck[MEM_SIZE][MEM_SIZE];
bool *OutCheck = new bool[MEM_SIZE*MEM_SIZE];
Outx[0] = -2;
Outy[0] = -2;
for(int i= 0; i < MEM_SIZE-1 ;i++)
{
Outx[i+1] = Outx[i] + (4.0 / MEM_SIZE);
Outy[i+1] = Outy[i] + (4.0 / MEM_SIZE);

for(int j = 0; j < MEM_SIZE ;j++)
{
OutCheck[i*MEM_SIZE+j] = true;
}
}

cl_mem memoutx, memouty, memoutcheck;
memoutx = clCreateBuffer(context, CL_MEM_READ_WRITE, MEM_SIZE * sizeof(float), NULL, &status);
//cout <<status<<endl;
memouty = clCreateBuffer(context, CL_MEM_READ_WRITE, MEM_SIZE * sizeof(float), NULL, &status);
//cout <<status<<endl;
memoutcheck = clCreateBuffer(context, CL_MEM_READ_WRITE, MEM_SIZE * MEM_SIZE * sizeof(bool), NULL, &status);
//cout <<status<<endl;

status = clEnqueueWriteBuffer( queue, memoutx, CL_TRUE, 0, MEM_SIZE * sizeof( float ), Outx, 0, NULL, NULL );
//cout << status << endl;
status = clEnqueueWriteBuffer( queue, memouty, CL_TRUE, 0, MEM_SIZE * sizeof( float ), Outy, 0, NULL, NULL );
//cout << status << endl;
status = clEnqueueWriteBuffer( queue, memoutcheck, CL_TRUE, 0, MEM_SIZE * MEM_SIZE * sizeof( bool ), OutCheck, 0, NULL, NULL );
//cout << status << endl;

status = clSetKernelArg(kernel, 0,sizeof(cl_mem),(void *)&memoutx);
status = clSetKernelArg(kernel, 1,sizeof(cl_mem),(void *)&memouty);
status = clSetKernelArg(kernel, 2,sizeof(cl_mem),(void *)&memoutcheck);
//cout <<"カーネルに渡す引数セット:"<<status<<endl;

//status = clEnqueueTask(queue, kernel, 0, NULL, NULL);
size_t global_work_size[] = {MEM_SIZE * MEM_SIZE};
size_t local_work_size[] = {MEM_SIZE};

clock_t t1, t2;
t1 = clock();
status = clEnqueueNDRangeKernel(queue, kernel, 1, local_work_size, global_work_size, NULL, 0, NULL, NULL);
t2 = clock();
if( status < 0){
cout <<"実行:"<<status<<endl;
cout << CL_DEVICE_MAX_WORK_GROUP_SIZE << endl;
cout << CL_DEVICE_MAX_WORK_ITEM_SIZES << endl;
exit(0);
}

//status = clEnqueueReadBuffer(queue, memoutx, CL_TRUE, 0, MEM_SIZE * sizeof(float), Out, 0, NULL, NULL);
//status = clEnqueueReadBuffer(queue, memouty, CL_TRUE, 0, MEM_SIZE * sizeof(float), Out, 0, NULL, NULL);
status = clEnqueueReadBuffer(queue, memoutcheck, CL_TRUE, 0, MEM_SIZE * MEM_SIZE * sizeof(bool), OutCheck, 0, NULL, NULL);
//cout <<"結果取り出し:"<<status<<endl;

for(int i = 0;i < MEM_SIZE; i++)
{
for(int j = 0;j < MEM_SIZE; j++)
{
if(OutCheck[i*MEM_SIZE+j] == true){
cout << Outx[i]<< " " << Outy[j] << endl;
}
}
}

//cout <<"time = "<< (double)(t2 – t1) / CLOCKS_PER_SEC << endl;

delete OutCheck;

clReleaseMemObject(memoutx);
clReleaseMemObject(memouty);
clReleaseMemObject(memoutcheck);
clReleaseKernel(kernel);
clReleaseProgram(program);
clReleaseCommandQueue(queue);
clReleaseContext(context);
}
[/cpp]

[cpp]
//#define MEM_SIZE (2000)

__kernel void
calc(__global float *outx,
__global float *outy,
__global bool *outcheck )
{

#define MaxCalcNum 10000

//int width = 2, height = 2, j = 0;
//int out[MEM_SIZE*MEM_SIZE];

#pragma OPENCL EXTENSION cl_khr_fp64:enable
//int index_x = get_global_id(0);
//int index_y = get_global_id(1);
int index_x = get_group_id(0);
int index_y = get_local_id(0);

//if(index_x > MEM_SIZE)index_x = 1;
//if(index_y > MEM_SIZE)index_y = 1;
double prevX = 0.0f;
double prevY = 0.0f;

for(int i = 0; i < MaxCalcNum ; i++)
{
double newX = (prevX * prevX) – (prevY * prevY) + outx[index_x];
double newY = 2.0f * prevX * prevY + outy[index_y];

if ((newX * newX) + (newY * newY) > 4.0f)
{
outcheck[index_x * get_local_size(0) + index_y] = false;
break;
}
else
{
prevX = newX;
prevY = newY;
}
}
}
[/cpp]