You are on page 1of 20

Micha Kaczara 181132 Marek Karpiski 181172

Architektura komputerw 2

Projekt:
Mnoenie macierzy rzadkich przez wektor na procesorach graficznych z architektur CUDA. Badanie wydajnoci i optymalizacja funkcji mnocych.

Prowadzcy: dr in. Tadeusz Tomczak Grupa: wtorek/TN, godz. 18:55-20:30

POLITECHNIKA WROCAWSKA CZERWIEC 2011

Spis treci
1. Wstp ......................................................................................................3
1.1 Macierz i wektor. Proces ich mnoenia ...........................................................3 1.2 Format CSR ....................................................................................................4 1.3 Dlaczego GPU? ..............................................................................................4 1.4 Architektura oblicze rwnolegych CUDA .....................................................5 1.4.1 Informacje oglne .............................................................................5 1.4.2 Budowa i zasada dziaania ...............................................................5 1.4.3 Organizacja pamici .........................................................................6 1.5 Cel i zaoenia projektu ...................................................................................6

2. Badanie i optymalizacja algorytmw ...................................................7


2.1 Opis implementacji i platformy testowej ..........................................................7 2.1.1 Oglny opis programw ....................................................................7 2.1.2 Obsuga macierzy w formacie MatrixMarket .....................................7 2.1.3 Pomiar czasu ....................................................................................8 2.1.4 Platforma testowa .............................................................................8 2.2 Kernel skalarny ...............................................................................................8 2.2.1 Opis algorytmu ..................................................................................8 2.2.2 Wyniki bada wydajnoci ..................................................................9 2.2.3 Optymalizacja i jej rezultaty ............................................................10 2.3 Kernel ze zoptymalizowanym nakadaniem wtkw .....................................12 2.3.1 Opis algorytmu ................................................................................12 2.3.2 Wyniki bada wydajnoci ................................................................13 2.3.3 Optymalizacja i jej rezultaty ............................................................14 2.4 Kernel przeczany ........................................................................................16 2.4.1 Opis algorytmu ................................................................................16 2.4.2 Wyniki bada wydajnoci ................................................................17 2.5 Podsumowanie ..............................................................................................18

3. Bibliografia ...........................................................................................20

1. Wstp
1.1 Macierz i wektor. Proces ich mnoenia
Jednym z poj, ktre pojawiy si w temacie projektu jest macierz(ang matrix) kluczowe pojcie algebry liniowej, definiowane jako ukad danych zapisanych w postaci prostoktnej tablicy o wymiarach m wierszy i n kolumn. W szczeglnym przypadku, gdy liczba wierszy i kolumn jest sobie rwna, mamy do czynienia z tzw. macierz kwadratow. Kad dan umieszczon w macierzy nazywa si jej elementem. Kady element moe przyjmowa dowolne wartoci liczbowe. Prostoktn(lub kwadratow) tablic elementw, w ktrej przewaaj elementy zerowe nazywamy macierz rzadk(ang. sparse matrix). To wanie na tym typie macierzy bdziemy operowa w dalszej czci projektu. Macierz, ktra ma m wierszy i jedn kolumn lub jeden wiersz i n kolumn nazywamy wektorem, odpowiednio: kolumnowym i wierszowym. Dla macierzy(podobnie jak dla liczb) zdefiniowane s podstawowe dziaania algebraiczne, takie jak: dodawanie, odejmowanie i mnoenie. W projekcie skoncentrujemy si na procesie mnoenia macierzy rzadkich przez wektor kolumnowy. Mnoc dwie macierze musimy speni jeden podstawowy warunek liczba kolumn pierwszej z nich musi by rwna liczbie wierszy drugiej. Wynikiem mnoenia takich tablic danych jest macierz o wymiarach odpowiadajcych drugiej macierzy. W wyniku mnoenia dowolnej macierzy przez odpowiedni wektor kolumnowy otrzymamy wic wyjciowy wektor o strukturze wektora wejciowego. Jego elementy bd sum iloczynw kolejnych elementw wierszy macierzy i kolumny wektora(Rys. 1.).

Rys. 1: Proces mnoenia macierzy przez wektor kolumnowy

W informatyce reprezentacj macierzy jest tablica dwuwymiarowa elementw danego typu, a wektora tablica jednowymiarowa. Dla macierzy o duych rozmiarach oraz okrelonej strukturze(np. macierz rzadka) reprezentacja tablicowa jest nieoptymalna.
3

1.2 Format CSR


Jak powszechnie wiadomo mnoenie dowolnej niezerowej liczby przez zero daje w wyniku rwnie zero. W odniesieniu do macierzy rzadkich i ich mnoenia przez wektor, ta banalna zasada matematyki ma bardzo due znaczenie. Przemnoenie dowolnego zerowego elementu macierzy przez wektor zawsze da w wyniku zero. Dla takich elementw proces mnoenia nie ma wic adnego sensu. Z tego te powodu pozbawione sensu jest przechowywanie w pamici komputera tablicy dwuwymiarowej ze wszystkimi elementami macierzy rzadkiej. Skoro wikszo elementw takiej macierzy stanowi zera, to naley pj w kierunku znacznego zmniejszenia zuycia pamici i zapisania w niej tylko niezerowych elementw macierzy. Formatw takiego zapisu jest wiele. Jednym z najprostszych jest format CSR(ang. Compressed Sparse Row). Zgodnie z jego specyfikacj, macierz rzadka, zamiast w postaci dwuwymiarowej tablicy, zapisana jest w postaci trzech tablic jednowymiarowych(Rys. 2.): tablicy wartoci, zawierajcej niezerowe elementy macierzy, uoone po kolei, od pierwszego w pierwszym wierszu do ostatniego w wierszu ostatnim, tablicy indeksw kolumn, zawierajcej numery kolumn dla kadego elementu niezerowego, tablicy wskanikw na pocztek wierszy, zawierajcej indeksy pierwszych niezerowych elementw w kadym wierszu macierzy, zapisanych w tablicy wartoci.

