POLITECHNIKA ŁÓDZKA WYDZIAŁ ELEKTROTECHNIKI, ELEKTRONIKI, INFORMATYKI I AUTOMATYKI INSTYTUT INFORMATYKI STOSOWANEJ. Autoreferat

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

i3: internet - infrastruktury - innowacje

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

Programowanie procesorów graficznych GPGPU

Metody numeryczne Wykład 4

Tesla. Architektura Fermi

UKŁADY ALGEBRAICZNYCH RÓWNAŃ LINIOWYCH

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

Podstawy Informatyki Systemy sterowane przepływem argumentów

Wysokowydajna implementacja kodów nadmiarowych typu "erasure codes" z wykorzystaniem architektur wielordzeniowych

UKŁADY ALGEBRAICZNYCH RÓWNAŃ LINIOWYCH

Zaawansowane programowanie w języku C++ Zarządzanie pamięcią w C++

5. Rozwiązywanie układów równań liniowych

Przetwarzanie Równoległe i Rozproszone

Architektura komputerów

Zaawansowane metody numeryczne

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

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

Układy równań liniowych. Krzysztof Patan

Praca dyplomowa magisterska

Moc płynąca z kart graficznych

Programowanie aplikacji równoległych i rozproszonych

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

Podsystem graficzny. W skład podsystemu graficznego wchodzą: karta graficzna monitor

Programowanie z wykorzystaniem technologii CUDA i OpenCL Wykład 1

Numeryczna algebra liniowa

Procesory wielordzeniowe (multiprocessor on a chip) Krzysztof Banaś, Obliczenia wysokiej wydajności.

Przygotowanie kilku wersji kodu zgodnie z wymogami wersji zadania,

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

Wykorzystanie architektury Intel MIC w obliczeniach typu stencil

Rozwiązywanie układów równań liniowych

Podstawy OpenCL część 2

Programowanie równoległe i rozproszone. Praca zbiorowa pod redakcją Andrzeja Karbowskiego i Ewy Niewiadomskiej-Szynkiewicz

Programowanie kart graficznych

Obliczenia równoległe na klastrze opartym na procesorze CELL/B.E.

Spis treści. I. Skuteczne. Od autora... Obliczenia inżynierskie i naukowe... Ostrzeżenia...XVII

Nowoczesne technologie przetwarzania informacji

Algorytmy i Struktury Danych

Rozwiązywanie równań różniczkowych cząstkowych metodą elementów skończonych - wprowadzenie

III TUTORIAL Z METOD OBLICZENIOWYCH

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

Procesory wielordzeniowe (multiprocessor on a chip) Krzysztof Banaś, Obliczenia wysokiej wydajności.

Algorytmy dla maszyny PRAM

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

Algorytm. a programowanie -

Architektury komputerów Architektury i wydajność. Tomasz Dziubich

Budowa Mikrokomputera

3. Macierze i Układy Równań Liniowych

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

Metody optymalizacji soft-procesorów NIOS

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

Libra.cs.put.poznan.pl/mailman/listinfo/skisrkolo.

Metoda eliminacji Gaussa. Autorzy: Michał Góra

Dr inż. hab. Siergiej Fialko, IF-PK,

Wykład z Technologii Informacyjnych. Piotr Mika

RDZEŃ x86 x86 rodzina architektur (modeli programowych) procesorów firmy Intel, należących do kategorii CISC, stosowana w komputerach PC,

CUDA. cudniejsze przyk ady

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

Zastosowanie technologii nvidia CUDA do zrównoleglenia algorytmu genetycznego dla problemu komiwojażera

Obliczenia iteracyjne

Rozwiązywanie układów równań liniowych metody dokładne Materiały pomocnicze do ćwiczeń z metod numerycznych

Wykład 6. Metoda eliminacji Gaussa: Eliminacja z wyborem częściowym Eliminacja z wyborem pełnym

V Seminarium Naukowe Tomografia procesowa aplikacje, systemy pomiarowe i algorytmy numeryczne - relacja

Logiczny model komputera i działanie procesora. Część 1.

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

Architektura komputerów

Algorytmy numeryczne 1

Strojenie systemu Linux pod k¹tem serwera bazy danych Oracle 9i

Budowa i zasada działania komputera. dr Artur Bartoszewski

Budowa komputera Komputer computer computare

Programowanie kart graficznych

Projekt współfinansowany ze środków Europejskiego Funduszu Rozwoju Regionalnego w ramach Programu Operacyjnego Innowacyjna Gospodarka

Temat: Sieci neuronowe oraz technologia CUDA

VI Seminarium Naukowe Tomografia procesowa aplikacje, systemy pomiarowe i algorytmy numeryczne - relacja

Mechatronika i inteligentne systemy produkcyjne. Modelowanie systemów mechatronicznych Platformy przetwarzania danych

Obliczenia równoległe w zagadnieniach inżynierskich. Wykład 6

Programowanie celowe #1

PRZETWARZANIE RÓWNOLEGŁE I ROZPROSZONE. Mnożenie macierzy kwadratowych metodą klasyczną oraz blokową z wykorzystaniem OpenMP.

Parametry techniczne. Testy

Struktury systemów operacyjnych

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

Budowa komputera. Magistrala. Procesor Pamięć Układy I/O

Budowa komputera. Magistrala. Procesor Pamięć Układy I/O

ECTS (Część 2. Metody numeryczne) Nazwa w języku angielskim: Algorithms and data structures.

KADD Metoda najmniejszych kwadratów funkcje nieliniowe

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

Programowanie Współbieżne

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

Wprowadzenie do programowania w środowisku CUDA. Środowisko CUDA

Metodyki i techniki programowania

Politechnika Gdańska. Gdańsk, 2016

Przetwarzanie równoległe Zadanie domowe III

Programowanie dynamiczne

Podstawy Programowania C++

Zapoznanie z technikami i narzędziami programistycznymi służącymi do tworzenia programów współbieżnych i obsługi współbieżności przez system.

LEKCJA TEMAT: Zasada działania komputera.

Teraz bajty. Informatyka dla szkół ponadpodstawowych. Zakres rozszerzony. Część 1.

Sortowanie zewnętrzne

Test dysku Intel SSD DC S GB. Wpisany przez Mateusz Ponikowski Wtorek, 22 Październik :22

<Nazwa firmy> <Nazwa projektu> Specyfikacja dodatkowa. Wersja <1.0>

Transkrypt:

