MPI Fini
This commit is contained in:
parent
7037335bff
commit
65b8e4294d
BIN
deadlock.png
Normal file
BIN
deadlock.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
@ -1212,6 +1212,25 @@ $ python pi_server_python.py &
|
|||||||
- Receive:
|
- Receive:
|
||||||
~MPI_RECV(buffer, count, datatype, source, tag, communicator,
|
~MPI_RECV(buffer, count, datatype, source, tag, communicator,
|
||||||
status, ierror)~
|
status, ierror)~
|
||||||
|
|
||||||
|
** Synchronous or asynchronous?
|
||||||
|
|
||||||
|
- ~MPI_Ssend~ :: Blocking synchronous send. Returns upon notification
|
||||||
|
that the message has been received (safe).
|
||||||
|
- ~MPI_Isend~ :: Non-blocking send. Returns immediately (dangerous).
|
||||||
|
- ~MPI_Send~ :: Returns when the send buffer is ready for
|
||||||
|
use. Non-deterministic: depends on MPI implementation, size of
|
||||||
|
the data, number of ranks, ... (dangerous)
|
||||||
|
|
||||||
|
#+LATEX: \begin{alertblock}{Important}
|
||||||
|
- Writing the program and Debugging:
|
||||||
|
- /Always/ use ~MPI_Ssend~
|
||||||
|
- Use ~MPI_Isend~ only when ~MPI_Ssend~ is irrelevant
|
||||||
|
- Once the code is well checked
|
||||||
|
- You can replace ~MPI_Ssend~ by ~MPI_Send~ as an optimization.
|
||||||
|
- If ~MPI_Send~ is still too slow, consider rewriting for ~MPI_Isend~
|
||||||
|
#+LATEX: \end{alertblock}
|
||||||
|
|
||||||
** Point-to-point communication (Python)
|
** Point-to-point communication (Python)
|
||||||
|
|
||||||
#+begin_src python :tangle Codes/mpi_rank.py
|
#+begin_src python :tangle Codes/mpi_rank.py
|
||||||
@ -1225,7 +1244,7 @@ def main():
|
|||||||
if rank == 0:
|
if rank == 0:
|
||||||
data = 42
|
data = 42
|
||||||
print("Before: Rank: %d Size: %d Data: %d"%(rank, size, data))
|
print("Before: Rank: %d Size: %d Data: %d"%(rank, size, data))
|
||||||
comm.send(data, dest=1, tag=11)
|
comm.ssend(data, dest=1, tag=11)
|
||||||
print("After : Rank: %d Size: %d Data: %d"%(rank, size, data))
|
print("After : Rank: %d Size: %d Data: %d"%(rank, size, data))
|
||||||
elif rank == 1:
|
elif rank == 1:
|
||||||
data = 0
|
data = 0
|
||||||
@ -1278,7 +1297,7 @@ program test_rank
|
|||||||
if (rank == 0) then
|
if (rank == 0) then
|
||||||
data = 42
|
data = 42
|
||||||
print *, "Before: Rank:", rank, "Size:", size, "Data: ", data
|
print *, "Before: Rank:", rank, "Size:", size, "Data: ", data
|
||||||
call MPI_SEND(data, 1, MPI_INTEGER, 1, 11, MPI_COMM_WORLD, ierr)
|
call MPI_SSEND(data, 1, MPI_INTEGER, 1, 11, MPI_COMM_WORLD, ierr)
|
||||||
print *, "After : Rank:", rank, "Size:", size, "Data: ", data
|
print *, "After : Rank:", rank, "Size:", size, "Data: ", data
|
||||||
|
|
||||||
else if (rank == 1) then
|
else if (rank == 1) then
|
||||||
@ -1293,18 +1312,223 @@ program test_rank
|
|||||||
end program
|
end program
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
** Deadlocks
|
||||||
|
#+LATEX: \begin{columns}
|
||||||
|
#+LATEX: \begin{column}{0.3\textwidth}
|
||||||
|
#+ATTR_LATEX: :height 0.8 \textheight
|
||||||
|
[[./deadlock.png]]
|
||||||
|
#+LATEX: \end{column}
|
||||||
|
#+LATEX: \begin{column}{0.7\textwidth}
|
||||||
|
|
||||||
|
#+LATEX: \begin{exampleblock}{Deadlock}
|
||||||
|
Each process waits for a message coming from another process
|
||||||
|
#+LATEX: \end{exampleblock}
|
||||||
|
|
||||||
|
Example: round-robin
|
||||||
|
#+LATEX: \end{column}
|
||||||
|
#+LATEX: \end{columns}
|
||||||
|
|
||||||
|
** Deadlock example
|
||||||
|
|
||||||
|
#+begin_src fortran :tangle Codes/mpi_deadlock.f90
|
||||||
|
program deadlock
|
||||||
|
use mpi
|
||||||
|
implicit none
|
||||||
|
integer :: rank, size, value, source, destination, ierr
|
||||||
|
integer, parameter :: tag=100
|
||||||
|
|
||||||
|
call MPI_INIT(ierr)
|
||||||
|
call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
|
||||||
|
call MPI_COMM_SIZE(MPI_COMM_WORLD, size, ierr)
|
||||||
|
|
||||||
|
source = mod(size+rank-1, size)
|
||||||
|
destination = mod(rank+1 , size)
|
||||||
|
|
||||||
|
call MPI_SSEND(rank+10, 1, MPI_INTEGER, destination, tag, MPI_COMM_WORLD, ierr)
|
||||||
|
call MPI_RECV(value, 1, MPI_INTEGER, source, tag, MPI_COMM_WORLD, MPI_STATUS_IGNORE, ierr)
|
||||||
|
|
||||||
|
print *, rank, 'received', value, 'from', source
|
||||||
|
call MPI_FINALIZE(ierr)
|
||||||
|
end program
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Send-receive
|
||||||
|
|
||||||
|
The ~MPI_Sendrecv~ function sends and receives a message /simultaneously/.
|
||||||
|
It can avoid deadlocks.
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
MPI_SENDRECV(SENDBUF, SENDCOUNT, SENDTYPE, DEST, SENDTAG,
|
||||||
|
RECVBUF, RECVCOUNT, RECVTYPE, SOURCE, RECVTAG,
|
||||||
|
COMM, STATUS, IERROR)
|
||||||
|
|
||||||
|
<type> SENDBUF(*), RECVBUF(*)
|
||||||
|
INTEGER :: SENDCOUNT, SENDTYPE, DEST, SENDTAG
|
||||||
|
INTEGER :: RECVCOUNT, RECVTYPE, SOURCE, RECVTAG, COMM
|
||||||
|
INTEGER :: STATUS(MPI_STATUS_SIZE), IERROR
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
** Send-receive
|
||||||
|
|
||||||
|
#+begin_src fortran :tangle Codes/mpi_sendrecv.f90
|
||||||
|
program sendrecv
|
||||||
|
use mpi
|
||||||
|
implicit none
|
||||||
|
integer :: rank, size, value, source, destination, ierr
|
||||||
|
integer, parameter :: tag=100
|
||||||
|
|
||||||
|
call MPI_INIT(ierr)
|
||||||
|
call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
|
||||||
|
call MPI_COMM_SIZE(MPI_COMM_WORLD, size, ierr)
|
||||||
|
|
||||||
|
source = mod(size+rank-1, size)
|
||||||
|
destination = mod(rank+1 , size)
|
||||||
|
|
||||||
|
call MPI_SENDRECV(rank+10, 1, MPI_INTEGER, destination, tag, value, &
|
||||||
|
1, MPI_INTEGER, source, tag, MPI_COMM_WORLD, &
|
||||||
|
MPI_STATUS_IGNORE, ierr)
|
||||||
|
|
||||||
|
print *, rank, 'received', value, 'from', source
|
||||||
|
|
||||||
|
call MPI_FINALIZE(ierr)
|
||||||
|
end program
|
||||||
|
#+end_src
|
||||||
|
|
||||||
** Collective communications
|
** Collective communications
|
||||||
|
|
||||||
*** One-to-all
|
*** One-to-all
|
||||||
- Broadcast: send same data to all
|
- ~MPI_Bcast~ :: Broadcast the same data to all
|
||||||
- Scatter: distribute an array
|
- ~MPI_Scatter~ :: distribute an array
|
||||||
*** All-to-one
|
*** All-to-one
|
||||||
- Reduction: Sum/product/... of data coming from all ranks
|
- ~MPI_Reduce~ :: Sum/product/... of data coming from all ranks
|
||||||
- Gather: collect a distributed array
|
- ~Gather~ :: collect a distributed array
|
||||||
*** All-to-all
|
*** All-to-all
|
||||||
- Reduction and broadcast
|
- ~MPI_Barrier~ :: Global synchronization
|
||||||
|
- ~MPI_AllReduce~ :: Reduce and broadcast the result
|
||||||
|
- ~MPI_AllGather~ :: Gather and broadcast the result
|
||||||
|
- ~MPI_Alltoall~ :: Gather and scatter the result
|
||||||
|
|
||||||
|
** Computation of \pi with MPI
|
||||||
|
|
||||||
|
\[
|
||||||
|
\pi = 4 \int_{0}^{1} \sqrt{1-x^2} dx
|
||||||
|
\sim 4 \sum_{i=1}^M \sqrt{1-x_i^2}\, \Delta x
|
||||||
|
\]
|
||||||
|
\[
|
||||||
|
\; \text{with} \;
|
||||||
|
0 \le x_i \le 1 \;\text{and}\; \Delta x = x_{i+1} - x_i
|
||||||
|
\]
|
||||||
|
|
||||||
|
- Define a grid of $M$ points
|
||||||
|
- Split the grid on $N$ processes
|
||||||
|
- Each process computes part of the sum
|
||||||
|
- The partial sums are reduced on the master process
|
||||||
|
|
||||||
|
** Computation of \pi with MPI (Python)
|
||||||
|
|
||||||
|
#+begin_src python :tangle Codes/mpi_pi.py
|
||||||
|
#!/usr/bin/env python
|
||||||
|
from mpi4py import MPI
|
||||||
|
import sys
|
||||||
|
from math import sqrt
|
||||||
|
|
||||||
|
def main():
|
||||||
|
comm = MPI.COMM_WORLD
|
||||||
|
rank = comm.Get_rank()
|
||||||
|
size = comm.Get_size()
|
||||||
|
|
||||||
|
M = int(sys.argv[1]) # Total Number of grid points
|
||||||
|
M_local = (M-1) // size + 1 # Number of grid points to compute locally
|
||||||
|
istart = rank * M_local # Beginning of interval
|
||||||
|
iend = min(istart + M_local, M) # End of interval
|
||||||
|
dx = 1./float(M) # Delta x
|
||||||
|
|
||||||
|
sum = 0.
|
||||||
|
for i in range(istart, iend):
|
||||||
|
x = (i+0.5)*dx
|
||||||
|
sum += sqrt(1.-x*x)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Computation of \pi with MPI (Python)
|
||||||
|
|
||||||
|
#+begin_src python :tangle Codes/mpi_pi.py
|
||||||
|
result = 4. * dx * sum
|
||||||
|
pi = comm.reduce(result, MPI.SUM)
|
||||||
|
print("%10f -> %10f : %10f"%(istart*dx, iend*dx, result))
|
||||||
|
if rank == 0:
|
||||||
|
print("Result = ", pi)
|
||||||
|
|
||||||
|
if __name__ == "__main__": main()
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+LATEX: \begin{columns}
|
||||||
|
#+LATEX: \begin{column}{0.6\textwidth}
|
||||||
|
#+begin_src text
|
||||||
|
$ mpiexec -n 4 python mpi_pi.py 100000000
|
||||||
|
0.000000 -> 0.250000 : 0.989483
|
||||||
|
Result = 3.1415926535902408
|
||||||
|
0.250000 -> 0.500000 : 0.923740
|
||||||
|
0.500000 -> 0.750000 : 0.775058
|
||||||
|
0.750000 -> 1.000000 : 0.453312
|
||||||
|
#+end_src
|
||||||
|
#+LATEX: \end{column}
|
||||||
|
#+LATEX: \begin{column}{0.3\textwidth}
|
||||||
|
#+ATTR_LATEX: :width \textwidth
|
||||||
|
[[./pi_v1.png]]
|
||||||
|
#+LATEX: \end{column}
|
||||||
|
#+LATEX: \end{columns}
|
||||||
|
|
||||||
|
** Alternate Computation of \pi with MPI (Python)
|
||||||
|
|
||||||
|
#+begin_src python :tangle Codes/mpi_pi_v2.py
|
||||||
|
#!/usr/bin/env python
|
||||||
|
from mpi4py import MPI
|
||||||
|
import sys
|
||||||
|
from math import sqrt
|
||||||
|
|
||||||
|
def main():
|
||||||
|
comm = MPI.COMM_WORLD
|
||||||
|
rank = comm.Get_rank()
|
||||||
|
size = comm.Get_size()
|
||||||
|
|
||||||
|
M = int(sys.argv[1]) # Total Number of grid points
|
||||||
|
dx = 1./float(M) # Delta x
|
||||||
|
|
||||||
|
sum = 0.
|
||||||
|
for i in range(rank, M, size):
|
||||||
|
x = (i+0.5)*dx
|
||||||
|
sum += sqrt(1.-x*x)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
** Computation of \pi with MPI (Python)
|
||||||
|
|
||||||
|
#+begin_src python :tangle Codes/mpi_pi_v2.py
|
||||||
|
result = 4. * dx * sum
|
||||||
|
pi = comm.reduce(result, MPI.SUM)
|
||||||
|
print(rank, result)
|
||||||
|
if rank == 0:
|
||||||
|
print("Result = ", pi)
|
||||||
|
|
||||||
|
if __name__ == "__main__": main()
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+LATEX: \begin{columns}
|
||||||
|
#+LATEX: \begin{column}{0.6\textwidth}
|
||||||
|
#+begin_src text
|
||||||
|
$ mpiexec -n 8 python mpi_pi_v2.py 100000000
|
||||||
|
0 0.7853981783959749
|
||||||
|
Result = 3.1415926535901777
|
||||||
|
2 0.7853981583983196
|
||||||
|
3 0.7853981483981102
|
||||||
|
1 0.7853981683977732
|
||||||
|
#+end_src
|
||||||
|
#+LATEX: \end{column}
|
||||||
|
#+LATEX: \begin{column}{0.3\textwidth}
|
||||||
|
#+ATTR_LATEX: :width \textwidth
|
||||||
|
[[./pi_v2.png]]
|
||||||
|
#+LATEX: \end{column}
|
||||||
|
#+LATEX: \end{columns}
|
||||||
|
|
||||||
** Deadlocks
|
|
||||||
* OpenMP
|
* OpenMP
|
||||||
|
|
||||||
* Exercises
|
* Exercises
|
||||||
@ -1527,6 +1751,19 @@ digraph G {
|
|||||||
|
|
||||||
#+RESULTS:
|
#+RESULTS:
|
||||||
|
|
||||||
|
#+BEGIN_SRC dot :output file :file deadlock.png
|
||||||
|
digraph G {
|
||||||
|
graph [layout=dot]
|
||||||
|
A -> B ;
|
||||||
|
B -> C ;
|
||||||
|
C -> D ;
|
||||||
|
D -> A ;
|
||||||
|
}
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
#+RESULTS:
|
||||||
|
[[file:deadlock.png]]
|
||||||
|
|
||||||
* Exam questions :noexport:
|
* Exam questions :noexport:
|
||||||
|
|
||||||
|
|
||||||
@ -1600,7 +1837,7 @@ digraph G {
|
|||||||
(setq org-latex-listings 'minted)
|
(setq org-latex-listings 'minted)
|
||||||
(setq org-latex-custom-lang-environments nil)
|
(setq org-latex-custom-lang-environments nil)
|
||||||
(setq org-latex-minted-options
|
(setq org-latex-minted-options
|
||||||
'(("frame" "lines")
|
'(
|
||||||
("fontsize" "\\scriptsize")
|
("fontsize" "\\scriptsize")
|
||||||
("linenos" "")))
|
("linenos" "")))
|
||||||
(setq org-latex-to-pdf-process
|
(setq org-latex-to-pdf-process
|
||||||
|
Loading…
Reference in New Issue
Block a user