Rys. 2. Macierz rzadka i jej reprezentacja w formacie CSR

1.3 Dlaczego GPU?


Podstawow jednostk przetwarzania kadego komputera jest CPU(ang. Central Processing Unit), realizujca operacje arytmetyczno-logiczne. W wikszoci przypadkw jeden wielordzeniowy procesor lub wiele procesorw wystarczy, aby zapewni naleyt szybko operacji. Fakt, i procesor(lub jego kady rdze) wykonuje instrukcje sekwencyjnie, jedna po drugiej, powoduje jednak, e np. w przypadku mnoenia duych(kilkadziesit, kilkaset tysicy) macierzy przez wektor, szybko operacji drastycznie spada. Sekwencyjna metoda wykonywania instrukcji jest poyteczna, gdy kada nastpna operacja wymaga wyniku poprzedniej. Ze schematu(Rys. 1.) mona z atwoci wyczyta, e np. operacja mnoenia elementu macierzy przez element wektora nie zaley od adnych innych. Warto wic w tym przypadku pokusi si o zastosowanie metody oblicze rwnolegych. Potentatami we wdraaniu architektur przetwarzania rwnolegego s producenci procesorw graficznych(GPU, ang. Graphics Processing Unit). W projekcie wykorzystana zostaa jednostka z architektur CUDA firmy NVIDIA.
4

1.4 Architektura oblicze rwnolegych CUDA


1.4.1 Informacje oglne Procesory graficzne s jednymi z najbardziej efektywnych spord wszystkich systemw wieloprocesorowych dostpnych obecnie na rynku. Wprowadzenie rozwiza umoliwiajcych rwnolege przetwarzanie danych na GPU uczynio je ciekaw i chtnie wykorzystywan alternatyw dla tradycyjnych jednostek przetwarzania. CUDA(ang. Compute Unified Device Architecture) jest architektur oblicze rwnolegych wspieran i rozwijan przez firm NVIDIA. Cho gwnym celem jej rozwoju jest zwikszenie wydajnoci jednostek graficznych producenta w zakresie przetwarzania grafiki, to jest ona chtnie wykorzystywana do wykonywania oblicze oglnego przeznaczenia(GPGPU, ang. General-Purpose Computing on Graphics Processing Units). Dzieje si tak dziki udostpnianym przez firm-matk narzdziom i dokumentacji oraz wykorzystaniu do tworzenia oprogramowania rozszerzonego i dobrze wszystkim znanego jzyka C. 1.4.2 Budowa i zasada dziaania Opracowywane oprogramowanie mona podzieli na funkcje wykonywane przez CPU hosta oraz GPU urzdzenie. Funkcja wykonywana przez urzdzenie nosi nazw kernela. W wykonywaniu kernela na urzdzeniu bior udzia wtki. Kady z nich ma swj numer i wykonuje te same operacje zdefiniowane w kernelu(Rys. 3.). W porwnaniu

Wtki wykonujce kernel s grupowane w bloki, a te w siatk(Rys. 4.). Kady blok moe mie okrelon liczb wtkw w trzech wymiarach, podobn waciwo ma te siatka. Wtki w bloku mog si ze sob komunikowa poprzez tzw. pami wspdzielon, mona je take zsynchronizowa. Wsppraca wtkw z rnych blokw i ich synchronizacja nie jest moliwa.

Procesor graficzny w kartach opartych o architektur CUDA skada si z tzw. multiprocesorw, w ktrych znajduj si: jednostki przetwarzajce wtki, jednostka arytmetyczna podwjnej precyzji oraz pami wspdzielona. Szczegy architektury GPU zale od jego wersji. Przykadowo, procesor graficzny karty GeForce GTX 275 skada si z 30 multiprocesorw. O tym, w ktrym multiprocesorze bd wykonywane bloki decyduje urzdzenie. 1.4.3 Organizacja pamici Pami w urzdzeniach opartych o architektur CUDA stanowi oddzielony od GPU modu DRAM(ang. Dynamic Random-access Memory), w ktrym wyrnia si cztery bloki: pami lokaln, pami globaln, pami tekstur i pami sta. Dodatkowo, w kadym z multiprocesorw, prcz rejestrw, znajduje si blok pamici wspldzielonej. Specyfikacja architektury jasno okrela dostp do ronych typw pamici: wtek podczas swojego dziaania moe uywa rejestrw multiprocesora lub pamici lokalnej, moe te odczytywa wartoci z pamici tekstur i sta, bloki wtkw mog wykorzystywa pami wspdzielon, Siatki blokw odpowiedzialne za wykonywanie okrelonego kernela mog korzysta z pamici globalnej, z niej kernel pobiera dane i do niej zapisuje wyniki, przesyanie danych z urzdzenia do hosta i odwrotnie moe odbywa si jedynie poprzez pami globaln, pami tekstur lub pami sta.

1.5 Cel i zaoenia projektu


Celem projektu jest opracowanie oprogramowania umoliwiajcego mnoenie macierzy rzadkich w formacie CSR przez wektor na procesorach graficznych z architektur CUDA, zastosowanie w nim dostpnych algorytmw(kerneli), a nastpnie zbadanie ich efektywnoci w zalenoci od rozmiaru macierzy i jej struktury oraz prba ich optymalizacji wraz z analiz rezultatw. Celem porednim projektu jest zdobycie podstawowej wiedzy z zakresu oblicze rwnolegych oraz budowy i sposobu dziaania urzdze opartych o architektur CUDA. Aby zawzi obszar bada, zdecydowalimy si na zaimplementowanie aplikacji mnocych macierze rzadkie przez wektor, korzystajcych z dwch dostpnych kerneli: skalarnego, opisanego w raporcie[2], ktry zawiera najprostszy algorytm mnoenia, ze zoptymalizowanym nakadaniem wtkw, zaproponowanego przez specjalistw z firmy IBM w publikacji[1], ktry zawiera algorytm bardziej skomplikowany. Zakres optymalizacji zdecydowalimy si zawzi do wykorzystania podczas mnoenia pamici tekstur oraz stworzenia wasnego kernela mnocego, bdcego poczeniem obu wymienionych powyej. Wartoci, ktre bd opisywa wyniki testw wszystkich wariantw kerneli to: czas mnoenia i szybko operacji. Zaprezentujemy take mapy czasw dostpu do poszczeglnych elementw macierzy. W celu dokadnego zaobserwowania efektywnoci kadego z algorytmw, do testw wybralimy macierze posiadajce co najmniej kilkadziesit tysicy wierszy i kolumn, rnice si gstoci. Wszystkie pochodz ze strony[4].