POLITECHNIKA ŁÓDZKA WYDZIAŁ ELEKTROTECHNIKI, ELEKTRONIKI, INFORMATYKI I AUTOMATYKI INSTYTUT INFORMATYKI STOSOWANEJ Autoreferat Algorytmy obliczeń równoległych z użyciem procesorów graficznych (GPU) do przetwarzania i wizualizacji danych pomiarowych z przemysłowych systemów tomograficznych mgr inż. Bartosz Matusiak Promotor: Prof. dr hab. inż. Dominik Sankowski Promotor pomocniczy: dr inż. Andrzej Romanowski Łódź, 2013

Wprowadzenie 1. Wprowadzenie W przeciągu ostatnich kilku lat można było zaobserwować spowolnienie w rozwoju układów CPU (ang. Central Processing Unit) przy jednoczesnym bardzo dynamicznym rozwoju oraz rosnącym znaczeniu wykorzystania procesorów graficznych (ang. GPU graphical processing unit) do wykonywania obliczeń ogólnego przeznaczenia (ang. GPGPU General-Purpose computation on Graphics Processing Units) [Harris, 2003; Ikeda i inni, 2006]. Pomimo częstotliwości taktowania kilkukrotnie niższej niż układów CPU, układy GPU umożliwiają uzyskanie nawet kilkunastokrotnego skrócenia czasu wykonywania obliczeń dla algorytmów, które mogą być wykonywane w sposób równoległy. Obecnie zdecydowana większość dostępnych na rynku komputerów klasy PC zawiera karty graficzne z układami GPU umożliwiającymi przeprowadzenie na nich takich obliczeń [Lindholm i inni, 2008]. Tak duża popularność układów GPU daje efekt w postaci bardzo korzystnego stosunku ceny do mocy obliczeniowej jaką te układy dostarczają, a do tego nie zajmują one tyle miejsca ile systemy wielomaszynowe o zbliżonej mocy obliczeniowej. Jednak, aby w pełni wykorzystać moc obliczeniową dostarczaną przez układy GPU konieczne są modyfikacje istniejących lub implementacje zupełnie nowych algorytmów, co jest spowodowane charakterem i specyfiką obliczeń równoległych. Poza tym, oryginalne przeznaczenie układów GPU do przetwarzania grafiki (przeważnie 3D) narzuca dodatkowe ograniczenia oraz niezbędne modyfikacje algorytmów jak np. konieczność wymiany informacji pomiędzy pamięcią operacyjną układu CPU oraz GPU, czy też minimalizację dostępów do pamięci operacyjnej układu GPU. Skutkiem tego nawet algorytmy przeznaczone dla systemów wieloprocesorowych nie zawsze sprawdzają się w przypadku zaimplementowania ich na układach GPU i wymagają pewnych modyfikacji. Innym aspektem, który należy brać pod uwagę przy projektowaniu algorytmów dla układów GPU jest fakt, że układy te są jednocześnie odpowiedzialne za operacje graficzne, co z kolei daje nowe możliwości w zakresie wizualizacji przetwarzanych danych. Mając na uwadze powyższe cechy układów GPU, należy zwrócić uwagę na potencjalne korzyści wynikające z możliwości ich wykorzystania do przetwarzania danych z przemysłowych systemów tomograficznych. Do tej pory opracowano bardzo wiele technik tomografii procesowej. Bazują one przeważnie na właściwościach fizyko-chemicznych substancji biorących udział w procesie. Stosowny dobór odpowiedniej techniki tomograficznej zależy więc głównie od typu procesu jaki ma być monitorowany, ale także od takich parametrów jak inwazyjność metody, czy też rozdzielczość czasowa lub przestrzenna. 1

Środowisko CUDA Jedną z często wykorzystywanych technik tomograficznych jest elektryczna tomografia pojemnościowa (ang. Electrical Capacitance Tomography ECT) [Reinecke i Mewes, 2006]. Nośnikiem informacji są w tym przypadku pojemności pomiędzy elektrodami czujnika, które wykorzystuje się do zobrazowania gęstości (rozkładu) przenikalności elektrycznej ε [F/m]. Ważną cechą pomiaru w ECT jest brak konieczności fizycznego kontaktu z badanym medium. Niestety zrekonstruowanie obrazu prezentującego ten rozkład wymaga często dużego nakładu obliczeń. Obliczenia te mogą zostać przyśpieszone dzięki zastosowaniu układów graficznych. 2. Środowisko CUDA Sprawne programowanie układów graficznych wymaga odpowiednich narzędzi i środowiska programistycznego. Do najpopularniejszych rozwiązań w tym zakresie należą obecnie [Verdiere, 2011] CUDA (ang. Compute Unified Device Architecture ) Jest to pierwsza dedykowana dla GPU architektura zarówno sprzętowa jak i programowa. Została ona opracowana przez firmę NVIDIA i zaprezentowana po raz pierwszy w listopadzie 2006 roku [NVIDIA CUDA C Programming Guide, 2011]. Umożliwia programowanie z wykorzystaniem takich języków jak C/C++, Fortran, czy Python. Zawiera także dodatkowe biblioteki, takie jak np. CUBLAS dla podstawowych operacji algebry liniowej oraz CUFFT dla szybkiej transformaty Fouriera [Kirk, 2007]. OpenCL (ang. Open Computing Language) Jest otwartym i niezależnym od platformy standardem zawierającym jednolity interfejs programowania aplikacji (API) do programowania równoległego zarówno CPU jak i GPU z wykorzystaniem języka C. Standard ten był początkowo rozwijany przez firmę Apple, która w 2008 roku zgłosiła jego pomysł do Khronos Group w celu przyjęcia go jako otwartego standardu. Do rozwijania OpenCL przyłączyły się także inne firmy z NVIDIA i ATI na czele. Wersja 1.0 standardu została opublikowana pod koniec 2008 roku, a jako pierwsza udostępniła go firma Apple wraz z systemem Mac OS X Snow Leopard [Stone i inni, 2010]. Przedstawione w dalszej części tego artykułu rozwiązania wykorzystują architekturę CUDA, która pomimo faktu, że można ją wykorzystywać wyłącznie z produktami firmy NVIDIA jest obecnie najpopularniejszym rozwiązaniem dla obliczeń równoległych na procesorach graficznych. 2

