Programowanie CUDA informacje praktycznie i. Wersja

Podobne dokumenty
Programowanie CUDA informacje praktycznie i przykłady. Wersja

Programowanie PKG - informacje praktycznie i przykłady. Wersja z Opracował: Rafał Walkowiak

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

EFEKTYWNOŚĆ MNOŻENIA MACIERZY W SYSTEMACH Z PAMIĘCIĄ WSPÓŁDZIELONĄ

ANALIZA EFEKTYWNOŚCI MNOŻENIA MACIERZY W SYSTEMACH Z PAMIĘCIĄ WSPÓŁDZIELONĄ

CUDA. cudniejsze przyk ady

Przygotowanie kilku wersji kodu zgodnie z wymogami wersji zadania,

Zadania na zaliczenie przedmiotu Przetwarzanie równoległe Zebrał dla roku.ak. 2015/2016 Rafał Walkowiak,

Programowanie kart graficznych

Wprowadzenie do programowania w środowisku CUDA. Środowisko CUDA

Programowanie Współbieżne

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

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

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

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

Programowanie kart graficznych. Architektura i API część 2

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

Materiały pomocnicze do laboratorium. 1. Miary oceny efektywności 2. Mnożenie macierzy 3. Znajdowanie liczb pierwszych

MATERIAŁY POMOCNICZE DO LABORATORIUM Z PRZETWARZANIA RÓWNOLEGŁEGO KWIECIEŃ 2018

Programowanie aplikacji równoległych i rozproszonych

Przetwarzanie Równoległe i Rozproszone

Obliczenia na GPU w technologii CUDA

Procesory kart graficznych i CUDA wer

Programowanie procesorów graficznych GPGPU

Programowanie procesorów graficznych w CUDA.

Tesla. Architektura Fermi

Programowanie procesorów graficznych GPGPU

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

Wprowadzenie do programowania w środowisku CUDA. Środowisko CUDA

Zadania na zaliczenie przedmiotu Przetwarzanie równoległe Zebrał dla r.ak. 2014/2015 Rafał Walkowiak,

i3: internet - infrastruktury - innowacje

PROGRAMOWANIE WSPÓŁCZESNYCH ARCHITEKTUR KOMPUTEROWYCH DR INŻ. KRZYSZTOF ROJEK

CUDA ćwiczenia praktyczne

Przykładem jest komputer z procesorem 4 rdzeniowym dostępny w laboratorium W skład projektu wchodzi:

Procesory kart graficznych i CUDA

Programowanie kart graficznych. Architektura i API część 1

Procesory kart graficznych i CUDA wer PR

CUDA. obliczenia na kartach graficznych. Łukasz Ligowski. 11 luty Łukasz Ligowski () CUDA 11 luty / 36

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

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

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

Literatura. 11/16/2016 Przetwarzanie równoległe - wstęp 1

Programowanie kart graficznych

Wykład 1_2 Algorytmy sortowania tablic Sortowanie bąbelkowe

GTX260 i CUDA wer

Wydajność systemów a organizacja pamięci, czyli dlaczego jednak nie jest aż tak źle. Krzysztof Banaś, Obliczenia wysokiej wydajności.

Wiadomości wstępne Środowisko programistyczne Najważniejsze różnice C/C++ vs Java

Wskaźniki. Przemysław Gawroński D-10, p marca Wykład 2. (Wykład 2) Wskaźniki 8 marca / 17

Organizacja pamięci w procesorach graficznych

PROJEKT 3 PROGRAMOWANIE RÓWNOLEGŁE. K. Górzyński (89744), D. Kosiorowski (89762) Informatyka, grupa dziekańska I3

Algorytmy równoległe: ocena efektywności prostych algorytmów dla systemów wielokomputerowych

Wstęp do informatyki. Maszyna RAM. Schemat logiczny komputera. Maszyna RAM. RAM: szczegóły. Realizacja algorytmu przez komputer

- - Ocena wykonaniu zad3. Brak zad3

Podstawy Programowania C++