2. Badanie i optymalizacja algorytmw


2.1 Opis implementacji i platformy testowej
2.1.1 Oglny opis programw Na potrzeby projektu zaimplementowalimy w jzyku C trzy aplikacje. Kada z nich wykorzystuje funkcje z tzw. Driver API(ang. Application Programming Interface)[3] i jest dedykowana do wykonywania mnoenia macierzy rzadkiej przez wektor za pomoc innego kernela: program spmv_std - mnoy macierz z pliku o nazwie podanej w linii komend jako pierwszy argument, przez wektor wypeniony losowymi wartociami z zakresu 1-65535, korzystajc z kernela skalarnego, program spmv_ibm - mnoy macierz z pliku o nazwie podanej w linii komend jako pierwszy argument przez, wektor wypeniony losowymi wartociami z zakresu 1-65535, korzystajc z kernela ze zoptymalizowanym nakadaniem wtkw, program spmv_switch - mnoy macierz z pliku o nazwie podanej w linii komend jako pierwszy argument, przez wektor wypeniony losowymi wartociami z zakresu 1-65535, korzystajc z kernela przeczanego. 2.1.2 Obsuga macierzy w formacie MatrixMarket Poniewa macierze rzadkie s udostpniane w rnych formatach, musielimy podj decyzj, ktry z nich maj obsugiwa nasze programy(w zakresie wczytywania danych). Wybralimy nieskomplikowany w budowie format MatrixMarket[5]. Pliki macierzy zapisanych w tym formacie maj rozszerzenie *.mtx. Aby zapewni naleyt organizacj plikw projektu, wszystkie macierze umiecilimy w osobnym podkatalogu o nazwie matrices. 2.1.3 Pomiar czasu Kada z trzech aplikacji wyznacza czas operacji w ten sam sposb. Do pomiaru czasu uylimy funkcji gettimeofday() z bliblioteki time.h. jest ona wywoywana tu przed uruchomieniem kernela i tu po zakoczeniu jego wykonywania. Aby wyniki byy reprezentacyjne, operacja mnoenia macierzy rzadkiej przez wektor jest wykonywana
7

dziesiciokrotnie, a ostateczny czas jest redni arytmetyczn z dziesiciu czasw porednich. W celu stworzenia map czasu dostpu do elementw macierzy zmodyfikowalimy dziaanie kerneli, kompilujc je do postaci asemblera procesora graficznego PTX i dodajc w kodzie moliwo zapisu do odpowiednich tablic liczby cykli GPU przed i po pobraniu elementu macierzy z pamici. Ich rnica stanowi czas dostpu do elementu (w cyklach). Liczb cykli procesor graficzny przechowuje w rejestrze o nazwie %clock. 2.1.4 Platforma testowa Wszystkie testy zostay wykonane przy uyciu opisanych programw, ktrych kody w jzyku C oraz PTX zostay skompilowane z najwysz flag optymalizacji -O3. Jako host wykorzystany zosta komputer z procesorem AMD Phenom II X4 940 o taktowaniu zegara 3,0 GHz oraz posiadajcy 7 GB pamici RAM i systemem operacyjnym Ubuntu. Urzdzenie dysponujce GPU opartym o architektur CUDA wykorzystane do testw to karta NVIDIA GeForce GTX 275, posiadajca procesor o taktowaniu 1,37 GHz, 886 MB pamici DRAM typu DDR3 oraz 30 multiprocesorw.

2.2 Kernel skalarny


2.2.1 Opis algorytmu Kernel skalarny zosta zaprezentowany w raporcie[2]. Zawarty w nim algorytm jest prostym odpowiednikiem kodu mnocego macierz rzadk na hocie, w architekturze oblicze rwnolegych(Listing 1.). W algorytmie tym, pocztek zakresu wierszy macierzy, ktrymi zajmuje si blok wtkw, jest obliczany na podstawie rozmiaru bloku oraz jego numeru(iloczyn). Kady wtek z bloku przypada na jeden wiersz macierzy, ktrego numer jest wyznaczany poprzez dodanie numeru wtku do pocztku zakresu wierszy. Na przykad dla bloku o rozmiarze 32 wtkw, numerze 2 i wtku o numerze 5, wiersz macierzy, ktrym bdzie zajmowa si wtek to wiersz numer 32*2 + 5 = 69. Kady wtek musi sprawdzi, czy jeszcze znajduje si w macierzy. Jeli tak, to przeprowadza on proces mnoenia wiersza przez wektor.
Listing 1. Kod kernela skalarnego __global__ void spmv_csr_scalar_kernel( const int num_rows, const int *ptr, const int *indices, const double *data, const double *x, double *y) { int row = blockDim.x * blockIdx.x + threadIdx.x; if (row < num_rows){ double dot = 0; int row_start = ptr[row]; int row_end = ptr[row +1]; for (int jj = row_start; jj < row_end; jj ++) dot += data [jj] * x[indices [jj]]; y[row] += dot; } }

