Advertisement
Guest User

Untitled

a guest
Jan 22nd, 2019
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.19 KB | None | 0 0
  1. package io.konwolucja;
  2.  
  3. import java.util.concurrent.CompletableFuture;
  4.  
  5. /**
  6. * Zoptymalizowana konwolucja wykorzystująca wielowątkowść.
  7. *
  8. * Optymalizacja została osiągnięta m.in. poprzez zamianę dwuwymiarowej tablicy wartości (values[][]) na jednowymiarową
  9. * tablicę wartości (value[]).
  10. *
  11. * Najważniejszym elementem przyspieszający konwolucję jest wykorzystanie wielowątkowości. Szachownica została podzielona
  12. * na dwie główne części: krańce szachownicy (edges) oraz wnętrze szachownicy (parts). Następnie podzielone rówież zostało
  13. * wnętrze szachownicy na oddzielne pasy, na których dokonywana jest osobna konwolucja. Jest to możliwe dzięki temu, że
  14. * pomijane są w tym momencie, elementy graniczne, dla których trzeba było przyjąć inne warunki obliczania konwolucji
  15. * (elementy graniczne nie zawierają wokół siebie wszystkich pikseli, dlatego w zależności od krawędzi lub rogu brane są
  16. * pod uwagę tylko odpowiednie sąsiadujące piksele).
  17. *
  18. * Dodatkowo przed wykonaniem serii 200. konwolucji stworzyłem dodatkową tablicę przechowującą wyniki konwolucji. Celem
  19. * tego jest pominięcie tworzenia nowej tablicy przechowującej wyniki konwolucji. Wykonanie tego kroku zaoszczędziło około
  20. * 20% czasu w porównaniu do wersji, w której w każdej pojedynczej konwolucji tworzona została nowa tablica.
  21. *
  22. * Oprócz tego zoptymalizowałem jak najbardziej liczbę wykonanych operacji. Między innymi było to przechowanie wartości
  23. * brzegowej dla jednego wiersza w zmiennej corner (corner = rows-1). Dodatkowo sklejone zostały wszystkie operacje mnożenia.
  24. *
  25. *
  26. *
  27. */
  28.  
  29. public class ParallelConvolution extends PgmImage {
  30. float values[];
  31. int corner;
  32.  
  33. public ParallelConvolution(int dimensions){
  34. super(dimensions);
  35. values = new float[rows*cols];
  36. corner=rows-1;
  37. }
  38.  
  39. @Override
  40. public float getValue(int i, int j){
  41. return values[i*cols+j];
  42. }
  43.  
  44. @Override
  45. public void setValue(int i, int j, float val){
  46. values[i*cols+j]=val;
  47. }
  48.  
  49. @Override
  50. public void convolute(){
  51. float[] tmpImg = new float[rows*cols];
  52. final int threads = 8;
  53. CompletableFuture[] convolutionDiv = new CompletableFuture[threads+1];
  54. for (int i = 0; i<200; i+=2){
  55. convolutionDiv[0] = CompletableFuture.runAsync(()-> convoluteParts(tmpImg, values, threads, 0));
  56. convolutionDiv[1] = CompletableFuture.runAsync(()-> convoluteParts(tmpImg, values, threads, 1));
  57. convolutionDiv[2] = CompletableFuture.runAsync(()-> convoluteParts(tmpImg, values, threads, 2));
  58. convolutionDiv[3] = CompletableFuture.runAsync(()-> convoluteParts(tmpImg, values, threads, 3));
  59. convolutionDiv[4] = CompletableFuture.runAsync(()-> convoluteParts(tmpImg, values, threads, 4));
  60. convolutionDiv[5] = CompletableFuture.runAsync(()-> convoluteParts(tmpImg, values, threads, 5));
  61. convolutionDiv[6] = CompletableFuture.runAsync(()-> convoluteParts(tmpImg, values, threads, 6));
  62. convolutionDiv[7] = CompletableFuture.runAsync(()-> convoluteParts(tmpImg, values, threads, 7));
  63. convolutionDiv[8] = CompletableFuture.runAsync(()-> convoluteEdges(tmpImg, values));
  64. CompletableFuture.allOf(convolutionDiv).join();
  65.  
  66. convolutionDiv[0] = CompletableFuture.runAsync(()-> convoluteParts(values, tmpImg, threads, 0));
  67. convolutionDiv[1] = CompletableFuture.runAsync(()-> convoluteParts(values, tmpImg, threads, 1));
  68. convolutionDiv[2] = CompletableFuture.runAsync(()-> convoluteParts(values, tmpImg, threads, 2));
  69. convolutionDiv[3] = CompletableFuture.runAsync(()-> convoluteParts(values, tmpImg, threads, 3));
  70. convolutionDiv[4] = CompletableFuture.runAsync(()-> convoluteParts(values, tmpImg, threads, 4));
  71. convolutionDiv[5] = CompletableFuture.runAsync(()-> convoluteParts(values, tmpImg, threads, 5));
  72. convolutionDiv[6] = CompletableFuture.runAsync(()-> convoluteParts(values, tmpImg, threads, 6));
  73. convolutionDiv[7] = CompletableFuture.runAsync(()-> convoluteParts(values, tmpImg, threads, 7));
  74. convolutionDiv[8] = CompletableFuture.runAsync(()-> convoluteEdges(values, tmpImg));
  75. CompletableFuture.allOf(convolutionDiv).join();
  76. }
  77. }
  78.  
  79. @Override
  80. public void testConvolution(int loops){
  81. long startTime = System.nanoTime();
  82. convolute();
  83. long timeElapsed = System.nanoTime() - startTime;
  84. System.out.println(timeElapsed/1000000);
  85. }
  86.  
  87. /**
  88. * convoluteEdges() jest funkcją obliczającą konwolucję tylko i wyłącznie dla wartości brzegowych, tzn. krawędzi bocznych,
  89. * górnych i dolnych oraz wszystkich czterech rogów.
  90. * @param tmpImg - tablica przechowująca wynik konwolucji
  91. * @param originalImg - tablica wejściowa z wartościami poszczególnych pikseli w aktualnym momencie
  92. */
  93. private void convoluteEdges(float[] tmpImg, float[] originalImg){
  94. tmpImg[0] = originalImg[0] * 0.6f + (originalImg[1] + originalImg[rows]) * 0.1f;
  95. tmpImg[corner] = originalImg[corner] * 0.6f + (originalImg[corner] + originalImg[corner]) * 0.1f;
  96. int it = corner * cols;
  97. tmpImg[corner * rows] = originalImg[it] * 0.6f + (originalImg[it + 1] + originalImg[it - cols]) * 0.1f;
  98. it += corner;
  99. tmpImg[it] = originalImg[it] * 0.6f + (originalImg[it - 1] + originalImg[it - cols]) * 0.1f;
  100.  
  101. for (int i = 1; i < corner; ++i){
  102. tmpImg[i] = originalImg[i] * 0.6f + (originalImg[i - 1] + originalImg[i + 1] + originalImg[cols + i]) * 0.1f;
  103. it = i * cols;
  104. tmpImg[it] = originalImg[it] * 0.6f + (originalImg[it - cols] + originalImg[it + cols] + originalImg[it + 1]) * 0.1f;
  105. it = corner * rows + i;
  106. tmpImg[corner * rows + i] = originalImg[it] * 0.6f + (originalImg[it - 1] + originalImg[it + 1] + originalImg[it - cols]) * 0.1f;
  107. it = i * rows + corner;
  108. tmpImg[it] = originalImg[it] * 0.6f + (originalImg[it - cols] + originalImg[it + cols] + originalImg[it - 1]) * 0.1f;
  109. }
  110. }
  111.  
  112. /**
  113. * convolutePart oblicza konwolucję wewnętrznych fragmentów macierzy, przekazywane fragmenty oznaczają fragment który
  114. * na którym ma zostać dokonana konwolucja
  115. * @param tmpImg - tablica wynikowa
  116. * @param originalImg - tablica wejściowa
  117. * @param parts - liczba pasów na które dzielona jest wewnętrzna macierz
  118. * @param currentPart - aktualna część
  119. */
  120. private void convoluteParts(float[] tmpImg, float[] originalImg, int parts, int currentPart){
  121. int partSize = rows / parts;
  122. int start = partSize * currentPart;
  123. int stop = Math.min(corner, start + partSize + 1);
  124.  
  125. for (int i = start + 1; i < stop; i++){
  126. int row = i * rows;
  127. for (int j = 1; j < corner; j++){
  128. int column = row + j;
  129. tmpImg[column] = originalImg[column] * 0.6f + (originalImg[column - 1] + originalImg[column + 1] + originalImg[column - cols] + originalImg[column + cols]) * 0.1f;
  130. }
  131. }
  132. }
  133. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement