60
Programação para GPU Aleardo Manacero Jr.

Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

  • Upload
    others

  • View
    7

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Programação para GPU

Aleardo Manacero Jr.

Page 2: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Introdução

O uso de GPUs em computação de alto desempenho começou com o desenvolvimento de APIs que permitissem a programação das placas gráficas em alto nível

Isso significa abandonar bibliotecas gráficas, como DirectX e usar primitivas apropriadas à paralelização de aplicações

Page 3: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Introdução

Três bibliotecas para programação de GPU:

CUDA

OpenCL

DirectCompute

Esse processo, infelizmente, depende da arquitetura de cada máquina

Page 4: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Arquitetura de GPUs

GPUs são dispositivos originalmente criados para acelerar o processamento gráfico

Sua arquitetura é massivamente paralela

Os elementos de processamento são direcionados para operações aritméticas

O alto grau de paralelismo dá seu desempenho

Page 5: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Arquitetura de GPUs

ATI Radeon 5870

Page 6: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Arquitetura de GPUs

ATI Radeon 5870

Page 7: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Arquitetura de GPUs

Nvidia Kepler

Page 8: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Arquitetura de GPUs

Nvidia Kepler

Page 9: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Programação

As diferenças de arquitetura tornam a programação sensível ao contexto

Um programa otimizado para uma GPU pode não funcionar bem em outra

O que fazer então?

Page 10: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Programação

Usar técnicas de particionamento do problema adequadas para a GPU a ser usada

Usar a biblioteca para paralelização adequada para a GPU a ser usada

Page 11: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

openCL

Page 12: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Programação

OpenCL (Open Computing Language) é uma API para programação de GPUs (ou outros dispositivos) e sua interação com a CPU

Framework de três partes (linguagem, plataforma e execução)

Page 13: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Programação

Linguagem baseada em C99, com extensões e restrições adicionais

API de Plataforma com rotinas para tratar o sistema e seus recursos

API de execução gerencia objetos criados na execução de processos openCL

Page 14: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Kernel

Programas são divididos em dois componentes:

Host, que executa na CPU e envia kernels para as GPUs

Kernel, que executa nas GPUs, de modo paralelo (dados ou tarefas)

Page 15: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Kernel

Para a paralelização de kernel é preciso definir o número de dimensões do objeto a ser tratado

Cada elemento no objeto é chamado de work-item

O número de kernels a ser criado depende da dimensão global do objeto

Page 16: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Kernel

Pode haver aglomeração de work-itens em um work-group

Page 17: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Kernel

Pode haver aglomeração de work-itens em um work-group

Page 18: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Exemplo (paralelismo de dados)

SEQUENCIAL

void square(int n, const float *a,

float *result)

{ int i;

for (i=0; i<n; i++)

result[i] = a[i] * a[i];

}

PARALELO

kernel dp_square (const float *a,

float *result)

{ int id = get_global_id(0);

result[id] = a[id] * a[id];

}

// dp_square executes over “n” work-items

Page 19: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Host

Gerencia os recursos openCL, ou seja, gerencia:

Dispositivos

Rotinas (código) de kernel

Kernel

Memória

Page 20: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Memória

É gerenciada explicitamente pelo programa

Cuida das movimentações entre host e kernel

Se divide em quatro níveis dentro da GPU

Page 21: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Memória

Na GPU temos:

Global – R/W para todos itens e groups

Constante – R/W para host e R para itens

Local – R/W para itens no mesmo group

Privada – R/W para um item apenas

Page 22: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Memória

Page 23: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Execução de um programa

Envolve várias etapas:Buscar dispositivos no sistema

Criar contexto para associar dispositivos

Criar programas para execução nos dispositivos

Selecionar kernels para execução

Criar objetos de memória (host e dispositivo)

Transferir dados para dispositivos

Submeter kernels para fila de comandos

Copiar resultados para o host

Page 24: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Execução de um programa

Identificação das plataformas disponíveis

cl_platform_id platforms;cl_uint num_platforms;

// query for 1 available platformcl_int err = clGetPlatformIDs (

1, // the number of entries that can be added to platforms&platforms, // list of OpenCL found&num_platforms); // the number of OpenCL platforms found

// platforms are NVIDIA, INTEL, AMD, ...

Page 25: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Execução de um programa

Identificação dos dispositivos disponíveis

