AUTH's THMMY "Parallel and distributed systems" course assignments.
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. #
  2. # ---------------------------------------------
  3. # Bitonic v0.5 functionality
  4. #
  5. function exchange(localid, remoteid)
  6. # if verbose
  7. # println("Exchange local data from $localid with partner $remoteid")
  8. # end
  9. nothing # We have all data here ;)
  10. end
  11. function minmax(data, localid, remoteid, keepsmall)
  12. # Keep min-max on local data
  13. temp = copy(data[localid+1, :])
  14. if (keepsmall)
  15. view(data, localid+1, :) .= min.(temp, data[remoteid+1, :])
  16. view(data, remoteid+1, :) .= max.(temp, data[remoteid+1, :])
  17. else
  18. view(data, localid+1, :) .= max.(temp, data[remoteid+1, :])
  19. view(data, remoteid+1, :) .= min.(temp, data[remoteid+1, :])
  20. end
  21. end
  22. function is_bitonic(arr)
  23. n = length(arr)
  24. if n <= 2
  25. return true # Any sequence of length <= 2 is bitonic
  26. end
  27. # State for state machine. 1: inc, -1: dec, 0: z-state
  28. state = 0
  29. inc_count = 0
  30. dec_count = 0
  31. ret = false
  32. for i in 1:n-1
  33. # Find the first order
  34. if state == 0
  35. if arr[i] > arr[i+1]
  36. state = -1
  37. dec_count += 1
  38. elseif arr[i] < arr[i+1]
  39. state = 1
  40. inc_count += 1
  41. end
  42. elseif state == -1 # decreasing
  43. if arr[i] < arr[i + 1]
  44. state = 1
  45. inc_count += 1
  46. end
  47. elseif state == 1 # increasing
  48. if arr[i] > arr[i+1]
  49. state = -1
  50. dec_count += 1
  51. end
  52. end
  53. end
  54. if inc_count <= 1 && dec_count <= 1
  55. ret = true # Sequence is bitonic
  56. elseif inc_count == 2 && dec_count == 1
  57. ret = (arr[1] >= arr[n])
  58. elseif inc_count == 1 && dec_count == 2
  59. ret = (arr[1] <= arr[n])
  60. end
  61. ret
  62. end
  63. function is_sort(arr)
  64. # State for state machine. 1: inc, -1: dec, 0: z-state
  65. state = 0
  66. inc_count = 0
  67. dec_count = 0
  68. for i in 1:length(arr)-1
  69. # Find the first order
  70. if state == 0
  71. if arr[i] > arr[i+1]
  72. state = -1
  73. dec_count += 1
  74. elseif arr[i] < arr[i+1]
  75. state = 1
  76. inc_count += 1
  77. end
  78. elseif state == -1 # decreasing
  79. if arr[i] < arr[i + 1]
  80. state = 1
  81. inc_count += 1
  82. end
  83. elseif state == 1 # increasing
  84. if arr[i] > arr[i+1]
  85. state = -1
  86. dec_count += 1
  87. end
  88. end
  89. end
  90. ret = ((inc_count + dec_count) == 1) ? state : 0
  91. ret
  92. end
  93. function sort_network!(data, n, depth)
  94. nodes = 0:n-1
  95. bitonicFlag = zeros(Int8, size(data, 1))
  96. sortFlag = zeros(Int8, size(data, 1))
  97. for step = depth-1:-1:0
  98. partnerid = nodes .⊻ (1 << step)
  99. direction = (nodes .& (1 << depth)) .== 0 .& (nodes .< partnerid)
  100. keepsmall = ((nodes .< partnerid) .& direction) .| ((nodes .> partnerid) .& .!direction)
  101. if verbose
  102. println("depth: $depth | step: $step | partner: $partnerid | keepsmall: $keepsmall")
  103. end
  104. # exchange with partner and keep small or large (run all MPI nodes)
  105. for i in 0:n-1
  106. if (i < partnerid[i+1])
  107. exchange(i, partnerid[i+1])
  108. minmax(data, i, partnerid[i+1], keepsmall[i+1])
  109. end
  110. end
  111. if verbose
  112. for i in 1:size(data, 1)
  113. bitonicFlag[i] = is_bitonic(data[i, :])
  114. sortFlag[i] = is_sort(data[i, :])
  115. end
  116. println("depth: $depth | step: $step | bitonicFlag: $bitonicFlag | sorfFlag: $sortFlag")
  117. end
  118. end
  119. end
  120. """
  121. distbitonic!(p, data)
  122. distributed bitonic sort v1 using elbow merge locally except for the first step
  123. p: The number of processes
  124. data: (p, N/p) array
  125. """
  126. function distbitonic!(p, data)
  127. q = Int(log2(p)) # CPU order
  128. pid = 0:p-1
  129. ascending = mod.(pid,2) .== 0
  130. if verbose
  131. println("ascending: $ascending")
  132. end
  133. # local full sort here (run all MPI nodes)
  134. for i in 1:p
  135. sort!(view(data, i, :), rev = !ascending[i])
  136. end
  137. for depth = 1:q
  138. sort_network!(data, p, depth)
  139. ascending = (pid .& (1 << depth)) .== 0
  140. if verbose
  141. println("ascending: $ascending")
  142. end
  143. # local elbowmerge here (run all MPI nodes)
  144. for i in 1:p
  145. sort!(view(data, i, :), rev = !ascending[i])
  146. end
  147. end
  148. nothing
  149. end
  150. #
  151. # Homework setup
  152. # ---------------------------------------------
  153. #
  154. p::Int8 = 3 # The order of number of "processors"
  155. q::Int8 = 8 # The data size order (power of 2) of each "processor"
  156. verbose = false;
  157. # Run Script
  158. # ---------------------------------------------
  159. P::Int = 2^p
  160. Q::Int = 2^q
  161. N::Int = 2^(q+p)
  162. println("Distributed bitonic (v1) test")
  163. println("p: $p -> Number of processors: $P")
  164. println("q: $q -> Data length for each node: $Q, Total: $(P*Q)")
  165. println("Create an $P x $Q array")
  166. Data = rand(Int8, P, Q)
  167. println("Sort array with $P (MPI) nodes")
  168. @time distbitonic!(P, Data)
  169. # Test
  170. if issorted(vec(permutedims(Data)))
  171. println("Test: Passed")
  172. else
  173. println("Test: Failed")
  174. end