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]