Martin Lísal listopad 2003 1 Často používané MPI příkazy (pokračování) 1.1 Příkazy pro kolektivní komunikaci (pokračování) 1.1.1 Distribuce informací nestejné velikosti na jednotlivé procesy call MPI_SCATTERV(sendbuf,sendcounts,displs,send_MPI_data_type, recvbuf,recvcount, recv_mpi_data_type, root,comm,ierr) Funkce příkazu je vysvětlena na obr. 1 a použití MPI SCATTERV demonstruje následující program. program scatterv implicit none include mpif.h preprocessor directive integer :: nprocs, # of processes myrank, my process rank ierr integer :: send_count(0:3), send count recv_count, receive count displ(0:3) displacement real :: sendmsg(10), send message recvmsg(4) recieve message start up MPI call MPI_INIT(ierr) find out how many processes are being used call MPI_COMM_SIZE(MPI_COMM_WORLD,nprocs,ierr) 1
if(nprocs > 4) stop " scatterv: nprocs > 4" get my process rank call MPI_COMM_RANK(MPI_COMM_WORLD,myrank,ierr) if(myrank == 0) then sendmsg=(/1.0,2.0,2.0,3.0,3.0,3.0,4.0,4.0,4.0,4.0/) send_count=(/1,2,3,4/) displ=(/0,1,3,6/) endif recv_count=myrank+1 call MPI_SCATTERV(sendmsg,send_count,displ,MPI_REAL, recvmsg,recv_count, MPI_REAL, 0,MPI_COMM_WORLD,ierr) print*," myrank =",myrank," recvmsg:",recvmsg shut down MPI call MPI_FINALIZE(ierr) end program scatterv 1.1.2 Shromáždění informací nestejné velikosti z jednotlivých procesů call MPI_GATHERV(sendbuf,sendcount, send_mpi_data_type, recvbuf,recvcounts,displs,recv_mpi_data_type, root,comm,ierr) Funkce příkazu je vysvětlena na obr. 2 a použití MPI GATHERV demonstruje následující program. 2
program gatherv implicit none include mpif.h preprocessor directive integer :: nprocs, # of processes myrank, my process rank ierr,i integer :: send_count, send count recv_count(0:3), receive count displ(0:3) displacement real :: sendmsg(4), send message recvmsg(10) recieve message start up MPI call MPI_INIT(ierr) find out how many processes are being used call MPI_COMM_SIZE(MPI_COMM_WORLD,nprocs,ierr) if(nprocs > 4) stop " gatherv: nprocs > 4" get my process rank call MPI_COMM_RANK(MPI_COMM_WORLD,myrank,ierr) do i=1,myrank+1 sendmsg(i)=myrank+1 enddo send_count=myrank+1 recv_count=(/1,2,3,4/) displ=(/0,1,3,6/) call MPI_GATHERV(sendmsg,send_count, MPI_REAL, recvmsg,recv_count,displ,mpi_real, 0,MPI_COMM_WORLD,ierr) 3
if(myrank == 0) then print*," recvmsg:",recvmsg endif shut down MPI call MPI_FINALIZE(ierr) end program gatherv Příkazy MPI GATHER a MPI GATHERV mají ještě ALL verze MPI ALLGATHER a MPI ALLGATHERV, které shromažďují informace na všechny procesy a tudíž neobsahují argument root. 1.1.3 Posílání informací stejné velikosti z jednotlivých procesů na všechny procesy call MPI_ALLTOALL(sendbuf,sendcount,send_MPI_data_type, recvbuf,recvcount,recv_mpi_data_type, comm,ierr) Funkce příkazu je vysvětlena na obr. 3 a použití MPI ALLTOALL demonstruje následující program. program alltoall implicit none include mpif.h preprocessor directive integer :: nprocs, # of processes myrank, my process rank ierr,i real :: sendmsg(4), send message recvmsg(4) start up MPI recieve message 4
call MPI_INIT(ierr) find out how many processes are being used call MPI_COMM_SIZE(MPI_COMM_WORLD,nprocs,ierr) if(nprocs > 4) stop " gather: nprocs > 4" get my process rank call MPI_COMM_RANK(MPI_COMM_WORLD,myrank,ierr) do i=1,nprocs sendmsg(i)=real(i+nprocs*myrank) enddo print*," myrank =",myrank," sendmsg:",sendmsg call MPI_ALLTOALL(sendmsg,1,MPI_REAL, recvmsg,1,mpi_real, MPI_COMM_WORLD,ierr) print*," myrank =",myrank," recvmsg:",recvmsg shut down MPI call MPI_FINALIZE(ierr) end program alltoall 1.1.4 Posílání informací nestejné velikosti z jednotlivých procesů na všechny procesy call MPI_ALLTOALLV(sendbuf,sendcounts,sdispls,send_MPI_data_type, recvbuf,recvcounts,rdispls,recv_mpi_data_type, comm,ierr) Funkce příkazu je vysvětlena na obr. 4 a použití MPI ALLTOALLV demonstruje následující program. 5
program alltoallv implicit none include mpif.h preprocessor directive integer :: nprocs, # of processes myrank, my process rank ierr,i integer :: scnt(0:3), send counts sdsp(0:3), send displacements rcnt(0:3), recv counts rdsp(0:3) recv displacements real :: sendmsg(10),recvmsg(16) sendmsg=(/1.0,2.0,2.0,3.0,3.0,3.0,4.0,4.0,4.0,4.0/) scnt=(/1,2,3,4/) sdsp=(/0,1,3,6/) start up MPI call MPI_INIT(ierr) find out how many processes are being used call MPI_COMM_SIZE(MPI_COMM_WORLD,nprocs,ierr) if(nprocs > 4) stop " gather: nprocs > 4" get my process rank call MPI_COMM_RANK(MPI_COMM_WORLD,myrank,ierr) sendmsg do i=1,10 sendmsg(i)=sendmsg(i)+real(nprocs*myrank) enddo print*," myrank =",myrank," sendmsg:",sendmsg rcnt and rdsp 6
do i=0,nprocs-1 rcnt(i)=myrank+1 rdsp(i)=i*(myrank+1) enddo call MPI_ALLTOALLV(sendmsg,scnt,sdsp,MPI_REAL, recvmsg,rcnt,rdsp,mpi_real, MPI_COMM_WORLD,ierr) print*," myrank =",myrank," recvmsg:",recvmsg shut down MPI call MPI_FINALIZE(ierr) end program alltoallv 1.2 Příkazy pro operace na proměnných distribuovaných na jednotlivých procesech call MPI_REDUCE(operand,result,count,MPI_data_type,operation,root, comm,ierr) Příkaz MPI REDUCE má ještě ALL verzi, které neobsahuje argument root. call MPI_SCAN(sendbuf,recvbuf,count,MPI_data_type,operation,comm,ierr) Funkce příkazu je vysvětlena na obr. 5 a použití MPI SCAN demonstruje následující program. 7
program scan implicit none include mpif.h preprocessor directive integer :: nprocs, # of processes myrank, my process rank ierr real :: sendmsg,recvmsg start up MPI call MPI_INIT(ierr) find out how many processes are being used call MPI_COMM_SIZE(MPI_COMM_WORLD,nprocs,ierr) if(nprocs > 4) stop " gather: nprocs > 4" get my process rank call MPI_COMM_RANK(MPI_COMM_WORLD,myrank,ierr) sendmsg sendmsg=real(myrank+1) call MPI_SCAN(sendmsg,recvmsg,1,MPI_REAL,MPI_SUM, MPI_COMM_WORLD,ierr) print*," myrank =",myrank," recvmsg:",recvmsg shut down MPI call MPI_FINALIZE(ierr) end program scan 8
call MPI_MPI_REDUCE_SCATTER(sendbuf,recvbuf,recvcounts,MPI_data_type, operation,comm,ierr) Funkce příkazu je vysvětlena na obr. 6 a použití MPI REDUCE SCATTER demonstruje následující program. program reduce_scatter implicit none include mpif.h preprocessor directive integer :: nprocs, # of processes myrank, my process rank ierr,i integer :: rcnt(0:3) recv counts real :: sendmsg(10), send message recvmsg(4) recieve message rcnt=(/1,2,3,4/) start up MPI call MPI_INIT(ierr) find out how many processes are being used call MPI_COMM_SIZE(MPI_COMM_WORLD,nprocs,ierr) if(nprocs > 4) stop " scatter: nprocs > 4" get my process rank call MPI_COMM_RANK(MPI_COMM_WORLD,myrank,ierr) do i=1,10 sendmsg(i)=real(i+myrank*10) enddo print*," myrank =",myrank," sendmsg:",sendmsg 9
call MPI_REDUCE_SCATTER(sendmsg,recvmsg,rcnt,MPI_REAL,MPI_SUM, MPI_COMM_WORLD,ierr) print*," myrank =",myrank," recvmsg =",recvmsg shut down MPI call MPI_FINALIZE(ierr) end program reduce_scatter 10
Obrázek 1: Schematický popis funkce příkazu MPI SCATTERV. Obrázek 2: Schematický popis funkce příkazu MPI GATHERV. Obrázek 3: Schematický popis funkce příkazu MPI ALLTOALL. 11
Obrázek 4: Schematický popis funkce příkazu MPI ALLTOALLV. Obrázek 5: Schematický popis funkce příkazu MPI SCAN. Obrázek 6: Schematický popis funkce příkazu MPI REDUCE SCATTER. 12
Figure 129. MPI_SCATTERV
Figure 131. MPI_GATHERV
Figure 134. MPI_ALLTOALL
Figure 135. MPI_ALLTOALLV
Figure 139. MPI_SCAN
Figure 140. MPI_REDUCE_SCATTER