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

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

Wprowadzenie do GPGPU

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

Wprowadzenie do GPGPU

Programowanie procesorów graficznych GPGPU

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

Przetwarzanie Równoległe i Rozproszone

Programowanie kart graficznych

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

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

DYNAMICZNE PRZYDZIELANIE PAMIECI

Wprowadzenie do programowania w środowisku CUDA. Środowisko CUDA

i3: internet - infrastruktury - innowacje

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 NVIDIA (rdzenie CUDA) Wykład nr 1

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

Tworzenie programów równoległych cd. Krzysztof Banaś Obliczenia równoległe 1

Programowanie Współbieżne

Tworzenie programów równoległych. Krzysztof Banaś Obliczenia równoległe 1

Programowanie aplikacji równoległych i rozproszonych

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

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

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

Wykład 3 Składnia języka C# (cz. 2)

Programowanie w języku C++

JĘZYKI PROGRAMOWANIA Z PROGRAMOWANIEM OBIEKTOWYM. Wykład 6

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

Tablice i struktury. czyli złożone typy danych. Programowanie Proceduralne 1

Programowanie procesorów graficznych GPGPU

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

ROZPROSZONY SYSTEM DO KRYPTOANALIZY SZYFRÓW OPARTYCH NA KRZYWYCH ELIPTYCZNYCH

Moc płynąca z kart graficznych

Stałe, tablice dynamiczne i wielowymiarowe

Tworzenie programów równoległych. Krzysztof Banaś Obliczenia równoległe 1

Opis protokołu RPC. Grzegorz Maj nr indeksu:

Tesla. Architektura Fermi

Programowanie kart graficznych. Sprzęt i obliczenia

PARADYGMATY PROGRAMOWANIA Wykład 3

Szablony klas, zastosowanie szablonów w programach

Programowanie współbieżne i rozproszone

Programowanie procesorów graficznych w CUDA.

Wskaźniki. nie są konieczne, ale dają językowi siłę i elastyczność są języki w których nie używa się wskaźników typ wskaźnikowy typ pochodny:

Tablice. Monika Wrzosek (IM UG) Podstawy Programowania 96 / 119

Ćwiczenie 7 z Podstaw programowania. Język C++, programy pisane w nieobiektowym stylu programowania. Zofia Kruczkiewicz

Jednostka GPU oraz OpenCL aplikacje

Programowanie z wykorzystaniem technologii CUDA i OpenCL Wykład 1

Programowanie kart graficznych

Języki programowania obiektowego Nieobiektowe elementy języka C++

Programowanie i struktury danych. Wykład 4 Dr Piotr Cybula

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

Wątek - definicja. Wykorzystanie kilku rdzeni procesora jednocześnie Zrównoleglenie obliczeń Jednoczesna obsługa ekranu i procesu obliczeniowego

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

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

Wskaźniki. Programowanie Proceduralne 1

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

Szablony funkcji i szablony klas

tablica: dane_liczbowe

Libra.cs.put.poznan.pl/mailman/listinfo/skisrkolo.

Programowanie w językach

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

Wstęp. Przetwarzanie współbieżne, równoległe i rozproszone

Wstęp do programowania obiektowego. WYKŁAD 3 Dziedziczenie Pola i funkcje statyczne Funkcje zaprzyjaźnione, this

ZASADY PROGRAMOWANIA KOMPUTERÓW

Programowanie i struktury danych

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

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość

Wstęp do programowania INP001213Wcl rok akademicki 2018/19 semestr zimowy. Wykład 4. Karol Tarnowski A-1 p.

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

Języki programowania. Przetwarzanie tablic znaków. Część druga. Autorzy Tomasz Xięski Roman Simiński

Podstawy programowania komputerów

Nowoczesne technologie przetwarzania informacji

Podstawy programowania

Przygotowanie kilku wersji kodu zgodnie z wymogami wersji zadania,

Programowanie w modelu równoległości danych oraz dzielonej globalnej pamięci wspólnej. Krzysztof Banaś Obliczenia równoległe 1

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

