AUTH's THMMY "Parallel and distributed systems" course assignments.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

bitonic_v1.jl 5.1 KiB

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