cl_device_id device_id;cl_uint num_of_devices;cl_int err;err = clGetDeviceIDs (platform_id, // platform_id retrieved from clGetPlatformIDsCL_DEVICE_TYPE_GPU, // device type to search for1, // number of id add to device_id list&device_id, // list of device ids&num_of_devices // number of compute devices found);

TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT, ALL

Page 26: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Execução de um programa

Criação de contexto

cl_context context; // context properties list - must be ended with 0properties[0]= CL_CONTEXT_PLATFORM; // tells platform to useproperties[1]= (cl_context_properties) platform_id;properties[2]= 0;context = clCreateContext (

properties, // list of context properties1, // num of devices in the device_id list&device_id, // the device id listNULL, // pointer to the error callback function (if required)NULL, // the argument data to pass to the callback function&err // the return code

);

Page 27: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Execução de um programa

Criação da fila de comandos

cl_command_queue command_queue;command_queue = clCreateCommandQueue (

context, // a valid contextdevice_id, // a valid device associated with the context0, // properties for the queue - not used here&err // the return code

);

Campo properties (0 no exemplo) pode ser:CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE CL_QUEUE_PROFILING_ENABLE

Page 28: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Execução de um programa

Criação de um programa

const char *ProgramSource ="__kernel void hello (__global float *input, __global float *output)\n"\"{\n"\" size_t id = get_global_id (0);\n"\" output[id] = input[id] * input[id];\n"\"}\n";

Neste exemplo o programa aparece na forma de string a ser lida pelo código do host

Page 29: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Execução de um programa

Criação de um programa

cl_program program;program = clCreateProgramWithSource (

Context, // a valid context1, // the number strings in the next parameter(const char **) &ProgramSource, // the array of stringsNULL, // the length of each string or can be NULL terminated&err // the error return code

);

Se o programa já for um executável trocar por clCreateProgramWithBinary

Page 30: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Execução de um programa

Criação do executável

err = clBuildProgram (program, // a valid program object0, // number of devices in the device listNULL, // device list – NULL means for all devicesNULL, // a string of build optionsNULL, // callback function when executable has been builtNULL // data arguments for the callback function

);

Page 31: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Execução de um programa

Criação do executável

err = clBuildProgram (program, // a valid program object0, // number of devices in the device listNULL, // device list – NULL means for all devicesNULL, // a string of build optionsNULL, // callback function when executable has been builtNULL // data arguments for the callback function

);

clGetBuildProgramInfo() permite recuperar o log da função acima, para eventuais erros de compilação

Page 32: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Execução de um programa

Criação de objetos kernel

cl_kernel kernel;

kernel = clCreateKernel(program, // a valid program object successfully built"hello", // the name of the kernel declared with __kernel&err // error return code

);

clCreateKernel retorna um valor diferente de zero se for bem sucedida ou zero se falhar (tipo de erro é retornado em “err”)

Page 33: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Execução de um programa

Erros podem ser:

CL_INVALID_PROGRAM — O programa não é um objeto válido

CL_INVALID_PROGRAM_EXECUTABLE — O programa não contém um executável construído com sucesso

CL_INVALID_KERNEL_NAME — Nome do kernel não foi localizado no programa objeto

CL_INVALID_VALUE — Nome do kernel é NULL.

CL_OUT_OF_HOST_MEMORY — Host não foi capaz de alocar recursos OpenCL

Page 34: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Execução de um programa

Definição de parâmetros do kernel

err = clSetKernelArg (kernel, // valid kernel object0, // the specific argument index of a kernelsizeof(cl_mem), // the size of the argument data&input_data // a pointer of data used as the argument

);

clGetKernelInfo() retorna informações sobre os parâmetros de um kernel

Page 35: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Execução de um programa

Colocando um kernel para execução

err = clEnqueueNDRangeKernel (command_queue, // valid command queuekernel, // valid kernel object1, // the work problem dimensionsNULL, // reserved for future revision - must be NULL&global, // work-items for each dimensionNULL, // work-group size for each dimension0, // number of event in the event listNULL, // list of events that needs to complete before this executesNULL // event object to return on completion

);

Page 36: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Execução de um programa

Para o comando anterior é preciso definir alguns parâmetros:

O número de dimensões pode ser 1, 2 ou 3

work-itens por dimensão precisa ser definida, como

size_t global[2]={512,512};

work-group por dimensão deve ser definido, como

size_t local[2]={8,8};

Page 37: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Execução de um programa

Terminando a execução (liberando recursos)

clReleaseMemObject(input);

clReleaseMemObject(output);

clReleaseProgram(program);

clReleaseKernel(kernel);

clReleaseCommandQueue(command_queue);

clReleaseContext(context);

Page 38: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Vetores em openCL

Vetores são definidos de forma explícita, como por exemplo int8 alfa;

Page 39: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Vetores em openCL

O número de elementos pode ser 2, 4, 8 ou 16