Programowanie w modelu przesyłania komunikatów specyfikacja MPI. Krzysztof Banaś Obliczenia równoległe 1

Lab 9 Podstawy Programowania

IMIĘ i NAZWISKO: Pytania i (przykładowe) Odpowiedzi

część 8 wskaźniki - podstawy Jarosław Gramacki Instytut Informatyki i Elektroniki Podstawowe pojęcia

Programowanie obiektowe W3

Programowanie CUDA informacje praktycznie i przykłady. Wersja

Tablice mgr Tomasz Xięski, Instytut Informatyki, Uniwersytet Śląski Katowice, 2011

DANE TEKSTOWE W JĘZYKU C/C++ - TABLICE ZNAKOWE

Podstawy programowania w języku C++

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

Procesy i wątki. Krzysztof Banaś Obliczenia równoległe 1

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

Podstawy programowania skrót z wykładów:

Wstęp do programowania INP001213Wcl rok akademicki 2017/18 semestr zimowy. Wykład 6. Karol Tarnowski A-1 p.

Język C, tablice i funkcje (laboratorium, EE1-DI)

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 3. Karol Tarnowski A-1 p.

Wykład 3. Procesy i wątki. Wojciech Kwedlo, Wykład z Systemów Operacyjnych -1- Wydział Informatyki PB

utworz tworzącą w pamięci dynamicznej tablicę dwuwymiarową liczb rzeczywistych, a następnie zerującą jej wszystkie elementy,

Wykład 1: Wskaźniki i zmienne dynamiczne

> C++ dynamiczna alokacja/rezerwacja/przydział pamięci. Dane: Iwona Polak. Uniwersytet Śląski Instytut Informatyki

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

Architektury komputerów Architektury i wydajność. Tomasz Dziubich

Linux Kernel III. Character devices

Biblioteka standardowa - operacje wejścia/wyjścia

Transkrypt:

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

OpenCL architektura OpenCL Open Computing Language otwarty standard do programowania heterogenicznych platform złożonych ze zbioru CPU, GPU oraz innych urządzeń obliczeniowych OpenCL = interfejs programistyczny (API) + biblioteki + system uruchomieniowy (np. sterownik karty graf.) Specyfikacja OpenCL definiuje OpenCL za pomocą modeli: platformy wykonania pamięci programowania

OpenCL platforma Platforma w OpenCL [[to]] system główny (host) połączony z jednym lub więcej urządzeniami OpenCL (devices) Urządzenie składa się z jednej lub więcej jednostek obliczeniowych (compute units, CU) Jednostki obliczeniowe zawierają jeden lub więcej elementów przetwarzania (processing elements, PEs)

OpenCL platforma

OpenCL platforma Jednostki obliczeniowe (compute units, CU) zawierają m.in. układy pobierania i dekodowania rozkazów, układy planowania i podziału pracy Elementy przetwarzania (processing elements, PE) realizują kolejne instrukcje kernela w modelu SPMD (single program, multiple data) Znaczenie CU i PE zależy od konkretnego typu urządzenia, np.: Nvidia: CU = multiprocesor strumieniowy, PE = rdzeń CUDA AMD: CU = jednostka SIMD (w terminologii AMD), PE = SIMD lane CPU: CU = PE = rdzeń procesora

OpenCL model wykonania Program OpenCL uruchamiany jest na hoście, który definiuje kontekst obliczeniowy oraz zarządza wykonaniem na urządzeniach OpenCL wskazanych funkcji kerneli Kontekst to zbiór danych związanych z wykonaniem programu na urządzeniach obliczeniowych Kontekst istnieje w ramach plaformy i odnosi się najczęściej do akceleratorów (urządzeń) tego samego typu Host Platforma 1 Platforma 2 GPU1 GPU2 Kontekst 1 Kontekst obejmuje: Platforma 1 urządzenia OpenCL kernele OpenCL CPU Kontekst 2 programy źródła i binaria z implementacją kerneli obiekty pamięciowe

