Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package io.konwolucja;
- import java.util.concurrent.CompletableFuture;
- /**
- * Zoptymalizowana konwolucja wykorzystująca wielowątkowść.
- *
- * Optymalizacja została osiągnięta m.in. poprzez zamianę dwuwymiarowej tablicy wartości (values[][]) na jednowymiarową
- * tablicę wartości (value[]).
- *
- * Najważniejszym elementem przyspieszający konwolucję jest wykorzystanie wielowątkowości. Szachownica została podzielona
- * na dwie główne części: krańce szachownicy (edges) oraz wnętrze szachownicy (parts). Następnie podzielone rówież zostało
- * wnętrze szachownicy na oddzielne pasy, na których dokonywana jest osobna konwolucja. Jest to możliwe dzięki temu, że
- * pomijane są w tym momencie, elementy graniczne, dla których trzeba było przyjąć inne warunki obliczania konwolucji
- * (elementy graniczne nie zawierają wokół siebie wszystkich pikseli, dlatego w zależności od krawędzi lub rogu brane są
- * pod uwagę tylko odpowiednie sąsiadujące piksele).
- *
- * Dodatkowo przed wykonaniem serii 200. konwolucji stworzyłem dodatkową tablicę przechowującą wyniki konwolucji. Celem
- * tego jest pominięcie tworzenia nowej tablicy przechowującej wyniki konwolucji. Wykonanie tego kroku zaoszczędziło około
- * 20% czasu w porównaniu do wersji, w której w każdej pojedynczej konwolucji tworzona została nowa tablica.
- *
- * Oprócz tego zoptymalizowałem jak najbardziej liczbę wykonanych operacji. Między innymi było to przechowanie wartości
- * brzegowej dla jednego wiersza w zmiennej corner (corner = rows-1). Dodatkowo sklejone zostały wszystkie operacje mnożenia.
- *
- *
- *
- */
- public class ParallelConvolution extends PgmImage {
- float values[];
- int corner;
- public ParallelConvolution(int dimensions){
- super(dimensions);
- values = new float[rows*cols];
- corner=rows-1;
- }
- @Override
- public float getValue(int i, int j){
- return values[i*cols+j];
- }
- @Override
- public void setValue(int i, int j, float val){
- values[i*cols+j]=val;
- }
- @Override
- public void convolute(){
- float[] tmpImg = new float[rows*cols];
- final int threads = 8;
- CompletableFuture[] convolutionDiv = new CompletableFuture[threads+1];
- for (int i = 0; i<200; i+=2){
- convolutionDiv[0] = CompletableFuture.runAsync(()-> convoluteParts(tmpImg, values, threads, 0));
- convolutionDiv[1] = CompletableFuture.runAsync(()-> convoluteParts(tmpImg, values, threads, 1));
- convolutionDiv[2] = CompletableFuture.runAsync(()-> convoluteParts(tmpImg, values, threads, 2));
- convolutionDiv[3] = CompletableFuture.runAsync(()-> convoluteParts(tmpImg, values, threads, 3));
- convolutionDiv[4] = CompletableFuture.runAsync(()-> convoluteParts(tmpImg, values, threads, 4));
- convolutionDiv[5] = CompletableFuture.runAsync(()-> convoluteParts(tmpImg, values, threads, 5));
- convolutionDiv[6] = CompletableFuture.runAsync(()-> convoluteParts(tmpImg, values, threads, 6));
- convolutionDiv[7] = CompletableFuture.runAsync(()-> convoluteParts(tmpImg, values, threads, 7));
- convolutionDiv[8] = CompletableFuture.runAsync(()-> convoluteEdges(tmpImg, values));
- CompletableFuture.allOf(convolutionDiv).join();
- convolutionDiv[0] = CompletableFuture.runAsync(()-> convoluteParts(values, tmpImg, threads, 0));
- convolutionDiv[1] = CompletableFuture.runAsync(()-> convoluteParts(values, tmpImg, threads, 1));
- convolutionDiv[2] = CompletableFuture.runAsync(()-> convoluteParts(values, tmpImg, threads, 2));
- convolutionDiv[3] = CompletableFuture.runAsync(()-> convoluteParts(values, tmpImg, threads, 3));
- convolutionDiv[4] = CompletableFuture.runAsync(()-> convoluteParts(values, tmpImg, threads, 4));
- convolutionDiv[5] = CompletableFuture.runAsync(()-> convoluteParts(values, tmpImg, threads, 5));
- convolutionDiv[6] = CompletableFuture.runAsync(()-> convoluteParts(values, tmpImg, threads, 6));
- convolutionDiv[7] = CompletableFuture.runAsync(()-> convoluteParts(values, tmpImg, threads, 7));
- convolutionDiv[8] = CompletableFuture.runAsync(()-> convoluteEdges(values, tmpImg));
- CompletableFuture.allOf(convolutionDiv).join();
- }
- }
- @Override
- public void testConvolution(int loops){
- long startTime = System.nanoTime();
- convolute();
- long timeElapsed = System.nanoTime() - startTime;
- System.out.println(timeElapsed/1000000);
- }
- /**
- * convoluteEdges() jest funkcją obliczającą konwolucję tylko i wyłącznie dla wartości brzegowych, tzn. krawędzi bocznych,
- * górnych i dolnych oraz wszystkich czterech rogów.
- * @param tmpImg - tablica przechowująca wynik konwolucji
- * @param originalImg - tablica wejściowa z wartościami poszczególnych pikseli w aktualnym momencie
- */
- private void convoluteEdges(float[] tmpImg, float[] originalImg){
- tmpImg[0] = originalImg[0] * 0.6f + (originalImg[1] + originalImg[rows]) * 0.1f;
- tmpImg[corner] = originalImg[corner] * 0.6f + (originalImg[corner] + originalImg[corner]) * 0.1f;
- int it = corner * cols;
- tmpImg[corner * rows] = originalImg[it] * 0.6f + (originalImg[it + 1] + originalImg[it - cols]) * 0.1f;
- it += corner;
- tmpImg[it] = originalImg[it] * 0.6f + (originalImg[it - 1] + originalImg[it - cols]) * 0.1f;
- for (int i = 1; i < corner; ++i){
- tmpImg[i] = originalImg[i] * 0.6f + (originalImg[i - 1] + originalImg[i + 1] + originalImg[cols + i]) * 0.1f;
- it = i * cols;
- tmpImg[it] = originalImg[it] * 0.6f + (originalImg[it - cols] + originalImg[it + cols] + originalImg[it + 1]) * 0.1f;
- it = corner * rows + i;
- tmpImg[corner * rows + i] = originalImg[it] * 0.6f + (originalImg[it - 1] + originalImg[it + 1] + originalImg[it - cols]) * 0.1f;
- it = i * rows + corner;
- tmpImg[it] = originalImg[it] * 0.6f + (originalImg[it - cols] + originalImg[it + cols] + originalImg[it - 1]) * 0.1f;
- }
- }
- /**
- * convolutePart oblicza konwolucję wewnętrznych fragmentów macierzy, przekazywane fragmenty oznaczają fragment który
- * na którym ma zostać dokonana konwolucja
- * @param tmpImg - tablica wynikowa
- * @param originalImg - tablica wejściowa
- * @param parts - liczba pasów na które dzielona jest wewnętrzna macierz
- * @param currentPart - aktualna część
- */
- private void convoluteParts(float[] tmpImg, float[] originalImg, int parts, int currentPart){
- int partSize = rows / parts;
- int start = partSize * currentPart;
- int stop = Math.min(corner, start + partSize + 1);
- for (int i = start + 1; i < stop; i++){
- int row = i * rows;
- for (int j = 1; j < corner; j++){
- int column = row + j;
- tmpImg[column] = originalImg[column] * 0.6f + (originalImg[column - 1] + originalImg[column + 1] + originalImg[column - cols] + originalImg[column + cols]) * 0.1f;
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement