Download pdf - OpenCL Grundlagen

Transcript
Page 1: OpenCL Grundlagen

OpenCL – Data Parallel Language

Parallel Computing auf CPU, GPU und Cell

Ein FG Workshop von Christopher Scherb

Page 2: OpenCL Grundlagen

Inhalt

• Was bedeutet Data – Parallel?• Was ist ein Streamprozessor?• Was ist OpenCL?• Wie programmiert man OpenCL?• Grenzen?• Beispiele

Page 3: OpenCL Grundlagen

Was bedeutet Data – Parallel?

• Verarbeitung von Daten zur gleichen Zeit

• Multicore CPU

• SSE bzw. SIMD

• Streamprozessor

• GPU

for (int i = 0; i < datasize; i++){ data[i] = data[i] + 1;}

#pragma omp parallel num_threads(datasize){ int i = omp_get_thread_num(); data[i] = data[i] + 1;}

Page 4: OpenCL Grundlagen

Was ist ein Streamprozessor?

• CO – Prozessor• Viele kleine „Streamprozessoren“ • Zur Verarbeitung von Datenströmen• Hohe Parallelität • GPU?

Page 5: OpenCL Grundlagen

Was ist OpenCL?

• Data/Task Parallel Language• Für CPUs, GPUs, Cell und DSPs• Von Apple entwickelt• Verwaltet von der Khronos – Group• Programmiert wird in OpenCL C

Page 6: OpenCL Grundlagen

Plattform Model

Page 7: OpenCL Grundlagen

Plattform Model

• Host = System – Prozessor (CPU)• Compute Device = CPU / GPU / Cell• Compute Unit = SIMD Einheit• Prozessing Element = ALU des

Compute Devices

Page 8: OpenCL Grundlagen

Speichermodel

Page 9: OpenCL Grundlagen

Speichermodel

• Host Memory = System Memory• Global Memory = für alle Compute Units• Local Memory = für eine SIMD Einheit• Private Memory = für eine ALU

• Nur Local Memory kann synchronisiert werden!

Page 10: OpenCL Grundlagen

Ausführmodel

• Verarbeite jedes Element „einzeln“– Verteile auf verschiedene Compute Units

– SIMD wird nicht genutzt

• Fasse bestimmte Anzahl der Elemente zu Blöcken zusammen

– SIMD

– Verteile mehrere Blöcke über die Compute Units

– Synchronisierung

Page 11: OpenCL Grundlagen

Ausführmodel

Page 12: OpenCL Grundlagen

Wie programmiert man OpenCL?

• Host (System) initialisiert das OpenCL Device• Host erstellt und compiliert ein OpenCL

Programm• Host erstellt Kernel (= ausführbarer Code)• Host schreibt Daten auf das Device• Device verarbeitet Daten• Host liest Daten zurück

Page 13: OpenCL Grundlagen

Initialiesiere OpenCL Device

• Wähle eine Platform (= SDK)• Lese Context Einstellungen aus Platform• Erstelle Context

• Initialisiere Platform:

cl_uint numPlatforms;cl_platform_id platform = NULL;clGetPlatformIDs(0, NULL,

&numPlatforms);

Page 14: OpenCL Grundlagen

Platform auswählen

if (0 < numPlatforms){cl_platform_id* platforms = new cl_platform_id[numPlatforms];clGetPlatformIDs(numPlatforms, platforms, NULL);for (unsigned i = 0; i < numPlatforms; ++i){

char pbuf[100];

clGetPlatformInfo(platforms[i],CL_PLATFORM_VENDOR,sizeof(pbuf),pbuf,NULL);

platform = platforms[i];if (!strcmp(pbuf, "Advanced Micro Devices, Inc."))break;

}delete[] platforms;

}

cl_context_properties cps[3] ={CL_CONTEXT_PLATFORM,(cl_context_properties)platform,0};cl_context_properties* cprops =(platform==NULL) ? NULL : cps;

Page 15: OpenCL Grundlagen

Context erstellen

cl_context hContext;

hContext=clCreateContextFromType(cprops,CL_DEVICE_TYPE_GPU,0,0, &error);

errcheck(error,"clCreateContextFromType");

Errorcheck Funktion (Sollte nach jeden Verweis auf error aufgerufen werden):

void errcheck(int error, std::string error_code){if(error != CL_SUCCESS){

std::cout<<"Error: "<<error_code<<"("<<error<<")"<<std::endl;

exit(-1);}

}

Page 16: OpenCL Grundlagen

Lese Programm ein

• Lese Programm von Datei oder String• Compiliere Programm

std::ifstream file(<filename>);std::string prog(std::istreambuf_iterator<char>(file),(std::istreambuf_iterator<char>()));const char *sProgramSource=prog.c_str();

hProgram = clCreateProgramWithSource(hContext,1,(const char **)&sProgramSource,0,&error);

error = clBuildProgram(hProgram,0,0,0,0,0);

Page 17: OpenCL Grundlagen

Erstelle Kernel

• Erstelle ausführbares Programm aus den compilierten Daten

cl_kernel hKernel;hKernel=clCreateKernel(hProgram, <KernelName>,0);

Page 18: OpenCL Grundlagen

Initialisiere Daten

• Daten müssen gebuffert werden

• Minimiere Transfer zwischen Host und Device!

• Setze Kernel Argumente

cl_int *a=new cl_int[32];cl_mem CL1;CL1=clCreateBuffer(hContext,CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR,

sizeof(cl_int)*32,a, &error);error = clSetKernelArg(hKernel,0,sizeof(cl_mem),(void *)&CL1);

Page 19: OpenCL Grundlagen

Erstelle CommandQueue

• Umgebung zum Ausführen von Kerneln

• Wichtig für Synchronisierung zwischen verschiedenen Kerneln

• Nutze gemeinsame Daten in verschiedenen Kerneln

hCmdQueue=clCreateCommandQueue(hContext,aDevices[0],0,0);

Page 20: OpenCL Grundlagen

Führe die Queue aus

• In Order oder Qut of Order

error = clEnqueueNDRangeKernel(hCmdQueue, hKernel,1,0,<globalworksize>, <localworksize>,0,0,0,0);

• Lese Daten zurückerror=clEnqueueReadBuffer(hCmdQueue,CL1,CL_TRUE,0,sizeof(cl_int)*32,a,0,0,0);

• Free Memory

delete [] a;clReleaseMemObject(CL1);

Page 21: OpenCL Grundlagen

Wie sieht ein Programm aus?

• Vectoraddition

• OpenCL C

__kernel void vecadd(__global int* a, __global int* b, __global int* c){

int i = get_global_id(0);c[i] = a[i] + b[i];

}

Page 22: OpenCL Grundlagen

Grenzen

• Mergesort• Letzter Mergevorgang nicht parallel• Auf Streamprozessor langsam• → Flexibel das Device wechseln

Page 23: OpenCL Grundlagen

Demos

• Vectoraddition• Mergesort• Mandelbrot

Page 24: OpenCL Grundlagen

Optimierungen● Maxiemiere Local Worksize● Code Vektorisierung (floatn)● Übertrage Vektoren statt Skalaren● Nutze Rechenleistung durch MIMD● OpenGL(D3D)/OpenCL Interaktion

(Speicherreduzierung)


Recommended