2.2.2 Wyniki bada wydajnoci Fakt, i w kernelu skalarnym kady blok zajmuje si innym obszarem macierzy oraz dodatkowa gwarancja rwnolegego wykonywania wtkw w bloku nasuwa hipotez, e opisywane rozwizanie bdzie o wiele szybsze od zwyczajnego mnoenia, przeprowadzanego na hocie. Stwierdzenie to znalazo swoje odzwierciedlenie w wynikach bada.

8,00 6,00
Czas [ms]

4,00 2,00 0,00 cage12 rma10 venkat50 hvdc2 scircuit mc2depi torso2 Baumann bcircuit hcircuit
Macierz

GPU kernel skalrny

CPU

Wykres 1. Porwnanie czasw mnoenia na GPU(kernel skalarny) i CPU

Czasy mnoenia uzyskiwane przez algorytm kernela skalarnego s w wikszoci przypadkw duo nisze ni czasy uzyskiwane przez CPU(Wykres 1.). Dla jednej z testowych macierzy rnica czasw wyniosa ok. 0,3s(hcircuit), natomiast w przypadku macierzy rma10 czas mnoenia na GPU by wikszy od czasu uzyskanego przez CPU, rwnie o ok. 0,3s.

Szybko operacji [GFLOP/s]

2,50 2,00 1,50 1,00 0,50 0,00 cage12 rma10 venkat50 hvdc2 scircuit mc2depi torso2 Baumann bcircuit hcircuit
Macierz

GPU kernel skalrny

CPU

Wykres 2. Porwnanie szybkoci operacji dla GPU(kernel skalarny) i CPU

Czas wykonywania mnoenia mona atwo przeoy na szybko operacji, wyraan w GFLOP/s(ang. Giga Floating Point Operations Per Second). Na Wykresie 2. wida, e szybkoci operacji dla kernela skalarnego nie s due, dla testowych macierzy wahaj si w zakresie 0,5 2,25 GFLOP/s. Warto wspomnie, e maksymalna szybko
9

operacji dla CPU to ok 0,75 GFLOP/s, czyli mniej wicej jedna trzecia szybkoci kernela skalarnego mnocego na GPU. Wynik porwnania wydaje si by jasny i jasno przemawia za zastosowaniem do oblicze kernela skalarnego wykonywanego na GPU. Na Wykresach: 1. i 2. widoczne s jednak due rnice pomidzy czasem i szybkoci operacji w obrbie samego kernela. Aby dokona analizy w tej dziedzinie, naley przyjrze si bliej macierzom testowym. Macierz rma10, dla ktrej wydajno algorytmu bya maa, jest tablic o 46 835 wierszach i kolumnach i a 2 329 092 elementach niezerowych, co wpywa znaczco na redni ilo elementw w wierszu. Macierz, dla ktrej czas wykonania mnoenia by najmniejszy jest macierz bcircuit. Jest ona tablic elementw o liczbie wierszy i kolumn rwnej 68 902. Liczba elementw niezerowych to zaledwie 375 558. Macierz ta ma wic ma gsto i ma redni ilo elementw w wierszu. Podobn charakterystyk mona przypisa macierzy Baumann, dla ktrej czas mnoenia rwnie nie by wysoki. Wnioskiem z powyszej analizy wydajnoci kernela skalarnego jest stwierdzenie, e dziaa on tym lepiej, im mniejsza jest gsto macierzy oraz rednia ilo elementw w wierszu. Przyczyn takiej tendencji jest fakt, e na kady wiersz macierzy przypada w opisanym algorytmie tylko jeden wtek. 2.2.3 Optymalizacja i jej rezultaty Zgodnie z zaoeniami projektu(Podrozdzia 1.5) metod optymalizacji, jak zastosujemy we wszystkich badanych algorytmach bdzie uycie podczas mnoenia pamici tekstur(Podrozdzia 1.4). Wykorzystamy j jako pami podrczn(ang. cache) do przechowywania elementw wektora, przez ktry mnoone s macierze. Proponowane rozwizanie powinno teoretycznie poprawi wydajno kernela czasy dostpu do pamici tekstur s bowiem duo mniejsze, ni czasy dostpu do pamici globalej. Aby umoliwi kernelowi dostp do wektora w pamici tekstur, musielimy wzbogaci kody programw o odpowiednie instrukcje(Listing 2.).
Listing 2. Instrukcje zapisujce wektor device_x w pamici tekstur i konfigurujce kernel CUtexref tex; cuModuleGetTexRef(&tex, module, "tex_y_int2"); cuTexRefSetFormat(tex, CU_AD_FORMAT_SIGNED_INT32, 2); cuTexRefSetAddress(NULL, tex, device_x, num_cols * sizeof(double)); cuParamSetTexRef(kernel, CU_PARAM_TR_DEFAULT, tex));

8,00 6,00
Czas [ms]

4,00 2,00 0,00 cage12 rma10 venkat50 hvdc2 scircuit mc2depi torso2 Baumann bcircuit hcircuit
Macierz

kernel skalarny z cache

kernel skalarny bez cache

Wykres 3. Porwnanie czasw mnoenia dla kernela skalarnego z wczonym i wyczonym cache

10

Analizujc Wykres 3. atwo doj do wniosku, e zastosowana przez nas optymalizacja wniosa niewiele. Najwikszy spadek czasu wystpi dla macierzy rma10, z ktr badany kernel radzi sobie wyjtkowo le. Wynis on jednak tylko ok. 0,5ms. Dla pozostaych macierzy czasy wykonywania mnoenia rni si o uamki milisekund. Rwnie zamieszczony poniej Wykres 4. pokazuje, e przyrost wydajnoci kernela skalarnego po wprowadzeniu optymalizacji jest niewielki.
2,5 2 1,5 1 0,5 0 cage12 rma10 venkat50 hvdc2 scircuit mc2depi torso2 Baumann bcircuit hcircuit
Macierz

Szybko operacji [GFLOP/s]

kernel skalarny z cache