LABORATORIUM 3 ALGORYTMY OBLICZENIOWE W ELEKTRONICE I TELEKOMUNIKACJI. Wprowadzenie do środowiska Matlab

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

Systemy wbudowane. Uproszczone metody kosyntezy. Wykład 11: Metody kosyntezy systemów wbudowanych

Algorytmy równoległe: ocena efektywności prostych algorytmów dla systemów wielokomputerowych

Analiza efektywności przetwarzania współbieżnego. Wykład: Przetwarzanie Równoległe Politechnika Poznańska Rafał Walkowiak Grudzień 2015

Języki i paradygmaty programowania 1 studia stacjonarne 2018/19. Lab 9. Tablice liczbowe cd,. Operacje na tablicach o dwóch indeksach.

Przetwarzanie Równoległe i Rozproszone

Literatura. 3/26/2018 Przetwarzanie równoległe - wstęp 1

System obliczeniowy laboratorium oraz. mnożenia macierzy

INFORMATYKA Z MERMIDONEM. Programowanie. Moduł 5 / Notatki

Moc płynąca z kart graficznych

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

10/14/2013 Przetwarzanie równoległe - wstęp 1. Zakres przedmiotu

Projektowanie algorytmów równoległych. Zbigniew Koza Wrocław 2012

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

tablica: dane_liczbowe

Wydajność systemów a organizacja pamięci. Krzysztof Banaś, Obliczenia wysokiej wydajności. 1

Mnożenie macierzy. Systemy z pamięcią współdzieloną Systemy z pamięcią rozproszoną Efektywność

PODSTAWY INFORMATYKI 1 PRACOWNIA NR 6

Algorytmy równoległe. Rafał Walkowiak Politechnika Poznańska Studia inżynierskie Informatyka 2010

Za pierwszy niebanalny algorytm uważa się algorytm Euklidesa wyszukiwanie NWD dwóch liczb (400 a 300 rok przed narodzeniem Chrystusa).

Procesy i wątki. 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.

Skalowalność obliczeń równoległych. Krzysztof Banaś Obliczenia Wysokiej Wydajności 1

Wskaźniki i dynamiczna alokacja pamięci. Spotkanie 4. Wskaźniki. Dynamiczna alokacja pamięci. Przykłady

Wydajność obliczeń równoległych. Krzysztof Banaś Obliczenia Wysokiej Wydajności 1

Podstawy programowania Laboratorium. Ćwiczenie 2 Programowanie strukturalne podstawowe rodzaje instrukcji

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

Architektura komputerów

Analiza efektywności przetwarzania współbieżnego

Algorytm poprawny jednoznaczny szczegółowy uniwersalny skończoność efektywność (sprawność) zmiennych liniowy warunkowy iteracyjny

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

Tablice cz. I Tablice jednowymiarowe, proste operacje na tablicach

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

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

Algorytm. a programowanie -

Wydajność systemów a organizacja pamięci. Krzysztof Banaś, Obliczenia wysokiej wydajności. 1

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

Lab 9 Podstawy Programowania

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

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

Programowanie Współbieżne. Algorytmy

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

Wydajność programów sekwencyjnych. Krzysztof Banaś Obliczenia Wysokiej Wydajności 1

KURS C/C++ WYKŁAD 2. char znak; znak = a ; Program 2 #include<stdio.h> void main() { char znak; while( (znak = getchar() )!= t ) putchar(znak); }

Transkrypt:

Programowanie CUDA informacje praktycznie i przykłady Wersja 16.12.2013

Podstawowe operacje na GPU cudasetdevice() Określenie GPU i ustanowienie kontekstu (analog w GPU tego czym jest proces dla CPU) dla GPU wykorzystywanego przez wątek CPU. Alokacje pamięci DEVICE I i uruchomienia kernela będą realizowane na wybranym urzadzeniu, z nim związane są strumienie i zdarzenia. Domyślnie wybrane jest urządzenie o devid =0. cudagetdevice(&devid) służy do sprawdzenia efektu wykonania cudasetdevice(), zwraca ewentualnie błąd. cudadevicereset() usuwa kontekst GPU używany przez wątek, wywołanie niezbędne do zakończenie profilowania. CUDA informacje praktycznie i przykłady 2

