\documentclass[a4paper,12pt]{article}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage[polish]{babel}
\usepackage{polski}
\usepackage[utf8]{inputenc}
\usepackage{indentfirst}
\usepackage{geometry}
\usepackage{array}
\usepackage[pdftex]{color,graphicx}
\usepackage{subfigure}
\usepackage{afterpage}
\usepackage{setspace}
\usepackage{color}
\usepackage{wrapfig}
\usepackage{listings}
\usepackage{datetime}

\renewcommand{\onehalfspacing}{\setstretch{1.6}}

\geometry{tmargin=2.5cm,bmargin=2.5cm,lmargin=2.5cm,rmargin=2.5cm}
\setlength{\parindent}{1cm}
\setlength{\parskip}{0mm}

\newenvironment{lista}{
\begin{itemize}
  \setlength{\itemsep}{1pt}
  \setlength{\parskip}{0pt}
  \setlength{\parsep}{0pt}
}{\end{itemize}}

\newcommand{\linia}{\rule{\linewidth}{0.4mm}}

\definecolor{lbcolor}{rgb}{0.95,0.95,0.95}
\lstset{
    backgroundcolor=\color{lbcolor},
    tabsize=4,
  language=C++,
  captionpos=b,
  tabsize=3,
  frame=lines,
  numbers=left,
  numberstyle=\tiny,
  numbersep=5pt,
  breaklines=true,
  showstringspaces=false,
  basicstyle=\footnotesize,
  identifierstyle=\color{magenta},
  keywordstyle=\color[rgb]{0,0,1},
  commentstyle=\color{Darkgreen},
  stringstyle=\color{red}
  }

\begin{document}

\noindent
\begin{tabular}{|c|p{11cm}|c|} \hline 
Grupa 1 & Piotr Dergun, Dominik Waśko & \ddmmyyyydate\today \tabularnewline
\hline 
\end{tabular}


\section*{Zadanie 6 - Rozmycie Gaussa GPU}

Celem zadania jest wykonanie rozmycia obrazu wykorzystując algorytm Gaussa za pomocą karty graficznej oraz technologii CUDA.  Poniżej przedstawiono kod kernela, który oblicza rozmycie Gaussa. 
\begin{lstlisting}
__global__ void gauss(int rows, int cols, unsigned char *in_r, unsigned char *in_g, unsigned char *in_b,unsigned char *out_r, unsigned char *out_g, unsigned char *out_b){
	const int r=5;
	int ratio[r][r] ={  {1, 4, 7, 4, 1},
					    {4, 16, 26, 16, 4},
						{7, 26, 41, 26, 7},
						{4, 16, 26, 16, 4},
						{1, 4, 7, 4, 1}};

	int N,i,row,col,poz,temp,sum_r,sum_g,sum_b,offset;
	offset = 2;
	N = rows * cols;
	i = blockIdx.x * blockDim.x + threadIdx.x;
	while(i<N){
		col = i%cols;
		row = (i/cols);
		if(!(row<offset||row>rows-offset-1||col<offset||col>cols-offset-1)){
			sum_r = 0;
			sum_g = 0;
			sum_b = 0;
			row-=offset;
			temp = col - offset;

			for (int j=0; j<r; ++j,++row){
				col= temp;
				for (int k=0; k<r; ++k,++col){
					poz = (row*cols) + col;
					sum_r  += ratio[j][k] *  in_r[poz];
					sum_g  += ratio[j][k] *  in_g[poz];
					sum_b  += ratio[j][k] *  in_b[poz];
				}
			}
			out_r[i] = sum_r / 273;
			out_g[i] = sum_g / 273;
			out_b[i] = sum_b / 273;
		}else{
			out_r[i] = in_r[i];
			out_g[i] = in_g[i];
			out_b[i] = in_b[i];
		}
		i+=blockDim.x * gridDim.x;
	}
}
\end{lstlisting}

Obraz do kernela przesyłany jest w postaci 3 tablic jednowymiarowych( po jednej dla każdego koloru). Konwersja z tablicy dwuwymiarowej A o rozmiarze NxM na jednowymiarową tablice B o rozmiarze N*M odbywa się wg wzoru: A[i][j] = B[M*i+j].
  
Zadanie zostało uruchomione na komputerze wyposażonym w karte graficzna NVIDIA GeForce GT 640M. Karta posiada dwa multiprocesory po 192 rdzenie CUDA, taktowane zegarem 709 MHz. Pamięć karty to 980MB. 

Program testowano na obrazie o rozmiarze 24107x4491 pikseli. Parametry dla jakich uruchomiono program to 3 rozmiary siatki: 16, 64, 256 oraz dla każdego rozmiaru siatki rozmiar bloku: 64,128,192,256,320.

Na rysunku 1. przedstawiono wykres zależności czasu obliczeń od rozmiaru bloku dla wszystkich trzech rozmiarów siatki. Można  zauważyć, że  czas obliczeń najbardziej spada przy zwiększeniu rozmiaru bloku do 128. Dalsze zwiększanie rozmiaru bloku nie powoduje tak dużego zmniejszenia czasu obliczeń, a w pewnym momencie zaczyna powodować wzrost czasu . Również rozmiar siatki ma wpływ na szybkość obliczeń: im siatka większa tym bardziej maleje czas.   





\begin{figure}[h]
\includegraphics[width=1.1\textwidth]{wykres.png}
\caption{Wykres czasu obliczeń od rozmiaru bloku.}
\label{fig:figure2}
\end{figure}

\section*{Porównanie}
Porównanie technologii OpenMP i MPI wykonano na komputerze MacPro3.1 wyposażonym w  2 procesory Xeon E5462, przy czym do dyspozycji było 6 rdzeni. Program z CUDA uruchomiono na innym komputerze wyposażonym w katę graficzną NVIDIA GeForce GT 640M z dwoma multiprocesorami po 192 rdzenie CUDA, taktowane zegarem 709 MHz. Do porównania użyto wykonanych na laboratoriach  programów obliczających rozmycie Gaussa . Do testów wybrano obraz o rozdzielczości 24107x4491. W tabeli przedstawiono czas wykonania przez poszczególne programy oraz liczbę użytych przez nie wątków, w przypadku CUDA jest to iloczyn rozmiaru siatki oraz rozmiaru bloku. 

 \vspace{8mm} 
\begin{table}
\centering
\begin{tabular}{|c|c|c|}
  \hline 
     & \textbf{wątki} & \textbf{czas[ms]}\\
  \hline
  \
\textbf{OpenMP} & 6 & 2227\\
  \hline
  \textbf{MPI} & 6 & 1483\\
  \hline
  \textbf{CUDA} & 98304 & 571\\
  \hline
\end{tabular} 
\end{table}
\end{document}