kernel skalarny bez cache

Wykres 4. Porwnanie szybkoci operacji dla kernela skalarnego z wczonym i wyczonym cache

Wprowadzona przez nas optymalizacja nie pomoga w znacznym zwikszeniu wydajnoci kernela skalarnego. Powodem odpornoci algorytmu na optymalizacj jest najprawdopodobniej jego koncepcja. Jeden wtek na wiersz to za mao, gdy chodzi o mnoenie macierzy rzadkich o duych rozmiarach i wzgldnie duej iloci elementw niezerowych.
MAX

MIN Rys. 5. Mapa czasw dostpu do elementw macierzy rzadkiej cage12 kernel skalarny

11

2.3 Kernel ze zoptymalizowanym nakadaniem wtkw


2.3.1 Opis algorytmu Kernel ze zoptymalizowanym nakadaniem wtkw, tzw. kernel halfwarp, zosta zaproponowany w publikacji[1] i okrelony jako implementacja rozwizujca problemy ze sab wydajnoci kernela skalarnego. W przeciwiestwie do prymitywnego algorytmu kernela badanego w Sekcji 2.2, kernel halfwarp prezentuje algorytm bardziej skomplikowany, w ktrym na jeden wiersz mnoonej macierzy przypada szesnacie wtkw. Pocztek zakresu wierszy, ktrym zajmuje si dany blok wyznaczany jest na podstawie iloczynu jego numeru i liczby szesnastowtkowych porcji w bloku(w przypadku programw testowych jest to liczba 32). Obszar, ktrym zajmuje si jeden wtek jest tylko fragmentem odpowiedniego wiersza i jest okrelany na zasadzie dzielenia modulo numeru wtku przez liczb wtkw w wierszu(16). Numer wiersza okrelany jest poprzez warto cakowit z dzielenia numeru wtku przez liczb wtkw w wierszu(Listing 3.). Na przykad, dla bloku o numerze 2 i wtku o numerze 25, numer wiersza, w ktrym bdzie pracowa wtek to 2*16 + [25/16] = 33, a numer indeksu startowego wtku w wierszu to 25%16 = 9.
Listing 3. Fragment kodu kernela halfwarp odpowiedzialny za okrelanie numeru wiersza i indeksu w nim unsigned int tid = threadIdx.y; unsigned int bid = blockIdx.y; unsigned unsigned unsigned unsigned int int int int ind2Dx = tid%16; ind2Dy = tid/16; myblock = bid*32; myi = myblock + ind2Dy;

Kady z wtkw produkuje iloczyny czciowe dla wiersza, w ktrym pracuje i zapisuje je w odpowiednich miejscach dwuwymiarowej tablicy umiejscowionej w pamici wspdzielonej dla bloku. Jest to rozwizanie bardzo szybkie, ze wzgldu na mae czasy dostpu wtkw do tego typu pamici. Gdy kod kernela jest wykonywany przez wtek, ktry rozpoczyna prac w kolejnym wierszu, iloczyny czciowe dla wiersza poprzedniego s sumowane i zapisywane pod odpowiednim indeksem w wektorze wyjciowym (Listing 4.). Tablica wartoci tymczasowych zostaje pniej nadpisana przez kolejne wtki.
Listing 4. Fragment kodu kernela halfwarp odpowiedzialny za sumowanie i zapis iloczynw czciowych if((ind2Dx == 0) && (myi < numRows)){ t = tempProd[ind2Dy][0] + tempProd[ind2Dy][1] + tempProd[ind2Dy][2] + tempProd[ind2Dy][3] +\ tempProd[ind2Dy][4] + tempProd[ind2Dy][5] + tempProd[ind2Dy][6] + tempProd[ind2Dy][7] +\ tempProd[ind2Dy][8] + tempProd[ind2Dy][9] + tempProd[ind2Dy][10] + tempProd[ind2Dy][11] +\ tempProd[ind2Dy][12] + tempProd[ind2Dy][13]+ tempProd[ind2Dy][14] + tempProd[ind2Dy][15]; x[myi] = t; }

Kernel ze zoptymalizowanym nakadaniem wtkw zawiera w sobie algorytm zupenie rny od algorytmu kernela skalarnego. Jest on bardziej zoony i trzeba przyzna, e pomysowy. Zwikszona liczba wtkw, jaka przypada na wiersz oraz uycie w funkcji pamici wspdzielonej pozwalaj zaoy, e bdzie ona szybsza od kernela skalarnego.
12

2.3.2 Wyniki bada wydajnoci Badania wydajnoci dla kernela halfwarp zostay przeprowadzone na tych samych macierzach testowych, co w przypadku kernela skalarnego. Wyniki osigane przez badany algorytm nie s jednak odnoszone do wynikw CPU, ale do wynikw poprzednika. Hipoteza, jak zaoylimy przed wykonaniem testw zakadaa, e kernel ze zoptymalizowanym nakadaniem wtkw bdzie zawsze szybszy od kernela skalarnego. Jednak ju pierwsze wyniki(Wykres 5.) pokazay, e zaoenie to nie jest prawdziwe.

9,00 8,00 7,00 6,00


Czas [ms]

5,00 4,00 3,00 2,00 1,00 0,00 cage12 rma10 venkat50 hvdc2 scircuit mc2depi torso2 Baumann bcircuit hcircuit
Macierz

kernel halfwrap bez cache

kernel skalarny bez cache

Wykres 5. Porwnanie czasw mnoenia dla kernela halfrap kernela skalarnego(oba z wyczonym cache)

Z wykresu mona odczyta, e dla dwch spord dziesiciu macierzy testowych, kernel halfwarp wykonuje mnoenie wolniej(Baumann, bcircuit), a w jednym przypadku znacznie wolniej(mc2depi). Najwiksze rnice czasw na korzy kernela halfwarp wystpuj w przypadku macierzy duych, o duej liczbie elementw niezerowych i duej redniej liczbie elementw w wierszu(cage12, rma10, venkat50). Wyniki potwierdza Wykres 6., ktry wyranie pokazuje, e szybko operacji w zakresie wymienionych macierzy jest nawet do trzech razy wiksza ni w przypadku kernela skalarnego.