Środowisko CUDA Uruchamianie programów w architekturze CUDA bazuje na tzw. kernelach (ang. kernel). Kernel jest funkcją wykonywaną równolegle w wielu równoległych wątkach. Wątki, które wykonują ten sam kernel i współdzielą pamięć, są razem synchronizowane i grupowane w trójwymiarowe bloki wątków (ang. thread blocks). Z kolei bloki wątków są wywoływane w trójwymiarowych gridach (ang. grid). Każdy z wątków ma swoją lokalną prywatną przestrzeń pamięci. Analogiczne każdy blok wątków ma pamięć współdzieloną (ang. shared memory) dostępną tylko dla wątków zawartych w danym bloku. Natomiast gridy mają dostęp do pamięci globalnej przydzielonej do aplikacji [NVIDIA CUDA C Programming Guide, 2011]. Podział ten jak i hierarchię pamięci obrazuje schemat na rysunku 1. Aby wątki mogły wykonać odpowiednie operacje są one indeksowane w obrębie bloku, podobnie jak bloki wątków są indeksowane w obrębie gridów. Pamięć globalna przydzielona dla aplikacji Grid (1,0,0) Blok (1,0,0) Blok (2,0,0) Blok (3,0,0) Blok (1,1,0) Blok (2,1,0) Blok (3,1,0) Blok (2,1,0) Współdzielona pamięć bloku Wątek (1,0,0) Wątek (2,0,0) Wątek (3,0,0) Wątek (4,0,0) Wątek (1,1,0) Wątek (2,1,0) Wątek (3,1,0) Wątek (4,1,0) Wątek (2,1,0) Prywatna pamięć lokalna wątku Rys. 1. Hierarchia wątków i pamięci w CUDA 3

Środowisko CUDA Układy zbudowane zgodnie z architekturą CUDA bazują na mikroprocesorach strumieniowych (ang. stream multiprocessor SM) złożonych z kilku procesorów strumieniowych (ang. stream procesor SP) nazywanych także rdzeniami CUDA. Za dystrybucję bloków wątków pomiędzy SM odpowiada globalny planer GigaThread. Aby obsłużyć setki wątków układy SM wykorzystują architekturę SIMT (ang. single instruction, multiple thread), czyli pojedyncza instrukcja wiele wątków. Zgodnie z nią wątki w celu wykonania są grupowane w 32-elementowe grupy nazywane warpami [Nickolls i inni, 2008]. Poszczególne modele układów GPU różnią się między sobą przede wszystkim pod względem liczby rdzeni, co wpływa na przebieg obliczeń. Korzystając z CUDA programista nie musi znać ich liczby ponieważ wbudowane mechanizmy podzielą wątki zawarte w gridzie pomiędzy dostępne rdzenie. Jednak aby uzyskać maksymalną wydajność konieczne jest rozważenie rozmiaru bloków w zależności od architektury GPU. W konkretnych zastosowaniach trzeba brać także pod uwagę inne ograniczenia, jak chociażby liczba rejestrów dostępnych w obrębie jednego SM. CPU WYKONANIE PROGRAMU Kopiowanie RAM CPU RAM GPU GPU Kopiowanie RAM CPU RAM GPU CPU Rys. 2. Schemat wykonywania programu zawierającego kod dla GPU Schematycznie proces wykonywania programu zawierającego kod dla GPU został przedstawiony na rysunku 2. Układy umożliwiające wykonywanie obliczeń GPGPU stanowią urządzenia zewnętrzne względem CPU. Układy GPU stanowią w tym przypadku koprocesor dla CPU umożliwiający uruchomienie wielu wątków równocześnie. W konsekwencji każde uruchomienie programu na GPU musi zostać przeprowadzone przez CPU. W obu typach 4

Problem prosty w tomografii elektrycznej układów występują moduły bezpośredniego dostępu do pamięci (ang. Direct Memory Access - DMA), jednak w GPU są one bardziej rozbudowane. Należy też zauważyć, że układ CPU korzysta z pamięci operacyjnej komputera, podczas gdy układ GPU musi się zadowolić pamięcią umieszczoną na karcie na której jest zamontowany. Pamięć na karcie jest szybsza od pamięci operacyjnej komputera, ale jest też mniejsza i nie można jej rozbudować. Taka architektura implikuje konieczność przekopiowania do pamięci karty danych, na których będą wykonywane obliczenia, a po zakończeniu obliczeń, wyników z pamięci karty do pamięci operacyjnej komputera, co wydłuża czas całej operacji. 3. Problem prosty w tomografii elektrycznej Głównym elementem systemu elektrycznej tomografii pojemnościowej jest czujnik składający się z elektrod umieszczonych na obwodzie zbiornika, w którym przebiega proces. Czujnik ten jest podłączony do układu elektronicznego, który mierzy pojemności pomiędzy poszczególnymi parami elektrod, co zostało przedstawione schematycznie na rysunku 3. Rys. 3. Schemat pomiaru w ECT dla czujnika pomiarowego z 12-ma elektrodami: φ potencjał elektryczny, V wartość potencjału przyłożonego do elektrody pomiarowej, C s,r pojemność pomiędzy elektrodami s oraz r Zmierzona pojemność elektryczna C jest wprost proporcjonalnie zależna od stałej względnej przenikalności elektrycznej r zgodnie z równaniem 1: C 0 r k g (1) gdzie 0 to przenikalność elektryczna próżni (8.85 pf m -1 ), a k g to współczynnik geometryczny zależny od powierzchni elektrod i odległości między nimi. Po zebraniu zestawu pomiarów pomiędzy wszystkimi elektrodami rozkład przenikalności elektrycznej 5

