Wprowadzenie do GPGPU

Podobne dokumenty
Wprowadzenie do GPGPU

Programowanie równoległe Wprowadzenie do OpenCL. Rafał Skinderowicz

Programowanie procesorów graficznych GPGPU

Programowanie procesorów graficznych do obliczeń ogólnego przeznaczenia GPGPU

Programowanie akceleratorów specyfikacja OpenCL. Krzysztof Banaś Obliczenia równoległe 1

Programowanie procesorów graficznych w CUDA.

Programowanie procesorów graficznych NVIDIA (rdzenie CUDA) Wykład nr 1

Moc płynąca z kart graficznych

Programowanie procesorów graficznych GPGPU. Krzysztof Banaś Obliczenia równoległe 1

i3: internet - infrastruktury - innowacje

Programowanie procesorów graficznych GPGPU. Krzysztof Banaś Obliczenia równoległe 1

ROZPROSZONY SYSTEM DO KRYPTOANALIZY SZYFRÓW OPARTYCH NA KRZYWYCH ELIPTYCZNYCH

Programowanie kart graficznych

Wstęp do OpenCL. Czyli jak wykorzystać moc drzemiącą w GPU. Marek Zając 2013r. zajacmarek.com

Programowanie Równoległe Wykład, CUDA praktycznie 1. Maciej Matyka Instytut Fizyki Teoretycznej

Programowanie Równoległe wykład, CUDA, przykłady praktyczne 1. Maciej Matyka Instytut Fizyki Teoretycznej

JCuda Czy Java i CUDA mogą się polubić? Konrad Szałkowski

Plan. krótkie opisy modułów. 1 Uwagi na temat wydajności CPython a. 2 Podstawowe techniki poprawiające wydajność obliczeniową

Porównanie wydajności CUDA i OpenCL na przykładzie równoległego algorytmu wyznaczania wartości funkcji celu dla problemu gniazdowego

Programowanie procesorów graficznych GPGPU

Programowanie Równoległe wykład 12. OpenGL + algorytm n ciał. Maciej Matyka Instytut Fizyki Teoretycznej

Wprowadzenie do programowania w środowisku CUDA. Środowisko CUDA

Wstęp do obliczeń równoległych na GPU

// Liczy srednie w wierszach i kolumnach tablicy "dwuwymiarowej" // Elementy tablicy są generowane losowo #include <stdio.h> #include <stdlib.

MMX i SSE. Zbigniew Koza. Wydział Fizyki i Astronomii Uniwersytet Wrocławski. Wrocław, 10 marca Zbigniew Koza (WFiA UWr) MMX i SSE 1 / 16

CUDA część 1. platforma GPGPU w obliczeniach naukowych. Maciej Matyka

Programowanie aplikacji równoległych i rozproszonych

Tesla. Architektura Fermi

Podstawy programowania w języku C++

Przetwarzanie Równoległe i Rozproszone

Programowanie Współbieżne

Języki programowania. Przetwarzanie plików amorficznych Konwencja języka C. Część siódma. Autorzy Tomasz Xięski Roman Simiński

Uzupełnienie dot. przekazywania argumentów

Temat: Dynamiczne przydzielanie i zwalnianie pamięci. Struktura listy operacje wstawiania, wyszukiwania oraz usuwania danych.

Podstawy programowania. Wykład 6 Wskaźniki. Krzysztof Banaś Podstawy programowania 1

Tablice w argumentach funkcji. Tablicy nie są przekazywane po wartości Tablicy są przekazywane przez referencje lub po wskaźniku

PROGRAMOWANIE w C prolog

Laboratorium 1 Temat: Przygotowanie środowiska programistycznego. Poznanie edytora. Kompilacja i uruchomienie prostych programów przykładowych.

Linux Kernel III. Character devices

Co to jest sterta? Sterta (ang. heap) to obszar pamięci udostępniany przez system operacyjny wszystkim działającym programom (procesom).

Programowanie procesorów graficznych GPU

Języki i metodyka programowania. Typy, operatory, wyrażenia. Wejście i wyjście.

CUDA ćwiczenia praktyczne

Programowanie procesorów graficznych GPGPU. Krzysztof Banaś Obliczenia równoległe 1