Os elementos podem ser indexados por valores hexadecimais ou letras (até 4 elem.)

float16 x;x.sa = 1.0f;

float4 c;c.x = 1.0f; c.y = 1.0f; c.z = 1.0f; c.w = 1.0f;

Page 40: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Vetores em openCL

O acesso ainda pode ser feito por grupos, como:

float4 f = (float4) (1.0f, 2.0f, 3.0f, 4.0f);float2 low, high;float2 o, e;

low = f.lo; // returns f.xy (1.0f, 2.0f)high = f.hi; // returns f.zw (3.0f, 4.0f)

o = f.odd; // returns f.yw (2.0f, 4.0f)e = f.even; // returns f.xz (1.0f, 3.0f)

Page 41: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Vetores em openCL

Casting é feito por funções de conversão, apesar de tipos escalares também aceitarem casting clássico

int4 i;float4 f = convert_float4(i); // int4 vector to float4

float f;int i = convert_int(f); // float scaler to an integer scaler

Page 42: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Exemplo em openCL

Multiplicação convencional de matrizes

Alguns trechos foram suprimidos (a geração dos conteúdos das matrizes, p.ex.)

O código do kernel está em arquivo lido pelo programa do host

As matrizes são tratadas como vetores

Page 43: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Host code openCL

#include <stdio.h> + <stdlib.h> + <string.h> + <math.h>#include <fcntl.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <stdbool.h>#include <CL/cl.h> // openCL headers

#define WA 1024#define HA 1024#define WB 1024

#define HB WA#define WC WB#define HC HA

Page 44: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Host code openCL

long LoadOpenCLKernel(char const* path, char **buf){ FILE *fp; size_t fsz; long off_end; int rc;

/* Open the file */ fp = fopen(path, "r"); if ( NULL == fp ) { return -1L; }

/* Seek to the end of the file */ rc = fseek(fp, 0L, SEEK_END); if ( 0 != rc ) { return -1L; }

Page 45: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Host code openCL

/* Byte offset to the end of the file (size) */ if ( 0 > (off_end = ftell(fp)) ) { return -1L; } fsz = (size_t)off_end;

/* Allocate a buffer to hold the whole file */ *buf = (char *) malloc( fsz+1); if ( NULL == *buf ) { return -1L; }

/* Rewind file pointer to start of file */ rewind(fp);

Page 46: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Host code openCL

/* Slurp file into buffer */ if( fsz != fread(*buf, 1, fsz, fp) ) { free(*buf); return -1L; }

/* Close the file */ if( EOF == fclose(fp) ) { free(*buf); return -1L; }

/* Make sure the buffer is NUL-terminated, just in case */ (*buf)[fsz] = '\0';

/* Return the file size */ return (long)fsz;}

Page 47: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Host code openCL

int main(int argc, char** argv){int err; // error code returned from api calls cl_device_id device_id; // compute device id cl_context context; // compute context cl_command_queue commands; // compute command queue cl_program program; // compute program cl_kernel kernel; // compute kernel

// OpenCL device memory for matrices cl_mem d_A; cl_mem d_B; cl_mem d_C;

Page 48: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Host code openCL

//Allocate host memory for matrices A and B unsigned int size_A = WA * HA; unsigned int mem_size_A = sizeof(float) * size_A; float* h_A = (float*) malloc(mem_size_A); unsigned int size_B = WB * HB; unsigned int mem_size_B = sizeof(float) * size_B; float* h_B = (float*) malloc(mem_size_B);

//Initialize host memory randomMemInit(h_A, size_A); randomMemInit(h_B, size_B); //Allocate host memory for the result C unsigned int size_C = WC * HC; unsigned int mem_size_C = sizeof(float) * size_C; float* h_C = (float*) malloc(mem_size_C);

Page 49: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Host code openCL

printf("Initializing OpenCL device...\n");

cl_uint dev_cnt = 0; clGetPlatformIDs(0, 0, &dev_cnt);

cl_platform_id platform_ids[100]; clGetPlatformIDs(dev_cnt, platform_ids, NULL);

// Connect to a compute device int gpu = 1; err = clGetDeviceIDs(platform_ids[0], gpu ? CL_DEVICE_TYPE_GPU : CL_DEVICE_TYPE_CPU, 1, &device_id, NULL); if (err != CL_SUCCESS) { printf("Error: Failed to create a device group!\n"); return EXIT_FAILURE; }

Page 50: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Host code openCL

// Create a compute context context = clCreateContext(0, 1, &device_id, NULL, NULL, &err); if (!context) { printf("Error: Failed to create a compute context!\n"); return EXIT_FAILURE; }

// Create a command commands commands = clCreateCommandQueue(context, device_id, 0, &err); if (!commands) { printf("Error: Failed to create a command commands!\n"); return EXIT_FAILURE; }

Page 51: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Host code openCL

// Create the compute program from the source file char *KernelSource; long lFileSize;

lFileSize = LoadOpenCLKernel("matrixmul_kernel.cl", &KernelSource); if( lFileSize < 0L ) { perror("File read failed"); return 1; }

program = clCreateProgramWithSource(context, 1, (const char **) & KernelSource, NULL, &err); if (!program) { printf("Error: Failed to create compute program!\n"); return EXIT_FAILURE; }

Page 52: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Host code openCL

// Build the program executable

err = clBuildProgram(program, 0, NULL, NULL, NULL, NULL); if (err != CL_SUCCESS) { size_t len; char buffer[2048]; printf("Error: Failed to build program executable!\n"); clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, sizeof(buffer), buffer, &len); printf("%s\n", buffer); exit(1); }