Szybko operacji [GFLOP/s]

5,00 4,00 3,00 2,00 1,00 0,00 cage12 rma10 venkat50 hvdc2 scircuit mc2depi torso2 Baumann bcircuit hcircuit
Macierz

kernel halfwrap bez cache

kernel skalarny bez cache

Wykres 6. Porwnanie szybkoci operacji dla kernela halfwarp i kernela skalarnego(oba z wyczonym cache)

13

Sabsza wydajno kernela ze zoptymalizowanym nakadaniem wtkw w przypadku macierzy Baumann, bcircuit oraz mc2depi jest cile powizana z ich charakterystyk. Macierze te odznaczaj si niewielk iloci elementw niezerowych w stosunku do liczby wierszy i kolumn. Zatem rednia liczba elementw w wierszu take jest niewielka(Podrozdzia 2.2.2). Nieefektywne dziaanie algorytmu kernela halfwarp w przypadku wymienionych macierzy pozwala wycign wniosek jeli w wierszach macierzy wystpuje maa liczba elementw niezerowych, to kernel ze zoptymalizowanym nakadaniem wtkw dziaa wolno. Wytumaczenia tego problemu doszukalimy si(podobnie jak w przypadku kernela skalarnego) w koncepcji algorytmu. Gdy w wierszu jest mao elementw niezerowych, nie wszystkie wtki przeznaczone do jego obsugi s wykorzystywane, co zwiksza czas potrzebny na ich synchronizacj oraz prowadzi do sytuacji, w ktrej w wierszu pracuje jeden lub kilka(a nie szesnacie) wtkw, wykonujcych mnoenie i dodatkowo sumujcych iloczyny czciowe uzyskane dla poprzedniego wiersza. 2.3.3 Optymalizacja i jej rezultaty Zgodnie z zaoeniami projektu, przeprowadzilimy prb optymalizacji dziaania kernela z wykorzystaniem pamici podrcznej tekstur. Biorc pod uwag koncepcj algorytmu kernela halfwarp, zaoylimy, e optymalizacja powinna przynie lepsze rezultaty ni w przypadku kernela skalarnego. Wynika to z faktu, i kady wtek spord szesnastu w wierszu musi mie dostp do elementw wektora. Jeli wic przyspieszymy czas tego dostpu, powinnimy zaobserwowa wzrost wydajnoci.

8,00 6,00
Czas [ms]

4,00 2,00 0,00 cage12 rma10 venkat50 hvdc2 scircuit mc2depi torso2 Baumann bcircuit hcircuit
Macierz

kernel halfwrap z cache

kernel halfwrap bez cache

Wykres 7. Porwnanie czasw mnoenia dla kernela halfwarp z wczonym i wyczonym

Wykres 7. pokazuje, e optymalizacja przyniosa najwikszy efekt w przypadku mnoenia macierzy, dla ktrych kernel dziaa optymalnie. Czas ich mnoenia przez wektor skrci si nawet o ponad 0,5 ms. Wykres 8. dowodzi, e przyspieszenie czasu mnoenia dla tych macierzy ma due odzwierciedlenie w szybkoci operacji dla kadej z macierzy wzrosa ona o ok. 1 GFLOP/s. Dla pozostaych macierzy wpyw optymalizacji jest praktycznie niezauwaalny. Podobnie jak w przypadku kernela skalarnego, trudno liczy na lepsze wyniki w przypadku macierzy, z ktrymi algorytm ma problem, skoro optymalizacja dotyczy sposobu przechowywania elementw wektora. Sposobw na globaln optymalizacj kernela halfwarp naley wic szuka w innych rozwizaniach. Jedn z zaproponowanych w publikacji[1] metod, jest uzupenianie wierszy zerami tak, aby w sumie liczba elementw bya wielokrotnoci liczby 16 i przyzwolenie
14

wtkom na ich przetwarzanie. Pozwala to zaj wszystkie wtki i rozwiza problem zwizany z duszym czasem ich synchronizacji oraz obcienia jednego/kilku z nich obliczaniem i sumowaniem iloczynw czciowych.
5,00 4,00 3,00 2,00 1,00 0,00 cage12 rma10 venkat50 hvdc2 scircuit mc2depi torso2 Baumann bcircuit hcircuit
Macierz

Szybko operacji [GFLOP/s]

kernel halfwrap z cache

kernel halfwrap bez cache

Wykres 8. Porwnanie szybkoci operacji dla kernela halfwarp wczonym i wyczonym

Na Rys. 6. zaprezentowana zostaa mapa czasw dostpu do elementw macierzy, jakie wygenerowa algorytm kernela ze zoptymalizowanym nakadaniem wtkw. W porwnaniu z Rys. 5, przedstawiajcym podobn map dla kernela skalarnego, czciej wystpuj na nim fragmenty ciemne, oznaczajce due czasy dostpu. Inne jest jednak rozmieszczenie czasw w strukturze macierzy. S one bardziej rozproszone i zrnicowane w danym obszarze. Mona take wyodrbni poziome pasy, w ktrych czasy dostpu byy podobne. Rnice w ukadzie czasw obu kerneli wynikaj z zaimplementowania w nich rnego sposobu przetwarzania danych tej samej struktury.
MAX

MIN Rys. 6. Mapa czasw dostpu do elementw macierzy rzadkiej cage12 kernel halfwarp

15

2.4 Kernel przeczany


