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月中には、卒論の第一稿を提出したい。

トリプルブート

時間がないので超速で書く。
Windows8が発売されたこともあり、自分のノートパソコンのOSを入れ替えた。

windows8とLinuxMintとCentOS。
綺麗なブーストの仕方ではない気がするけど、一応動いているのでここまでの流れの備忘録。

最初にLinuxMintをインストール
次にCentOSインストール
Windows8インストール

基本的にはそのままだが、パーティションだけ分けた。
LinuxMint 30G
CentOS 30G
Windows8 200G
ハードディスク上のパーティションもまさしくこの順番。ブートローダ系の知識が全くなく、途中MintやCentが起動できなくなったけど「grub4dos」を利用するという方法にぶつかった。

普通はWindowsを最初にインストールしてWindowsのブートローダの上にLinuxのブートローダのGRUBに書き換えるとスムーズらしいけど、

Grub4dosを使うとWindowsのブートローダにGrub4dosのブートローダを読みこませることができる。
Grub4dosのブートローダを編集してあげてLinuxを呼ぼうって話。

今の状態
Windows8ブートローダ→「Windows8」「Linux」→「Linux」選択→Grub4dos起動→Linux「LinuxMint」「CentOS」

引っかかったのは、Windows8入れたあとに
●Grub4dos入れる
●Linuxのブートローダの「Menu.lst」編集

●Grub4dosを入れる
Grub4dosの入れ方はググればいろんなとこで出てくる。
1. grub4dosをダウンロードしたら、grldrとgrldr.mbrをC:にコピー。
2. Windowsのブートメニューをいじるためにはコマンドラインからでなければならないので、管理者モードでコマンドプロンプトを開く。
3. 次のコマンドでLinuxを追加。

$ bcdesit
$ bcdedit /create /d "Linux" /application bootsector
エントリ {xxxx} は正常に作成されました。
$ bcdedit /set {xxxx} device partition=C:
$ bcdedit /set {xxxx} path grldr.mbr
$ bcdedit /displayorder {xxxx} /addlast

こんな感じ。{xxxx}はめちゃ長いけど写す。

●Linuxのブートローダの「Menu.lst」編集
ぼくの場合、CentOSをあとから入れたのでLinuxのブートローダはCentOSにある。Grub4dosでLinuxに入ったら、CentOSに入り、Menu.lstを編集する。(Mint入れたあとにCent入れたら自動的にデュアルになると思ってたんだけど結局なってなくて、ここでその設定をした。ここではまだMintはでてなかった。)
ここで入れないと少しめんどくさい。

<Grub4dosからLinuxに入れなかった場合>
Windows8のブートローダでGrub4dosに入り、そこからLinuxを選択したいわけだが、入れなかった場合、Grub4dos起動したあとすぐに矢印キー連打してCommandモード的な奴に入り、直接MintかCentを起動する。
よく分かんないけどこんな感じでLinuxMintを起動できた。

grub> root (hd0,0)
Filesystem type is ext2fs, partition type 0x83
 
grub> kernel /boot/vmlinuz-3.2.0-23-generic root=/dev/sda1
[Linux-bzImage, Setup=0x4200, size=0x4b81d0]

grub> initrd /boot/initrd.img-3.2.0-23-generic
[Linux-inited @ 0x7f279000, 0xd85e6b bytes]

grub> boot

変えなくちゃいけないのは、最初のroot(hd0,0)と、kernelって売った行の最後のsda1ってとこ。hd0って言うのはハードディスクの構成で一枚目だからhd0、二枚目ならhd1的な。そんで(hd0,0)の二個目の0はパーティションの順番を指している。ぼくの場合一番最初にMintを入れたから0、次に入れたCentを指定するときには(hd0,1)を指定する。
次にsda1っていうのはよくわからんけど、一番最初は1始まりだから1らしい。
ぼくの場合、Mintはsda1, Centはsda2っぽい。
こんな感じでLinuxどっちでもいいけど起動する。ここまでがLinuxに入れなかった場合。

そんで次にやっと「Menu.lst」を編集する作業に入る。
LinuxのブートローダのMenuを編集するんだが、まずそのファイルがどこにあるかを探す。
ぼくの場合、CentOSの「/boot/grub/menu.lst」にあった。これをvimで編集した奴がこれ。

[root@s-kotake]# cat menu.lst
# grub.conf generated by anaconda
#
# Note that you do not have to rerun grub after making changes to this file
# NOTICE:  You do not have a /boot partition.  This means that
#          all kernel and initrd paths are relative to /, eg.
#          root (hd0,1)
#          kernel /boot/vmlinuz-version ro root=/dev/sda2
#          initrd /boot/initrd-[generic-]version.img
#boot=/dev/sda
default=0
timeout=5
splashimage=(hd0,1)/boot/grub/splash.xpm.gz
hiddenmenu
title Linux Mint
        root (hd0,0)
        kernel /boot/vmlinuz-3.2.0-23-generic ro root=/dev/sda1
        initrd /boot/initrd.img-3.2.0-23-generic

title CentOS (2.6.32-279.11.1.el6.x86_64)
        root (hd0,1)
        kernel /boot/vmlinuz-2.6.32-279.11.1.el6.x86_64 ro root=UUID=79c217e1-c0f2-4d85-b942-561fd6cef379 rd_NO_LUKS  KEYBOARDTYPE=pc KEYTABLE=us rd_NO_MD crashkernel=128M LANG=ja_JP.UTF-8 rd_NO_LVM rd_NO_DM rhgb
        initrd /boot/initramfs-2.6.32-279.11.1.el6.x86_64.img

title CentOS (2.6.32-279.el6.x86_64)
        root (hd0,1)
        kernel /boot/vmlinuz-2.6.32-279.el6.x86_64 ro root=UUID=79c217e1-c0f2-4d85-b942-561fd6cef379 rd_NO_LUKS  KEYBOARDTYPE=pc KEYTABLE=us rd_NO_MD crashkernel=128M LANG=ja_JP.UTF-8 rd_NO_LVM rd_NO_DM rhgb
        initrd /boot/initramfs-2.6.32-279.el6.x86_64.img

って感じ。今のところこれで何とかトリプルブートができてる良い感じ良い感じ。

Windows8のブートのところがおしゃれ。

卒論の方向性について

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

 最終的な目的は「環境を考慮した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]

Just another WordPress site