115 wiersze
3.0 KiB
Julia
115 wiersze
3.0 KiB
Julia
#
|
|
# ---------------------------------------------
|
|
# Bitonic v0.5 functionality
|
|
#
|
|
|
|
function partner(node, step)
|
|
partner = node + ((((node+step) % 2) == 0) ? 1 : -1)
|
|
end
|
|
|
|
function active(id, p)
|
|
ret = (id >= 0) && (id < p)
|
|
end
|
|
|
|
function exchange(localid, remoteid)
|
|
if verbose
|
|
println("Exchange local data from $localid with partner $remoteid")
|
|
end
|
|
nothing # We have all data here ;)
|
|
end
|
|
|
|
function minmax(data, localid, remoteid, keepsmall)
|
|
# Keep min-max on local data
|
|
temp = copy(data[localid+1, :])
|
|
if (keepsmall)
|
|
view(data, localid+1, :) .= min.(temp, data[remoteid+1, :])
|
|
view(data, remoteid+1, :) .= max.(temp, data[remoteid+1, :])
|
|
else
|
|
view(data, localid+1, :) .= max.(temp, data[remoteid+1, :])
|
|
view(data, remoteid+1, :) .= min.(temp, data[remoteid+1, :])
|
|
end
|
|
end
|
|
|
|
"""
|
|
distbubletonic!(p, data)
|
|
|
|
distributed bitonic v0.5 sort using a "bubble sort"-like functionality to propagate large and small
|
|
items between nodes.
|
|
|
|
p: The number of processes
|
|
data: (p, N/p) array
|
|
"""
|
|
function distbubletonic!(p, data)
|
|
|
|
pid = 0:p-1
|
|
ascending = mod.(pid,2) .== 0
|
|
if verbose
|
|
println("ascending: $ascending")
|
|
end
|
|
# local full sort here (run all MPI nodes)
|
|
for i in 1:p
|
|
sort!(view(data, i, :), rev = !ascending[i])
|
|
end
|
|
for step in 0:p-1
|
|
direction = [true for x = 1:p]
|
|
partnerid = partner.(pid, step)
|
|
activeids = active.(partnerid, p)
|
|
keepsmall = pid .< partnerid
|
|
if verbose
|
|
println("step: $step | active ids: $activeids | partner: $partnerid | keepsmall: $keepsmall")
|
|
end
|
|
# exchange with partner and keep small or large (run all MPI nodes)
|
|
for i in 0:p-1
|
|
l_idx = i+1
|
|
r_idx = partnerid[i+1]+1
|
|
if activeids[l_idx] && i < partnerid[l_idx]
|
|
exchange(i, partnerid[l_idx])
|
|
minmax(data, i, partnerid[l_idx], keepsmall[l_idx])
|
|
sort!(view(data, l_idx, :), rev = !ascending[l_idx]) # elbow sort here
|
|
sort!(view(data, r_idx, :), rev = !ascending[r_idx]) # elbow sort here
|
|
end
|
|
end
|
|
end
|
|
# [optional] reverse the odd positions (run all MPI nodes)
|
|
for i in 1:p
|
|
if !ascending[i]
|
|
sort!(view(data, i, :))
|
|
end
|
|
end
|
|
nothing
|
|
end
|
|
|
|
|
|
|
|
#
|
|
# Homework setup
|
|
# ---------------------------------------------
|
|
#
|
|
p::Int8 = 3 # The order of number of "processors"
|
|
q::Int8 = 8 # The data size order (power of 2) of each "processor"
|
|
verbose = false;
|
|
|
|
|
|
# Run Script
|
|
# ---------------------------------------------
|
|
P::Int = 2^p
|
|
Q::Int = 2^q
|
|
N::Int = 2^(q+p)
|
|
|
|
println("Distributed Bubbletonic (v0.5) test")
|
|
println("p: $p -> Number of processors: $P")
|
|
println("q: $q -> Data length for each node: $Q, Total: $(P*Q)")
|
|
|
|
println("Create an $P x $Q array")
|
|
Data = rand(Int8, P, Q)
|
|
|
|
println("Sort array with $P (MPI) nodes")
|
|
@time distbubletonic!(P, Data)
|
|
|
|
# Test
|
|
if issorted(vec(permutedims(Data)))
|
|
println("Test: Passed")
|
|
else
|
|
println("Test: Failed")
|
|
end
|