2.4.1 Opis algorytmu Po przepadaniu pod ktem wydajnoci dwch kerneli: skalarnego(Podrozdzia 2.2) i ze zoptymalizowanym nakadaniem wtkw(Podrozdzia 2.3), prbach ich optymalizacji oraz zaobserwowaniu przedstawionych wczeniej prawidowoci stwierdzilimy, e warto zaimplementowa algorytm wykorzystujcy ju istniejce i odpowiednio sterujcy ich wykonywaniem. Skoro kernel skalarny sprawdza si przy mnoeniu macierzy o maej redniej iloci elementw niezerowych w wierszu, a kernel halfwarp dziaa dobrze dla macierzy, w ktrych owa rednia jest wiksza, to kernel bdcy ich poczeniem powinien korzystnie wpywa na wydajno w przypadkach, w ktrych dwa oddzielne algorytmy radziy sobie sabiej oraz wykazywa pewn uniwersalno. Kernel przeczany bdzie mia domylnie wczon moliwo trzymania elementw wektora w pamici tekstur.
Listing 5. Kod odpowiedzialny za obliczanie redniej liczby elementw niezerowych w bloku 32 wierszy int rowWarp = blockDim.x * blockIdx.x; int rowWarpBegin = row_offsets[rowWarp]; int rowWarpEnd = row_offsets[rowWarp + 32]; int nonZeros = (rowWarpEnd - rowWarpBegin)/32;

Zdecydowalimy si na implementacj prostego algorytmu(Rys. 7.). Kady blok kernela przeczanego skada si z 32 wtkw. Podczas jego wykonywania: kady z wtkw oblicza(Listing 5.) i sprawdza, czy rednia liczba elementw niezerowych dla bloku 32 wierszy, w ktrym pracuje, jest wiksza bd rwna 16, jeli tak, to blok ten zostaje przetworzony przez algorytm kernela halfwarp, uruchamiany w ptli 16 razy(jeli 16 wtkw obsuguje jeden wiersz, to 32-wtkowy blok obsuy dwa wiersze, wic zaptlenie jest konieczne), jeli nie, to blok wierszy zostaje przetworzony algorytmem kernela skalarnego.

Rys. 7. Schemat blokowy algorytmu kernela przeczanego

16

2.4.2 Wyniki bada wydajnoci Aby uzyska miarodajne wyniki testw, uylimy w nich takich samych macierzy co w przypadku kerneli: skalarnego i halfwarp. Moglimy dziki temu sprawdzi, czy kernel przeczany spenia warunki okrelone podczas projektowania jego algorytmu.

8,00 6,00
Czas [ms]

4,00 2,00 0,00 cage12 rma10 venkat50 hvdc2 scircuit mc2depi torso2 Baumann bcircuit hcircuit
Macierz

kernel halfwrap z cache

kernel przeczany

kernel skalarny z cache

Wykres 9. Porwnanie czasw mnoenia dla kerneli: halfrap, przeczanego oraz skalarnego

Wyniki badania czasw mnoenia dla poszczeglnych macierzy(Wykres 9.) pokazuj, e kernel przeczany w czterech przypadkach by szybszy od kernela skalarnego i ze zoptymalizowanym nakadaniem wtkw. Jego zastosowanie wpyno korzystnie na mnoenie macierzy o maej redniej iloci elementw niezerowych w wierszu(hcircuit, bcircuit, Baumann, mc2depi). W klasie macierzy o wikszej redniej iloci elementw niezerowych w wierszu, kernel przeczany ustpuje kernelowi halfwarp. Czasy mnoenia osigane przez algorytm zaimplementowany przez nas s jednak krtsze ni czasy zmierzone dla kernela skalarnego. W jednym z przypadkw(macierz scircuit) kernel przeczany osign wynik sabszy ni dwa pozostae. Jak wynika z naszych obserwacji, przyczyn takiego rezultatu moe by struktura macierzy, ktra wymagaa od krenela czstego przeczania stosowanego algorytmu.

Szybko operacji [GFLOP/s]

5,00 4,00 3,00 2,00 1,00 0,00 cage12 rma10 venkat50 hvdc2 scircuit mc2depi torso2 Baumann bcircuit hcircuit
Macierz

kernel halfwrap z cache

kernel przeczany

kernel skalarny z cache

Wykres 10. Porwnanie szybkoci operacji dla kerneli: halfwarp, przeczanego oraz skalarnego

17

Wynika badania szybkoci operacji(Wykres 10.) potwierdzaj wnioski wycignite podczas analizy porwnania czasw mnoenia. W grupie macierzy o maej redniej iloci elementw niezerowych w wierszu, szybko operacji, jak oferuje kernel przeczany jest wiksza od szybkoci osiganych przez kernel skalarny i halfwarp. Rnice te sigaj jednak nie wicej ni ok 0,5 GFLOP/s. W drugiej grupie macierzy, kernel zaimplementowany przez nas jest szybkociowym redniakiem.
MAX

MIN Rys. 8. Mapa czasw dostpu do elementw macierzy rzadkiej cage12 kernel przeczany

Zamieszczona powyej mapa czasw dostpu do elementw macierzy dla kernela przeczanego(Rys. 8.) przedstawia si zupenie inaczej, ni podobna mapa stworzona dla kernela skalarnego(Rys. 5.) oraz ze zoptymalizowanym nakadaniem wtkw(Rys. 6.). Na mapie moemy wyodrbni due obszary, w ktrych czasy dostpu s zblione do siebie. W porwnaniu z pozostaymi mapami, mniej jest na niej elementw cakowicie czarnych, oznaczajcych maksymalne czasy dostpu. Na rysunku atwo take dostrzec prawidowo, e czas dostpu do elementu macierzy maleje wraz ze zblianiem si do ostatniego elementu w ostatnim wierszu. Zaimplementowany kernel przeczany, zgodnie z zaoeniami, jest rozwizaniem porednim, oferujcym redni szybko operacji oraz czas trwania mnoenia. Poprawia wydajno kerneli: skalarnego i ze zoptymalizowanym nakadaniem wtkw podczas mnoenia problematycznych dla nich macierzy.