Problem prosty w tomografii elektrycznej wewnątrz czujnika można uzyskać na drodze rekonstrukcji obrazu bazującej na rozwiązaniu problemu odwrotnego dla równania 2: 1 Csr 0 r ( x, y) ( x, y) d s r r (2) W powyższym równaniu indeks r dotyczy elektrody odbiorczej, indeks s elektrody nadawczej, to potencjał elektryczny, a Ω r to obszar całkowania na elektrodzie odbiorczej. Po dyskretyzowaniu obszaru czujnika poprzez podzielenie go na N części równanie 2 można uprościć do formy liniowej, która przyjmie postać jak w równaniu 3 [Sankowski i Sikora, 2010]: C J ε (3) M 1 M N N 1 gdzie: C wektor zawierających M pomiarów pojemności J Jakobian reprezentujący zestaw map czułości dla wszystkich par elektrod M liczba pomiarów (par elektrod) N liczba części na które został podzielony obszar czujnika tomografu wektor zawierający wartości przenikalności elektrycznej we wszystkich częściach obszaru czujnika tomografu Rekonstrukcja obrazu dla elektrycznej tomografii pojemnościowej polega w tym przypadku na znalezieniu wektora przy znanym wektorze C. Zagadnienie to jest nazywane problemem odwrotnym. Problem ten jest niedookreślony (liczba danych M jest dużo mniejsza od szukanych N) oraz źle postawiony [Lionheart, 2004]. Zauważyć należy, że ponieważ M << N to nie jest możliwe obliczenie J -1, a więc nie istnieje rozwiązanie liniowe. Możliwe jest natomiast znalezienie rozwiązania problemu prostego, które polega na znalezieniu wektora C przy znanym [Soleimani i inni, 2005]. Rozwiązanie problemu prostego metodą elementów skończonych należy rozpocząć od podziału obszaru czujnika tomografu na N podobszarów opartych na K węzłach. Funkcję rozkładu potencjału φ(x,y) można wtedy opisać z wykorzystaniem funkcji kształtu, zależnej od kształtu elementu służącego do podziału obszaru czujnika, jako funkcji wartości potencjału w węzłach siatki [Bolkowski i inni, 1993]. Rozkład potencjału elektrycznego wewnątrz obszaru tomografu Ω w dwuwymiarowej płaszczyźnie XY, ograniczonego krzywą zamkniętą jest opisany przez równanie Laplace a [Sikora, 1998]: div( ( x, y) grad[ ( x, y)]) 0 (4) 6

Problem prosty w tomografii elektrycznej Przy poszukiwaniu rozwiązania problemu prostego należy zastosować warunki brzegowe Dirichleta w punktach należących do elektrod zgodnie ze wzorem 5 oraz warunki Neumana na pozostałej części brzegu [Bolkowski i inni, 1993]. gdzie: s indeks elektrody nadawczej r indeks elektrody odbiorczej V 0 potencjał przyłożony do elektrody nadawczej V 0 dla x, y s ( x, y) (5) 0 dla x, y r Rozwiązanie równania Laplace a z równania 4 można znaleźć poprzez szukanie minimum wyrażenia funkcjonalnego przedstawionego przez równanie 6, które obrazuje energię pola elektrycznego zgromadzoną wewnątrz czujnika tomografu [Bolkowski i inni, 1993]. W 1 2 I( ( x, y)) ( x, y)( grad[ ( x, y)]) dxdy (6) 2 gdzie: W energia pola elektrycznego zgromadzona wewnątrz czujnika tomografu Ω powierzchnia tomografu Szukanie minimum wartości funkcjonału z równania 6, można sprowadzić do znalezienia punktu stacjonarnego (ekstremum) ze względu na wektor wartości węzłowych szukanego rozkładu potencjału Φ [Bolkowski i inni, 1993]: I I 1 0 (7) I K Mając jednak na uwadze warunki brzegowe należy przyjąć ogólną postać równania liniowego Metody Elementów Skończonych jak we wzorze 8: I A B (1) gdzie elementy macierzy A stanowią współczynniki równania zależne od funkcji kształtu. 7

Algorytm rozwiązywania problemu prostego dla GPU Powyższy układ równań należy rozwiązać dla każdej elektrody nadawczej, ponieważ dla każdej z nich występują inne warunki brzegowe. Znając rozkład potencjału elektrycznego dla poszczególnych elektrod nadawczych oraz rozkład przenikalności elektrycznej można obliczyć pojemności pomiędzy każdą parą elektrod korzystając z zależności przedstawionej na równaniu 2 ograniczając obszar całkowania do obszaru elektrody odbiorczej [Wajman i inni, 2004]. 4. Algorytm rozwiązywania problemu prostego dla GPU Rozwiązanie problemu prostego opiera się w głównej mierze na rozwiązaniu układu równań ze wzoru 8, czyli znalezieniu rozkładu potencjałów w obszarze czujnika tomografu. Przy stosowanych rozmiarach siatek, a w konsekwencji rozmiarach macierzy A (rozmiar macierzy to K x K gdzie K to liczba węzłów zastosowanej siatki), jest to proces czasochłonny przy wykorzystaniu pojedynczego układu CPU. Należy więc poszukać metody, która pozwoli na możliwie szybkie rozwiązanie tego układu równań. Metody rozwiazywania numerycznego układów równań dzielą się na dwie główne grupy [Fortuna i inni, 1998]: metody dokładne które po wykonaniu skończonej liczby działań arytmetycznych pozwalają otrzymać rozwiązanie np. metoda eliminacji Gaussa, metoda eliminacji Jordana, metoda Cholesky ego-banachiewicza; metody iteracyjne które w każdej iteracji zwracają kolejne przybliżenia rozwiązania np. metoda Jacobiego, metoda Gaussa-Seidla, metoda Czebyszewa. W rozważanym przypadku można zauważyć, że macierz A jest macierzą rzadką, jednak jej struktura zależy od zastosowanej do podziału obszaru czujnika siatki, co uniemożliwia wyprowadzenie stałych uproszczonych wzorów na rozwiązanie układu równań. Macierz A jest także macierzą pasmową, symetryczną względem głównej przekątnej. Można także wykazać, że macierz ta jest dodatnio określona, co pozwala zastosować metodę Cholesky ego Banachiewicza do rozkładu tej macierzy na iloczyn dwóch macierzy trójkątnych [Bolkowski i inni, 1993, Fortuna i inni, 1998]: (9) przy czym macierz L jest macierzą trójkątną dolną z elementami na diagonali niekoniecznie równymi 1. Rozwiązanie układu równań sprowadzi się wtedy do rozwiązania dwóch układów równań z macierzami trójkątnymi: 8

