58 INTEGER,
INTENT(IN) :: npow, output_unit
60#if defined(__parallel)
62 INTEGER :: i, itask, itests, j, jtask, left, nbufmax, &
63 ncount, ngrid, nloc, nprocs, ntot, partner, right, taskid, tag, source
64 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: rcount, rdispl, scount, sdispl
66 REAL(kind=
dp) :: maxdiff, t1, &
68 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: buffer1, buffer2, buffer3, &
70 REAL(kind=
dp),
ALLOCATABLE, &
71 DIMENSION(:, :) :: grid, grid2, grid3, &
72 send_timings, send_timings2
73 REAL(kind=
dp),
PARAMETER :: threshold = 1.0e-8_dp
80 ionode = comm%is_source()
81 IF (ionode .AND. output_unit > 0)
THEN
82 WRITE (output_unit, *)
"Running with ", nprocs
83 WRITE (output_unit, *)
"running messages with npow = ", npow
84 WRITE (output_unit, *)
"use MPI X in the input for larger (e.g. 6) of smaller (e.g. 3) messages"
85 IF (
modulo(nprocs, 2) /= 0)
WRITE (output_unit, *)
"Testing only with an even number of tasks"
88 IF (
modulo(nprocs, 2) /= 0)
RETURN
95 ALLOCATE (rcount(nprocs))
96 ALLOCATE (scount(nprocs))
97 ALLOCATE (sdispl(nprocs))
98 ALLOCATE (rdispl(nprocs))
99 ALLOCATE (buffer1(nbufmax))
100 ALLOCATE (buffer2(nbufmax))
101 ALLOCATE (buffer3(nbufmax))
102 ALLOCATE (grid(nloc, nprocs))
103 ALLOCATE (grid2(nloc, nprocs))
104 ALLOCATE (grid3(nloc, nprocs))
105 ALLOCATE (lgrid(nloc))
106 ALLOCATE (lgrid2(nloc))
107 ALLOCATE (lgrid3(nloc))
108 ALLOCATE (send_timings(0:nprocs - 1, 0:nprocs - 1))
109 ALLOCATE (send_timings2(0:nprocs - 1, 0:nprocs - 1))
114 send_timings = 0.0_dp
115 send_timings2 = 0.0_dp
120 IF (ionode .AND. output_unit > 0)
THEN
121 WRITE (output_unit, *)
"Testing in memory copies just 1 CPU "
122 WRITE (output_unit, *)
" could tell something about the motherboard / cache / compiler "
127 cpassert(ncount <= nbufmax)
128 DO j = 1, 3**(npow - i)
131 buffer2(1:ncount) = buffer1(1:ncount)
132 t2 = t2 + mpi_wtime() - t1 + threshold
135 IF (ionode .AND. output_unit > 0)
THEN
136 WRITE (output_unit,
'(I9,A,F12.4,A)') 8*ncount,
" Bytes ", (3**(npow - i))*ncount*8.0e-6_dp/t2,
" MB/s"
143 IF (ionode .AND. output_unit > 0)
THEN
144 WRITE (output_unit, *)
"Testing in memory copies all cpus"
145 WRITE (output_unit, *)
" is the memory bandwidth affected on an SMP machine ?"
150 cpassert(ncount <= nbufmax)
151 DO j = 1, 3**(npow - i)
154 buffer2(1:ncount) = buffer1(1:ncount)
155 t2 = t2 + mpi_wtime() - t1 + threshold
158 IF (ionode .AND. output_unit > 0)
THEN
159 WRITE (output_unit,
'(I9,A,F12.4,A)') 8*ncount,
" Bytes ", (3**(npow - i))*ncount*8.0e-6_dp/t2,
" MB/s"
166 IF (ionode .AND. output_unit > 0)
THEN
167 WRITE (output_unit, *)
"Testing truly point to point communication (i with j only)"
168 WRITE (output_unit, *)
" is there some different connection between i j (e.g. shared memory comm)"
171 IF (ionode .AND. output_unit > 0)
WRITE (output_unit, *)
"For messages of ", ncount*8,
" bytes"
172 cpassert(ncount <= nbufmax)
173 DO itask = 0, nprocs - 1
174 DO jtask = itask + 1, nprocs - 1
177 IF (taskid == itask)
THEN
178 CALL comm%send(buffer1, jtask, itask*jtask)
180 IF (taskid == jtask)
THEN
183 CALL comm%recv(buffer1, source, tag)
185 send_timings(itask, jtask) = mpi_wtime() - t1 + threshold
188 CALL comm%max(send_timings, 0)
189 IF (ionode .AND. output_unit > 0)
THEN
190 DO itask = 0, nprocs - 1
191 DO jtask = itask + 1, nprocs - 1
192 WRITE (output_unit,
'(I4,I4,F12.4,A)') itask, jtask, ncount*8.0e-6_dp/send_timings(itask, jtask),
" MB/s"
200 IF (ionode .AND. output_unit > 0)
THEN
201 WRITE (output_unit, *)
"Testing all nearby point to point communication (0,1)(2,3)..."
202 WRITE (output_unit, *)
" these could / should all be on the same shared memory node "
207 cpassert(ncount <= nbufmax)
208 DO j = 1, 3**(npow - i)
211 IF (
modulo(taskid, 2) == 0)
THEN
212 CALL comm%send(buffer1, taskid + 1, 0)
216 CALL comm%recv(buffer1, source, tag)
218 t2 = t2 + mpi_wtime() - t1 + threshold
221 IF (ionode .AND. output_unit > 0)
THEN
222 WRITE (output_unit,
'(I9,A,F12.4,A)') 8*ncount,
" Bytes ", (3**(npow - i))*ncount*8.0e-6_dp/t2,
" MB/s"
229 IF (ionode .AND. output_unit > 0)
THEN
230 WRITE (output_unit, *)
"Testing all far point to point communication (0,nprocs/2),(1,nprocs/2+1),.."
231 WRITE (output_unit, *)
" these could all be going over the network, and stress it a lot"
236 cpassert(ncount <= nbufmax)
237 DO j = 1, 3**(npow - i)
241 IF (taskid < nprocs/2)
THEN
242 CALL comm%send(buffer1, taskid + nprocs/2, 0)
244 source = taskid - nprocs/2
246 CALL comm%recv(buffer1, source, tag)
248 t2 = t2 + mpi_wtime() - t1 + threshold
251 IF (ionode .AND. output_unit > 0)
THEN
252 WRITE (output_unit,
'(I9,A,F12.4,A)') 8*ncount,
" Bytes ", (3**(npow - i))*ncount*8.0e-6_dp/t2,
" MB/s"
259 IF (ionode .AND. output_unit > 0)
THEN
260 WRITE (output_unit, *)
"Testing root to all broadcast "
261 WRITE (output_unit, *)
" using trees at least ? "
266 cpassert(ncount <= nbufmax)
267 DO j = 1, 3**(npow - i)
270 CALL comm%bcast(buffer1, 0)
271 t2 = t2 + mpi_wtime() - t1 + threshold
274 IF (ionode .AND. output_unit > 0)
THEN
275 WRITE (output_unit,
'(I9,A,F12.4,A)') 8*ncount,
" Bytes ", (3**(npow - i))*ncount*8.0e-6_dp/t2,
" MB/s"
282 IF (ionode .AND. output_unit > 0)
WRITE (output_unit, *)
"Test global summation (mpi_allreduce) "
286 cpassert(ncount <= nbufmax)
287 DO j = 1, 3**(npow - i)
291 CALL comm%sum(buffer2)
292 t2 = t2 + mpi_wtime() - t1 + threshold
295 IF (ionode .AND. output_unit > 0)
THEN
296 WRITE (output_unit,
'(I9,A,F12.4,A)') 8*ncount,
" Bytes ", (3**(npow - i))*ncount*8.0e-6_dp/t2,
" MB/s"
303 IF (ionode .AND. output_unit > 0)
THEN
304 WRITE (output_unit, *)
"Test all to all communication (mpi_alltoallv)"
305 WRITE (output_unit, *)
" mpi/network getting confused ? "
310 cpassert(ncount <= nbufmax)
311 scount = ncount/nprocs
312 rcount = ncount/nprocs
314 sdispl(j) = (j - 1)*(ncount/nprocs)
315 rdispl(j) = (j - 1)*(ncount/nprocs)
317 DO j = 1, 3**(npow - i)
320 CALL comm%alltoall(buffer1, scount, sdispl, buffer2, rcount, rdispl)
321 t2 = t2 + mpi_wtime() - t1 + threshold
324 IF (ionode .AND. output_unit > 0)
THEN
325 WRITE (output_unit,
'(I9,A,F12.4,A)') 8*(ncount/nprocs)*nprocs,
" Bytes ", &
326 (3**(npow - i))*(ncount/nprocs)*nprocs*8.0e-6_dp/t2,
" MB/s"
333 IF (ionode .AND. output_unit > 0)
THEN
334 WRITE (output_unit, *)
" Clean tests completed "
335 WRITE (output_unit, *)
" Testing MPI_REDUCE scatter"
339 IF (ionode .AND. output_unit > 0)
THEN
340 WRITE (output_unit, *)
"------------------------------- test ", itests,
" ------------------------"
345 grid(i, j) =
modulo(i*j*taskid, itests)
349 CALL comm%mp_sum_scatter_dv(grid, lgrid, rcount)
350 t2 = mpi_wtime() - t1 + threshold
352 IF (ionode .AND. output_unit > 0)
WRITE (output_unit, *)
"MPI_REDUCE_SCATTER ", t2
356 grid2(i, j) =
modulo(i*j*taskid, itests)
362 lgrid2(:) = lgrid2 + grid(:,
modulo(taskid - i, nprocs) + 1)
363 IF (i == nprocs)
EXIT
364 CALL comm%shift(lgrid2, 1)
366 t4 = mpi_wtime() - t3 + threshold
368 maxdiff = maxval(abs(lgrid2 - lgrid))
369 CALL comm%max(maxdiff)
370 IF (ionode .AND. output_unit > 0)
WRITE (output_unit, *)
"MPI_SENDRECV_REPLACE ", t4, maxdiff
372 cpassert(
modulo(nprocs, 2) == 0)
375 grid3(i, j) =
modulo(i*j*taskid, itests)
383 IF (
modulo(taskid, 2) == 0)
THEN
386 CALL comm%sendrecv(grid3(:, i + 1), partner, lgrid3, partner, 17)
387 grid3(:, i) = grid3(:, i) + lgrid3(:)
392 CALL comm%sendrecv(grid3(:, i), partner, lgrid3, partner, 17)
393 grid3(:, i + 1) = grid3(:, i + 1) + lgrid3(:)
396 t4 = mpi_wtime() - t3 + threshold
399 left =
modulo(taskid - 2, nprocs)
400 right =
modulo(taskid + 2, nprocs)
404 lgrid3(:) = lgrid3 + grid3(:,
modulo(taskid - i - 1, nprocs) + 1)
405 IF (i == nprocs - 1)
EXIT
406 CALL comm%shift(lgrid3, 2)
408 t5 = mpi_wtime() - t3 + threshold
411 maxdiff = maxval(abs(lgrid3 - lgrid))
412 CALL comm%max(maxdiff)
413 IF (ionode .AND. output_unit > 0)
WRITE (output_unit, *)
"INVOLVED SHIFT ", t4 + t5,
"(", t4,
",", t5,
")", maxdiff
428 DEALLOCATE (send_timings)
429 DEALLOCATE (send_timings2)
433 IF (output_unit > 0)
WRITE (output_unit, *)
"No MPI tests for a serial program"