2.5 Podsumowanie
Zgodnie z celem i zaoeniami projektu stworzylimy oprogramowanie umoliwiajce mnoenie macierzy rzadkich w formacie CSR przez wektor na procesorach graficznych z architektur CUDA. Z ich pomoc zbadalimy dwa spord dostpnych kerneli mnocych: skalarny i ze zoptymalizowanym nakadaniem wtkw, pod ktem czasu wykonywania mnoenia oraz szybkoci operacji. Kernel skalarny(Podrozdzia 2.2), w ktrym za mnoenie przez wektor jednego
18

wiersza macierzy odpowiedzialny jest jeden wtek, okaza si by rozwizaniem wydajnym podczas mnoenia macierzy o maej redniej liczbie elementw niezerowych w wierszu. Jeden wtek dziaajcy na wierszu wypenionym du liczb wartoci niezerowych nie jest w stanie wykona swojego zadania w sposb optymalny. Std te, dla macierzy o duej redniej liczbie elementw w wierszu, czas mnoenia obserwowany dla kernela skalarnego drastycznie ronie, a szybko operacji spada. Prba zoptymalizowania algorytmu poprzez dodanie pamici podrcznej z elementami wektora zlokalizowanej w bloku pamici tekstur urzdzenia przyniosa znikome rezultaty.
Tabela 1. Czasy mnoenia dla poszczeglnych algorytmw(z wczon pamici podrczn), w milisekundach
Macierz Algorytm spmv_std spmv_ibm spmv_switch cage12 3,84 1,39 2,30 rma10 6,05 1,06 1,35 venkat50 3,48 0,75 0,89 hvdc2 2,01 1,87 1,89 scircuit 1,93 1,75 2,02 mc2depi 1,78 5,02 1,73 torso2 1,54 1,13 1,49 Baumann 0,97 1,10 0,96 bcircuit 0,58 0,69 0,52 hcircuit 1,62 1,17 0,85

Kernel ze zoptymalizowanym nakadaniem wtkw(Podrozdzia 2.3) jest rozwizaniem dobrym, jeli chodzi o mnoenie macierzy o duej redniej liczbie elementw niezerowych w wierszu. Szesnacie wtkw pracujcych jednoczenie w obszarze jednego wiersza radzi sobie dobrze z wikszoci macierzy. Jednak przy zastosowaniu algorytmu kernela halfwarp do mnoenia macierzy o maej redniej liczbie elementw niezerowych w wierszu, to jego wydajno spada. W takim wypadku, szesnacie wtkw dziaajcych w jednym wierszu spowalnia cay algorytm. Prba zoptymalizowania algorytmu poprzez przechowywanie elementw wektora w bloku pamici tekstur przyniosa niewielkie rezultaty, wiksze ni w przypadku kernela skalarnego. Na podstawie analizy wynikw dla kerneli: skalarnego i halfwarp, stwierdzilimy, e warto zaimplementowa algorytm, bdcy ich poczeniem i odpowiednio sterujcy ich wywoywaniem. Napisalimy wic kernel przeczany(Podrozdzia 2.4), ktry bloki wierszy o redniej liczbie elementw wikszej bd rwnej 16, mnoy przez wektor przy uyciu algorytmu z kernela halfwarp. W przeciwnym wypadku wykorzystywany jest kernel skalarny. Po zbadaniu wydajnoci naszej implementacji, doszlimy do wniosku, e kernel ten korzystnie wpywa na wyniki pomiaru czasu i szybkoci operacji w przypadku macierzy, ktre sprawiay problem dla dwch pozostaych algorytmw. Czasy mnoenia macierzy o maej redniej liczbie elementw niezerowych w wierszu przy uyciu kernela przeczanego byy najnisze w porwnaniu z wczeniej zbadanymi kernelami. W wyniku poczenia dwch algorytmw mnocych macierze rzadkie przez wektor zapewnienia odpowiedniego sterowania ich przeczaniem powsta kernel, ktry dla macierzy o duej redniej liczbie elementw niezerowych w wierszu osiga rednie czasy mnoenia oraz szybko operacji.
Tabela 2. Szybko operacji dla poszczeglnych algorytmw(z wczon pamici podrczn), w GFLOP/s
Macierz Algorytm spmv_std spmv_ibm spmv_switch cage12 1,06 2,93 1,77 rma10 0,78 4,48 3,52 venkat50 0,99 4,60 3,86 hvdc2 1,34 1,44 1,43 scircuit 1,00 1,09 0,95 mc2depi 2,35 0,84 2,43 torso2 1,35 1,82 1,39 Baumann 1,57 1,39 1,59 bcircuit 1,29 1,09 1,45 hcircuit 0,63 0,88 1,45

W toku dalszych prac nad projektem, naleaoby przede wszystkim zastanowi si nad warunkiem przeczania pomidzy kernelami, wielkoci bloku wierszy, dla ktrych liczona jest rednia liczba elementw niezerowych oraz moliwoci dalszej optymalizacji kernela ze zoptymalizowanym nakadaniem wtkw. Cz moliwych rozwiza zawarli jego autorzy w artykule[1].
19

3. Bibliografia
[1] Optimizing Sparse Matrix-Vector Multiplication on GPUs" - Muthu Manikandan Baskaran, Rajesh Bordawekar - IBM Technical Report RC24704, 2008. [2] Efficient Sparse Matrix-Vector Multiplication on CUDA" - Nathan Bell, Michael Garland - NVIDIA Technical Report NVR-2008-004, 2008. [3] NVIDIA CUDA Programming Guide" - NVIDIA Corporation - wersja 3.2, 2010. [4] The University of Florida Sparse Matrix Collection" URL - http://www.cise.ufl.edu/research/sparse/matrices/ [5] The Matrix Market Formats: Initial Design - Ronald F. Boisvert, Roldan Pozo, Karin A. Remington, 2009.

20

You might also like