OpenCL model wykonania Host po utworzeniu kontekstu tworzy (jedną lub więcej) powiązaną z nim kolejkę zadań (command queue) Kernele (zadania) do wykonania na urządzeniach OpenCL wstawiane są do kolejki Kernele mogą być wykonywane w sposób asynchroniczny (out-of-order) i w kolejności niezależnej od kolejności zlecania

OpenCL model wykonania Program OpenCL składa się ze zbioru kerneli Kod kerneli pisany jest w zmodyfikowanej wersji języka C (ISO C99) Kod kernela kompilowany jest przez system uruchomieniowy OpenCL (np. ster. karty graf.) w trakcie wykonania programu Możliwe jest również skomilowanie kodu kernela wcześniej i korzystanie z wersji binarnej

OpenCL model wykonania indeksowanie Dla każdego kernela definiowana jest dyskretna przestrzeń indeksów (index space) Instancja kernela (wątek, work-item) wykonywana jest dla każdego punktu przestrzeni indeksów każdy wątek ma unikalny identyfikator globalny Każdy wątek wykonuje współbieżnie kod kernela, jednak przebieg wykonania może różnić się od pozostałych (np. na skutek rozgałęzienia)

OpenCL model wykonania indeksowanie Każdy wątek należy do jednej z grup (work-group), na które podzielona jest przestrzeń indeksów implementowaną w OpenCL przez typ NDRange W ramach grupy każdy wątek ma swój lokalny identyfikator unikalny wew. grupy Każda grupa wątków również ma swój unikalny identyfikator

OpenCL przestrzeń indeksów Przestrzeń indeksów w OpenCL definiowana jest za pomocą typu NDRange, który jest 1-, 2- albo 3-wymiarową tablicą liczb całkowitych określających wartości indeksów w każdym kierunku Indeksy globalne i lokalne wątku są N-wymiarowymi krotkami, gdzie N {1, 2, 3} Wątek może zostać zidentyfikowany na podstawie: identyfikatora globalnego identyfikatora lokalnego oraz identyfikatora grupy

OpenCL przestrzeń indeksów Przykładowo dla 2-wymiarowej przestrzeni indeksów istnieje następująca zależność między identyfikatorem globalnym (g x, g y ) a lokalnym (s x, s y ): (g x, g y ) = (w x S x + s x + F x, w y S y + s y + F y ), gdzie: (w x, w y ) to identyfikator grupy (S x, S y ) to rozmiar grupy (F x, F y ) to przesunięcie (offset)

OpenCL przestrzeń indeksów

OpenCL model pamięci Wątki (work-items) wykonujące kod kernela mają dostęp do czterech typów pamięci: pamięci globalnej dostępna do odczytu i zapisu dla wszystkich wątków we wszystkich grupach pamięci stałej fragment pamięci globalnej tylko do odczytu pamięci lokalnej pamięć dostępna dla wątków należących do tej samej grupy pamięci prywatnej każdy wątek ma swoją pamięć prywatną

OpenCL model pamięci Rysunek : Schemat modelu pamięci OpenCL, źródło OpenCL Specification, v1.2

OpenCL model pamięci Host Kernel Dostęp do pamięci Globalna Stała Lokalna Prywatna Alokacja dynamiczna Alokacja dynamiczna Alokacja dynamiczna Brak Odczyt / zapis Odczyt / zapis Brak dostępu Brak dostępu Brak Alokacja statyczna Alokacja statyczna Alokacja statyczna Odczyt / zapis Tylko odczyt Odczyt / zapis Odczyt / zapis Pamięci hosta i urządzenia są w większości niezależne konieczny jest transfer danych z jednej do drugiej Transfer może odbywać się: za pomocą operacji kopiowania za pomocą odwzorowania (mapowania) z pamięci hosta do pamięci urządzenia

OpenCL model programownia OpenCL wspiera dwa rodzaje równoległości w programach: równoległość danych (ang. data parallelism) sekwencja instrukcji wykonywana jest wielokrotnie, ale dla różnych danych, np. kolejnych punktów obrazu przydział danych dla jednostek przetwarzania równoległość zadaniowa (ang. task parallelism) pojedyncza instancja kernela (zadanie) wykonywana jest dla całej przestrzeni indeksowania

