CUDA (Compute Unified Device Architecture)

Slides:



Advertisements
Podobne prezentacje
Język C/C++ Funkcje.
Advertisements

Użytkowanie Sieci Marcin KORZEB WSTI - Użytkowanie Sieci.
Programowanie wielowątkowe
Standardowa biblioteka języka C++
Programowanie obiektowe
Zmienne i Typy.
Programowanie w języku C++. Jak napisać prosty program obliczeniowy lub grę komputerową? Zbigniew Nagórny Pracownia Komputerowa Wyższa Szkoła Humanistyczno-Przyrodnicza.
Język ANSI C Funkcje Wykład: Programowanie komputerów
Prowadzący: mgr inż. Elżbieta Majka
Systemy rozproszone W. Bartkiewicz
dynamiczny przydział pamięci
argumenty wiersza poleceń: getopt
Uzupełnienie dot. przekazywania argumentów #include struct nowa { int f; char line[20000]; int k; } reprezentant; int main() { void funkcja7( struct nowa.
Implementacja algorytmów na procesory kart graficznych
Internet Communication Engine
Procesor DSP Sharc ADSP21161 firmy Analog Devices
Systemy plików FAT i FAT 32
Obliczenia równoległe w grafice komputerowej
Systemy operacyjne Wykład nr 5: Wątki Piotr Bilski.
Biblioteki i przestrzenie nazw
Sprawy organizacyjne 1. Zasady zaliczenia przedmiotu
Magistrala & mostki PN/PD
Mechanika dzielenia na podsieci. Wykład 6
Wykład 1: Wskaźniki Podstawy programowania Programowanie w C
Podstawy programowania PP – WYK2 Wojciech Pieprzyca.
Zachodniopomorskie Centrum Edukacyjne Zadanie domowe.
Tablice tablica jest sekwencją elementów tego samego typu (prostego lub obiektowego) w Javie tablice są obiektami, a zmienne tablicowe przechowują referencję
Semafory według normy POSIX
Systemów Operacyjnych
Wieloprocesowy system operacyjny dla komputerów ATARI XL/XE
Mikroprocesory i mikrokontrolery
Pamięć wspólna Opis własnego rozwiązania Marcin Kamiński, Michał Kotra Wydział EAIiE Katedra Automatyki Kraków, 2008.
Zastosowanie technologii CUDA w sztucznej inteligencji
nowe operatory & . (kropka) * operator rzutowy -> , (przecinek)
Podstawy programowania
Podstawy programowania II
Pamięci półprzewodnikowe
CUDA & CUDA.NET – czyli istne CUDA Piotr Ablewski
Podstawy informatyki 2013/2014
Podstawy programowania
Programowanie w języku Matlab
Łódź, 3 października 2013 r. Katedra Analizy Nieliniowej, WMiI UŁ Podstawy Programowania Złożona składnia języka C++
Jerzy F. Kotowski1 Informatyka I Wykład 11 STRUKTURY I UNIE.
Podstawy programowania
ZASADY PODZIAŁU SIECI NA PODSIECI, OBLICZANIA ADRESÓW PODSIECI,
Mikroprocesory.
Programowanie obiektowe III rok EiT dr inż. Jerzy Kotowski Wykład VIII.
Jerzy F. Kotowski1 Informatyka I Wykład 14 DEKLARATORY.
Programowanie obiektowe – zastosowanie języka Java SE
Programowanie obiektowe Wykład 3 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/21 Dariusz Wardowski.
Programowanie strukturalne i obiektowe
Definiowanie typów danych użytkownika
Rodzaje pamięci Kamiński Daniel TI s1.
Podstawy informatyki 2013/2014
Użytkowanie i programowanie Matlaba
Wykład nr 9 Programowanie sterowników PLC Piotr Bilski
PWSZ Gniezno // codefly 2009 Łukasz Tomczak
WYKŁAD 3 Temat: Arytmetyka binarna 1. Arytmetyka binarna 1.1. Nadmiar
K URS JĘZYKA C++ – WYKŁAD 1 ( ) Łagodne wprowadzenie do języka C++
1 dynamiczny przydział pamięci malloc() free() realloc() calloc() memset() memcpy( ) mempcpy( ) memmove() (wskaźniki!! )
1 Uzupełnienie dot. przekazywania argumentów #include struct nowa { int f; char line[20000]; int k; } reprezentant; int main() { void funkcja7( struct.
Typy liczbowe, zmienne, operatory Zajęcia 4. Zmienne Zmienna – to w programowaniu element programu, który może mieć przypisaną pewną wartość (wartość.
Wykład 4 Klasa Vec, której konstruktory alokują pamięć dla obiektów 1.Przykład definicji klasy Vec 2.Definicje konstruktorów i destruktora 3.Definicja.
Wykład 5 Klasa Vec i jej operatory 1.Kategorie operatorów 2.Operatory ogólne - przykłady 3.Operatory specjalne [ ], ( ) oraz –> 4.Operatory new i delete.
Programowanie procesorów graficznych Piotr Białas Wydział Fizyki, Astronomii i Informatyki Stosowanej Zakład Technologii Gier.
Uzupełnienie dot. przekazywania argumentów
Mikrokontrolery MSP430 DMA
Język C++ Typy Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi i Pawła Jerzego.
dynamiczny przydział pamięci
Tworzenie wątków w Javie
Zapis prezentacji:

CUDA (Compute Unified Device Architecture) GPGPU - General-purpose computing on graphics processing units CUDA (Compute Unified Device Architecture) W. Bożejko

Plan Wstęp Model programowania Model pamięci CUDA API Przykład – iloczyn skalarny

Wstęp

Tesla C870 Produkt Tesla C870 Obudowa ATX, 4.38” x 12.28” Ilość GPU Tesla 1 Dedykowana pamięć 1.5 GB GDDR3 Szczytowa wydajność Ponad 500 gigaflopów Precyzja obliczeń zmiennoprzecinkowych Pojedyncza precyzja w standardzie IEEE 754 Interfejs pamięci 384-bit Przepustowość pamięci 76.8 GBps Maksymalny pobór mocy 170W Interfejs systemowy PCI Express x16 Dodatkowe źródła zasilania Tak (2) Liczba slotów 2 Chłodzenie wentylator całkowity rozmiar pamięci globalnej 1,61 GB liczba multiprocesorów 16 liczba rdzeni (procesorów) 128 całkowity rozmiar pamięci stałej 65536 KB całkowity rozmiar pamięci współdzielonej przypadającej na jeden blok 16384 KB liczba rejestrów dostępna dla każdego bloku 8192 częstotliwość zegara 1,35 GHz

CUDA – model programowania GPU jest widziane jako urządzenie obliczeniowe mogące wykonać część aplikacji która musi być wykonana wielokrotnie może być wyizolowana jako funkcja działa niezależnie na różnych danych (model SIMD) Taka funkcja może być skompilowana o wykonana na GPU

CUDA – model programowania Blok wątków (Thread Block) Wątki mogą kooperować Mają szybką pamięć współdzieloną Są zsynchronizowane można je łatwo rozróżniać (mają Thread ID) Blok może być 1,2 lub 3-wymiarową tablicą

CUDA – model programowania Grid bloków wątków Ograniczona ilość wątków w bloku Pozwala wywołać większą liczbę wątków za pomocą jednego wywołania Bloki są identyfikowane za pomocą block ID Wymaga zmniejszenia kooperacji wątków Bloki mogą być 1 lub 2-wymiarowymi tablicami

CUDA – model programowania

CUDA – model pamięci

CUDA – model pamięci Shared Memory Wbudowana w chip Znacznie szybsza niż pamięć lokalna i globalna Tak szybka jak rejestry (jeśli nie ma konfliktów) Dzielna na równej wielkości banki Kolejne 32-bitowe słowa są przypisane do kolejnych banków, Każdy bank ma przepustowość (bandwidth) 32 bity na 1 cykl zegara

CUDA – model pamięci Shared Memory

CUDA API Rozszerzenie języka C Kwalifikatory typu funkcji specyfikujące wykonanie na procesorze (host) lub na urządzeniu GPU Kwalifikatory typu zmiennej specyfikujące rodzaj pamięci w GPU Nowe składnia <<< mówiąca jak wykonać program na urządzeniu Cztery wbudowane zmienne pamiętające rozmiary grid’a i bloku oraz numery bloku i wątku

CUDA API Kwalifikatory typu funkcji __device__ __global__ __host__ Wykonywane na GPU Wywoływane tylko z GPU __global__ Wywoływane tylko z procesora głównego (host’a) __host__ Wykonywane na host’cie,

CUDA API Kwalifikatory typu zmiennych __device__ Umieszone w pamięci globalnej Widoczne przez cały czas działania programu Dostępne dla wszystkich wątków w grid’zie oraz z hosta (poprzez runtime library) __constant__ (ewentulanie razem z __device__) Umieszczone w pamięci stałej (constant memory space), __shared__ (ewentulanie razem z __device__) Umieszczone w pamięci współdzielonej (shared memory) bloku danego wątku Widoczne tak długo jak istnieje blok Dostępne tylko dla wszystkich wątków w bloku

CUDA API Konfiguracja wykonania Musi być sprecyzowana dla kazdego wywołania funkcji typu __global__ Definiuje rozmiary grid’a i bloków Umieszczana pomiędzy nazwą funkcji a listą argumentów: funkcja: __global__ void Func(float* parameter); musi być wywołana tak: Func<<< Dg, Db, Ns >>>(parameter);

CUDA API Konfiguracja wykonania gdzie Dg, Db, Ns są: Dg jest typu dim3  wymiar i rozmiar grida Dg.x * Dg.y = ilość uruchamianych bloków; Db jest typu dim3  wymiar i rozmiar bloków Db.x * Db.y * Db.z = ilość wątków na blok; Ns jest typu size_t  ilość bajtów w pamięci współdzielonej (shared memory) która jest dynamiczne alokowana dodatkowo do pamięci alokowanej statycznie Ns jest opcjonalne; domyślnie 0.

CUDA API Wbdowane zmienne gridDim typu dim3 wymiary grida. blockIdx typu uint3  number bloku w grid’zie blockDim typu dim3  wymiary bloku threadIdx is of type uint3  numer wątku w bloku

Przykład – iloczyn skalarny Policzyć iloczyn skalarny 32 par wektorów Kożdy po 4096 elementów Efektywna organizacja obliczeń: grid składający się z 32 bloków z 256 wątkami na blok Otrzymamy 4096/265 = 16 segmentów na wektor

Przykład – iloczyn skalarny Dane będą trzymane w GPU jako dwie tablice; wynik umieszczony zostanie w tablicy Każdy iloczyn par wektórw An, Bn będzie obliczany w segmentach, dodawanych do wyniku … Vector A0 Vector A1 Vector AN-1 … Vector B0 Vector B1 Vector BN-1 Results 0 to N-1 segment 0 segment 1 … segment S-1 Vector A0 Vector B0 Partial results 0 to S-1 Results 0 Results 1

Przykład – iloczyn skalarny Program dla host’a int main(int argc, char *argv[]){ CUT_CHECK_DEVICE(); … h_A = (float *)malloc(DATA_SZ); cudaMalloc((void **)&d_A, DATA_SZ); cudaMemcpy(d_A, h_A, DATA_SZ, cudaMemcpyHostToDevice); ProdGPU<<<BLOCK_N, THREAD_N>>>(d_C, d_A, d_B); cudaMemcpy(h_C_GPU, d_C, RESULT_SZ, cudaMemcpyDeviceToHost); CUDA_SAFE_CALL( cudaFree(d_A) ); free(h_A); CUT_EXIT(argc, argv); }

Przykład – iloczyn skalarny Funkcja dla GPU (Kernel Function) Parametry: d_C: wskaźnik do wyniku (tj. tablicy) d_A, d_B wskaźniki do danych (tablic) Tablice lokalne: t[]: wynkki8 pojedynczego wątku r[]: używane do dodawania wyników segmentów I: numer (Id) wątku w bloku __global__ void ProdGPU(float *d_C, float *d_A, float *d_B){ __shared__ float t[THREAD_N]; __shared__ float r[SLICE_N]; const int I = threadIdx.x; for(int vec_n=blockIdx.x; vec_n<VECTOR_N; vec_n+=gridDim.x){ int base = ELEMENT_N * vec_n; for(int slice = 0; slice < SLICE_N; slice++, base += THREAD_N){ t[I] = d_A[base + I] * d_B[base + I]; __syncthreads(); for(int stride = THREAD_N / 2; stride > 0; stride /= 2){ if(I < stride) t[I] += t[stride + I]; } if(I == 0) r[slice] = t[0]; for(int stride = SLICE_N / 2; stride > 0; stride /= 2){ if(I < stride) r[I] += r[stride + I]; if(I == 0) d_C[vec_n] = r[0];

Przykład – iloczyn skalarny Funkcja dla GPU Uruchamiane dla każdej pary wektorów wejściowych Zostanie uruchomione tylko raz, ponieważ: Grid dimension == number of vectors  vector number = block Id __global__ void ProdGPU(float *d_C, float *d_A, float *d_B){ __shared__ float t[THREAD_N]; __shared__ float r[SLICE_N]; const int I = threadIdx.x; for(int vec_n=blockIdx.x; vec_n<VECTOR_N; vec_n+=gridDim.x){ int base = ELEMENT_N * vec_n; for(int slice = 0; slice < SLICE_N; slice++, base += THREAD_N){ t[I] = d_A[base + I] * d_B[base + I]; __syncthreads(); for(int stride = THREAD_N / 2; stride > 0; stride /= 2){ if(I < stride) t[I] += t[stride + I]; } if(I == 0) r[slice] = t[0]; for(int stride = SLICE_N / 2; stride > 0; stride /= 2){ if(I < stride) r[I] += r[stride + I]; if(I == 0) d_C[vec_n] = r[0];

Przykład – iloczyn skalarny Funkcja dla GPU Uruchamiane dla każdego segmentu wektorów wejściowych Każdy wątek wylicza jeden iloczyn i zapamiętuje go __global__ void ProdGPU(float *d_C, float *d_A, float *d_B){ __shared__ float t[THREAD_N]; __shared__ float r[SLICE_N]; const int I = threadIdx.x; for(int vec_n=blockIdx.x; vec_n<VECTOR_N; vec_n+=gridDim.x){ int base = ELEMENT_N * vec_n; for(int slice = 0; slice < SLICE_N; slice++, base += THREAD_N){ t[I] = d_A[base + I] * d_B[base + I]; __syncthreads(); for(int stride = THREAD_N / 2; stride > 0; stride /= 2){ if(I < stride) t[I] += t[stride + I]; } if(I == 0) r[slice] = t[0]; for(int stride = SLICE_N / 2; stride > 0; stride /= 2){ if(I < stride) r[I] += r[stride + I]; if(I == 0) d_C[vec_n] = r[0];

Przykład – iloczyn skalarny Funkcja dla GPU Wyliczenie wyniku częściowego dla segmentu Zapamiętanie wyniku częsciowego __global__ void ProdGPU(float *d_C, float *d_A, float *d_B){ __shared__ float t[THREAD_N]; __shared__ float r[SLICE_N]; const int I = threadIdx.x; for(int vec_n=blockIdx.x; vec_n<VECTOR_N; vec_n+=gridDim.x){ int base = ELEMENT_N * vec_n; for(int slice = 0; slice < SLICE_N; slice++, base += THREAD_N){ t[I] = d_A[base + I] * d_B[base + I]; __syncthreads(); for(int stride = THREAD_N / 2; stride > 0; stride /= 2){ if(I < stride) t[I] += t[stride + I]; } if(I == 0) r[slice] = t[0]; for(int stride = SLICE_N / 2; stride > 0; stride /= 2){ if(I < stride) r[I] += r[stride + I]; if(I == 0) d_C[vec_n] = r[0]; t[0] += t[128] t[1] += t[129] t[0] += t[64] t[2] += t[130] t[1] += t[65] … t[0] += t[1] … … … t[64]+= t[127] t[127]+= t[255]

Przykład – iloczyn skalarny Funkcja dla GPU Dodanie wyników dla wszystkich segmentów Zapisanie wyniku w pamięci __global__ void ProdGPU(float *d_C, float *d_A, float *d_B){ __shared__ float t[THREAD_N]; __shared__ float r[SLICE_N]; const int I = threadIdx.x; for(int vec_n=blockIdx.x; vec_n<VECTOR_N; vec_n+=gridDim.x){ int base = ELEMENT_N * vec_n; for(int slice = 0; slice < SLICE_N; slice++, base += THREAD_N){ t[I] = d_A[base + I] * d_B[base + I]; __syncthreads(); for(int stride = THREAD_N / 2; stride > 0; stride /= 2){ if(I < stride) t[I] += t[stride + I]; } if(I == 0) r[slice] = t[0]; for(int stride = SLICE_N / 2; stride > 0; stride /= 2){ if(I < stride) r[I] += r[stride + I]; if(I == 0) d_C[vec_n] = r[0];