Informacja o błędach przetwarzania CUDA Wszystkie wywołania funkcji CUDA (oprócz uruchomienia kernela) zwracają kod błędu typu cudaerror_t cudaerror_t cudagetlasterror(void) Zwraca kod ostatniego błędu (braku błędu) char* cudageterrorstring(cudaerror_t code) Zwraca zakończony zerem ciąg znaków opisujący błąd. Użycie: printf( %s\n, cudageterrorstring( cudagetlasterror() ) ); Funkcje informacyjne cudagetdevicecount(),cudagetdeviceproperties() CUDA informacje praktycznie i przykłady 3

Błędy uruchomienia kernela Uruchomienia kernela nie zwracają kodu błędu. Wywołania cudapeekatlasterror() lub cudagetlasterror() powinny być zrealizowane dla uzyskania informacji o błędach przeduruchomieniowych ( parametrów, konfiguracji uruchomienia). Dla zapewnienia, że błąd zwracany przez cudapeekatlasterror() cudagetlasterror() nie pochodzi z wcześniejszych wywołań ważne jest wyzerowanie zmiennej błędu (ustawienie jej na cudasuccess) lub wywołanie cudagetlasterror() (funkcja zeruje błąd) przed wywołaniem kernela. Wywołania kernela są asynchroniczne i dlatego należy je zsynchronizować (np. cudadevicesynchronize()) z przetwarzaniem CPU przed wywołaniami cudapeekatlasterror(), cudagetlasterror(), aby mieć pewność że się zakończyły i pobierane błędy dotyczą wywołania kernela. CUDA informacje praktycznie i przykłady 4