OpenCL obiekty pamięci Złożone dane wejściowe dla kernela oraz wyniki jego wykonania zapisywane są w obiektach pamięci (memory objects) OpenCL wyróżnia dwa typy obiektów pamięci: buforach tablica jednowymiarowa obrazach 2- lub 3-wymiarowa tekstura lub obraz Bufor jest sekwencją danych typów podstawowych lub zdefiniowanych przez użytkownika Obraz to tablica punktów dostępnych dla kernela w postaci 4 elementowych wektorów wewnętrzny format obrazu może być inny

OpenCL API inicjalizacja Platform Devices Context Queue

OpenCL API inicjalizacja 1 #include <CL/cl.h> // użyjemy API z języka C 2... 3 int main() { 4 cl_int status; // CL_SUCCESS jeżeli ok, kod błędu wpp. 5 cl_uint num_platforms = 0; 6 // Sprawdź liczbę platform OpenCL 7 status = clgetplatformids(0, NULL, &num_platforms); 8 if (num_platforms == 0 status!= CL_SUCCESS) { return EXIT_FAILURE; } 9 // Pobierz identyfikatory platform 10 std::vector<cl_platform_id> platforms(num_platforms); 11 // Drugi raz clgetplatformids, inne parametry 12 status = clgetplatformids(num_platforms, &platforms.front(), NULL);

OpenCL API inicjalizacja 1 // Szukamy platformy z odpowiednim typem urządzenia 2 const cl_device_type kdevicetype = CL_DEVICE_TYPE_GPU; 3 cl_device_id device; // Wystarczy nam pierwsze z brzegu urządzenie 4 cl_platform_id platform; 5 bool found = false; 6 for (cl_uint i = 0; i < num_platforms &&!found; ++i) { 7 cl_uint count = 0; 8 status = clgetdeviceids(platforms[i], kdevicetype, 1, &device, & count); 9 if (count == 1) { // OK, znaleźliśmy 10 platform = platforms[i]; 11 found = true; 12 } 13 }

OpenCL API inicjalizacja 1 // Tworzymy kontekst obliczeniowy 2 const cl_context_properties prop[] = { // Parametry określające kontekst 3 CL_CONTEXT_PLATFORM, (cl_context_properties)platform, 4 0 // 0 -> znacznik końca listy parametrów 5 }; 6 cl_context context = clcreatecontextfromtype(prop, kdevicetype, NULL, 7 NULL, &status); 8 if (status!= CL_SUCCESS) { 9 cout << "Problem z tworzeniem kontekstu obliczeniowego. Kod błędu: " 10 << status << endl; 11 } 12 // Tworzymy kolejkę poleceń OpenCL 13 cl_command_queue cmd_queue = clcreatecommandqueue(context, 14 device, 15 0, &status);

OpenCL API program OpenCL 1 // Nasz program w postaci łańcucha 2 const char *src = "" 3 " kernel void example( global const float* A," 4 " int k," 5 " global float* C) {" 6 " int id = get_global_id(0);" 7 " C[id] = A[id] * k;" 8 "}"; 9 // Tworzymy obiekt programu OpenCL 10 cl_program program = clcreateprogramwithsource(context, 1, 11 (const char**)&src, 12 NULL, NULL); 13 status = clbuildprogram(program, 1, devices, NULL, NULL, NULL); 14 if (status!= CL_SUCCESS) { 15 char log[1024] = {}; 16 clgetprogrambuildinfo(program, devices[0], CL_PROGRAM_BUILD_LOG, 17 1024, log, NULL); 18 cout << "Build log:\n" << log << endl; 19 return EXIT_FAILURE; 20 }