CUDA obliczenia ogólnego przeznaczenia na mocno zrównoleglonym sprzęcie. W prezentacji wykorzystano materiały firmy NVIDIA (

DYNAMICZNE PRZYDZIELANIE PAMIECI

Wykład 1

Technologie cyfrowe semestr letni 2018/2019

Krótkie wprowadzenie do korzystania z OpenSSL

Shared memory and messages. Functions. process 0. process 1. program 0. program 0. data 0. data 1. program 1. data 0. data 1.

Wstęp do programowania 1

TABLICE W JĘZYKU C/C++ typ_elementu nazwa_tablicy [wymiar_1][wymiar_2]... [wymiar_n] ;

Programowanie obiektowe

CUDA PROGRAMOWANIE PIERWSZE PROSTE PRZYKŁADY RÓWNOLEGŁE. Michał Bieńkowski Katarzyna Lewenda

Wykład VII. Programowanie. dr inż. Janusz Słupik. Gliwice, Wydział Matematyki Stosowanej Politechniki Śląskiej. c Copyright 2014 Janusz Słupik

Struktury czyli rekordy w C/C++

Technologie cyfrowe semestr letni 2018/2019

tablica: dane_liczbowe

Język ANSI C. część 11. Jarosław Gramacki Instytut Informatyki i Elektroniki

Wskaźniki. Programowanie Proceduralne 1

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

Pętle i tablice. Spotkanie 3. Pętle: for, while, do while. Tablice. Przykłady

2 Przygotował: mgr inż. Maciej Lasota

SUMA KONTROLNA (icmp_cksum) NUMER KOLEJNY (icmp_seq)

Stałe, tablice dynamiczne i wielowymiarowe

Programowanie kart graficznych

wykład III uzupełnienie notatek: dr Jerzy Białkowski Programowanie C/C++ Język C - zarządzanie pamięcią, struktury,

Podstawy Programowania ELEMENTY PROGRAMU i TYPY DANYCH

typ y y p y z łoż o on o e n - tab a lice c e w iel e owym m ar a o r we, e stru r kt k ury

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

Biblioteka standardowa - operacje wejścia/wyjścia

PhysX Visual Debugger. Tomasz Gańko

Programowanie Procedurale

HPC na biurku. Wojciech De bski

Funkcja (podprogram) void

Wykład 15. Literatura. Kompilatory. Elementarne różnice. Preprocesor. Słowa kluczowe

Pobieranie argumentów wiersza polecenia

main( ) main( void ) main( int argc, char argv[ ] ) int MAX ( int liczba_1, liczba_2, liczba_3 ) źle!

Kurs programowania. Wykład 9. Wojciech Macyna. 28 kwiecień 2016

nowe operatory &. (kropka) * operator rzutowy ->, (przecinek) sizeof

Zaawansowane programowanie w języku C++ Zarządzanie pamięcią w C++

Sieciowa komunikacja procesów - XDR i RPC

Dla każdej operacji łącznie tworzenia danych i zapisu ich do pliku przeprowadzić pomiar czasu wykonania polecenia. Wyniki przedstawić w tabelce.

Programowanie i struktury danych

CUDA Median Filter filtr medianowy wykorzystujący bibliotekę CUDA sprawozdanie z projektu

Podstawy programowania komputerów

Lab 8. Tablice liczbowe cd,. Operacje macierzowo-wektorowe, memcpy, memmove, memset. Wyrażenie warunkowe.

Język ludzki kod maszynowy

Programowanie obiektowe W3

Java. język programowania obiektowego. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak

Powyższe wyrażenie alokuje 200 lub 400 w zależności od rozmiaru int w danym systemie. Wskaźnik wskazuje na adres pierwszego bajtu pamięci.

Kompilator języka C na procesor 8051 RC51 implementacja

Pliki w C/C++ Przykłady na podstawie materiałów dr T. Jeleniewskiego

Grzegorz Cygan. Wstęp do programowania mikrosterowników w języku C

Typy złożone. Struktury, pola bitowe i unie. Programowanie Proceduralne 1

Programowanie Proceduralne

Podstawy programowania obiektowego

Potok graficzny i shadery. Hubert Rutkowski

PROGRAMOWANIE SYSTEMÓW CZASU RZECZYWISTEGO

Programowanie proceduralne INP001210WL rok akademicki 2015/16 semestr letni. Wykład 6. Karol Tarnowski A-1 p.

Transkrypt:

(py)opencl na kartach graficznych: Wprowadzenie do GPGPU kolodziejj.info

wyszukiwanie obiektów na zdjęciu CPU-bound 32 MPix implementacje: Matlab: 6 godzin Python + OpenCL: 1 minuta Tak, słownie: jedna minuta. 360 x szybciej.

Agenda zastosowanie co muszę umieć? rys historyczny sprzęt terminologia omówienie przykładowego kodu co dalej?

GPGPU General-Purpose computing on GPU

Zastosowanie strumieniowe przetwarzanie obrazów dużych tablic w podobny sposób obrazy, video kryptografia fizyka (od astrofizyki do fizyki kwantowej) biologia, medycyna bazy danych...

Co przyda się z C funkcje podstawowe typy danych ([unsigned] integer, float, double) tablice wskaźniki umiejętność rozrzucania wszędzie tych dziwnych znaczków { } ;

Historia programowalne shadery, obsługa floatów programowanie via OpenGL, DirectX pierwsze dedykowane platformy Sh/RapidMind, Brook, Accelerator

Platformy GPGPU nvidia CUDA i nadal mają się nieźle MicroSoft's F# + DirectCompute AMD's FireStream C++ AMP OpenACC

Tylko takie GPU? @ CSIRO

Tylko takie GPU? @ nvidia

@ nvidia @ benchmark.pl

Zrównoleglalny przykład Dodawanie wektorów!

Zrównoleglalny przykład A[0] B[0] C[0] = A[0] + B[0] A[1] B[1] C[1] = A[1] + B[1] C[2] = A[2] + B[2] A[2] A[n-1] + B[2] B[n-1] = C[n-1] = A[n-1] + B[n-1]

Zrównoleglalny przykład void add(float * a, float * b, unsigned int n, float * c) { for (int i = 0; i < n; ++i) { c[i] = a[i] + b[i]; } }

CPU, szeregowo N ops CPU ops

Zrównoleglalny przykład A[0] B[0] C[0] = A[0] + B[0] A[1] B[1] C[1] = A[1] + B[1] C[2] = A[2] + B[2] A[2] A[n-1] + B[2] B[n-1] = C[n-1] = A[n-1] + B[n-1]

Zrównoleglalny przykład A[i] + B[i] = C[i] = A[i] + B[i]

CPU, równolegle N ops / 4 CPU ops

Trochę liczb Dodawanie: N = 24, jeden wątek 24 kroki N = 24, 4 wątki 6 kroków N = 220, 4 wątki 218 kroków potrzebujemy więcej wątków!

GPGPU massive parallelism - setki-tysiące wątków na raz

GPGPU Optymalizowanie: maksymalnego wykorzystania jednostek obliczeniowych w GPU vs. maksymalną przepustowość przesyłania danych

GPGPU Metryka: przepustowość obliczeń [MB/s]

OpenCL kernele work items work groups model pamięci

Kernele z grubsza funkcje w C z keyword'em global global void add( global const global const const unsigned global float int gid = get_global_id(0); if (gid < n) { c[gid] = a[gid] + b[gid]; } } float * a, float * b, int n, * c) {

Kernele z grubsza funkcje w C z keyword'em global global void add( global const global const const unsigned global float int gid = get_global_id(0); if (gid < n) { c[gid] = a[gid] + b[gid]; } } float * a, float * b, int n, * c) {

Work items instancje kerneli bardzo ograniczona prywatna pamięć (rzędu KB) powinny żyć bardzo krótko ale może ich być bardzo dużo

Work items A[0] B[0] C[0] = A[0] + B[0] A[1] B[1] C[1] = A[1] + B[1] C[2] = A[2] + B[2] A[2] A[n-1] + B[2] B[n-1] = C[n-1] = A[n-1] + B[n-1]

Work items C[0] = A[0] + B[0] C[1] = A[1] + B[1] C[2] = A[2] + B[2] C[n-1] = A[n-1] + B[n-1]

Work items C[2] = A[2] + B[2]

Work groups grupy work items wielkość grupy local work size maksymalna wielkość zależy od urządzenia pamięć lokalna

Work groups C[0] = A[0] + B[0] C[1] = A[1] + B[1] C[2] = A[2] + B[2] C[n-1] = A[n-1] + B[n-1]

Work groups C[0] C[1] C[2] C[n-1]

Work groups

Work groups local work size = 1024 N = 3 * 1024 = 3072

Model pamięci

Model pamięci a t e m e m local memory local memory local memory work group 1 work group 2 work group n p r i v global memory device host memory host

Czas na kod! global void add( global const global const const unsigned global float int gid = get_global_id(0); if (gid < n) { c[gid] = a[gid] + b[gid]; } } float * a, float * b, int n, * c) {

ret = clbuildprogram(program, 1, &device_id, NULL, NULL, NULL); if (ret!= 0) { printf("clbuildprogram returned non-zero status %d: ", ret); #include <stdio.h> #include <stdlib.h> #include <time.h> if (ret == CL_INVALID_PROGRAM) { printf("invalid program\n"); } else if (ret == CL_INVALID_VALUE) { printf("invalid value\n"); } else if (ret == CL_INVALID_DEVICE) { printf("invalid device\n"); } else if (ret == CL_INVALID_BINARY) { printf("invalid binary\n"); } else if (ret == CL_INVALID_BUILD_OPTIONS) { printf("invalid build options\n"); } else if (ret == CL_INVALID_OPERATION) { printf("invalid operation\n"); } else if (ret == CL_COMPILER_NOT_AVAILABLE) { printf("compiler not available\n"); } else if (ret == CL_BUILD_PROGRAM_FAILURE) { printf("build program failure\n"); #include <CL/cl.h> #define ARRAY_SIZE 4096 #define MAX_SOURCE_SIZE (0x100000) int main(void) { const size_t ARRAY_BYTES = ARRAY_SIZE * sizeof(float); float h_a[array_size]; float h_b[array_size]; for (int i = 0; i < ARRAY_SIZE; i++) { h_a[i] = (float)i; h_b[i] = (float)(2 * i); } float h_c[array_size]; size_t log_size; clgetprogrambuildinfo(program, device_id, CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size); FILE *fp; char *source_str; size_t source_size; char *log = (char *) malloc(log_size); fp = fopen("vectors_cl.cl", "r"); if (!fp) { fprintf(stderr, "Failed to load kernel.\n"); exit(1); } source_str = (char *)malloc(max_source_size); source_size = fread(source_str, 1, MAX_SOURCE_SIZE, fp); fclose(fp); clgetprogrambuildinfo(program, device_id, CL_PROGRAM_BUILD_LOG, log_size, log, NULL); printf("%s\n", log); } else if (ret == CL_OUT_OF_HOST_MEMORY) { printf("out of host memory\n"); } exit(1); } cl_platform_id platform_id = NULL; cl_device_id device_id = NULL; cl_uint ret_num_devices; cl_uint ret_num_platforms; cl_int ret = clgetplatformids(1, &platform_id, &ret_num_platforms); ret = clgetdeviceids(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, &ret_num_devices); cl_kernel kernel = clcreatekernel(program, "add", &ret); ret = clsetkernelarg(kernel, 0, ret = clsetkernelarg(kernel, 1, ret = clsetkernelarg(kernel, 2, size_t array_size = ARRAY_SIZE; ret = clsetkernelarg(kernel, 3, cl_context context = clcreatecontext(null, 1, &device_id, NULL, NULL, &ret); sizeof(const size_t), (void *)&array_size); size_t global_item_size = ARRAY_SIZE; // Process the entire lists size_t local_item_size = 1; // Divide work items into groups of 64 ret = clenqueuendrangekernel(command_queue, kernel, 1, NULL, &global_item_size, &local_item_size, 0, NULL, NULL); cl_command_queue command_queue = clcreatecommandqueue(context, device_id, 0, &ret); cl_mem a_mem_obj = clcreatebuffer(context, CL_MEM_READ_ONLY, ARRAY_BYTES, NULL, &ret); cl_mem b_mem_obj = clcreatebuffer(context, CL_MEM_READ_ONLY, ARRAY_BYTES, NULL, &ret); cl_mem c_mem_obj = clcreatebuffer(context, CL_MEM_WRITE_ONLY, ARRAY_BYTES, NULL, &ret); ret = clenqueuereadbuffer(command_queue, c_mem_obj, CL_TRUE, 0, ARRAY_BYTES, h_c, 0, NULL, NULL); ret ret ret ret ret ret ret ret ret ret = clenqueuewritebuffer(command_queue, a_mem_obj, CL_TRUE, 0, ARRAY_BYTES, h_a, 0, NULL, NULL); ret = clenqueuewritebuffer(command_queue, b_mem_obj, CL_TRUE, 0, ARRAY_BYTES, h_b, 0, NULL, NULL); cl_program program = clcreateprogramwithsource(context, 1, (const char **)&source_str, (const size_t *)&source_size, &ret); if (ret!= 0) { printf("clcreateprogramwithsource returned non-zero status %d\n\n", ret); exit(1); } sizeof(cl_mem), (void *)&a_mem_obj); sizeof(cl_mem), (void *)&b_mem_obj); sizeof(cl_mem), (void *)&c_mem_obj); } = = = = = = = = = clflush(command_queue); clfinish(command_queue); clreleasekernel(kernel); clreleaseprogram(program); clreleasememobject(a_mem_obj); clreleasememobject(b_mem_obj); clreleasememobject(c_mem_obj); clreleasecommandqueue(command_queue); clreleasecontext(context); return 0;

Jak to odpalić? Instalacja OpenCL + ICD ICD Installable Client Driver

Jak to odpalić? kompilacja, uruchomienie: $ gcc -std=c99 vectors_cl.c -o vectors_cl -l OpenCL $./vectors_cl

pyopencl

Czas na ładny kod! global void add( global const global const const unsigned global float int gid = get_global_id(0); if (gid < n) { c[gid] = a[gid] + b[gid]; } } float * a, float * b, int n, * c) {

import numpy import os import pyopencl def add(a, b): # Create context. context = pyopencl.create_some_context() # Create command queue withing it. queue = pyopencl.commandqueue(context) # Build the "program". program = pyopencl.program( context, open(os.path.join( os.path.dirname(os.path.abspath( file )), "vectors_cl.cl") ).read() ).build()

# Create two readable buffers on the device memory and # copy the input data there. a_in = pyopencl.buffer( context, pyopencl.mem_flags.read_only pyopencl.mem_flags.copy_host_ptr, hostbuf=a) b_in = pyopencl.buffer( context, pyopencl.mem_flags.read_only pyopencl.mem_flags.copy_host_ptr, hostbuf=b) # Create one writeable buffer on the device memory for # result. c_out = pyopencl.buffer( context, pyopencl.mem_flags.write_only, a.nbytes # Size. )

# Execute the kernel. program.add(queue, a.shape, None, a_in, b_in, numpy.uint32(array_size), c_out) # Create empty numpy array on the host for result. c = numpy.empty_like(a) # Copy the result from the device to the host. pyopencl.enqueue_copy(queue, c, c_out) return c

# Execute the kernel. program.add(queue, a.shape, None, a_in, b_in, numpy.uint32(array_size), c_out) # Create empty numpy array on the host for result. c = numpy.empty_like(a) # Copy the result from the device to the host. pyopencl.enqueue_copy(queue, c, c_out) return c global void add( global const global const const unsigned global float int gid = get_global_id(0); if (gid < n) { c[gid] = a[gid] + b[gid]; } } float * a, float * b, int n, * c) {

ARRAY_SIZE = 4096 def test_add(): # Generate the input array on the host. a = numpy.empty(array_size, dtype=numpy.float32) b = numpy.empty(array_size, dtype=numpy.float32) for i in range(array_size): a[i] = i b[i] = 2 * i c = add(a, b) assert assert assert assert c[0] == 0 c[1] == 3 c[-2] == 12282 c[-1] == 12285

$ py.test examples/test_vectors_cl.py. ================= 1 passed in 0.21 seconds =================

Więcej o work items get_global_id(0);

Więcej o work items get_global_id(0); get_global_id(1);

Więcej o work items ge t _g l ob a l_ id (2 ); get_global_id(1); get_global_id(0);

Czas na ładny kod! global void add( global const float * in, const int width, const int height, global float * c) { int x = get_global_id(0); int y = get_global_id(1); int gid = y * width + x; } if (x < width && y < height) { // }

Optymalizacja rozmiar work group sekwencyjny dostęp do pamięci uruchamianie wielu kerneli naraz...

Wzorce mapa redukcja scan histogram scatter gather sort

Wzorce pyopencl.elementwise pyopencl.reduction pyopencl.scan pyopencl.algorithm pyopencl.bitonic_sort

from pyopencl import... Image array clmath clrandom characterize tools

Wsparcie OpenCL OpenCV ClBLAS, ViennaCL, clfft Rivertrail, WebCL ViNN Go, Haskell, Lua, Rust, Java PgOpenCL

Randomowe uwagi typy danych ile bajtów jest we floacie? zawsze ustawiać dtype w numpy.array wielkość danych jak zwykle, testy :)

Dzięki :) Pytania? kolodziejj.info/talks/gpgpu/