Algorytm rozwiązywania problemu prostego dla GPU (10) (11) O ile do rozwiązania układu równań z macierzą trójkątną przy pomocy układu GPU można wykorzystać dostarczoną w bibliotece CUBLAS odpowiednią funkcję, to problemem jaki należy rozwiązać jest rozkład macierzy A na macierze L oraz L T. Zgodnie z definicją metody Cholesky ego Banachiewicza obliczenia należy przeprowadzać kolejno zgodnie ze wzorami [Fortuna i inni, 1998]: (12) ( ) (13) gdzie: L ii element macierzy L w i-tym rzędzie i i-tej kolumnie A ii element macierzy A w i-tym rzędzie i i-tej kolumnie L ji element macierzy L w j-tym rzędzie i i-tej kolumnie A ji element macierzy A w j-tym rzędzie i i-tej kolumnie K liczba wierszy (liczba kolumn) macierzy A W celu zaoszczędzenia miejsca w pamięci operacyjnej RAM, elementy macierzy A zostają zastąpione elementami macierzy L, w taki sposób że po zakończeniu obliczeń dolna trójkątna część macierzy A odpowiada dolnej trójkątnej części macierzy L. W przedstawionych fragmentach kodu przyjęto kolejność zapisywania w pamięci komputera elementów macierzy wierszami. Przykład kodu w języku C++ implementującego tę metodę rozkładu Cholesky ego-banachiewicza został przedstawiony na listingu 1. 1 for(unsigned i=0; i<size; i++) 2 { 3 float S = 0; 4 for(unsigned k=0; k<i; k++) 5 S+=pow(aA[i*size+k],2); 6 7 aa[i*size+i] = sqrt(aa[i*size+i] - S); 8 9 for(unsigned j=i+1; j<size; j++) 10 { 11 S = 0; 12 for(unsigned k=0; k<i; k++) 13 S+= aa[j*size+k] * aa[i*size+k]; 14 15 aa[j*size+i]=(aa[j*size+i]-s) / aa[i*size+i]; 16 } 17 } Listing 1. Implementacja metody rozkładu Cholesky ego Banachiewicza dla układu CPU 9

