I.はじめに
最近、3Dデータ処理に非常に時間がかかる3D点群処理プロジェクトに取り組んでいますが、プロジェクトアルゴリズムの処理速度を高速化するために、コンピュータのGPU処理性能をフルに発揮させ、プロジェクトアルゴリズムの各モジュールにOpenclとCUDAアクセラレーション技術を採用しました。この記事では Opencl 部分のみを記録しており、CUDA 部分は後で更新されます。いつものように、簡単な紹介から始めて、以下はサブセクションで始まります。
2. OpenCL の関連概念
OpenCL は、CPU、GPU、またはその他の種類のプロセッサで構成される異種プラットフォーム用のプログラムを作成するためのフレームワークです。OpenCL は、カーネル (OpenCL デバイス上で実行されるカーネル関数) を記述するための言語 (C99 ベース) と、プラットフォームを定義および制御するための API セットで構成されます。OpenCL は、データ並列処理とタスク並列処理という 2 つのレベルの並列処理を提供します。完全な OpenCL アクセラレーション テクノロジ プロセスには、プラットフォーム (Platform)、デバイス (Device)、コンテキスト (Context)、OpenCL プログラム (Program)、命令キュー (Command)、カーネル関数 (Kernel)、メモリ オブジェクト (Memory Object)、および呼び出しデバイス インターフェイス (NDRange) が含まれます。以下にそれぞれ簡単に紹介し、参考資料への関連リンクを後で示します。
- プラットフォーム: OpenCL フレームワークの管理下にあるホストと複数のデバイスがプラットフォームを構成し、アプリケーションはこのプラットフォームを通じてデバイスとリソースを共有し、デバイス上でカーネルを実行できます。
- デバイス: 公式の説明では、コンピューティング ユニットの集合です。たとえば、GPU は典型的なデバイスです。Intel や AMD のマルチコア CPU も OpenCL インターフェイスを提供しているため、デバイスとしても使用できます。
- コンテキスト: カーネル、デバイス、メモリ オブジェクト、コマンド キューなどを含む、OpenCL プラットフォーム上のリソースを共有および使用するための環境。一般に、プラットフォームは使用中のコンテキストに対応します。
- OpenCL プログラム (プログラム): OpenCL プログラムは、カーネル関数、その他の関数、および宣言で構成されます。
- コマンド キュー (コマンド キュー): 指定したデバイス上の複数のコマンド (コマンド) を管理します。キュー内の命令は、順番に実行することも、順不同で実行することもできます。デバイスは複数の命令キューに対応できます。
- カーネル: ホスト側から呼び出してデバイス側で実行できる関数。アルゴリズムの高速化が必要な部分です。
- メモリ オブジェクト (メモリ オブジェクト): ホストとデバイス間でデータを転送するオブジェクト。通常、OpenCL プログラムのグローバル メモリにマップされます。具体的なタイプとしては、バッファ オブジェクト (キャッシュ オブジェクト) とイメージ オブジェクト (イメージ オブジェクト) の 2 つがあります。
- コール デバイス インターフェイス (NDRange): ホストがデバイス側のカーネル関数を実行するためのメイン インターフェイス。実際には他にもあります。NDRange は非常に一般的で、操作のグループ化に使用されます。将来使用すると違いがわかるでしょう。
3. OpenCL プログラミングの手順
Opencl プログラミングの手順は比較的面倒ですが、比較的固定されており、以下のコレクション コードが導入され、操作を理解して使用できます。
1. プラットフォームの検索と初期化
clGetPlatformIDs 関数を 2 回呼び出します。1 回目は使用可能なプラットフォームの数を取得し、2 回目は使用可能なプラットフォームを取得します。コードリファレンスは次のとおりです。
int getPlatform(cl_platform_id &platform)
{
platform = NULL;//the chosen platform
cl_uint numPlatforms;//the NO. of platforms
cl_int status = clGetPlatformIDs(0, NULL, &numPlatforms);
if (status != CL_SUCCESS)
{
cout << "Error: Getting platforms!" << endl;
return -1;
}
/**For clarity, choose the first available platform. */
if (numPlatforms > 0)
{
cl_platform_id* platforms =
(cl_platform_id*)malloc(numPlatforms * sizeof(cl_platform_id));
status = clGetPlatformIDs(numPlatforms, platforms, NULL);
platform = platforms[0];
free(platforms);
}
else
return -1;
}
2. デバイスの検索と初期化
clGetDeviceIDs 関数を 2 回呼び出します。1 回目は使用可能なデバイスの数を取得し、2 回目は使用可能なデバイスを取得します。コードリファレンスは次のとおりです。
cl_device_id *getCl_device_id(cl_platform_id &platform)
{
cl_uint numDevices = 0;
cl_device_id *devices = NULL;
cl_int status = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 0, NULL, &numDevices);
if (numDevices > 0) //GPU available.
{
devices = (cl_device_id*)malloc(numDevices * sizeof(cl_device_id));
status = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, numDevices, devices, NULL);
}
return devices;
}
3. コンテキストを作成する
clCreateContext 関数を呼び出すと、コンテキスト コンテキストで複数のデバイスを管理できます。コードリファレンスは次のとおりです。
oclContext=clCreateContext(NULL,1,&oclComputeDeviceID,NULL,NULL,&ret_ocl);
4. コマンドキューを作成する
clCreateCommandQueue 関数を呼び出すと、デバイスがコマンド キューに対応します。コンテキスト conetxt はデバイスに対応するコマンド キューにコマンドを送信し、デバイスはコマンド キュー内のコマンドを実行できます。コードリファレンスは次のとおりです。
oclCommandQueue=clCreateCommandQueue(oclContext,oclComputeDeviceID,0,&ret_ocl);
5. メモリオブジェクトを作成する
clCreateBuffer 関数を呼び出すと、データ オブジェクトがバッファーに保存されます。これは、デバイスがプログラムを実行するために必要なデータです。バッファはコンテキスト conetxt によって作成されるため、コンテキストによって管理される複数のデバイスがバッファ内のデータを共有します。コードリファレンスは次のとおりです。
deviceInput1=clCreateBuffer(oclContext,CL_MEM_READ_ONLY,size,NULL,&ret_ocl);
6. プログラムオブジェクトの作成
プログラム ソース ファイルまたはバイナリ コード データを表すプログラム オブジェクトを作成します。ここではOpenclの組み込み関数と、Kernelのカーネル関数を読み込むための自作のツール関数を呼び出します。ファイル拡張子は .cl です。コードリファレンスは次のとおりです。
ret_ocl=clBuildProgram(oclProgram,0,NULL,NULL,NULL,NULL);
char * ReadKernelSourceFile(const char* filename, size_t* length)
{
FILE *file = NULL;
size_t sourcesLength;
char* sourcesString;
int ret;
file = fopen(filename, "rb");
if (file==NULL)
{
//printf("%s at %d:Can't open %s\n", _FILE, _LINE_ - 2, filename);
return NULL;
}
fseek(file, 0, SEEK_END);
sourcesLength = ftell(file);//the file length;
fseek(file, 0, SEEK_SET);
sourcesString = (char*)malloc(sourcesLength + 1);
//sourcesString[0] = '\0';
ret = fread(sourcesString, sourcesLength, 1, file);
//read file fail
if (ret==0)
{
//printf("%s at %d:Can't open %s\n", _FILE, _LINE_ - 2, filename);
return NULL;
}
fclose(file);
if (length!=0)
{
*length = sourcesLength;
}
sourcesString[sourcesLength] = '\0';//最后一位加0表示结束
return sourcesString;
}
7. カーネル関数カーネルの作成
clCreateKernel 関数を呼び出して、デバイス プログラムのエントリを表すプログラム オブジェクトに従ってカーネル オブジェクトを生成します。参照コードは次のとおりです。
// create OpenCL kernel by passing kernel function name that we used in .cl file
oclKernel=clCreateKernel(oclProgram,"vecAdd",&ret_ocl);
8. カーネルパラメータの設定
clSetKernelArg 関数を呼び出します。参照コードは次のとおりです。
ret_ocl=clSetKernelArg(oclKernel,0,sizeof(cl_mem),(void *)&deviceInput1); // 'deviceInput1' maps to 'in1' param of kernel function in .cl file
9. ワークアイテムのサイズを設定し、カーネル関数を実行します
ワークアイテム(ワークサイズ)の設定は、単純にスレッド数として理解できます。カーネル関数を実行するには、clEnqueueNDRangeKernel 関数を呼び出します。参照コードは次のとおりです。
ret_ocl=clEnqueueNDRangeKernel(oclCommandQueue,oclKernel,1,NULL,&globalWorkSize,&localWorkSize,0,NULL,NULL);
10. 結果をホストに読み取ります
デバイス側で結果を実行した後、結果をホスト側にコピーし、次のステップで対応する計算に参加し、clEnqueueReadBuffer 関数を呼び出す必要があります。参照コードは次のとおりです。
ret_ocl=clEnqueueReadBuffer(oclCommandQueue,deviceOutput,CL_TRUE,0,size,hostOutput,0,NULL,NULL);
11. リソースの解放。
必要な高速化部分が完了し、結果が得られた後、デバイス側のリソースを解放して、操作プロセス全体を完了する必要があります。リソースリリース opencl には組み込み関数があり、参照コードは次のとおりです。
void cleanup(void)
{
// code
// OpenCL cleanup
if(oclSourceCode)
{
free((void *)oclSourceCode);
oclSourceCode=NULL;
}
if(oclKernel)
{
clReleaseKernel(oclKernel);
oclKernel=NULL;
}
if(oclProgram)
{
clReleaseProgram(oclProgram);
oclProgram=NULL;
}
if(oclCommandQueue)
{
clReleaseCommandQueue(oclCommandQueue);
oclCommandQueue=NULL;
}
if(oclContext)
{
clReleaseContext(oclContext);
oclContext=NULL;
}
// free allocated device-memory
if(deviceInput1)
{
clReleaseMemObject(deviceInput1);
deviceInput1=NULL;
}
if(deviceInput2)
{
clReleaseMemObject(deviceInput2);
deviceInput2=NULL;
}
if(deviceOutput)
{
clReleaseMemObject(deviceOutput);
deviceOutput=NULL;
}
// free allocated host-memory
if(hostInput1)
{
free(hostInput1);
hostInput1=NULL;
}
if(hostInput2)
{
free(hostInput2);
hostInput2=NULL;
}
if(hostOutput)
{
free(hostOutput);
hostOutput=NULL;
}
if(gold)
{
free(gold);
gold=NULL;
}
}
ここまでで、opencl のプロセス全体が完了しましたが、参考までに、ベクターを追加した完全な例を以下に示します。
4. プログラムインスタンスベクトルの追加
この例には、ツール ファイル、関数カーネル関数ファイル、メイン プログラム、ツール ファイル tools.h および tools.cpp、カーネル関数 VceAdd.cl が含まれています。メイン プログラム コード リファレンスは次のとおりで、他の 2 つのダウンロード リンク サンプル プロジェクト ファイルは次のとおりです。
// headers
#include <stdio.h>
#include <stdlib.h> // exit()
#include <string.h> // strlen()
#include <math.h> // fabs()
#include <iostream>
#include "CL/opencl.h"
#include "helper_timer.h"
// global OpenCL variables
cl_int ret_ocl;
cl_platform_id oclPlatformID;
cl_device_id oclComputeDeviceID; // compute device id
cl_context oclContext; // compute context
cl_command_queue oclCommandQueue; // compute command queue
cl_program oclProgram; // compute program
cl_kernel oclKernel; // compute kernel
char *oclSourceCode=NULL;
size_t sizeKernelCodeLength;
// odd number 11444777 is deliberate illustration ( Nvidia OpenCL Samples )
int iNumberOfArrayElements = 11444777;
size_t localWorkSize=256;
size_t globalWorkSize;
float *hostInput1=NULL;
float *hostInput2=NULL;
float *hostOutput=NULL;
float *gold=NULL;
cl_mem deviceInput1=NULL;
cl_mem deviceInput2=NULL;
cl_mem deviceOutput=NULL;
float timeOnCPU;
float timeOnGPU;
int main(void)
{
// function declarations
void fillFloatArrayWithRandomNumbers(float *, int);
size_t roundGlobalSizeToNearestMultipleOfLocalSize(int, unsigned int);
void vecAddHost(const float *, const float *, float *, int);
char* loadOclProgramSource(const char *,const char *,size_t *);
void cleanup(void);
void FileInit(float *, int );
// code
// allocate host-memory
hostInput1=(float *)malloc(sizeof(float) * iNumberOfArrayElements);
if(hostInput1== NULL)
{
printf("CPU Memory Fatal Error = Can Not Allocate Enough Memory For Host Input Array 1.\nExitting ...\n");
cleanup();
exit(EXIT_FAILURE);
}
hostInput2=(float *)malloc(sizeof(float) * iNumberOfArrayElements);
if(hostInput2== NULL)
{
printf("CPU Memory Fatal Error = Can Not Allocate Enough Memory For Host Input Array 2.\nExitting ...\n");
cleanup();
exit(EXIT_FAILURE);
}
// allocate host-memory to hold 'float' type host vector hostOutput
hostOutput=(float *)malloc(sizeof(float) * iNumberOfArrayElements);
if(hostOutput== NULL)
{
printf("CPU Memory Fatal Error = Can Not Allocate Enough Memory For Host Output Array.\nExitting ...\n");
cleanup();
exit(EXIT_FAILURE);
}
gold=(float *)malloc(sizeof(float) * iNumberOfArrayElements);
if(gold== NULL)
{
printf("CPU Memory Fatal Error = Can Not Allocate Enough Memory For Gold Output Array.\nExitting ...\n");
cleanup();
exit(EXIT_FAILURE);
}
// fill above input host vectors with arbitary but hard-coded data
// fillFloatArrayWithRandomNumbers(hostInput1,iNumberOfArrayElements);
// fillFloatArrayWithRandomNumbers(hostInput2,iNumberOfArrayElements);
FileInit(hostInput1, iNumberOfArrayElements);
FileInit(hostInput2, iNumberOfArrayElements);
// get OpenCL supporting platform's ID
ret_ocl=clGetPlatformIDs(1,&oclPlatformID,NULL);
if(ret_ocl != CL_SUCCESS)
{
printf("OpenCL Error - clGetDeviceIDs() Failed : %d. Exitting Now ...\n",ret_ocl);
cleanup();
exit(EXIT_FAILURE);
}
// get OpenCL supporting GPU device's ID
ret_ocl=clGetDeviceIDs(oclPlatformID,CL_DEVICE_TYPE_GPU,1,&oclComputeDeviceID,NULL);
if(ret_ocl != CL_SUCCESS)
{
printf("OpenCL Error - clGetDeviceIDs() Failed : %d. Exitting Now ...\n",ret_ocl);
cleanup();
exit(EXIT_FAILURE);
}
char gpu_name[255];
clGetDeviceInfo(oclComputeDeviceID,CL_DEVICE_NAME,sizeof(gpu_name),&gpu_name,NULL);
printf("%s\n",gpu_name);
// create OpenCL compute context
oclContext=clCreateContext(NULL,1,&oclComputeDeviceID,NULL,NULL,&ret_ocl);
if(ret_ocl!=CL_SUCCESS)
{
printf("OpenCL Error - clCreateContext() Failed : %d. Exitting Now ...\n",ret_ocl);
cleanup();
exit(EXIT_FAILURE);
}
// create command queue
oclCommandQueue=clCreateCommandQueue(oclContext,oclComputeDeviceID,0,&ret_ocl);
if(ret_ocl!=CL_SUCCESS)
{
printf("OpenCL Error - clCreateCommandQueue() Failed : %d. Exitting Now ...\n",ret_ocl);
cleanup();
exit(EXIT_FAILURE);
}
// create OpenCL program from .cl
oclSourceCode=loadOclProgramSource("VecAddenw.cl","",&sizeKernelCodeLength);
cl_int status=0;
oclProgram = clCreateProgramWithSource(oclContext, 1, (const char **)&oclSourceCode, &sizeKernelCodeLength, &ret_ocl);
if(ret_ocl!=CL_SUCCESS)
{
printf("OpenCL Error - clCreateProgramWithSource() Failed : %d. Exitting Now ...\n",ret_ocl);
cleanup();
exit(0);
}
// build OpenCL program
ret_ocl=clBuildProgram(oclProgram,0,NULL,NULL,NULL,NULL);
if(ret_ocl!=CL_SUCCESS)
{
printf("OpenCL Error - clBuildProgram() Failed : %d. Exitting Now ...\n",ret_ocl);
size_t len;
char buffer[2048];
clGetProgramBuildInfo(oclProgram,oclComputeDeviceID,CL_PROGRAM_BUILD_LOG,sizeof(buffer),buffer,&len);
printf("OpenCL Program Build Log : %s\n",buffer);
cleanup();
exit(EXIT_FAILURE);
}
// create OpenCL kernel by passing kernel function name that we used in .cl file
oclKernel=clCreateKernel(oclProgram,"vecAdd",&ret_ocl);
if(ret_ocl!=CL_SUCCESS)
{
printf("OpenCL Error - clCreateKernel() Failed : %d. Exitting Now ...\n",ret_ocl);
cleanup();
exit(EXIT_FAILURE);
}
int size=iNumberOfArrayElements * sizeof(cl_float);
// allocate device-memory
deviceInput1=clCreateBuffer(oclContext,CL_MEM_READ_ONLY,size,NULL,&ret_ocl);
if(ret_ocl!=CL_SUCCESS)
{
printf("OpenCL Error - clCreateBuffer() Failed For 1st Input Array : %d. Exitting Now ...\n",ret_ocl);
cleanup();
exit(EXIT_FAILURE);
}
deviceInput2=clCreateBuffer(oclContext,CL_MEM_READ_ONLY,size,NULL,&ret_ocl);
if(ret_ocl!=CL_SUCCESS)
{
printf("OpenCL Error - clCreateBuffer() Failed For 2nd Input Array : %d. Exitting Now ...\n",ret_ocl);
cleanup();
exit(EXIT_FAILURE);
}
deviceOutput=clCreateBuffer(oclContext,CL_MEM_WRITE_ONLY,size,NULL,&ret_ocl);
if(ret_ocl!=CL_SUCCESS)
{
printf("OpenCL Error - clCreateBuffer() Failed For 2nd Input Array : %d. Exitting Now ...\n",ret_ocl);
cleanup();
exit(EXIT_FAILURE);
}
// set OpenCL kernel arguments. Our OpenCL kernel has 4 arguments 0,1,2,3
// set 0 based 0th argument i.e. deviceInput1
ret_ocl=clSetKernelArg(oclKernel,0,sizeof(cl_mem),(void *)&deviceInput1); // 'deviceInput1' maps to 'in1' param of kernel function in .cl file
if(ret_ocl != CL_SUCCESS)
{
printf("OpenCL Error - clSetKernelArg() Failed For 1st Argument : %d. Exitting Now ...\n",ret_ocl);
cleanup();
exit(EXIT_FAILURE);
}
// set 0 based 1st argument i.e. deviceInput2
ret_ocl=clSetKernelArg(oclKernel,1,sizeof(cl_mem),(void *)&deviceInput2); // 'deviceInput2' maps to 'in2' param of kernel function in .cl file
if(ret_ocl != CL_SUCCESS)
{
printf("OpenCL Error - clSetKernelArg() Failed For 2nd Argument : %d. Exitting Now ...\n",ret_ocl);
cleanup();
exit(EXIT_FAILURE);
}
// set 0 based 2nd argument i.e. deviceOutput
ret_ocl=clSetKernelArg(oclKernel,2,sizeof(cl_mem),(void *)&deviceOutput); // 'deviceOutput' maps to 'out' param of kernel function in .cl file
if(ret_ocl != CL_SUCCESS)
{
printf("OpenCL Error - clSetKernelArg() Failed For 3rd Argument : %d. Exitting Now ...\n",ret_ocl);
cleanup();
exit(EXIT_FAILURE);
}
// set 0 based 3rd argument i.e. len
ret_ocl=clSetKernelArg(oclKernel,3,sizeof(cl_int),(void *)&iNumberOfArrayElements); // 'iNumberOfArrayElements' maps to 'len' param of kernel function in .cl file
if(ret_ocl != CL_SUCCESS)
{
printf("OpenCL Error - clSetKernelArg() Failed For 4th Argument : %d. Exitting Now ...\n",ret_ocl);
cleanup();
exit(EXIT_FAILURE);
}
// write abve 'input' device buffer to device memory
ret_ocl=clEnqueueWriteBuffer(oclCommandQueue,deviceInput1,CL_FALSE,0,size,hostInput1,0,NULL,NULL);
if(ret_ocl != CL_SUCCESS)
{
printf("OpenCL Error - clEnqueueWriteBuffer() Failed For 1st Input Device Buffer : %d. Exitting Now ...\n",ret_ocl);
cleanup();
exit(EXIT_FAILURE);
}
ret_ocl=clEnqueueWriteBuffer(oclCommandQueue,deviceInput2,CL_FALSE,0,size,hostInput2,0,NULL,NULL);
if(ret_ocl != CL_SUCCESS)
{
printf("OpenCL Error - clEnqueueWriteBuffer() Failed For 2nd Input Device Buffer : %d. Exitting Now ...\n",ret_ocl);
cleanup();
exit(EXIT_FAILURE);
}
// run the kernel
globalWorkSize=roundGlobalSizeToNearestMultipleOfLocalSize(localWorkSize, iNumberOfArrayElements);
// start timer
StopWatchInterface *timer = NULL;
sdkCreateTimer(&timer);
sdkStartTimer(&timer);
ret_ocl=clEnqueueNDRangeKernel(oclCommandQueue,oclKernel,1,NULL,&globalWorkSize,&localWorkSize,0,NULL,NULL);
if(ret_ocl != CL_SUCCESS)
{
printf("OpenCL Error - clEnqueueNDRangeKernel() Failed : %d. Exitting Now ...\n",ret_ocl);
cleanup();
exit(EXIT_FAILURE);
}
// finish OpenCL command queue
clFinish(oclCommandQueue);
// stop timer
sdkStopTimer(&timer);
timeOnGPU = sdkGetTimerValue(&timer);
sdkDeleteTimer(&timer);
// read back result from the device (i.e from deviceOutput) into cpu variable (i.e hostOutput)
ret_ocl=clEnqueueReadBuffer(oclCommandQueue,deviceOutput,CL_TRUE,0,size,hostOutput,0,NULL,NULL);
if(ret_ocl != CL_SUCCESS)
{
printf("OpenCL Error - clEnqueueReadBuffer() Failed : %d. Exitting Now ...\n",ret_ocl);
cleanup();
exit(EXIT_FAILURE);
}
vecAddHost(hostInput1, hostInput2, gold, iNumberOfArrayElements);
// compare results for golden-host
const float epsilon = 0.000001f;
bool bAccuracy=true;
int breakValue=0;
int i;
for(i=0;i<iNumberOfArrayElements;i++)
{
/*
float val1 = gold[i];
float val2 = hostOutput[i];
if(fabs(val1-val2) > epsilon)
{
bAccuracy = false;
breakValue=i;
break;
}
*/
//std::cout << "HostOutPut:" << hostOutput[i] << std::endl;
}
if(bAccuracy==false)
{
printf("Break Value = %d\n",breakValue);
}
char str[125];
if(bAccuracy==true)
sprintf(str,"%s","Comparison Of Output Arrays On CPU And GPU Are Accurate Within The Limit Of 0.000001");
else
sprintf(str,"%s","Not All Comparison Of Output Arrays On CPU And GPU Are Accurate Within The Limit Of 0.000001");
printf("1st Array Is From 0th Element %.6f To %dth Element %.6f\n",hostInput1[0], iNumberOfArrayElements-1, hostInput1[iNumberOfArrayElements-1]);
printf("2nd Array Is From 0th Element %.6f To %dth Element %.6f\n",hostInput2[0], iNumberOfArrayElements-1, hostInput2[iNumberOfArrayElements-1]);
printf("Global Work Size = %u And Local Work Size Size = %u\n",(unsigned int)globalWorkSize, (unsigned int)localWorkSize);
printf("Sum Of Each Element From Above 2 Arrays Creates 3rd Array As :\n");
printf("3nd Array Is From 0th Element %.6f To %dth Element %.6f\n",hostOutput[0], iNumberOfArrayElements-1, hostOutput[iNumberOfArrayElements-1]);
printf("The Time Taken To Do Above Addition On CPU = %.6f (ms)\n",timeOnCPU);
printf("The Time Taken To Do Above Addition On GPU = %.6f (ms)\n",timeOnGPU);
printf("%s\n",str);
// total cleanup
cleanup();
system("pause");
return(0);
}
void cleanup(void)
{
// code
// OpenCL cleanup
if(oclSourceCode)
{
free((void *)oclSourceCode);
oclSourceCode=NULL;
}
if(oclKernel)
{
clReleaseKernel(oclKernel);
oclKernel=NULL;
}
if(oclProgram)
{
clReleaseProgram(oclProgram);
oclProgram=NULL;
}
if(oclCommandQueue)
{
clReleaseCommandQueue(oclCommandQueue);
oclCommandQueue=NULL;
}
if(oclContext)
{
clReleaseContext(oclContext);
oclContext=NULL;
}
// free allocated device-memory
if(deviceInput1)
{
clReleaseMemObject(deviceInput1);
deviceInput1=NULL;
}
if(deviceInput2)
{
clReleaseMemObject(deviceInput2);
deviceInput2=NULL;
}
if(deviceOutput)
{
clReleaseMemObject(deviceOutput);
deviceOutput=NULL;
}
// free allocated host-memory
if(hostInput1)
{
free(hostInput1);
hostInput1=NULL;
}
if(hostInput2)
{
free(hostInput2);
hostInput2=NULL;
}
if(hostOutput)
{
free(hostOutput);
hostOutput=NULL;
}
if(gold)
{
free(gold);
gold=NULL;
}
}
void fillFloatArrayWithRandomNumbers(float *pFloatArray, int iSize)
{
// code
int i;
const float fScale = 1.0f / (float)RAND_MAX;
for (i = 0; i < iSize; ++i)
{
pFloatArray[i] = fScale * rand();
}
}
void FileInit(float *p, int N)
{
for (int i = 0; i < N; i++)
{
p[i] = i;
}
}
size_t roundGlobalSizeToNearestMultipleOfLocalSize(int local_size, unsigned int global_size)
{
// code
unsigned int r = global_size % local_size;
if(r == 0)
{
return(global_size);
}
else
{
return(global_size + local_size - r);
}
}
// "Golden" Host processing vector addition function for comparison purposes
void vecAddHost(const float* pFloatData1, const float* pFloatData2, float* pFloatResult, int iNumElements)
{
int i;
StopWatchInterface *timer = NULL;
sdkCreateTimer(&timer);
sdkStartTimer(&timer);
for (i = 0; i < iNumElements; i++)
{
pFloatResult[i] = pFloatData1[i] + pFloatData2[i];
}
sdkStopTimer(&timer);
timeOnCPU = sdkGetTimerValue(&timer);
sdkDeleteTimer(&timer);
}
char* loadOclProgramSource(const char *filename, const char *preamble, size_t *sizeFinalLength)
{
// locals
FILE *pFile=NULL;
size_t sizeSourceLength;
pFile=fopen(filename,"rb"); // binary read
if(pFile==NULL)
return(NULL);
size_t sizePreambleLength=(size_t)strlen(preamble);
// get the length of the source code
fseek(pFile,0,SEEK_END);
sizeSourceLength=ftell(pFile);
fseek(pFile,0,SEEK_SET); // reset to beginning
// allocate a buffer for the source code string and read it in
char *sourceString=(char *)malloc(sizeSourceLength+sizePreambleLength+1);
memcpy(sourceString, preamble, sizePreambleLength);
if(fread((sourceString)+sizePreambleLength,sizeSourceLength,1,pFile)!=1)
{
fclose(pFile);
free(sourceString);
return(0);
}
// close the file and return the total length of the combined (preamble + source) string
fclose(pFile);
if(sizeFinalLength != 0)
{
*sizeFinalLength = sizeSourceLength + sizePreambleLength;
}
sourceString[sizeSourceLength + sizePreambleLength]='\0';
return(sourceString);
}
タイトな仕事のため、少し急いで書いており、間違いがあるのは避けられませんが、皆さんが私を修正し、お互いに学び合うことができれば幸いです。