A. Dziekoński, Materiały na laboratorium
Transkrypt
A. Dziekoński, Materiały na laboratorium
A. Dziekoński, [email protected] Materiały na laboratorium: Programowanie GPU w architekturze CUDA CZĘŚĆ-I (czas max. 20 minut - wprowadzenie) Wprowadzenie do programowania w CUDA na przykładzie dodawania DWÓCH WEKTORÓW: kod: vectorAdd.cu kompilacja: sh make_vectorAdd.sh uruchomienie: ./vectorAdd W trakcie analizy tego przykładu student poznaje podstawową kolejność modelu wykorzystania GPU jako koprocesor dla CPU: a) alokacja danych na CPU, b) alokacja danych na GPU c) transfer danych CPU->GPU d) wykonanie kernela: przedstawienie podstawowych parametrów uruchomienia kernela (bloki,wątki), przedstawienie na operacji dodawania wektorów jak zrównoleglane są obliczenia na GPU. e) transfer GPU->CPU CZĘŚC-II (czas max. 20 minut) Zrównoleglenie metody gradientów sprzężonych służącej do iteracyjnego rozwiązania układu równań Ax = b 1. Krotka analiza met. gradientów sprzężonych, w kontekście operacji do zrównoleglenia (zakomentowane i na zielono) input : d_A, d_x, d_r, N, tol ; output: d_x d_Ax = zeros(N,1); max_iter = 10; alpha = 1.0; alpham1 = -1.0; beta d_Ax = beta*d_Ax + alpha * d_A * d_x; d_r = d_r + alpham1 * d_Ax; r1 = d_rT * d_r; k = 1; while (r1 > tol*tol && k <= max_iter) if k > 1 b = r1 ./ r0; d_p = b * d_p; d_p = d_p + alpha * d_r; else d_p = d_r; end d_Ax = beta*d_Ax + alpha * d_A * d_p; dot = d_p' * d_Ax; a = r1 / dot; d_x = d_x + a*d_p; na = -a; d_r = d_r + na*d_Ax; r0 = r1; r1 = d_r'*d_r; k = k + 1; end = 0.0; r0 = 0.0; // sparse matrix-vector multiplication // axpy: y = y + alfa * x // dot: scalar = aT * a // // scal: axpy: y = alfa * y y = y + alfa * x // cpy: y = x // sparse matrix-vector multiplication // dot: scalar = aT * b // axpy: y = y + alfa * x // axpy: y = y + alfa * x // dot: scalar = aT * b 2. Wytłumaczenie jakie obliczenia są do wykonania się poszczególne operacjach na wektorach (które student będzie musiał potem zaimplementować) : a) axpy: y = y + alfa *x [ y1, y2, ...., yn ] = [ y1, y2, ...., yn ] + alfa * [ x1, x2, ...., xn ] yi = yi + alfa * xi b) scal: y = alfa *y [ y1, y2, ...., yn ] = alfa * [ y1, y2, ...., yn ] yi = alfa * yi c) mnożenie macierzy przez wektor Przykład: KOD C: for (int i =0; i < N; i++){ float sub = 0.0; for (int j =0; j < N; j++){ sub += A[i*N + j] * x[j]; y[i] = sub; } mnożenie macierzy rzadkiej przez wektor: KOD C: for (int i =0; i < N; i++){ float sub = 0.0; for (int j = rowptr[i]; j < rowptr[i+1]; j++) sub += values[j] * x[colind[j]]; y[i] = sub; } d) dot product: input: 2 wektory output: skalar Przykład: 3. Uruchomienie przygotowanego kodu w oparciu o CUBLAS i CUSPARSE (plik: cgs.cu, funkcja cgs_basic()) kod: cgs.cu kompilacja: sh make_cgs.sh uruchomienie: ./cgs_lab CZĘŚC-III (czas min. 50 minut) 1. Przedstawienie zadań do wykonania, kod należy wstawić w plik: cgs.cu, funkcja cgs_TODO() - gdzie zakomentowane są funkcje z CUBLAS i CUSPARSE, które należy zastąpić własnymi kernelami. ZADANIE-1 (0-60%) student ma do napisania własne kernele : cpy - kopiowanie (y=x), scal - skalowanie wektora (y=alfa * y), axpy - dodawania wektorów z przeskalowaniem jednego z nich przez skalar (y=y+a*x) ZADANIE-2: (0-30%) - student ma do napisania własny kernel: MatVec – mnożenie macierzy rzadkiej przez wektor (do tej operacji student otrzymał kod w C) *wskazówka zrównoleglenia: 1 watek CUDA pracuje na jednym wierszu macierzy. for (int i =0; i < N; i++){ // 1 watek - 1 wiersz float sub = 0.0; for (int j = rowptr[i]; j < rowptr[i+1]; j++) sub += values[j] * x[colind[j]]; y[i] = sub; } ZADANIE-3: (0-10%) - student ma do napisania własne kernele : dot – inner product : *wskazówka zrównoleglenia: rozbij obliczenia na 2 kernele kernel-1: a) wewnątrz każdego bloku wątków: wymnożenie a[i] * b[i] i zapis do tablicy pomocniczej w pamięci shared c_shared[i] b) wykonaj redukcje na tablicy c_shared[0] = c_shared[i] c) zapisz wynik w pamięci globalnej do tablicy o rozmiarze równym liczbie bloków dot_sub[blockIdx.x] = c_shared[0] kernel-2: wykonaj redukcje na tablicy dot = dot_sub[i]