Algorytm rozwiązywania problemu prostego dla GPU Powyższa implementacja sprawdza się dobrze w przypadku wykonywania przez jeden wątek w układzie CPU, jednak skutkuje bardzo ograniczonymi możliwościami w zakresie równoległego wykonania operacji, ponieważ musi być zachowana kolejność wykonywania operacji arytmetycznych. Aby zwiększyć możliwości zrównoleglenia obliczeń w tej metodzie należy zamienić kolejnością pętlę z linii 1 z pętlami z linii 4 i 12 listingu 1. W efekcie kod w języku C++ przyjmie następującą postać: 1 for(unsigned k=0; k<size; k++) 2 { //krok 1 3 aa[k*size+k] = sqrt(aa[k*size+k]); 4 //krok2 5 for(unsigned j=k+1; j<size; j++) 6 aa[j*size+k] = aa[j*size+k] / aa[k*size+k]; 7 //krok3 8 for(unsigned i=k+1; i<size; i++) 9 for(unsigned j=i; j<size; j++) 10 aa[j*size+i] -= aa[i*size+k] * aa[j*size+k]; 11 } Listing 2. Implementacja metody rozkładu Cholesky ego Banachiewicza dla układu CPU po zamianie kolejności pętli Pomimo zwiększenia stopnia skomplikowania obliczeń, uzyskano większą niezależność wykonywanych operacji. W efekcie operacje w linii 6 mogą być wykonane równolegle dla wszystkich elementów j z pętli z linii 5 (krok 2), a także operacje w linii 10 mogą być wykonane równolegle dla wszystkich wartości i oraz j z obu pętli z linii 8 oraz 9 (krok 3) listingu 2. Kolejność wykonywania obliczeń dla kolejnych wartości k (pętla z linii 1) musi zostać zachowana, podobnie jak kolejność operacji w poszczególnych krokach. Implementacja algorytmu z listingu 2 dla układów GPU byłaby jednak mało wydajna ze względu na dużą ilość operacji odczytu pamięci globalnej w stosunku do operacji arytmetycznych. Deklarowana przez producenta wydajność dla karty NVIDIA Tesla C1060 wynosi maksymalnie 933 GFLOPs dla operacji na liczbach o pojedynczej precyzji podczas gdy przepustowość pamięci wynosi maksymalnie 102GB/s. Dla operacji z linii 6 listingu 2 na jedną operację dzielenia przypadają 3 operacje dostępu do pamięci (2 operacje odczytu oraz 1 operacja zapisu). Liczba o pojedynczej precyzji zajmuje w pamięci 4kB, tak więc maksymalna prędkość z jaką mogą być dostarczone dane do układu obliczeniowego to 102/4/3 = 8,5 GB/s, przez co maksymalna teoretyczna wydajność spada do 8,5 GLOPS, czyli ok. 100 razy mniej od maksymalnej deklarowanej przez producenta. Równie niekorzystna sytuacja występuje w linii 10 listingu 2. Ponieważ w prezentowanym algorytmie te same elementy macierzy odczytywane są wielokrotnie przez różne wątki, można ograniczyć liczbę dostępów do pamięci globalnej karty z układem GPU (pamięć RAM GPU) poprzez ładowanie danych seriami z pamięci globalnej do dużo szybszej pamięci współdzielonej w ramach 10

Algorytm rozwiązywania problemu prostego dla GPU jednego bloku wątków. Przy takim podejściu wątki w ramach każdego z takich bloków muszą operować na tych samych elementach macierzy. Przy podziale problemu na bloki należy kierować się jak największą możliwością wykorzystania odczytanych danych w obrębie jednego bloku dla zminimalizowania liczby odczytów pamięci. Z drugiej strony rozmiar bloku oraz współdzielonej w jego ramach pamięci są ograniczone architekturą układu GPU, który będzie wykorzystywany do obliczeń. Ponieważ wraz z nowymi układami GPU dostępnymi na rynku ich możliwości są coraz większe, rozmiar bloku należy dobrać do konkretnego układu GPU dla otrzymania maksymalnej wydajności. Na rysunku 4 przedstawiono schemat blokowy proponowanego algorytmu wykorzystującego podział macierzy na bloki wspólnych obliczeń. Rys. 4. Schemat blokowy algorytmu rozkładu Cholesky ego Banachiewicza z podziałem macierzy na bloki umożliwiające przeprowadzenie obliczeń w sposób równoległy. 11

Algorytm rozwiązywania problemu prostego dla GPU Zaproponowany algorytm wykonuje obliczenia zawsze na prawej górnej części macierzy przesuwając po każdym przebiegu pętli wskaźnik pierwszego bloku o jeden wiersz i jedną kolumnę tj. po kolejnych blokach znajdujących się na diagonali. Algorytm kończy działanie, gdy rozkład Choleksy ego-banachiewicza zostanie obliczony dla ostatniego bloku na diagonali w dolnym prawym rogu. Komentarza wymagają operacje wykonywane w każdym kroku algorytmu. W kroku pierwszym pierwszy blok zostaje poddany klasycznej implementacji rozkładu Cholesky ego-banchiewicza. Funkcja kernela, jest uruchamiana w gridzie składającym się z jednego bloku o rozmiarach odpowiadających rozmiarowi bloku. W ten sposób każdy wątek odpowiada za odczyt jednego elementu macierzy do tablicy we współdzielonej pamięci bloku, a następnie za obliczenia dla jednego elementu macierzy. Na koniec każdy wątek zapisuje wartość jednego elementu tablicy ze współdzielonej pamięci bloku do pamięci globalnej. Synchronizacja pomiędzy wątkami jest niezbędna dla zagwarantowania, że wszystkie elementy z pamięci globalnej zostały załadowane do tablicy w pamięci współdzielonej. Synchronizacja zapewnia także, że etapy obliczeń dla wszystkich elementów tablicy zostały zakończone przed przejściem do kolejnych etapów. Drugi krok pętli składa się de facto z dwóch etapów, ale ponieważ wykorzystują one te same dane wejściowe, dla ograniczenia liczby odczytów z pamięci globalnej są one wykonywane w jednej funkcji kernela, a co za tym idzie przy jednym wywołaniu. Każdy z wątków odpowiada za odczyt z pamięci globalnej do tablic w pamięci współdzielonej w obrębie wątku jednego elementu z bloku na diagonali oraz jednego elementu z bloku w pierwszej kolumnie pod diagonalą. Ponieważ funkcja kernela jest wywoływana w jednowymiarowym gridzie składającym się z tylu bloków wątków ile bloków jest w macierzy pod blokiem na diagonali, to każdy blok wątków będzie odpowiadał za inny blok danych macierzy. Z kolei każdy blok wątków składa się z tylu wątków ile elementów jest w bloku macierzy. Taki podział zapewnia, że operacje w poszczególnych blokach wątków mogą być wykonane niezależnie od siebie. W pierwszym etapie funkcja kernela aktualizuje dane w blokach pod blokiem na diagonali przesuwając się kolumna po kolumnie, następnie aktualizuje dane w kolejnych blokach na diagonali, także przesuwając się kolumna po kolumnie w obrębie każdego bloku. Funkcja kernela dla trzeciego etapu obciąża układ GPU w największym stopniu. Jest ona wywoływana w dwuwymiarowym kwadratowym gridzie, przy czym długość jak i szerokość tego gridu są równe liczbie bloków w macierzy pod blokiem na diagonali. Podobnie jak i w przypadku funkcji kernela dla pierwszego oraz drugiego etapu liczba 12

Algorytm rozwiązywania problemu prostego dla GPU elementów w bloku wątków odpowiada liczbie elementów w bloku danych macierzy. Każdy blok wątków odczytuje dwa bloki danych i aktualizuje jeden blok danych macierzy w pamięci globalnej odpowiedni do umiejscowienia w macierzy odczytanych bloków danych. Operacje odczytu są wykonywane dla wszystkich niepowtarzających się par bloków danych znajdujących się w pierwszej kolumnie macierzy pod blokiem na diagonali. Dzięki takiemu podziałowi operacje w każdym bloku wątków, jak i w pojedynczym wątku mogą być wykonywane równolegle (pomijają synchronizację wątków w bloku po odczycie danych z pamięci globalnej do tablic w pamięci współdzielonej bloku). Zastosowanie zaproponowanego algorytmu rozkładu Cholesky ego-banachiewicza wymusza, aby rozmiar macierzy A był wielokrotnością rozmiaru bloku. Rozwiązaniem tego wymagania jest dopełnianie macierzy do rozmiaru będącego wielokrotnością rozmiaru bloku, w taki sposób, że dodane elementy będą miały wartość 0, z wyjątkiem elementów na diagonali które będą miały wartość 1. Takie podejście doprowadzi do zwiększenia liczby obliczeń, jednak przy rozmiarze macierzy dużo większym od rozmiaru bloku, a takie przypadki są rozważane, będzie to wzrost marginalny. Dodatkowo, przy założeniu że rozmiar macierzy jest zawsze wielokrotnością rozmiaru bloku można zastosować rozwinięcie pętli for w funkcjach kernela, czyli zastąpienie pętli kodem instrukcji wykonywanych w każdym kroku pętli. Jest to znana praktyka w przypadku programowania dla układów GPU, która prowadzi do lepszego wykorzystania ich zasobów [Sanders i Kandrot, 2010]. Przed przystąpieniem do rozwiązywania układu równań 8 konieczne jest jeszcze wprowadzenie informacji o warunkach brzegowych. Jest to realizowane poprzez zastąpienie prawej strony równania macierzą B, której elementy są obliczane zgodnie ze wzorem (14): B B A dla j 1,2, K; j i j j ji i (2) gdzie: i indeks węzła należącego do elektrody j indeks węzła K liczba węzłów Konieczne jest także usunięcie z macierzy B wierszy o indeksach odpowiadających indeksom węzłów należącym do elektrod, a co za tym idzie także utworzenie macierzy A jako kopii macierzy A zredukowanej o wiersze oraz kolumny o indeksach odpowiadających indeksom węzłów należących do elektrod [Sikora, 1998]. Choć proponowana metoda wiąże się z większym zapotrzebowaniem na pamięć RAM oraz większą ilością czasu potrzebnego na kopiowanie danych pomiędzy macierzami A - A oraz B - B, to prowadzi do znacznej 13

Algorytm rozwiązywania problemu prostego dla GPU redukcji liczby elementów w układzie równań. Po otrzymaniu rozwiązania dla tak zmodyfikowanego układu równań konieczne jest uzupełnienie go o wartości potencjałów w węzłach należących do elektrod. W opracowanej implementacji tego algorytmu zdecydowano się na obliczenie macierzy A oraz B jeszcze przed przekopiowaniem ich do pamięci RAM układu GPU. Decyzja taka była umotywowana krótszym czasem wykonywania tej operacji przez układ CPU niż w przypadku wykonywania jej w pamięci RAM układu GPU, czy też w trakcie kopiowania do pamięci RAM układu GPU. Podsumowując wszystkie powyższe rozważania, proponowany algorytm rozwiązywania problemu prostego przyjął postać zaprezentowaną jako schemat blokowy na rysunku 5. Rys. 5. Schemat blokowy algorytmu rozwiązywania problemu prostego dla ECT 14

Algorytm rozwiązywania problemu prostego dla GPU W celu porównania wydajności proponowanego algorytmu dla GPU oraz algorytmu dla CPU, próby wydajnościowe algorytmów rozwiązywania problemu w ECT na komputerze, którego dokładna specyfikacja jest przedstawiona w tabeli 1. Ze względu na znaczne rozmiary macierzy A, część obliczeń przeznaczona dla układu GPU była przeprowadzona na karcie NVIDIA Tesla C1060. Karta ta pomimo braku wyjścia służącego do podłączenia monitora została wyposażona w 4 GB pamięci RAM, czyli 4 razy więcej niż znajdująca się na wyposażeniu używanego komputera karta graficzna NVIDIA Geforce GTX 285. Ponieważ czas potrzebny na wykonanie obliczeń na liczbach zmiennoprzecinkowych o podwójnej precyzji (double) dla układów GPU z compute capability 1.3, w jakie było wyposażone stanowisko badawcze, jest ok. 10-krotnie dłuższy niż w przypadku tych samych operacji wykonanych przy pojedynczej precyzji, wszystkie obliczenia były wykonywane na liczbach zmiennoprzecinkowych o pojedynczej precyzji (float lub single). Należy jednak wspomnieć, że w przypadku nowszych układów GPU firmy NVIDIA z compute capabilty 2.0 czas potrzebny na wykonanie operacji na liczbach zmiennoprzecinkowych o podwójnej precyzji jest jedynie 2-krotnie dłuższy niż dla liczb zmiennoprzecinkowych o pojedynczej precyzji. Dla tych układów zaleca się wykonywanie opisanych algorytmów przy zachowaniu podwójnej precyzji, dla maksymalnego ograniczenia błędów numerycznych. Tabela 1. Szczegółowa konfiguracja wykorzystywanego komputera Element Opis procesor Intel Core i7-920 płyta główna Gigabyte EX58-UD5 (Intel X58+ICH10R) pamięć operacyjna RAM Patriot 1600LL 6GB (2x3GB) PC3-12800 DDR3 dysk twardy Samsung HE103UJ (1TB, 32MB cache, SATA) karta graficzna NVIDIA GeForce GTX285 (GT200) 1GB GDDR3 compute capability karty graficznej 1.3 karta do obliczeń GPU NVIDIA Tesla C1060 (GT200) 4 GB GDDR3 compute capability karty do obliczeń GPU 1.3 system operacyjny Windows XP Professional x64 środowisko programistyczne Visual Studio 2008 W porównaniach wzięto pod uwagę obie metody wprowadzania warunków brzegowych, tzn. wersję bez zmiany warunków brzegowych oraz wersję zmieniającą rozmiar macierzy A poprzez usunięcie wierszy oraz kolumn odpowiadających węzłom należącym do elektrod. Próby te przeprowadzono dla czujników składających się z 8 oraz 16 elektrod przy założeniu, że 2% wszystkich węzłów należy do elektrod. Wykresy prezentujące zależności czasu wykonywania obliczeń poszczególnych algorytmów od liczby węzłów siatki przedstawiono na rysunkach 6 oraz 7. Liczba węzłów siatki odpowiada w tym przypadku 15

czas (ms) czas (ms) Algorytm rozwiązywania problemu prostego dla GPU liczbie wierszy (macierz jest kwadratowa więc liczba wierszy jest taka sama jak kolumn) macierzy A przed wprowadzeniem warunków brzegowych. 250000 8 elektrod 200000 150000 100000 CPU pełne A CPU przycięte A GPU pełne A GPU przycięte A 50000 0 0 1000 2000 3000 4000 5000 6000 7000 8000 9000 10000 liczba węzłów siatki Rys. 6. Wykres prezentujący zależność czasu wykonywania obliczeń przez poszczególne algorytmy rozwiązywania problemu prostego od liczby węzłów siatki, dla czujnika zawierającego 8 elektrod. 250000 16 elektrod 200000 150000 100000 CPU pełne A CPU przycięte A GPU pełne A GPU przycięte A 50000 0 0 1000 2000 3000 4000 5000 6000 7000 8000 9000 10000 liczba węzłów siatki Rys. 7. Wykres prezentujący zależność czasu wykonywania obliczeń przez poszczególne algorytmy rozwiązywania problemu prostego od liczby węzłów siatki, dla czujnika zawierającego 16 elektrod. 16

Podsumowanie Powyższe wykresy ilustrują około 7,5-krotne skrócenie czasu rozwiązywania problemu prostego przez zaproponowany przez autora algorytm dla układu GPU w przypadku czujnika z 8 elektrodami, a także około 8,2 krotne w przypadku czujnika z 16 elektrodami. Można także zauważyć, że zarówno dla układu CPU, jak i układu GPU metoda wprowadzania warunków brzegowych poprzez ograniczenie rozmiaru macierzy A pozwala skrócić o około 5% czas potrzebny na wykonanie obliczeń dla czujnika z 8 elektrodami oraz o około 10% czasu dla czujnika z 16 elektrodami. Płynie z tego wniosek, że w przypadku gdy dysponujemy dostatecznie dużą ilością pamięci operacyjnej aby dokonać redukcji macierzy A warto rozważyć zastosowanie tej metody. 5. Podsumowanie W niniejszej pracy przedstawiono pionierskie w skali światowej prace badawcze nad zastosowaniem procesorów graficznych (GPU) do obliczeń równoległych dla potrzeb tomografii procesowej. Celem tych prac było opracowanie algorytmów przetwarzania tomograficznych danych pomiarowych z wykorzystaniem procesorów graficznych w celu przyspieszenia obliczeń i w efekcie uzyskania wyższej rozdzielczości czasowo-przestrzennej rekonstruowanych obrazów. Najistotniejszym elementem przedstawionym w niniejszej pracy jest nowatorski algorytm rozwiązywania problemu prostego w systemach ECT oparty na autorskiej metodzie rozkładu macierzy współczynników równania liniowego na macierze L oraz L T. Algorytm dekompozycji macierzy bazuje na metodzie Cholesky ego-banchiewicza. O ile metoda Cholesky ego-banachiewicza jest typowym algorytmem, który można wykonać wyłącznie sekwencyjnie, to opracowany przez autora algorytm dekompozycji macierzy umożliwia wykonanie większości operacji arytmetycznych równolegle. Pozwoliło to na użycie układów GPU przetwarzania danych pomiarowych z przemysłowych systemów tomograficznych. Przeprowadzone próby wydajnościowe dowiodły, że użycie zaproponowanego algorytmu dla układów GPU pozwoliło uzyskać ponad 8-krotne skrócenie czasu przetwarzania danych pomiarowych dla ECT. Tak znaczące przyśpieszenie obliczeń może zostać wykorzystane w przemysłowych systemach tomograficznych w celu: 1) zwiększenia rozdzielczości przestrzennej obrazów, 2) uzyskania większej liczby obrazów w jednostce czasu (rozdzielczości czasowej), 3) zwiększenia rozdzielczości czasowo-przestrzennej obrazów. 17