// Create the compute kernel in the program we wish to run

kernel = clCreateKernel(program, "matrixMul", &err); if (!kernel || err != CL_SUCCESS) { printf("Error: Failed to create compute kernel!\n"); exit(1); }

Page 53: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Host code openCL

// Create the input and output arrays in device memory for our calculation d_C = clCreateBuffer(context, CL_MEM_READ_WRITE, mem_size_A, NULL, &err); d_A = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, mem_size_A, h_A, &err); d_B = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, mem_size_B, h_B, &err);

if (!d_A || !d_B || !d_C) { printf("Error: Failed to allocate device memory!\n"); exit(1); }

Page 54: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Host code openCL

printf("Running matrix multiplication for matrices A (%dx%d) and B (%dx%d) ...\n", WA,HA,WB,HB);

//Launch OpenCL kernel size_t localWorkSize[2], globalWorkSize[2];

int wA = WA; int wC = WC; err = clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&d_C); err |= clSetKernelArg(kernel, 1, sizeof(cl_mem), (void *)&d_A); err |= clSetKernelArg(kernel, 2, sizeof(cl_mem), (void *)&d_B); err |= clSetKernelArg(kernel, 3, sizeof(int), (void *)&wA); err |= clSetKernelArg(kernel, 4, sizeof(int), (void *)&wC);

if (err != CL_SUCCESS) { printf("Error: Failed to set kernel arguments! %d\n", err); exit(1); }

Page 55: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Host code openCL

localWorkSize[0] = 16; localWorkSize[1] = 16; globalWorkSize[0] = 1024; globalWorkSize[1] = 1024; err = clEnqueueNDRangeKernel(commands, kernel, 2, NULL, globalWorkSize, localWorkSize, 0, NULL, NULL);

if (err != CL_SUCCESS) { printf("Error: Failed to execute kernel! %d\n", err); exit(1); } //Retrieve result from device err = clEnqueueReadBuffer(commands, d_C, CL_TRUE, 0, mem_size_C, h_C, 0, NULL, NULL);

Page 56: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Host code openCL

if (err != CL_SUCCESS) { printf("Error: Failed to read output array! %d\n", err); exit(1); }

printf("Matrix multiplication completed...\n");

//Shutdown and cleanup free(h_A); free(h_B); free(h_C);

clReleaseMemObject(d_A); clReleaseMemObject(d_C); clReleaseMemObject(d_B);

clReleaseProgram(program); clReleaseKernel(kernel); clReleaseCommandQueue(commands); clReleaseContext(context);

return 0;}

Page 57: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Kernel em openCL

// Arquivo matrixmul_kernel.cl

// OpenCL Kernel__kernel void matrixMul(__global float* C, __global float* A, __global float* B, int wA, int wB){ int tx = get_global_id(0); int ty = get_global_id(1); // value stores the element that is computed by the thread float value = 0;

Page 58: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Kernel em openCL

for (int k = 0; k < wA; ++k) { float elementA = A[ty * wA + k]; float elementB = B[k * wB + tx]; value += elementA * elementB; } // Write the matrix to device memory each // thread writes one element C[ty * wA + tx] = value;}

Page 59: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

CUDA

Page 60: Programação para GPU - dcce.ibilce.unesp.braleardo/cursos/hpc/gpus2020.pdf · &num_of_devices // number of compute devices found); TYPE pode ser CPU, GPU, ACCELERATOR, DEFAULT,

Introdução

Criada para programação de GPUs da Nvidia

Programação mais simples do que openCL

Problema é ser restrita ao fabricante

Usaremos material da própria Nvidia