OpenCL API kernel 1 cl_kernel kernel = clcreatekernel(program, "example", NULL); 2 // Dane wejściowe dla obliczeń 3 cl_float scores[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; 4 const int n = sizeof(scores) / sizeof(scores[0]); 5 // Alokacja buforów na dane wejściowe i wyniki obliczeń kernela 6 cl_mem in_mem = clcreatebuffer(context, CL_MEM_READ_ONLY CL_MEM_COPY_HOST_PTR, 7 sizeof(cl_float4) * n, scores, NULL); 8 cl_mem out_mem = clcreatebuffer(context, CL_MEM_READ_WRITE, 9 sizeof(cl_float) * n, NULL, NULL); 10 cl_int k = 20; // Parametr typu podstawowego 11 // Przekaż parametry dla kernela 12 clsetkernelarg(kernel, 0, sizeof(cl_mem), (void *) &in_mem); 13 clsetkernelarg(kernel, 1, sizeof(cl_int), (void *) &k); 14 clsetkernelarg(kernel, 2, sizeof(cl_mem), (void *) &out_mem);

OpenCL API wykonanie kernela 1 const int dimensions = 1; 2 // Definiujemy przestrzeń indeksowania 3 size_t global_work_size[dimensions] = { n }; 4 cl_event event; 5 status = clenqueuendrangekernel(cmd_queue, kernel, dimensions, NULL, 6 global_work_size, NULL, 0, NULL, &event); 7 clwaitforevents(1, &event); // Czekaj na wykonanie kernela 8 // Kopiujemy wynik z pamięci urządzenia do pamięci hosta 9 cl_float result[n] = {}; 10 status = clenqueuereadbuffer(cmd_queue, out_mem, CL_TRUE, 11 0, n * sizeof(cl_float), result, 0, NULL, NULL ); 12 // Pokaż wynik 13 cout << "Result: "; 14 for (int i = 0; i < n; ++i) { 15 cout << result[i] << " "; 16 } 17 cout << endl;

OpenCL API sprzątanie 1 clfinish(cmd_queue); // Czekamy na zakończenie zadań 2 // Zwalniamy pamięć 3 clreleasememobject(in_mem); 4 clreleasememobject(out_mem); 5 clreleasekernel(kernel); 6 clreleaseprogram(program); 7 clreleasecommandqueue(cmd_queue); 8 clreleasecontext(context);

OpenCL API podsumowanie sekwencji operacji

Funkcje dotyczące przestrzeni indeksowania uint get_work_dim() zwraca liczbę wymiarów przestrzeni indeksowania (1,2 lub 3) size_t get_global_size(uint dim) zwraca globalną liczbę wątków dla wymiaru dim size_t get_global_id(uint dim) zwraca globalny identyfikator wątku dla wymiaru dim size_t get_local_size(uint dim) zwraca liczbę wątków dla wymiaru dim w grupie, do której należy wątek size_t get_local_id(uint dim) zwraca identyfikator wątku dla wymiaru dim wew. grupy, do której należy wątek size_t get_num_groups(uint dim) zwraca liczbę grup dla podanego wymiaru size_t get_group_id(uint dim) zwraca identyfikator grupy dal podanego wymiaru size_t get_global_offset(uint dim) zwraca przesunięcie (offset) dla podanego wymiaru; domyślnie 0

Funkcje dotyczące przestrzeni indeksowania 1 // Przestrzeń indeksowania definiujemy przy zlecaniu zadania 2 const size_t dim = 2; 3 size_t offset[] = { 0, 0 }; 4 size_t global_threads[] = { 100, 50 }; // 100x50 wątków 5 size_t local_threads[] = { 16, 16 }; // Grupy 16x16 6... 7 status = clenqueuendrangekernel(cmd_queue, kernel, 8 dim, 9 offset, // może być NULL dla {0, 0} 10 global_threads, 11 local_threads,// dla NULL automatycznie 12 0, NULL, &event); 1 // Każdy wątek wykonujący kernel otrzymuje indeks w przestrzeni 2 // indeksowania 3 size_t x = get_global_id(0); 4 size_t y = get_global_id(1); 5 // Albo 6 size_t x = get_group_id(0) * get_local_size(0) + get_local_id(0) + 7 get_global_offset(0); 8 size_t y = get_group_id(1) * get_local_size(1) + get_local_id(1) + 9 get_global_offset(1);

OpenCL a CUDA CUDA Krata (grid) Blok (block) Wątek (thread) OpenCL Przestrzeń indeksowania (index space) Grupa zadań (work-group) Zadanie (work-item)