Podziękowania Daje to możliwość szerszego zastosowania tomografii procesowej w systemach monitorowania dynamicznych procesów przemysłowych. Jest to szczególnie istotne w przypadku procesów monitorowanych z użyciem tomografii procesowej, w których czas przetwarzania danych był dotychczas zbyt długi, by wyniki tego przetwarzania mogły zostać użyte do sterowania procesem. Nie bez znaczenia jest również stosunkowo niska cena oraz niewielkie rozmiary kart z układami GPU w porównaniu do rozwiązań dostarczających podobną moc obliczeniową, ale w oparciu o układy CPU. To wszystko powinno przełożyć się na rosnące zainteresowanie ze strony przemysłu, a w konsekwencji do upowszechnienia się procesorów graficznych w zastosowaniach do obliczeń w diagnostycznych systemach tomograficznych. Doświadczenia zebrane w trakcie prowadzonych przez autora prac badawczych wskazują na dużą zależność wydajności proponowanego algorytmu od wykorzystywanej platformy sprzętowej z układami GPU. Autor proponuje przeprowadzenie dalszych prac badawczych w kierunku poszukiwania metod modyfikujących działanie algorytmów w zależności od możliwości układu GPU, na którym wykonywane są obliczenia. Możliwe jest także przeprowadzenie adaptacji zaproponowanego algorytmu w celu uruchomienia go w środowisku złożonym z wielu układów GPU. Powinno to przynieść korzyść w postaci dalszego skrócenia czasu obliczeń, jednak pociągnie za sobą konieczność uwzględnienia kolejnych ograniczeń, głównie w zakresie transferu danych. 6. Podziękowania Komputer, który umożliwił opracowanie algorytmów oraz przeprowadzenie opisanych testów został zakupiony w ramach uzyskanego przez autora stypendium celowego na dofinansowanie prac naukowo-badawczych dla doktorantów w ramach projektu pt.: Stypendia wspierające innowacyjne badania naukowe doktorantów (Projekt finansowany ze środków Unii Europejskiej z Europejskiego Funduszu Społecznego oraz budżetu państwa w ramach Zintegrowanego Programu Operacyjnego Rozwoju Regionalnego). Autor był także stypendystą w ramach projektu Innowacyjna dydaktyka bez ograniczeń - zintegrowany rozwój Politechniki Łódzkiej - zarządzanie uczelnią, nowoczesna oferta edukacyjna i wzmacnianie zdolności do zatrudniania, także osób niepełnosprawnych (Projekt współfinansowany przez Unię Europejską w ramach Europejskiego Funduszu Społecznego). 18

