Give every peer one contiguous run of the exchange buffer, with the chunks inside a run ordered by the key. Both ranks compute the same key for the same chunk, so sorting by it makes the sender's run and the receiver's run agree element for element without any handshake.
size_of(k) is the extent of chunk k in buffer elements; peers come out ascending, peer_off/peer_len delimit their runs, and off_of(k) is where chunk k starts.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | n | |||
| integer, | intent(in) | :: | pe_of(:) | |||
| integer, | intent(in) | :: | key_of(:) | |||
| integer, | intent(in) | :: | size_of(:) | |||
| integer, | intent(out) | :: | off_of(:) | |||
| integer, | intent(out) | :: | npeer | |||
| integer, | intent(out) | :: | peer(:) | |||
| integer, | intent(out) | :: | peer_off(:) | |||
| integer, | intent(out) | :: | peer_len(:) |
subroutine layout_runs(n, pe_of, key_of, size_of, off_of, npeer, peer,& peer_off, peer_len) use mod_global_parameters, only: npe integer, intent(in) :: n, pe_of(:), key_of(:), size_of(:) integer, intent(out) :: off_of(:), npeer, peer(:), peer_off(:), peer_len(:) integer :: k, p, j integer :: nper(0:npe-1), cursor(0:npe-1) integer, allocatable :: perm(:) npeer = 0 if (n == 0) return ! how long each peer's run is, in buffer elements nper = 0 do k = 1, n nper(pe_of(k)) = nper(pe_of(k)) + size_of(k) end do ! peers ascending, each run following the previous one j = 1 do p = 0, npe-1 if (nper(p) == 0) cycle npeer = npeer + 1 peer(npeer) = p peer_off(npeer) = j peer_len(npeer) = nper(p) cursor(p) = j j = j + nper(p) end do ! walk the chunks in ascending key order and hand each one the next slot ! in its peer's run, so the two ranks fill a run identically allocate(perm(n)) call rank_keys(n, key_of, perm) do k = 1, n j = perm(k) p = pe_of(j) off_of(j) = cursor(p) cursor(p) = cursor(p) + size_of(j) end do deallocate(perm) end subroutine layout_runs