Early 80s:
1992:
After finalization:
1994: MPI-1
1998: MPI-2
2012: MPI-3
Open a terminal and run the following commands. For ssh-keygen
, hit Enter
for everything and don't put in a password when asked.
$ cd ~
$ sudo yum -y group install "Development Tools"
$ wget https://download.open-mpi.org/release/open-mpi/v3.1/openmpi-3.1.2.tar.gz
$ tar xzf openmpi-3.1.2.tar.gz
$ cd openmpi-3.1.2
$ ./configure --prefix=/opt/openmpi/3.1.2
$ sudo make
$ sudo make all install
$ echo "export PATH='$PATH:/opt/openmpi/3.1.2/bin'" >> ~/.bashrc
$ echo "export LD_LIBRARY_PATH='$LD_LIBRARY_PATH:/opt/openmpi/3.1.2/lib/'" >> ~/.bashrc
$ source ~/.bashrc
$ cd ~
$ ssh-keygen
$ ssh-copy-id localhost
After the above steps are completed successfully, you will need to return to the VM, run the command source ~/.bashrc
and restart the Jupyter notebook server.
The next cells can be run from inside the Jupyter notebook.
In [1]:
%%writefile codes/openmpi/first.c
#include <stdio.h>
#include <sys/utsname.h>
#include <mpi.h>
int main(int argc, char *argv[]){
MPI_Init(&argc, &argv);
struct utsname uts;
uname (&uts);
printf("My process is on node %s.\n", uts.nodename);
MPI_Finalize();
return 0;
}
In [1]:
!mpicc codes/openmpi/first.c -o ~/first
!mpirun -np 2 ~/first
Basic parameters available to individual processes:
MPI.COMM_WORLD
MPI_Comm_rank()
MPI_Comm_size()
MPI_Get_processor_name()
In [11]:
%%writefile codes/openmpi/hello.c
#include <mpi.h>
#include <stdio.h>
int main(int argc, char** argv) {
int size;
int my_rank;
char proc_name[MPI_MAX_PROCESSOR_NAME];
int proc_name_len;
/* Initialize the MPI environment */
MPI_Init(&argc, &argv);
/* Get the number of processes */
MPI_Comm_size(MPI_COMM_WORLD, &size);
/* Get the rank of the process */
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
/* Get the name of the processor */
MPI_Get_processor_name(proc_name, &proc_name_len);
/* Print off a hello world message */
printf("Hello world from processor %s, rank %d out of %d processes\n",
proc_name, my_rank, size);
/* Finalize the MPI environment. */
MPI_Finalize();
}
In [14]:
!mpicc codes/openmpi/hello.c -o ~/hello
!mpirun -np 2 ~/hello
In [68]:
!mpirun -np 8 ~/hello
!mpirun -np 8 --map-by core:OVERSUBSCRIBE ~/hello
In [17]:
%%writefile codes/openmpi/evenodd.c
#include <mpi.h>
#include <stdio.h>
int main(int argc, char** argv) {
int my_rank;
/* Initialize the MPI environment */
MPI_Init(&argc, &argv);
/* Get the rank of the process */
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
if (my_rank % 2 == 1) {
printf ("Process %d is even \n", my_rank);
} else {
printf ("Process %d is odd \n", my_rank);
}
MPI_Finalize();
}
In [18]:
!mpicc codes/openmpi/evenodd.c -o ~/evenodd
!mpirun -np 4 --map-by core:OVERSUBSCRIBE ~/evenodd
In [24]:
%%writefile codes/openmpi/rank_size.c
#include <mpi.h>
#include <stdio.h>
int main(int argc, char** argv) {
int size;
int my_rank;
int A[16] = {2,13,4,3,5,1,0,12,10,8,7,9,11,6,15,14};
int i;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
for (i = 0; i < 16; i++){
if (i % size == my_rank){
printf ("Process %d has elements %d at index %d \n",
my_rank, A[i], i);
}
}
/* Finalize the MPI environment. */
MPI_Finalize();
}
In [28]:
!mpicc codes/openmpi/rank_size.c -o ~/rank_size
!mpirun -np 4 ~/rank_size
Original MPI C Syntax: MPI_Send
int MPI_Send(void *buf,
int count,
MPI_Datatype datatype,
int dest,
int tag,
MPI_Comm comm)
Original MPI C Syntax: MPI_Recv
int MPI_Recv(
void *buf,
int count,
MPI_Datatype datatype,
int source,
int tag,
MPI_Comm comm,
MPI_Status *status)
In [ ]:
We want to write an MPI program that exchange the ranks of two processes, 0 and 1.
In [29]:
%%writefile codes/openmpi/send_recv.c
#include <mpi.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char** argv)
{
int my_rank;
int size;
int tag=0;
int buf,i;
int des1,des2;
MPI_Status status;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
/* set up data */
buf = my_rank;
printf("Process %2d has original value %2d \n",my_rank,buf);
if (my_rank == 0){
MPI_Send(&buf,1,MPI_INT,1,tag,MPI_COMM_WORLD);
MPI_Recv(&buf,1,MPI_INT,1,tag,MPI_COMM_WORLD,&status);
}
if (my_rank == 1){
MPI_Recv(&buf,1,MPI_INT,0,tag,MPI_COMM_WORLD,&status);
MPI_Send(&buf,1,MPI_INT,0,tag,MPI_COMM_WORLD);
}
printf("Process %2d now has value %2d\n",my_rank,buf);
MPI_Finalize();
} /* end main */
In [30]:
!mpicc codes/openmpi/send_recv.c -o ~/send_recv
!mpirun -np 2 ~/send_recv
In [31]:
%%writefile ~/send_recv_fixed.c
#include <mpi.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char** argv)
{
int my_rank;
int size;
int tag=0;
int buf,i;
int des1,des2;
MPI_Status status;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
/* set up data */
buf = my_rank;
printf("Process %2d has original value %2d \n",my_rank,buf);
if (my_rank == 0){
MPI_Send(&buf,1,MPI_INT,1,tag,MPI_COMM_WORLD);
MPI_Recv(&buf,1,MPI_INT,1,tag,MPI_COMM_WORLD,&status);
}
if (my_rank == 1){
MPI_Recv(&buf,1,MPI_INT,0,tag,MPI_COMM_WORLD,&status);
MPI_Send(&buf,1,MPI_INT,0,tag,MPI_COMM_WORLD);
}
printf("Process %2d now has value %2d\n",my_rank,buf);
MPI_Finalize();
} /* end main */
In [32]:
!mpicc ~/send_recv_fixed.c -o ~/send_recv_fixed
!mpirun -np 2 ~/send_recv_fixed
How do we do point-to-point communication at scale?
In [32]:
%%writefile codes/openmpi/multi_send_recv.c
#include <mpi.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char** argv)
{
int my_rank;
int size;
int tag=0;
int buf,i;
int des1,des2;
MPI_Status status;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
/* set up data */
buf = my_rank;
//printf("Process %2d has original value %2d \n",my_rank,buf);
/* set up source and destination */
des1 = (my_rank + 1) % size;
des2 = (my_rank + size - 1) % size;
//printf("Process %2d has des1 %2d and des2 %2d\n",my_rank,des1,des2);
/* shift the data n/2 steps */
for (i = 0; i < size/2; i++){
MPI_Send(&buf,1,MPI_INT,des1,tag,MPI_COMM_WORLD);
MPI_Recv(&buf,1,MPI_INT,MPI_ANY_SOURCE,tag,MPI_COMM_WORLD,&status);
MPI_Barrier(MPI_COMM_WORLD);
}
MPI_Send(&buf,1,MPI_INT,des2,tag,MPI_COMM_WORLD);
MPI_Recv(&buf,1,MPI_INT,MPI_ANY_SOURCE,tag,MPI_COMM_WORLD,&status);
MPI_Barrier(MPI_COMM_WORLD);
printf("Process %2d now has value %2d\n",my_rank,buf);
/* Shut down MPI */
MPI_Finalize();
} /* end main */
In [39]:
!mpicc codes/openmpi/multi_send_recv.c -o ~/multi_send_recv
!mpirun -np 4 --map-by core:OVERSUBSCRIBE ~/multi_send_recv
Blocking risks
In [42]:
%%writefile codes/openmpi/deadlock_send_recv.c
#include <mpi.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[])
{
int my_rank; /* rank of process */
int size; /* number of processes */
int source; /* rank of sender */
int dest; /* rank of receiver */
int tag=0; /* tag for messages */
char message[100]; /* storage for message */
MPI_Status status; /* return status for receive */
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
fprintf(stderr,"I am here! ID = %d\n", my_rank);
sprintf(message, "Greetings from process %d!", my_rank);
if (my_rank == 0) {
dest = 1;
MPI_Recv(message, 100, MPI_CHAR, dest, tag, MPI_COMM_WORLD, &status);
MPI_Send(message, strlen(message)+1, MPI_CHAR, dest, tag, MPI_COMM_WORLD);
printf("Process 0 printing: %s\n", message);
}
else {
/* my rank == 1 */
dest = 0;
MPI_Recv(message, 100, MPI_CHAR, dest, tag, MPI_COMM_WORLD, &status);
MPI_Send(message, strlen(message)+1, MPI_CHAR, dest, tag, MPI_COMM_WORLD);
printf("Process 1 printing: %s\n", message);
}
MPI_Finalize();
} /* end main */
In [44]:
!mpicc codes/openmpi/deadlock_send_recv.c -o ~/deadlock_send_recv
!mpirun -np 2 ~/deadlock_send_recv
# The [*] is indicative of a running notebook shell, and if it does not turn into a number,
# it means the cell is hanged (deadlocked by MPI).
# To escape a hanged cell, click the Square (Stop) button in the tool bar
To correct the above error, we need to change the order of the MPI_Recv and MPI_Send in the one of the communication code block
int MPI_Bcast(
void *buf,
int count,
MPI_Datatype datatype,
int root,
MPI_Comm comm);
In [19]:
%%writefile codes/openmpi/bcast.c
#include <stdio.h>
#include <mpi.h>
int main(int argc, char* argv[])
{
int my_rank;
int size;
int value;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
value = my_rank;
printf("process %d: Before MPI_Bcast, value is %d\n", my_rank, value);
MPI_Bcast(&value, 1, MPI_INT, 0, MPI_COMM_WORLD);
printf("process %d: After MPI_Bcast, value is %d\n", my_rank, value);
MPI_Finalize();
return 0;
}
In [20]:
!mpicc codes/openmpi/bcast.c -o ~/bcast
!mpirun -np 4 --map-by core:OVERSUBSCRIBE ~/bcast
Original MPI C Syntax: MPI_Scatter
int MPI_Scatter(
void *sendbuf,
int sendcount,
MPI_Datatype sendtype,
void *recvbuf,
int recvcnt,
MPI_Datatype recvtype,
int root,
MPI_Comm comm);
In [25]:
%%writefile codes/openmpi/scatter.c
#include <mpi.h>
#include <stdio.h>
int main(int argc, char** argv) {
int size;
int my_rank;
int sendbuf[16] = {2,13,4,3,5,1,0,12,10,8,7,9,11,6,15,14};
int recvbuf[5];
int i;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
MPI_Scatter(&sendbuf, 5, MPI_INT, &recvbuf, 5, MPI_INT, 0, MPI_COMM_WORLD);
for (i = 0; i < 5; i++){
printf ("Process %d has element %d at index %d in its recvbuf \n",
my_rank, recvbuf[i], i);
}
/* Finalize the MPI environment. */
MPI_Finalize();
}
In [26]:
!mpicc codes/openmpi/scatter.c -o ~/scatter
!mpirun -np 4 --map-by core:OVERSUBSCRIBE ~/scatter
Original MPI C Syntax: MPI_Gather
int MPI_Gather(
void *sendbuff,
int sendcount,
MPI_Datatype sendtype,
void *recvbuff,
int recvcnt,
MPI_Datatype recvtype,
int root,
MPI_Comm comm);
In [27]:
%%writefile codes/openmpi/gather.c
#include <mpi.h>
#include <stdio.h>
int main(int argc, char** argv) {
int size;
int my_rank;
int sendbuf[2];
int recvbuf[8] = {-1,-1,-1,-1,-1,-1,-1,-1};
int i;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
for (i = 0; i < 2; i++){
sendbuf[i] = my_rank;
}
MPI_Gather(&sendbuf, 2, MPI_INT, &recvbuf, 2, MPI_INT, 0, MPI_COMM_WORLD);
for (i = 0; i < 8; i++){
printf ("Process %d has element %d at index %d in its recvbuf \n",
my_rank, recvbuf[i], i);
}
/* Finalize the MPI environment. */
MPI_Finalize();
}
In [28]:
!mpicc codes/openmpi/gather.c -o ~/gather
!mpirun -np 4 --map-by core:OVERSUBSCRIBE ~/gather
Original MPI C Syntax: MPI_Reduce
int MPI_Reduce(
void *sendbuf,
void *recvbuff,
int count,
MPI_Datatype datatype,
MPI_OP op,
int root,
MPI_Comm comm);
In [30]:
%%writefile codes/openmpi/reduce.c
#include <mpi.h>
#include <stdio.h>
int main(int argc, char** argv) {
int size;
int my_rank;
int rank_sum;
int i;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
rank_sum = my_rank;
MPI_Reduce(&my_rank, &rank_sum, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
printf ("The total sum of all ranks at process %d is %d \n", my_rank, rank_sum);
/* Finalize the MPI environment. */
MPI_Finalize();
}
In [31]:
!mpicc codes/openmpi/reduce.c -o ~/reduce
!mpirun -np 4 --map-by core:OVERSUBSCRIBE ~/reduce
In [67]:
!mpicc codes/openmpi/reduce.c -o ~/reduce
!mpirun -np 8 --map-by core:OVERSUBSCRIBE ~/reduce