Literatura 7. Literatura [1] Bolkowski S., Stabrowski M., Sroka J., Sikora J.: Komputerowe metody analizy pola elektromagnetycznego, wyd. II, WN-T, Warszawa, 1993. [2] Fortuna Z., Macukow B., Wąsowski J.: Metody numeryczne, wyd. czwarte, Wydawnictwo Naukowo-Techniczne, Warszawa, 1998. [3] Harris M.: Real-Time Cloud Simulation and Rendering, Ph. D. dissertation, University of North Carolina, 2003. [4] Ikeda T., Ino F., Hagihara K.: A code motion technique for accelerating generalpurpose computation on the GPU, 20th International Parallel and Distributed Processing Symposium, 2006. [5] Kirk D.: NVIDIA CUDA software and GPU parallel computing architecture, Proceedings - International Symposium on Memory Management, 2007, s. 103. [6] Lindholm E., Nickolls J., Oberman S., Montrym J.: NVIDIA Tesla: A Unified Graphics and Computing Architecture, IEEE Micro, 28(2), 2008, s. 39-55. [7] Lionheart W. R. B.,: Review: Developments in EIT reconstruction algorithms: pitfalls, challenges and recent developments, Physiol. Meas., 25, 2004, s. 125-142. [8] Nickolls J., Buck I, Garland M., Skadron K.: Scalable Parallel Programming, ACM Queue - GPU Computing, 6 (2), 2008, s. 40-53. [9] NVIDIA CUDA C Programming Guide, wersja 4, 06.05.2011, http://developer.nvidia.com [10] Reinecke N., Mewes D.: Recent developments and industrial/research applications of capacitance tomography, Meas. Sci. Technol., 7, 2006, s. 233 246. [11] Sanders J., Kandrot E.: CUDA by Example, NVIDIA / Addison-Wesley (Pearson Education), Second Printing, United States, 2010. [12] Sankowski D., Sikora J.: Electrical Capacitance Tomography: Theoretical Basis and Applications, Wydawnictwo Książkowe Instytutu Elektrotechniki, Warszawa, 2010. [13] Sikora J.: Algorytmu numeryczne w tomografii impedancyjnej, wyd. I, Oficyna Wydawnicza Politechniki Warszawskiej, Warszawa, 1998. [14] Soleimani M., Lionheart W. R. B., Byars M., Pendleton J., (2005): Nonlinear Image Reconstruction of Electrical Capacitance Tomography (ECT) based on a Validated Forward Model, 4th World Congress on Industrial Process Tomography, Japan, pp. 558-563. [15] Stone J.E., Gohara D., Shi G.,(2010), OpenCL: A Parallel Programming Standard for Heterogeneous Computing Systems, Computing in Science & Engineering, 12 (3), pp. 66 73. [16] Verdiere G. C. de, (2011), Introduction to GPGPU, a hardware and software background, Comptes Rendus Mecanique, 339 (2-3), High Performance Computing, pp. 78-89. [17] Wajman R., Mazurkiewicz Ł, Sankowski D., (2004), Mapy czułości w procesie rekonstrukcji obrazów dla elektrycznej tomografii pojemnościowej, Automatyka, tom 8, zeszyt 3. 19