Pomiar czasu kernela lub przez program profilujący cudaevent_t start; error = cudaeventcreate(&start); if (error!= cudasuccess) { fprintf(stderr, Nie udało się utworzyć zdarzenia start (kod bledu %s)!\n", cudageterrorstring(error)); exit(exit_failure); } cudaevent_t stop; error = cudaeventcreate(&stop); if (error!= cudasuccess)... error = cudaeventrecord(start, 0); zerowym if (error!= cudasuccess)... //zapisywanie zdarzenia startowego w strumieniu // uruchomienie kernela error = cudaeventrecord(stop, 0); zerowym error = cudaeventsynchronize(stop); if (error!= cudasuccess)... //zapisywanie zdarzenia końcowego w strumieniu if (error!= cudasuccess)...//oczekiwanie na zakończenie float msectotal = 0.0f; error = cudaeventelapsedtime(&msectotal, start, stop); if (error!= cudasuccess)... cudaeventdestroy(start); cudaeventdestroy(stop); Zwracane wartości są mierzone w oparciu o zegar GPU i dlatego rozdzielczość pomiaru jest niezależna od sprzętu i systemu operacyjnego komputera host. CUDA informacje praktycznie i przykłady 5

Mnozenie macierzy Jeden blok Wiele blokow Wykorzystanie pamięci współdzielonej Zwiększenie ilości pracy między synchronizacjami CUDA informacje praktycznie i przykłady 6

Dostęp do elementów tablic width Ze względu na lokację tablic wierszami, pozycję: j-tego elementu w i-tym wierszu tablicy określamy wzorem: i*width+j Kolejne elementy tablicy CUDA informacje praktycznie i przykłady 7

Wyznaczanie elementu macierzy A * B = C For (k=0, k<width,k++) C[i*width+j]+=A[i*width+k]*B[k*width+j]; //czyli C[i][j]=A[i][k]*B[k,j]; CUDA informacje praktycznie i przykłady 8

Tworzenie warpów z wątków bloku - przykład Załóżmy blok wątków o wymiarach 7 na 7 liczba wątków wynosi 49 MAX liczba bloków na SM (cc 1.3) 8 49 wątków to 2 warpy max zajętość SM to 8 bloków po 2 warpy czyli 16 warpów zajętosc warpami 50%, zajętość wątkami 392/1024 = 38 % 3 wątki wątki 4wątki Niewykorzystane pozycje warpu 32 wątki 17 wątków CUDA informacje praktycznie i przykłady 9

Mnożenie macierzy wer.1 // funkcja mnożenia macierzy GPU wer.1 global void MatrixMulKernel_1(float* Ad, float* Bd, float* Cd, int WIDTH) { // 2 wymiarowy blok, indeksy obliczanego elementu int tx = threadidx.x; int ty = threadidx.y; float C_local = 0; //obliczany wynik for (int k = 0; k < WIDTH; ++k) { float A_d_element = Ad[ty * WIDTH+ k]; // Ad[ty,k] dostęp nieefektywny ta sama wartość potrzebna wątkom float B_d_element = Bd[k * WIDTH + tx]; // Bd[k,tx] dostęp efektywny sąsiednie lokacje dla wątków w warpie - wiązce C_local += A_d_element * B_d_element; } Cd[ty * WIDTH + tx] = C_local; } Obliczenia za pomocą jednego bloku wątków (kluczowe są zmienne threadidx.x, threadidx.y) Każdy wątek oblicza jeden element wyniku liczba wątków równa liczbie elementów macierzy. Rozmiar bloku równy rozmiarowi macierzy lub więcej pracy dla każdego wątku (stosunek wielkości tablicy i bloku) CUDA informacje praktycznie i przykłady 10

Uruchomienie przetwarzania - MM ver.1 // parametry konfiguracji uruchomienia kernela dim3 wymiarybloku(width, WIDTH); dim3 wymiarygridu(1, 1); // uruchomienie obliczeń MatrixMulKernel_1<<< wymiarygridu, wymiarybloku >>> (Ad, Bd, Cd,WIDTH); CUDA informacje praktycznie i przykłady 11

Efektywność - MM ver.1 Jeden blok - obliczenia wykonywane na jednym SM. W każdej chwili aktywny jest maksymalnie tylko jeden warp 32 wątki (GTX260). Dla pozostałych wątków (z innych warp) możliwe jest pobieranie operandów z pamięci globalnej GPU. Maksymalna liczba wątków na SM i wielkość bloku wątków ograniczona przez parametry CC (zdolności obliczeniowej) i zasoby GPU. Max wydajność rozwiązania - obliczenia: 1,4 *10 9 (częstotliwość) 32/4 X 3 (cykle - - szeregowanie wątków ) = 30 Gflop Max przepustowość pamięci dla karty: 112 GB/s (GTX260) CUDA informacje praktycznie i przykłady 12

Analiza ograniczenia prędkości obliczeń przez przepustowość pamięci - MM ver.1 Współczynnik CGMA (compute to global memory access ratio) stosunek liczby operacji do liczby dostępów do pamięci. Dla mnożenia macierzy 2 operacje (+,*) przypadają na 2 dostępy do pamięci globalnej (pobranie operandów) CGMA =1 CGMA wyrażone w bajtach - 2/8 opearacji / bajt Przepustowość pamięci 112 GB/s stanowiłaby ograniczenie dla prędkości obliczeń (CGMA) do 28 Gflops (float 4 bajty). CUDA informacje praktycznie i przykłady 13

Efektywność - MM ver.1 Przepustowość dostępu do pamięci nie jest silnym ograniczeniem dla szczytowej prędkości obliczeń (900/27 = 33 Gflops ) tego kernela korzystającego z 1 SM Wykorzystujemy tylko jeden SM stąd 1/27 mocy GPU. Ograniczona liczba wątków, jeden blok (512 wątków) to 16 warpów - za mało aby obliczać w sposób ciągły, ze względu na czas dostępu (ok. 100 cykli procesora do pamięci globalnej). Cykl obliczeń dla wszystkich wątków trwający 2 (operacje) * 16 (warpy) ok. 30 cykli będzie można powtarzać co ok 200 cykli (po czasie dostępu do 2 słów danych) - daje to zajętość obliczeniami rzędu 15 % czasu. CUDA informacje praktycznie i przykłady 14

Mnożenie macierzy wer.2 Określenie elementu macierzy obliczanego przez wątek w bloku Zakładamy, że wymiar macierzy WIDTH jest podzielny przez wymiar podmacierzy SUB_WIDTH Kwadratowy blok wątków oblicza kwadratowy blok elementów macierzy wynikowej, każdy wątek wyznacza jeden element podmacierzy, SUB_WIDTH= blockdim.x= blockdim.y Dla określenia lewego górnego elementu podtablicy obliczanej przez blok potrzebne są zmienne automatyczne środowiska - indeksy bloków blockid.x, blockid.y blockid.x* blockdim.x, blockid.y* blockdim.y Dla wyznaczenia elementu w ramach bloku potrzebne są indeksy wątków w bloku: threadid.x, threadid.y Indeksy elementów tablicy zatem : blockid.x* blockdim.x + threadid.x, blockidd.y* blockdim.y + threadid.y Zrzutowanie na elementy w macierzy jednowymiarowej: (blockid.y* blockdim.y + threadid.y )* WIDTH + (blockid.x* blockdim.x + threadid.x )* 1,1 0,0 0,1 0,2 1,0 1,1 1,2 2,0 2,1 2,2 blockid.x* SUB_WIDTH, blockid.y* SUB_WIDTH threadid.x threadid.y CUDA informacje praktycznie i przykłady 15

Mnożenie macierzy wer2 Obliczenia za pomocą wielu bloków wątków o wielkości blockdim.x * blockdim.y (kluczowe są zmienne threadidx.x, threadidx.y, blockid.x, blockid.y) Każdy wątek oblicza jeden element wyniku liczba wątków równa liczbie elementów macierzy. Liczba bloków równa zależna od wielkości macierzy i wielkości bloku (WIDTH/ blockdim.x) 2 Obliczenia mogą być wykonywane na wielu SM - różne bloki na tym samym lub różnych SM. Liczba jednocześnie przetwarzanych warp zależy od: liczby SM ograniczenia sprzętu jeden warp w jednym SM, Liczby bloków - kolejny SM wymaga kolejnego bloku Liczby aktywnych warp im więcej warp można przydzielić do SM jednocześnie (ograniczenia zasobowe) tym większa możliwość ukrycia kosztu dostępu do operandów pod obliczeniami innych gotowych warp. CUDA informacje praktycznie i przykłady 16

global void MatrixMulKernel_2(float* Ad, float* Bd, float* Cd, int WIDTH) { // wyznaczenie indeksu wiersza/kolumny obliczanego elementu tablicy Cd int Row = blockid.y * blockdim.y + threadid.y; int Col = blockid.x * blockdim.x + threadid.x; float C_local= 0; // każdy wątek z bloku oblicza element podmacierzy for (int k = 0; k < WIDTH; ++k) C_local += A_d[Row][k] * B_d[k][Col]; // A_d[Row][k] dostęp nieefektywny // B_d[k][Col] dostęp efektywny sąsiednie wątki wiązki czytają sąsiednie słowa Cd[Row][Col] = C_local; //zapis efektywny j.w. } MM ver. 2 CUDA informacje praktycznie i przykłady 17

Uruchomienie przetwarzania Mnożenie macierzy wer2 // parametry konfiguracji uruchomienia kernela dim3 wymiarybloku(sub_width, SUB_WIDTH); dim3 wymiarygridu(width / SUB_WIDTH, WIDTH / SUB_WIDTH); (uwaga na liczbę wątków aby ich starczyło (SUFIT) i wszystkie realizowały właściwą pracę czy wątek jest w zakresie pracy) // uruchomienie obliczeń MatrixMulKernel_2<<< wym_gridu, wym_bloku >>>(Ad, Bd, Cd,WIDTH); CUDA informacje praktycznie i przykłady 18

Wydajność rozwiązania - mnożenie macierzy wer2 współczynnik CGMA = 1 op/dostęp (1/4 Flops/ Bajt): Max prędkość obliczeń: 900 Gflops (SP) - ze względu na 27 (SM)*1,4 *10 9 (częstotliwość) 3 (Flops)*32 (warp)/4 (cykle) Przepustowość pamięci * : 112 GB/s ogranicza prędkość obliczeń do 28 GFlops - słowo 4 bajty, CGMA =1 Dalsze ograniczenie prędkości przetwarzania wynika z czasu dostępu do pamięci. * Przepustowość pamięci - MemoryClock*MemInterfaceWidth*2( pamięci DDR) CUDA informacje praktycznie i przykłady 19

Ograniczenia na poziom równoległości przetwarzania Ograniczenia wydajnościowe: 1. Poziom wiele SM - poziom równoległości (min, max, śr.) zależy od liczby bloków wątków przetwarzających grid. 2. Poziom jednego SM poziom równoległości i efektywność obliczeń w ramach jednego SM zależy od liczby wiązek (warps) (wypełnionych), które można równocześnie przydzielić do jednego SM. Jest ona ograniczona: liczbą bloków w SM 8 problemem są małe bloki liczba warps w SM 32 - czyli max 1024 wątki (CC 1.2) wymaganiami na pamięć współdzieloną bloku wątków wymaganiami na liczbę rejestrów bloku wątków (wielkość bloku * liczba rejestrów potrzebnych wątkowi) CUDA informacje praktycznie i przykłady 20

r x r Z innego wykładu: Mnożenie macierzy pamięć podręczna [operacje na fragmentach tablic][graficznie] C A B for (int kk = k ; kk < k+r ; kk++) C[ii][jj] + = A[ii][kk] * B[kk][jj]; for (int jj = j ; jj < j+r ; jj++) for (int kk = k ; kk < k+r ; kk++) C[ii][jj] + = A[ii][kk] * B[kk][jj]; for ( int ii = i ; ii < i+r; ii++) for (int jj = j ; jj < j+r ; jj++) for (int kk = k ; kk < k+r ; kk++) C[ii][jj] + = A[ii][kk] * B[kk][jj]; for (int k = 0 ; k < n ; k+=r) for ( int ii = i ; ii < i+r; ii++) for (int jj = j ; jj < j+r ; jj++) for (int kk = k ; kk < k+r ; kk++) C[ii][jj] + = A[ii][kk] * B[kk][jj]; CUDA informacje praktycznie i przykłady 21

Wykorzystanie pamięci współdzielonej jako efektywnej pamięci bliskiej (MM wer.3) Zastosujemy to samo podejście jak w mnożeniu macierzy algorytmem zagnieżdżonych 6 pętli i optymalizacją wykorzystania pamięci podręcznej. Zamiast pamięci podręcznej pamięć współdzielona zadania wątków i ich mozliwości. Pobrania danych do pamięci współdzielonej wykorzystywanych bloków danych realizują wątki kolektywnie. Konieczna synchronizacja zakończenia pobrania. ETAPY pracy: Pobranie danych do pamięci współdzielonej bloku wątków możliwość łączenia dostępów Każdy wątek wylicza wynik częściowy na podstawie danych w dostępnej mu pamięci współdzielonej. Synchronizacja każdego bloku wątków przed wymianą danych w pamięci współdzielonej. Kolejny krok kolektywnego pobrania danych przez blok wątków do pamięci współdzielonej, a następnie uzupełnienie sum częściowych o wyniki kolejnych mnożeń pobranych elementów. Kolektywny zapis wyników (każdy wątek jeden wynik) do pamięci. Zysk mniejszy czas pobierania danych z pamięci mniej pobrań MM wer 1 i 2 - pobrania danych determinowały czas przetwarzana. Strata - obliczenia konkretnego bloku wątków nie mogą być realizowane jednocześnie z pobieraniem danych dla tego bloku. Im większy blok tym większa krotność wykorzystania raz pobranych do pamięci współdzielonej danych - CGMA Im większy blok tym niższy stopień zrównoleglenia pobrań danych i obliczeń (synchronizacja w kodzie). CUDA informacje praktycznie i przykłady 22

Mnożenie macierzy wersja 3 cz.1 global void MatrixMulKernel_3(float* Ad, float* Bd, float* Cd, int Width) { shared float Ads[SUB_WIDTH][SUB_WIDTH]; shared float Bds[SUB_WIDTH][SUB _WIDTH]; int bx = blockidx.x; int by = blockidx.y; int tx = threadidx.x; int ty = threadidx.y; // obliczenie indeksów obliczanego elementu tablicy Cd int Row = by * blockdim.y + ty; int Col = bx * blockdim.x + tx; int C_local = 0; // pętla po poszczególnych podmacierzach wejściowych niezbędnych do wyznaczenia wyniku TUTAJ FRAGMENT KODU ZE STRONY KOLEJNEJ Cd[Row][Col] = C_local; } Mnożenie macierzy przez bloki wątków CUDA informacje w przy praktycznie użyciu i przykłady pamięci współdzielonej cz1 23

Mnożenie macierzy wersja 3 cz.2 for (int m = 0; m < WIDTH/ SUB_WIDTH; ++m) { // wątki wspólnie bloku ładują podmacierze do pamięci współdzielonej //WĄTKI O SĄSIEDNICH ID ładują sąsiednie elementy z pamięci Ads[tx][ty] = Ad [Row][m*SUB_WIDTH + tx]; Bds[tx][ty] = Bd[m*SUB_WIDTH + ty][col]; //oczekiwanie na dane podmacierzy w pamięci współdzielonej syncthreads(); } for (int k = 0; k < SUB_WIDTH; ++k) C_local += Ads[tx][k] * Bds[k][ty]; //oczekiwanie na koniec obliczeń przed pobraniem nowych danych syncthreads(); CUDA informacje praktycznie i przykłady 24

Efektywność wersji 3 Im większy blok ładowany do ShMem tym mniej razy dane ładowane do ShMem i mniejsze wymagania na przepustowość pamięci globalnej. Dla tego kodu rozmiar bloku danych w etapie (w ShMem) równy rozmiarowi bloku wątków. Rozmiar bloku wątków wpływa na wielkość potrzebnej ShMem i możliwości uruchamiania bloku w SM. Każdy wątek wykonuje BLOCK_SIZE operacji MUL_ADD i dwa pobrania danych macierzy wejściowej. Blok wątków - BLOCK_SIZE x BLOCK_SIZE Dla BLOKu watków - 16 X 16 - CGMA jest równe 32/2 operacja/dostęp ----- -(lub 4 operacje/bajt) Przepustowość pamięci 112 GB/s stanowi ogranicznie prędkości obliczeń (dla tego CGMA) do 448 Gflop. Ograniczeniem na prędkość obliczeń są również: duży czas dostępu do pamięci globalnej, synchronizacja pracy wątków w bloku wątków faza pobrań danych i faza obliczeń nie są równoległe spróbujemy te fazy zrównoleglić. CUDA informacje praktycznie i przykłady 25

Wersja 3 Pętla po blokach { Mnożenie macierzy wersja 4 Ładowanie kolejnego bloku danych do pamięci współdzielonej; Synchronizacja; Obliczenia; Synchronizacja; } Wersja 4 Pobranie pierwszego bloku danych z pamięci globalnej (do rejestru lub pamięci wspóldzielonej) Pętla po blokach { Przepisanie danych do pamięci współdzielonej; Synchronizacja; Pobranie kolejnego bloku danych z pamięci globalnej; Obliczenia; Synchronizacja; } Wzrost ilości operacji i większe wymagania zasobowe, lecz większe ziarno przetwarzania łagodzące koszty synchronizacji i umożliwiające nakładanie operacji wątków. CUDA informacje praktycznie i przykłady 26

Dalsze optymalizacje Rozwinięcie pętli zmniejsza ilość operacji (obsługujące pętle) #pragma unroll. Wzrost ilości pracy realizowanej przez wątek obliczanie większej liczby wyników. Ocena efektywności wprowadzonych rozwiązań: CUDA_Occupancy_Calculator.xls Nvidia Visual profiler CUDA informacje praktycznie i przykłady 27

CUDA informacje praktycznie i przykłady 28

CUDA informacje praktycznie i przykłady 29