- •1. Конструкторський розділ
- •1.1 Технологія OpenCl
- •1.2 Специфікація відеокарти Radeon hd 4850
- •1.3 Архітектура чіпу rv770
- •1.4 Мультипроцесор
- •2. Алгоритмічний розділ
- •2.1 Постановка завдання
- •2.2 Вибирання засобів розробки програмного забезпечення
- •2.3 Алгоритм
- •2.4 Збірка програмного забезпечення
- •3. Технологічний розділ
- •3.1 Опис алгоритму
- •4. Тестувальний розділ
- •4.1 Тестування програми
- •5. Висновок
- •6. Список літератури
- •7. Додаток
4. Тестувальний розділ
4.1 Тестування програми
Рис.4.1. Результати операцій над векторами і матрицями.
На Рис.4.1. показано, що операції виконував графічний процесор, перший вивід це додавання матриці, другий віднімання, третій най триваліший це добуток матриць. Нижче наведені такі ж дії але з векторами.
5. Висновок
Завдання курсової роботи було виконано, але програма була написана на графічному процесорі Nvidia gts 450 gddr3, тому що в результаті роботи 4850 не витримала навантаження. В ході роботи було реалізовано наступні алгоритми:
1. Додавання векторів(двох одномірних масивів) на мові openCL C.
2. Віднімання векторів(двох одномірних масивів) на мові openCL C.
3. Множення вектора на вектор(двох одномірних масивів)в результаті одне число на мові openCL C.
4. Множення вектора на скаляр(одного одномірного вектору на число) на мові openCL C.
5. Додавання матриць(двовимірних масивів) на мові openCL C.
6. Віднімання матриць(двовимірних масивів) на мові openCL C.
7. Множення матриць(двовимірних масивів) на мові openCL C.
В результаті виконаної роботи можна зробити висновок, що за допомогою GPGPU процесорів з підтримкою OpenCL, обробка досить великих об’ємів математичних даних є набагато швидшою ніж на CPU процесорі. Такої швидкості нам вдалося досягти завдяки паралельній обробці даних, що використовується на GPU процесорі.
6. Список літератури
1. http://www.khronos.org/opencl.html
2. http://www.cmsoft.com.br.html
3. Т. Бадд Об'єктно - орієнтоване програмування в дії - СПб.: Пітер 1997. – 464с.
4. http://opengl.gamedev.ru.html
5. М. Ласло Обчіслювальна Геометрія та комп'ютерна Графіка на С - М.: БІНОМ, 1997. – 304с
6. http://www.nvidia.ru/object/cuda_opencl_new_ru.html
7. Стівен Прата Язик програмування С. Лекції і вправи - Київ: DiaSoft, 2000.
8. Джефф Элджер. C++: Библиотека программиста. – Пітер, 2000.
9. Т.А. Павловська Програмування на мові високого рівня C / С - Москва, Санкт - Петербург, Мінськ, Київ 2002. – 450 ст.
10. Г. Шилт Теорія і практика С – СПб.: BHV, 1996. – 416 с.
11. (http://www.nvidia.com/object/product-geforce-gts-450-us.html
12. http://opencl.ru/design.html
7. Додаток
#include <oclUtils.h>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <windows.h>
#include <conio.h>
using namespace std;
//----------------------------------------------------------------------
typedef struct
{
unsigned W; unsigned H; cl_mem E;
} matrix_t ;
int main ( int argc , char ** argv )
{
const unsigned L = 1234 , M = 567 , N = 8910;
const unsigned BLOCK_SIZE = 16;
cl_context cntx ;
cl_command_queue cq;
cl_device_id * ds; // пристрій
cl_program p;
cl_kernel k;
char * program_source = "..."; // ядра
size_t global_work_size [2] = {L, N};
size_t local_work_size [2] = { BLOCK_SIZE , BLOCK_SIZE };
size_t cb;
float mem_A [L][M], mem_B [M][N], mem_R [L][N];
matrix_t A, B, R;
int i = -1;
// ...
cntx = clCreateContextFromType (NULL , CL_DEVICE_TYPE_GPU , NULL , NULL , NULL );
clGetContextInfo (cntx , CL_CONTEXT_DEVICES , 0, NULL , &cb );
ds = malloc (cb );
clGetContextInfo (cntx , CL_CONTEXT_DEVICES , cb , ds , NULL );
cq = clCreateCommandQueue (cntx , ds [0] , 0, NULL );
free (ds );
p = clCreateProgramWithSource (cntx , 1, & program_source , NULL , NULL );
clBuildProgram (p, 0, NULL , NULL , NULL , NULL );
k = clCreateKernel (p, " matrix_multiply ", NULL );
A.H = L; A.W = M;
A.E = clCreateBuffer (cntx , CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR ,
A.H * A.W * sizeof ( cl_float ), mem_A , NULL );
B.H = M; B.W = N;
B.E = clCreateBuffer (cntx , CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR ,
B.H * B.W * sizeof ( cl_float ), mem_B , NULL );
R.H = L; R.W = N;
R.E = clCreateBuffer (cntx , CL_MEM_READ_WRITE ,
R.H * R.W * sizeof ( cl_float ), NULL , NULL );
clSetKernelArg (k, i += 1, sizeof ( unsigned ), &A.H);
clSetKernelArg (k, i += 1, sizeof ( unsigned ), &A.W);
clSetKernelArg (k, i += 1, sizeof ( cl_mem ), &A.E);
clSetKernelArg (k, i += 1, sizeof ( unsigned ), &B.H);
clSetKernelArg (k, i += 1, sizeof ( unsigned ), &B.W);
clSetKernelArg (k, i += 1, sizeof ( cl_mem ), &B.E);
clSetKernelArg (k, i += 1, sizeof ( unsigned ), &R.H);
clSetKernelArg (k, i += 1, sizeof ( unsigned ), &R.W);
clSetKernelArg (k, i += 1, sizeof ( cl_mem ), &R.E);
clEnqueueNDRangeKernel (cq , k, 2, NULL ,
global_work_size , local_work_size , 0, NULL , NULL );
clEnqueueReadBuffer (cq , R.E, CL_TRUE , 0,
R.W * R.H * sizeof ( cl_float ), mem_R , 0, NULL , NULL );
clReleaseMemObject (A.E);
clReleaseMemObject (B.E);
clReleaseMemObject (R.E);
clReleaseKernel (k);
clReleaseProgram (p);
clReleaseCommandQueue (cq );
clReleaseContext ( cntx );
// ...
return 0;
}
class VectorGPU {
private:
// OpenCL Vars
cl_context cxGPUContext; // OpenCL контекст
cl_command_queue cqCommandQueue;// OpenCL команди черги
cl_platform_id cpPlatform; // OpenCL платформа
cl_device_id cdDevice; // OpenCL пристрій
cl_program cpProgram; // OpenCL програма
cl_kernel ckKernel; // OpenCL ядро
cl_mem cmDevSrcA; // OpenCL пристрій вихідний буфер A
cl_mem cmDevSrcB; // OpenCL пристрій вихідний буфер B
cl_mem cmDevDst; //OpenCL буфера пристрою призначення
size_t szGlobalWorkSize;
size_t szLocalWorkSize;
size_t szParmDataBytes; // Байт розмір інформаційним контекстом
size_t szKernelLength; // Байт розмір коду ядра
cl_int ciErr1, ciErr2; // Код помилки var
char* cPathAndName;
char* cSourceCL; // Буфер для зберігання джерелом для складання
public:
int n;
void *srcA, *srcB, *dst; // Хост буферів для OpenCL тест
VectorGPU();
VectorGPU(int size);
~VectorGPU();
int ClInit();
int CLAllocMem (int iNumElements);
int ClCreateProg(char *funcname, int iNumElements);
int ClWriteDataGPU();
int ClCompute();
int ClReadDataGPU();
unsigned int VAdd();
unsigned int VSub();
unsigned int MulSc(float scalar);
};
VectorGPU::VectorGPU()
{
}
VectorGPU::VectorGPU(int size)
{
if (ClInit()==1)
{
if (CLAllocMem(size)==1)
{
}
}
}
VectorGPU::~VectorGPU()
{
}
unsigned int VectorGPU::VAdd()
{
unsigned int t1,t2;
if (ClCreateProg("VectorAdd",n)==1)
{
t1=GetTickCount();
if (ClWriteDataGPU()==1)
{
if (ClCompute()==1)
{
t2=GetTickCount();
}
if (ClReadDataGPU()==1)
{
}
}
}
return ((int)(t2-t1));
}
unsigned int VectorGPU::VSub()
{
unsigned int t1,t2;
if (ClCreateProg("VectorSub",n)==1)
{
t1=GetTickCount();
if (ClWriteDataGPU()==1)
{
if (ClCompute()==1)
{
t2=GetTickCount();
}
if (ClReadDataGPU()==1)
{
}
}
}
return ((int)(t2-t1));
}
unsigned int VectorGPU::MulSc(float scalar)
{
unsigned int t1,t2;
float *b=(float*) srcB;
b[0]=scalar;
if (ClCreateProg("VectorMulSc",n)==1)
{
t1=GetTickCount();
if (ClWriteDataGPU()==1)
{
if (ClCompute()==1)
{
t2=GetTickCount();
}
if (ClReadDataGPU()==1)
{
}
}
}
return ((int)(t2-t1));
}
int VectorGPU::ClInit()
{
//Отримати OpenCL платформи
ciErr1 = clGetPlatformIDs(1, &cpPlatform, NULL);
if (ciErr1 != CL_SUCCESS)
{
return 0;
}
//Отримати пристроїв
ciErr1 = clGetDeviceIDs(cpPlatform, CL_DEVICE_TYPE_GPU, 1, &cdDevice, NULL);
if (ciErr1 != CL_SUCCESS)
{
return 0;
}
//Створення контексту
cxGPUContext = clCreateContext(0, 1, &cdDevice, NULL, NULL, &ciErr1);
if (ciErr1 != CL_SUCCESS)
{
return 0;
}
// Створити команду черги
cqCommandQueue = clCreateCommandQueue(cxGPUContext, cdDevice, 0, &ciErr1);
if (ciErr1 != CL_SUCCESS)
{
return 0;
}
return 1;
}
//----------------
int VectorGPU::CLAllocMem (int iNumElements)
{
szLocalWorkSize = 256;
szGlobalWorkSize = shrRoundUp((int)szLocalWorkSize, iNumElements); // округлюється до найближчого числа, кратного LocalWorkSize
// Виділяють і ініціалізації хост масивів
srcA = (void *)malloc(sizeof(cl_float) * szGlobalWorkSize);
srcB = (void *)malloc(sizeof(cl_float) * szGlobalWorkSize);
dst = (void *)malloc(sizeof(cl_float) * szGlobalWorkSize);
Golden = (void *)malloc(sizeof(cl_float) * iNumElements);
shrFillArray((float*)srcA, iNumElements);
shrFillArray((float*)srcB, iNumElements);
// Виділяють OpenCL буферної пам'яті об'єктів для джерела і результат на пристрій GMEM
cmDevSrcA = clCreateBuffer(cxGPUContext, CL_MEM_READ_ONLY, sizeof(cl_float) * szGlobalWorkSize, NULL, &ciErr1);
cmDevSrcB = clCreateBuffer(cxGPUContext, CL_MEM_READ_ONLY, sizeof(cl_float) * szGlobalWorkSize, NULL, &ciErr2);
ciErr1 |= ciErr2;
cmDevDst = clCreateBuffer(cxGPUContext, CL_MEM_WRITE_ONLY, sizeof(cl_float) * szGlobalWorkSize, NULL, &ciErr2);
ciErr1 |= ciErr2;
if (ciErr1 != CL_SUCCESS)
{
return 0;
}
return 1;
}
//----------------
int VectorGPU::ClCreateProg(char *funcname, int iNumElements)
{
// Створення програми
cSourceCL = oclLoadProgSource("VectorAdd.cl", "", &szKernelLength);
cpProgram = clCreateProgramWithSource(cxGPUContext, 1, (const char **)&cSourceCL, &szKernelLength, &ciErr1);
if (ciErr1 != CL_SUCCESS)
{
return 0;
}
ciErr1 = clBuildProgram(cpProgram, 0, NULL, NULL, NULL, NULL);
if (ciErr1 != CL_SUCCESS)
{
return 0;
}
// Створення ядра
ckKernel = clCreateKernel(cpProgram, funcname, &ciErr1);
if (ciErr1 != CL_SUCCESS)
{
return 0;
}
// Встановити Аргумент значення
ciErr1 = clSetKernelArg(ckKernel, 0, sizeof(cl_mem), (void*)&cmDevSrcA);
ciErr1 |= clSetKernelArg(ckKernel, 1, sizeof(cl_mem), (void*)&cmDevSrcB);
ciErr1 |= clSetKernelArg(ckKernel, 2, sizeof(cl_mem), (void*)&cmDevDst);
ciErr1 |= clSetKernelArg(ckKernel, 3, sizeof(cl_int), (void*)&iNumElements);
if (ciErr1 != CL_SUCCESS)
{
return 0;
}
return 1;
}
//---------------
int VectorGPU::ClWriteDataGPU()
{
//Asynchronous запису даних на GPU пристрої
ciErr1 = clEnqueueWriteBuffer(cqCommandQueue, cmDevSrcA, CL_FALSE, 0, sizeof(cl_float) * szGlobalWorkSize, srcA, 0, NULL, NULL);
ciErr1 |= clEnqueueWriteBuffer(cqCommandQueue, cmDevSrcB, CL_FALSE, 0, sizeof(cl_float) * szGlobalWorkSize, srcB, 0, NULL, NULL);
if (ciErr1 != CL_SUCCESS)
{
return 0;
}
return 1;
}
//----------------
int VectorGPU::ClCompute()
{
// Початок kernel
ciErr1 = clEnqueueNDRangeKernel(cqCommandQueue, ckKernel, 1, NULL, &szGlobalWorkSize, &szLocalWorkSize, 0, NULL, NULL);
if (ciErr1 != CL_SUCCESS)
{
return 0;
}
return 1;
}
//----------------
int VectorGPU::ClReadDataGPU()
{
// Synchronous / блокування читання результатів, а також перевірити накопичені помилки
ciErr1 = clEnqueueReadBuffer(cqCommandQueue, cmDevDst, CL_TRUE, 0, sizeof(cl_float) * szGlobalWorkSize, dst, 0, NULL, NULL);
if (ciErr1 != CL_SUCCESS)
{
return 0;
}
return 1;
}
//----------------
void FillMasData(float *x,int n)
{
for (int i=0;i<n;i++)
x[i]=i;
return;
}
//----------------
int main(int argc, char **argv)
{
int n;
unsigned int t1,t2;
n=20000000;
//---------------
VectorGPU v=VectorGPU(n);
//----------------
FillMasData((float*)v.srcA,n);
FillMasData((float*)v.srcB,n);
//----------------
printf("GPU:\nAdd - %d msec\nSub - %d msec\nMulSc - %d msec\n",v.VAdd(),v.VSub(),v.MulSc(10000.89));
//----------------
getch();
return 0;
}