29.01.2015 Views

Dr. David Cronk Innovative Computing Lab University of ... - It works!

Dr. David Cronk Innovative Computing Lab University of ... - It works!

Dr. David Cronk Innovative Computing Lab University of ... - It works!

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

An Introduction to Parallel Programming with<br />

MPI<br />

<strong>Dr</strong>. <strong>David</strong> <strong>Cronk</strong><br />

<strong>Innovative</strong> <strong>Computing</strong> <strong>Lab</strong><br />

<strong>University</strong> <strong>of</strong> Tennessee


Day 1<br />

Morning - Lecture<br />

Course Outline<br />

Parallel Processing<br />

Parallel Programming<br />

Introduction to MPI<br />

Getting started with MPI<br />

Afternoon – <strong>Lab</strong><br />

Hands on exercises building and executing basic<br />

MPI programs<br />

<strong>David</strong> <strong>Cronk</strong> 2


Day 2<br />

Course Outline (cont)<br />

Morning – Lecture<br />

Communication Modes<br />

Collective communication<br />

Afternoon – <strong>Lab</strong><br />

Hands on exercises using various<br />

communication methods in MPI<br />

<strong>David</strong> <strong>Cronk</strong> 3


Course Outline (cont)<br />

Day 3<br />

Morning – Lecture<br />

Derived Datatypes<br />

What else is there<br />

Groups and communicators<br />

MPI-2<br />

Dynamic process management<br />

One-sided communication<br />

MPI-I/O<br />

Afternoon – <strong>Lab</strong><br />

Hands on exercises creating and using derived datatypes<br />

<strong>David</strong> <strong>Cronk</strong> 4


Day 1<br />

Morning - Lecture<br />

Course Outline<br />

Parallel Processing<br />

Parallel Programming<br />

Introduction to MPI<br />

Getting started with MPI<br />

Afternoon – <strong>Lab</strong><br />

Hands on exercises building and executing basic<br />

MPI programs<br />

<strong>David</strong> <strong>Cronk</strong> 5


Parallel Processing<br />

Outline<br />

› What is parallel processing<br />

› An example <strong>of</strong> parallel processing<br />

› Why use parallel processing<br />

<strong>David</strong> <strong>Cronk</strong> 6


Parallel Processing<br />

What is parallel processing<br />

› Using multiple processors to solve a single<br />

problem<br />

• Task parallelism<br />

– The problem consists <strong>of</strong> a number <strong>of</strong> independent<br />

tasks<br />

– Each processor or groups <strong>of</strong> processors can perform<br />

a separate task<br />

• Data parallelism<br />

– The problem consists <strong>of</strong> dependent tasks<br />

– Each processor <strong>works</strong> on a different part <strong>of</strong> data<br />

<strong>David</strong> <strong>Cronk</strong> 7


Parallel Processing<br />

1<br />

!<br />

0<br />

4<br />

_1_ x 2 dx= _<br />

_<br />

We can approximate the integral as a sum <strong>of</strong> rectangles<br />

N<br />

! F _x __x" _<br />

i<br />

i = 0<br />

<strong>David</strong> <strong>Cronk</strong> 8


Parallel Processing<br />

<strong>David</strong> <strong>Cronk</strong> 9


Parallel Processing<br />

<strong>David</strong> <strong>Cronk</strong> 10


Parallel Processing<br />

Why parallel processing<br />

› Faster time to completion<br />

• Computation can be performed faster with<br />

more processors<br />

› Able to run larger jobs or at a higher<br />

resolution<br />

• Larger jobs can complete in a reasonable<br />

amount <strong>of</strong> time on multiple processors<br />

• Data for larger jobs can fit in memory when<br />

spread out across multiple processors<br />

<strong>David</strong> <strong>Cronk</strong> 11


Day 1<br />

Morning - Lecture<br />

Course Outline<br />

Parallel Processing<br />

Parallel Programming<br />

Introduction to MPI<br />

Getting started with MPI<br />

Afternoon – <strong>Lab</strong><br />

Hands on exercises building and executing basic<br />

MPI programs<br />

<strong>David</strong> <strong>Cronk</strong> 12


Parallel Programming<br />

Outline<br />

› Programming models<br />

› Message passing issues<br />

• Data distribution<br />

• Flow control<br />

<strong>David</strong> <strong>Cronk</strong> 13


Parallel Programming<br />

Programming models<br />

› Shared memory<br />

• All processes have access to global memory<br />

› Distributed memory (message passing)<br />

• Processes have access to only local memory.<br />

Data is shared via explicit message passing<br />

› Combination shared/distributed<br />

• Groups <strong>of</strong> processes share access to “local”<br />

data while data is shared between groups via<br />

explicit message passing<br />

<strong>David</strong> <strong>Cronk</strong> 14


Parallel Programming<br />

Message Passing Issues<br />

› Data Distribution<br />

• Minimize overhead<br />

– Latency (message start up time)<br />

» Few large messages is better than many small<br />

– Memory movement<br />

• Maximize load balance<br />

– Less idle time waiting for data or synchronizing<br />

– Each process should do about the same work<br />

› Flow Control<br />

• Minimize waiting<br />

<strong>David</strong> <strong>Cronk</strong> 15


Data Distribution<br />

<strong>David</strong> <strong>Cronk</strong> 16


Data Distribution<br />

<strong>David</strong> <strong>Cronk</strong> 17


Flow Control<br />

0 1 2 3 4 5 ………<br />

Send to 1 Recv Send to from 2 0<br />

Send Recv to from 2 0<br />

Recv Send to from 3 1<br />

Send Recv to from 3 1<br />

Recv Send to from 4 2<br />

Send Recv to from 4 2<br />

<strong>David</strong> <strong>Cronk</strong> 18


Day 1<br />

Morning - Lecture<br />

Course Outline<br />

Parallel Processing<br />

Parallel Programming<br />

Introduction to MPI<br />

Getting started with MPI<br />

Afternoon – <strong>Lab</strong><br />

Hands on exercises building and executing basic<br />

MPI programs<br />

<strong>David</strong> <strong>Cronk</strong> 19


Introduction to MPI<br />

Outline<br />

› What is MPI<br />

• History<br />

• Origins<br />

• What MPI is not<br />

• Specifications<br />

• What’s new and in the future<br />

<strong>David</strong> <strong>Cronk</strong> 20


What is MPI<br />

Introduction to MPI<br />

› MPI stands for “Message Passing<br />

Interface”<br />

› In ancient times (late 1980’s early 1990’s)<br />

each vender had its own message passing<br />

library<br />

• Non-portable code<br />

• Not enough people doing parallel computing<br />

due to lack <strong>of</strong> standards<br />

<strong>David</strong> <strong>Cronk</strong> 21


What is MPI<br />

April 1992 was the beginning <strong>of</strong> the MPI forum<br />

› Organized at SC92<br />

› Consisted <strong>of</strong> hardware vendors, s<strong>of</strong>tware vendors,<br />

academicians, and end users<br />

› Held 2 day meetings every 6 weeks<br />

› Created drafts <strong>of</strong> the MPI standard<br />

› This standard was to include all the functionality<br />

believed to be needed to make the message<br />

passing model a success<br />

› Final version released may, 1994<br />

<strong>David</strong> <strong>Cronk</strong> 22


What is MPI<br />

A standard library specification!<br />

› Defines syntax and semantics <strong>of</strong> an extended<br />

message passing model<br />

› <strong>It</strong> is not a language or compiler specification<br />

› <strong>It</strong> is not a specific implementation<br />

› <strong>It</strong> does not give implementation specifics<br />

• Hints are <strong>of</strong>fered, but implementers are free to do things<br />

however they want<br />

• Different implementations may do the same thing in a<br />

very different manner<br />

› http://www.mpi-forum.org<br />

<strong>David</strong> <strong>Cronk</strong> 23


What is MPI<br />

A library specification designed to support<br />

parallel computing in a distributed memory<br />

environment<br />

› Routines for cooperative message passing<br />

• There is a sender and a receiver<br />

• Point-to-point communication<br />

• Collective communication<br />

› Routines for synchronization<br />

› Derived data types for non-contiguous data<br />

access patterns<br />

› Ability to create sub-sets <strong>of</strong> processors<br />

› Ability to create process topologies<br />

<strong>David</strong> <strong>Cronk</strong> 24


Continuing to grow!<br />

What is MPI<br />

› New routines have been added to replace<br />

old routines<br />

› New functionality has been added<br />

• Dynamic process management<br />

• One sided communication<br />

• Parallel I/O<br />

<strong>David</strong> <strong>Cronk</strong> 25


TAKE<br />

A<br />

BREAK<br />

<strong>David</strong> <strong>Cronk</strong> 26


Day 1<br />

Morning - Lecture<br />

Course Outline<br />

Parallel Processing<br />

Parallel Programming<br />

Introduction to MPI<br />

Getting started with MPI<br />

Afternoon – <strong>Lab</strong><br />

Hands on exercises building and executing basic<br />

MPI programs<br />

<strong>David</strong> <strong>Cronk</strong> 27


Getting Started with MPI<br />

Outline<br />

› Introduction<br />

› 6 basic functions<br />

› Basic program structure<br />

› Groups and communicators<br />

› A very simple program<br />

› Message passing<br />

› A simple message passing example<br />

› Types <strong>of</strong> programs<br />

• Traditional<br />

• Master/Slave<br />

• Examples<br />

› Unsafe communication<br />

<strong>David</strong> <strong>Cronk</strong> 28


Getting Started with MPI<br />

MPI contains 125 routines (more with the<br />

extensions)!<br />

Many programs can be written with just 6<br />

MPI routines!<br />

Upon startup, all processes can be<br />

identified by their rank, which goes from<br />

0 to N-1 where there are N processes<br />

<strong>David</strong> <strong>Cronk</strong> 29


6 Basic Functions<br />

MPI_INIT: Initialize MPI<br />

MPI_Finalize: Finalize MPI<br />

MPI_COMM_SIZE: How many processes<br />

are running<br />

MPI_COMM_RANK: What is my process<br />

number<br />

MPI_SEND: Send a message<br />

MPI_RECV: Receive a message<br />

<strong>David</strong> <strong>Cronk</strong> 30


MPI_INIT (ierr)<br />

ierr: Integer error return value. 0 on<br />

success, non-zero on failure.<br />

This MUST be the first MPI routine called<br />

in any program.<br />

Can only be called once<br />

Sets up the environment to enable<br />

message passing<br />

This is NOT how you run an MPI program<br />

<strong>David</strong> <strong>Cronk</strong> 31


MPI_FINALIZE (ierr)<br />

ierr: Integer error return value. 0 on success, non-zero<br />

on failure.<br />

This routine must be called by each process before it<br />

exits<br />

This call cleans up all MPI state<br />

No other MPI routines may be called after<br />

MPI_FINALIZE<br />

All pending communication must be completed (locally)<br />

before a call to MPI_FINALIZE<br />

There must be no unmatched communication calls<br />

when last process finalizes<br />

Only process with rank 0 is guaranteed to return<br />

<strong>David</strong> <strong>Cronk</strong> 32


Basic Program Structure<br />

program main<br />

include ‘mpif.h’<br />

integer ierr<br />

call MPI_INIT (ierr)<br />

………<br />

Do some work<br />

………<br />

call MPI_FINALIZE (ierr)<br />

Maybe do some additional<br />

serial computation if rank 0<br />

………………….<br />

end<br />

#include “mpi.h”<br />

int main ()<br />

{<br />

MPI_Init ()<br />

………<br />

Do some work<br />

………<br />

MPI_Finalize ()<br />

Maybe do some additional<br />

serial computation if rank 0<br />

………………….<br />

}<br />

<strong>David</strong> <strong>Cronk</strong> 33


Groups and communicators<br />

We will not be using this, but it is important to<br />

understand so you understand other routines<br />

Groups can be thought <strong>of</strong> as sets <strong>of</strong> processes<br />

These groups are associated with what are called<br />

“communicators”<br />

A communicator defines a “communication domain”<br />

Upon startup, there is a single set <strong>of</strong> processes<br />

associated with the communicator<br />

MPI_COMM_WORLD<br />

Groups can be created which are sub-sets <strong>of</strong> this<br />

original group, also associated with communicators<br />

<strong>David</strong> <strong>Cronk</strong> 34


MPI_COMM_RANK (comm, rank, ierr)<br />

comm: Communicator (integer in Fortran,<br />

MPI_Comm in C) . We will always use<br />

MPI_COMM_WORLD<br />

rank: Returned rank <strong>of</strong> calling process<br />

Between 0 and n-1 with n processes<br />

ierr: Integer error return code<br />

This routine returns the relative rank <strong>of</strong> the<br />

calling process, within the group associated<br />

with comm.<br />

<strong>David</strong> <strong>Cronk</strong> 35


MPI_COMM_SIZE (comm, size, ierr)<br />

Comm: Communicator handle<br />

Size: Upon return, the number <strong>of</strong><br />

processes in the group associated with<br />

comm. For our purposes, always the<br />

total number <strong>of</strong> processes<br />

This routine returns the number <strong>of</strong><br />

processes in the group associated with<br />

comm<br />

<strong>David</strong> <strong>Cronk</strong> 36


program main<br />

include ‘mpif.h’<br />

integer ierr, size, rank<br />

A Very Simple Program<br />

Hello World<br />

call MPI_INIT (ierr)<br />

call MPI_COMM_RANK (MPI_COMM_WORLD, rank, ierr)<br />

call MPI_COMM_SIZE (MPI_COMM_WORLD, size, ierr)<br />

print *, ‘Hello World from process’, rank, ‘<strong>of</strong>’, size<br />

call MPI_FINALIZE (ierr)<br />

end<br />

<strong>David</strong> <strong>Cronk</strong> 37


Hello World<br />

> mpirun –np 4 a.out<br />

><br />

> Hello World from 2 <strong>of</strong> 4<br />

> Hello World from 0 <strong>of</strong> 4<br />

> Hello World from 3 <strong>of</strong> 4<br />

> Hello World from 1 <strong>of</strong> 4<br />

> mpirun –np 4 a.out<br />

><br />

> Hello World from 3 <strong>of</strong> 4<br />

> Hello World from 1 <strong>of</strong> 4<br />

> Hello World from 2 <strong>of</strong> 4<br />

> Hello World from 0 <strong>of</strong> 4<br />

<strong>David</strong> <strong>Cronk</strong> 38


Message Passing<br />

Message passing is the transfer <strong>of</strong> data from<br />

one process to another<br />

› This transfer requires cooperation <strong>of</strong> the<br />

sender and the receiver, but is initiated by<br />

the sender<br />

› There must be a way to “describe” the data<br />

› There must be a way to identify specific<br />

processes<br />

› There must be a way to identify kinds <strong>of</strong><br />

messages<br />

<strong>David</strong> <strong>Cronk</strong> 39


Message Passing<br />

Data is described by a triple<br />

1. Address: Where is the data stored<br />

2. Datatype: What is the type <strong>of</strong> the data<br />

› Basic types (integers, reals, etc)<br />

› Derived types (good for non-contiguous data<br />

access)<br />

3. Count: How many elements make up the<br />

message<br />

<strong>David</strong> <strong>Cronk</strong> 40


Message Passing<br />

Processes are specified by a double<br />

1. Communicator: We will always use<br />

MPI_COMM_WORLD<br />

2. Rank: The relative rank <strong>of</strong> the specified<br />

process within the group associated with<br />

the communicator<br />

Messages are identified by a single tag<br />

This can be used to differentiate between<br />

different kinds <strong>of</strong> messages<br />

<strong>David</strong> <strong>Cronk</strong> 41


MPI_SEND(buf, cnt, dtype, dest,<br />

tag, comm, ierr)<br />

buf: The address <strong>of</strong> the beginning <strong>of</strong> the<br />

data to be sent<br />

cnt: The number <strong>of</strong> elements to be sent<br />

dtype: datatype <strong>of</strong> each element<br />

dest: The rank <strong>of</strong> the destination<br />

tag: Integer message tag<br />

0 >= tag >= MPI_TAG_UB (at least 32767)<br />

comm: The communicator<br />

<strong>David</strong> <strong>Cronk</strong> 42


MPI_STATUS<br />

Since a receive call only specifies the maximum<br />

number <strong>of</strong> elements to receive, there must be<br />

a way to find out the number <strong>of</strong> elements<br />

actually received<br />

MPI_Get_count (status, datatype, count, ierr)<br />

This routine returns in count the actual number <strong>of</strong><br />

elements received by a call that returned status<br />

MPI_STATUS_IGNORE can be used to avoid<br />

the overhead <strong>of</strong> filling in the status<br />

<strong>David</strong> <strong>Cronk</strong> 43


Send/Recv Example<br />

program main<br />

include ‘mpif.h’<br />

CHARACTER*20 msg<br />

integer ierr, rank, tag, status (MPI_STATUS_SIZE)<br />

tag = 99<br />

call MPI_INIT (ierr)<br />

call MPI_COMM_RANK (MPI_COMM_WORLD, rank, ierr)<br />

if (myrank .eq. 0) then<br />

msg = “Hello there”<br />

call MPI_SEND (msg, 11, MPI_CHARACTER, 1, tag, &<br />

MPI_COMM_WORLD, ierr)<br />

else if (myrank .eq. 1) then<br />

call MPI_RECV(msg, 20, MPI_CHARACTER, 0, tag, &<br />

MPI_COMM_WORLD, status, ierr)<br />

write (*,*) msg<br />

endif<br />

call MPI_FINALIZE (ierr)<br />

end<br />

<strong>David</strong> <strong>Cronk</strong> 44


Types <strong>of</strong> data parallel MPI<br />

Programs<br />

Peer/SPMD<br />

› Break the problem up into about even sized parts<br />

and distribute across all processors<br />

› What if problem is such that you cannot tell how<br />

much work must be done on each part<br />

Master/Slave<br />

› Break the problem up into many more parts than<br />

there are processors<br />

› Master sends work to slaves<br />

› Parts may be all the same size or the size may<br />

vary<br />

<strong>David</strong> <strong>Cronk</strong> 45


Data Distribution<br />

1-D block distribution<br />

2-D block block<br />

distribution<br />

2-D block cyclic<br />

distribution<br />

<strong>David</strong> <strong>Cronk</strong> 46


Peer/SPMD Example<br />

Compute the sum <strong>of</strong> a large array <strong>of</strong> N integers<br />

Comm = MPI_COMM_WORLD<br />

Call MPI_COMM_RANK (comm, rank, ierr)<br />

Call MPI_COMM_SIZE (comm, npes, ierr)<br />

Stride = N/npes<br />

Start = (stride * rank) + 1<br />

Sum = 0<br />

DO I = start, start+stride<br />

sum = sum + array(I)<br />

ENDDO<br />

If (rank .eq. 0) then<br />

DO I = 1, npes-1<br />

call MPI_RECV(tmp, 1, MPI_INTEGER,<br />

&<br />

I, 2, comm, status, ierr)<br />

sum = sum + tmp<br />

ENDDO<br />

ELSE<br />

MPI_SEND (sum, 1, MPI_INTEGER,<br />

& 0, 2 comm, ierr)<br />

ENDIF<br />

<strong>David</strong> <strong>Cronk</strong> 47


Master/Slave Example<br />

Do some computation for each <strong>of</strong> N elements in a large array.<br />

The amount <strong>of</strong> computation depends on the value <strong>of</strong> each element.<br />

Main<br />

Call MPI_INIT (ierr)<br />

comm = MPI_COMM_WORLD<br />

Call MPI_COMM_RANK (comm, rank, ierr)<br />

Call MPI_COMM_SIZE (comm, size, ierr)<br />

stride = N/(10*(size-1))<br />

If (rank .eq. 0)<br />

call master ()<br />

Else<br />

call slave()<br />

Endif<br />

Call MPI_FINALIZE (ierr)<br />

<strong>David</strong> <strong>Cronk</strong> 48


Master/Slave Example<br />

Master code:<br />

current = 1<br />

DO I = 1, size-1<br />

call MPI_SEND (info[current], stride<br />

&, MPI_INTEGER, I, 2, comm, ierr)<br />

current = current + stride<br />

ENDDO<br />

Do I = 1, 9*(size-1)<br />

call MPI_RECV (tmp, 0, MPI_BYTE,<br />

& MPI_ANY_SOURCE, 3, comm, status,ierr)<br />

source = status(MPI_SOURCE)<br />

call MPI_SEND (info[current], stride ,<br />

&<br />

MPI_INTEGER,<br />

&<br />

source, 2, comm, ierr)<br />

current = current + stride<br />

enddo<br />

Do I = 1, size-1<br />

call MPI_SEND (info, 0, MPI_INTEGER,<br />

& I, 4, comm, ierr)<br />

Enddo<br />

<strong>David</strong> <strong>Cronk</strong> 49


Master/Slave Example<br />

Slave code<br />

1 Call MPI_RECV (info, stride, MPI_INTEGER, 0, MPI_ANY_TAG, comm,<br />

&<br />

status, ierr)<br />

if (status(MPI_TAG) .eq. 4)<br />

goto 200<br />

do I =1, stride<br />

do_compute (array(I))<br />

enddo<br />

call MPI_SEND (tmp, 0, MPI_BYTE, 0, 3, comm, ierr)<br />

goto 100<br />

200 continue<br />

<strong>David</strong> <strong>Cronk</strong> 50


Master/Slave Example<br />

Master code:<br />

current = 1<br />

DO I = 1, size-1<br />

call MPI_SEND (info[current], stride<br />

&, MPI_INTEGER, I, 2, comm, ierr)<br />

current = current + stride<br />

ENDDO<br />

Do I = 1, 9*(size-1)<br />

call MPI_RECV (tmp, 0, MPI_BYTE,<br />

& MPI_ANY_SOURCE, 3, comm, status,ierr)<br />

source = status(MPI_SOURCE)<br />

call MPI_SEND (info[current], stride ,<br />

&<br />

MPI_INTEGER,<br />

&<br />

source, 2, comm, ierr)<br />

current = current + stride<br />

enddo<br />

Do (I = 1, size-1)<br />

call MPI_RECV (tmp, 0, MPI_BYTE, &<br />

I, 3, comm, status, ierr)<br />

call MPI_SEND (info, 0, MPI_INTEGER,<br />

& I, 4, comm, ierr)<br />

Enddo<br />

<strong>David</strong> <strong>Cronk</strong> 51


Unsafe Communication Patterns<br />

› Process 0 and process 1 must exchange data<br />

› Process 0 sends data to process 1 and then<br />

receives data from process 1<br />

› Process 1 sends data to process 0 and then<br />

receives data from process 0<br />

› If there is not enough system buffer space for<br />

either message, this will deadlock<br />

› Any communication pattern that relies on<br />

system buffers is unsafe<br />

› Any pattern that includes a cycle <strong>of</strong> blocking<br />

sends is unsafe<br />

<strong>David</strong> <strong>Cronk</strong> 52


Unsafe Communication Patterns<br />

send<br />

recv<br />

send<br />

recv<br />

send<br />

recv<br />

Potential<br />

deadlock<br />

Potential<br />

deadlock<br />

send<br />

recv<br />

send<br />

recv<br />

send<br />

recv<br />

<strong>David</strong> <strong>Cronk</strong> 53


Jacobi <strong>It</strong>eration<br />

0<br />

0<br />

M+1<br />

A<br />

exchange<br />

exchange<br />

exchange<br />

…….<br />

N+1<br />

<strong>David</strong> <strong>Cronk</strong> 54


Jacobi <strong>It</strong>eration<br />

Initializations<br />

.<br />

.<br />

DO WHILE (.NOT. Converged(A))<br />

.<br />

do iteration<br />

.<br />

.<br />

! Perform exchange<br />

IF (myrank .GT. 0) THEN<br />

CALL MPI_SEND (A(1,1), n, MPI_REAL, &<br />

myrank-1, tag, comm, ierr)<br />

ENDIF<br />

IF (myrank .LT. nprocs-1) THEN<br />

CALL MPI_SEND (A(1,m), n, MPI_REAL, &<br />

myrank+1, tag, comm, ierr)<br />

ENDIF<br />

IF (myrank .GT. 0) THEN<br />

CALL MPI_RECV (A(1,0), n, MPI_REAL, &<br />

myrank-1, tag, comm, status, ierr)<br />

ENDIF<br />

IF (myrank .LT. nprocs-1) THEN<br />

CALL MPI_RECV (A(1,m+1), n, MPI_REAL, &<br />

myrank+1, tag, comm, status, ierr)<br />

ENDIF<br />

ENDDO<br />

POTENTIAL DEADLOCK!<br />

<strong>David</strong> <strong>Cronk</strong> 55


Jacobi <strong>It</strong>eration<br />

! Perform exchange<br />

IF (MOD(myrank,2) .EQ. 1) THEN<br />

CALL MPI_SEND (A(1,1), n, MPI_REAL, &<br />

myrank-1, tag, comm, ierr)<br />

IF (myrank .LT. Nprocs-1) THEN<br />

CALL MPI_SEND (A(1,m), n, MPI_REAL, &<br />

myrank+1, tag, comm, ierr)<br />

ENDIF<br />

CALL MPI_RECV (A(1,0), n, MPI_REAL, &<br />

myrank-1, tag, comm, status, ierr)<br />

IF (myrank .LT. Nprocs-1) THEN<br />

CALL MPI_RECV (A(1,m+1), n, MPI_REAL, &<br />

myrank+1, tag, comm, status, ierr)<br />

ENDIF<br />

ENDIF<br />

ELSE<br />

IF (myrank .GT. 0) THEN<br />

CALL MPI_RECV (A(1,0), n, MPI_REAL, &<br />

myrank-1, tag, comm, status, ierr)<br />

ENDIF<br />

IF (myrank .LT. nprocs-1) THEN<br />

CALL MPI_RECV (A(1,m+1), n, MPI_REAL, &<br />

myrank+1, tag, comm, status, ierr)<br />

ENDIF<br />

IF (myrank .GT. 0) THEN<br />

CALL MPI_SEND (A(1,1), n, MPI_REAL, &<br />

myrank-1, tag, comm, ierr)<br />

ENDIF<br />

IF (myrank .LT. nprocs-1) THEN<br />

CALL MPI_SEND (A(1,m), n, MPI_REAL, &<br />

myrank+1, tag, comm, ierr)<br />

ENDIF<br />

ENDIF<br />

<strong>David</strong> <strong>Cronk</strong> 56


Day 2<br />

Course Outline (cont)<br />

Morning – Lecture<br />

Communication Modes<br />

Collective communication<br />

Afternoon – <strong>Lab</strong><br />

Hands on exercises using various<br />

communication methods in MPI<br />

<strong>David</strong> <strong>Cronk</strong> 57


Communication Modes<br />

Outline<br />

› Standard mode<br />

• Blocking<br />

• Non-blocking<br />

› Non-standard mode<br />

• Buffered<br />

• Synchronous<br />

• Ready<br />

› Performance issues<br />

<strong>David</strong> <strong>Cronk</strong> 58


Point-to-Point Communication<br />

Modes<br />

Standard Mode:<br />

blocking:<br />

MPI_SEND (buf, count, datatype, dest, tag, comm, ierr)<br />

MPI_RECV (buf, count, datatype, source, tag, comm, status, ierr)<br />

Generally ONLY use if you cannot call earlier AND there is no other<br />

work that can be done!<br />

Standard ONLY states that buffers can be used once calls return. <strong>It</strong><br />

is implementation dependant on when blocking calls return.<br />

Blocking sends MAY block until a matching receive is posted. This<br />

is not required behavior, but the standard does not prohibit this<br />

behavior either. Further, a blocking send may have to wait for<br />

system resources such as system managed message buffers.<br />

Be VERY careful <strong>of</strong> deadlock when using blocking calls!<br />

<strong>David</strong> <strong>Cronk</strong> 59


Point-to-Point Communication<br />

Modes (cont)<br />

Standard Mode:<br />

Non-blocking (immediate) sends/receives:<br />

MPI_ISEND (buf, count, datatype, dest, tag, comm, request, ierr)<br />

MPI_IRECV (buf, count, datatype, source, tag, comm, request, ierr)<br />

MPI_WAIT (request, status, ierr)<br />

MPI_WAITANY (count, requests, index, status, ierr)<br />

MPI_WAITALL (count, requests, statuses, ierr)<br />

MPI_TEST (request, flag, status, ierr)<br />

MPI_TESTANY (count, requests, index, flag, status, ierr)<br />

MPI_TESTALL (count, requests, flag, statuses, ierr)<br />

Allows communication calls to be posted early, which may improve<br />

performance.<br />

Overlap computation and communication<br />

Latency tolerance<br />

Less (or no) buffering<br />

* MUST either complete these calls (with wait or test) or<br />

call MPI_REQUEST_FREE<br />

<strong>David</strong> <strong>Cronk</strong> 60


MPI_ISEND (buf, cnt, dtype, dest,<br />

tag, comm, request, ierr)<br />

Same syntax as MPI_SEND with the addition <strong>of</strong><br />

a request handle<br />

Request is a handle (int in Fortran<br />

MPI_Request in C) used to check for<br />

completeness <strong>of</strong> the send<br />

This call returns immediately<br />

Data in buf may not be accessed until the user<br />

has completed the send operation<br />

The send is completed by a successful call to<br />

MPI_TEST or a call to MPI_WAIT<br />

<strong>David</strong> <strong>Cronk</strong> 61


MPI_IRECV(buf, cnt, dtype,<br />

source, tag, comm, request, ierr)<br />

Same syntax as MPI_RECV except status is<br />

replaced with a request handle<br />

Request is a handle (int in Fortran<br />

MPI_Request in C) used to check for<br />

completeness <strong>of</strong> the recv<br />

This call returns immediately<br />

Data in buf may not be accessed until the user<br />

has completed the receive operation<br />

The receive is completed by a successful call to<br />

MPI_TEST or a call to MPI_WAIT<br />

<strong>David</strong> <strong>Cronk</strong> 62


MPI_WAIT (request, status, ierr)<br />

Request is the handle returned by the nonblocking<br />

send or receive call<br />

Upon return, status holds source, tag, and error<br />

code information<br />

This call does not return until the non-blocking<br />

call referenced by request has completed<br />

Upon return, the request handle is freed<br />

If request was returned by a call to MPI_ISEND,<br />

return <strong>of</strong> this call indicates nothing about the<br />

destination process<br />

<strong>David</strong> <strong>Cronk</strong> 63


MPI_WAITANY (count, requests,<br />

index, status, ierr)<br />

Requests is an array <strong>of</strong> handles returned by nonblocking<br />

send or receive calls<br />

Count is the number <strong>of</strong> requests<br />

This call does not return until a non-blocking call<br />

referenced by one <strong>of</strong> the requests has completed<br />

Upon return, index holds the index into the array <strong>of</strong><br />

requests <strong>of</strong> the call that completed<br />

Upon return, status holds source, tag, and error code<br />

information for the call that completed<br />

Upon return, the request handle stored in<br />

requests[index] is freed<br />

<strong>David</strong> <strong>Cronk</strong> 64


MPI_WAITALL (count, requests,<br />

statuses, ierr)<br />

requests is an array <strong>of</strong> handles returned by nonblocking<br />

send or receive calls<br />

count is the number <strong>of</strong> requests<br />

This call does not return until all non-blocking<br />

call referenced by requests have completed<br />

Upon return, statuses hold source, tag, and<br />

error code information for all the calls that<br />

completed<br />

Upon return, the request handles stored in<br />

requests are all freed<br />

<strong>David</strong> <strong>Cronk</strong> 65


MPI_TEST (request, flag, status,<br />

ierr)<br />

request is a handle returned by a non-blocking<br />

send or receive call<br />

Upon return, flag will have been set to true if the<br />

associated non-blocking call has completed.<br />

Otherwise it is set to false<br />

If flag returns true, the request handle is freed<br />

and status contains source, tag, and error<br />

code information<br />

If request was returned by a call to MPI_ISEND,<br />

return with flag set to true indicates nothing<br />

about the destination process<br />

<strong>David</strong> <strong>Cronk</strong> 66


MPI_TESTANY (count, requests,<br />

index, flag, status, ierr)<br />

requests is an array <strong>of</strong> handles returned by nonblocking<br />

send or receive calls<br />

count is the number <strong>of</strong> requests<br />

Upon return, flag will have been set to true if<br />

one <strong>of</strong> the associated non-blocking call has<br />

completed. Otherwise it is set to false<br />

If flag returns true, index holds the index <strong>of</strong> the<br />

call that completed, the request handle is<br />

freed, and status contains source, tag, and<br />

error code information<br />

<strong>David</strong> <strong>Cronk</strong> 67


MPI_TESTALL (count, requests,<br />

flag, statuses, ierr)<br />

requests is an array <strong>of</strong> handles returned by nonblocking<br />

send or receive calls<br />

count is the number <strong>of</strong> requests<br />

Upon return, flag will have been set to true if<br />

ALL <strong>of</strong> the associated non-blocking call have<br />

completed. Otherwise it is set to false<br />

If flag returns true, all the request handles are<br />

freed, and statuses contains source, tag, and<br />

error code information for each operation<br />

<strong>David</strong> <strong>Cronk</strong> 68


Non-blocking Communication<br />

100 continue<br />

if (err .lt. Delta) goto 200<br />

do some computation<br />

do I = 0, npes<br />

if (I .ne. myrank)<br />

set up data to send<br />

call MPI_SEND (sdata(I), cnt, dtype, &<br />

I, tag, comm, ierr)<br />

endif<br />

enddo<br />

do I = 0, npes<br />

if (I .ne. myrank)<br />

set up data to recv<br />

call MPI_RECV (rdata(I), cnt, dtype, &<br />

I, tag, comm, status, ierr)<br />

endif<br />

enddo<br />

goto 100<br />

Clearly unsafe<br />

100 continue<br />

if (err .lt. Delta) goto 200<br />

do some computation<br />

do I = 0, npes<br />

if (I .ne. myrank)<br />

set up data to send<br />

call MPI_ISEND (sdata(I), cnt, dtype, &<br />

I, tag, comm, request, ierr)<br />

endif<br />

enddo<br />

do I = 0, npes<br />

if (I .ne. myrank)<br />

set up data to recv<br />

call MPI_RECV (rdata(I), cnt, dtype, &<br />

I, tag, comm, status, ierr)<br />

endif<br />

enddo<br />

goto 100<br />

May run out <strong>of</strong> handles<br />

<strong>David</strong> <strong>Cronk</strong> 69


Non-blocking Communication<br />

100 continue<br />

…….<br />

J = 0<br />

do I = 0, npes<br />

if (I .ne. myrank)<br />

J = J+1<br />

set up data to send<br />

call MPI_ISEND (sdata(I), cnt, dtype, &<br />

I, tag, comm, request(J), ierr)<br />

endif<br />

enddo<br />

call MPI_WAITALL (npes-1, request,<br />

&<br />

………<br />

receive data<br />

………..<br />

Unsafe again<br />

statuses, ierr)<br />

100 continue<br />

………..<br />

J = 0<br />

do I = 0, npes<br />

if (I .ne. myrank)<br />

J = J+1<br />

set up data to send<br />

call MPI_ISEND (sdata(I), cnt, dtype, &<br />

I, tag, comm, request(J), ierr)<br />

endif<br />

enddo<br />

…………<br />

receive data<br />

………….<br />

call MPI_WAITALL (npes-1, request,<br />

&<br />

statuses, ierr)<br />

Safe…….but<br />

<strong>David</strong> <strong>Cronk</strong> 70


Non-blocking communication<br />

J = 0<br />

do I = 0, npes<br />

if (I .ne. myrank)<br />

J = J+1<br />

call MPI_ISEND (sdata(I), cnt, dtype, &<br />

I, tag, comm, s_request[J], ierr)<br />

endif<br />

enddo<br />

J = 0<br />

do (I = 0, npes)<br />

if (I .ne. myrank)<br />

J = J+1<br />

call MPI_IRECV (rdata(I), cnt, dtype, &<br />

I, tag, comm, r_request[J], ierr)<br />

endif<br />

enddo<br />

call MPI_WAITALL (…, s_request, …)<br />

call MPI_WAITALL (…, r_request, …)<br />

Safe, and pretty good<br />

<strong>David</strong> <strong>Cronk</strong> 71


Jacobi <strong>It</strong>eration<br />

0<br />

0<br />

M+1<br />

A<br />

exchange<br />

exchange<br />

exchange<br />

…….<br />

N+1<br />

<strong>David</strong> <strong>Cronk</strong> 72


Jacobi <strong>It</strong>eration<br />

IF (myrank .EQ. 0) THEN<br />

left = MPI_PROC_NULL<br />

ELSE<br />

left = myrank-1<br />

ENDIF<br />

IF (myrank .EQ. nprocs) THEN<br />

right = MPI_NULL_PROC<br />

ELSE<br />

right = myrank+1<br />

.<br />

.<br />

Compute boundary columns<br />

.<br />

.<br />

! Perform exchange<br />

CALL MPI_ISEND (A(1,1), n, MPI_REAL, &<br />

left, tag, comm, requests(1), ierr)<br />

CALL MPI_ISEND (A(1,m), n, MPI_REAL, &<br />

right, tag, comm, requests(2), ierr)<br />

CALL MPI_IRECV (A(1,0), n, MPI_REAL, &<br />

left, tag, comm, requests(3), ierr)<br />

CALL MPI_IRECV (A(1,m+1), n, MPI_REAL, &<br />

right, tag, comm, requests(4), ierr)<br />

.<br />

.<br />

Compute interior<br />

.<br />

.<br />

CALL MPI_WAITALL (4, requests, statuses, ierr)<br />

<strong>David</strong> <strong>Cronk</strong> 73


Point-to-Point Communication<br />

Modes (cont)<br />

Non-standard mode communication<br />

› Only used by the sender! (MPI uses the<br />

push communication model)<br />

› Buffered mode - A buffer must be provided<br />

by the application<br />

› Synchronous mode - Completes only after<br />

a matching receive has been posted<br />

› Ready mode - May only be called when a<br />

matching receive has already been posted<br />

<strong>David</strong> <strong>Cronk</strong> 74


Point-to-Point Communication<br />

Modes: Buffered<br />

MPI_BSEND (buf, count, datatype, dest, tag, comm, ierr)<br />

MPI_IBSEND (buf, count, dtype, dest, tag, comm, req, ierr)<br />

MPI_BUFFER_ATTACH (buff, size, ierr)<br />

MPI_BUFFER_DETACH (buff, size, ierr)<br />

Buffered sends do not rely on system buffers<br />

The user supplies a buffer that MUST be large enough for all<br />

messages<br />

User need not worry about calls blocking, waiting for system<br />

buffer space<br />

The buffer is managed by MPI<br />

The user MUST ensure there is no buffer overflow<br />

<strong>David</strong> <strong>Cronk</strong> 75


Buffered Sends<br />

#define BUFFSIZE 1000<br />

char *buff;<br />

char b1[500], b2[500]<br />

MPI_Buffer_attach (buff, BUFFSIZE);<br />

Seg violation<br />

#define BUFFSIZE 1000<br />

char *buff;<br />

char b1[500], b2[500];<br />

buff = (char*) malloc(BUFFSIZE);<br />

MPI_Buffer_attach(buff, BUFFSIZE);<br />

MPI_Bsend(b1, 500, MPI_CHAR, 1, 1,<br />

MPI_COMM_WORLD);<br />

MPI_Bsend(b2, 500, MPI_CHAR, 2, 1,<br />

MPI_COMM_WORLD);<br />

Buffer overflow<br />

int size;<br />

char *buff;<br />

char b1[500], b2[500];<br />

MPI_Pack_size (500, MPI_CHAR,<br />

MPI_COMM_WORLD, &size);<br />

size += MPI_BSEND_OVERHEAD;<br />

size = size * 2;<br />

buff = (char*) malloc(size);<br />

MPI_Buffer_attach(buff, size);<br />

MPI_Bsend(b1, 500, MPI_CHAR, 1, 1,<br />

MPI_COMM_WORLD);<br />

MPI_Bsend(b2, 500, MPI_CHAR, 2, 1,<br />

MPI_COMM_WORLD);<br />

MPI_Buffer_detach (&buff, &size);<br />

Safe<br />

<strong>David</strong> <strong>Cronk</strong> 76


Point-to-Point Communication<br />

Modes: Synchronous<br />

MPI_SSEND (buf, count, datatype, dest, tag, comm, ierr)<br />

MPI_ISSEND (buf, count, dtype, dest, tag, comm, req, ierr)<br />

Can be started (called) at any time.<br />

Does not complete until a matching receive has been posted<br />

and the receive operation has been started<br />

* Does NOT mean the matching receive has completed<br />

Can be used in place <strong>of</strong> sending and receiving<br />

acknowledgements<br />

Can be more efficient when used appropriately<br />

buffering may be avoided<br />

<strong>David</strong> <strong>Cronk</strong> 77


Point-to-Point Communication<br />

Modes: Ready Mode<br />

MPI_RSEND (buf, count, datatype, dest, tag, comm, ierr)<br />

MPI_IRSEND (buf, count, dtype, dest, tag, comm, req, ierr)<br />

May ONLY be started (called) if a matching receive has already<br />

been posted.<br />

If a matching receive has not been posted, the results are<br />

undefined<br />

May be most efficient when appropriate<br />

Removal <strong>of</strong> handshake operation<br />

Should only be used with extreme caution<br />

<strong>David</strong> <strong>Cronk</strong> 78


Ready Mode<br />

SLAVE<br />

MASTER<br />

while (!done) {<br />

MPI_Recv (NULL, 0, MPI_INT, MPI_ANYSOURCE,<br />

1, MPI_COMM_WORLD, &status);<br />

source = status.MPI_SOURCE;<br />

get_work (…..);<br />

MPI_Rsend (buff, count, datatype, source, 2,<br />

MPI_COMM_WORLD);<br />

if (no more work) done = TRUE;<br />

}<br />

while (!done) {<br />

MPI_Send (NULL, 0, MPI_INT, MASTER,<br />

1, MPI_COMM_WORLD);<br />

MPI_Recv (buff, count, datatype, MASTER,<br />

2, MPI_COMM_WORLD, &status);<br />

…<br />

}<br />

UNSAFE<br />

while (!done) {<br />

MPI_Irecv (buff, count, datatype, MASTER,<br />

2, MPI_COMM_WORLD, &request);<br />

MPI_Ssend (NULL, 0, MPI_INT, MASTER,<br />

1, MPI_COMM_WORLD);<br />

MPI_Wait (&request, &status);<br />

…<br />

}<br />

SAFE<br />

<strong>David</strong> <strong>Cronk</strong> 79


Point-to-Point Communication<br />

Modes: Performance Issues<br />

› Non-blocking calls are almost always the way to go<br />

› Communication can be carried out during blocking system<br />

calls<br />

› Computation and communication can be overlapped if there<br />

is special purpose communication hardware<br />

› Less likely to have errors that lead to deadlock<br />

› Standard mode is usually sufficient - but buffered mode can<br />

<strong>of</strong>fer advantages<br />

• Particularly if there are frequent, large messages being sent<br />

• If the user is unsure the system provides sufficient buffer space<br />

› Synchronous mode can be more efficient if acks are needed<br />

• Also tells the system that buffering is not required<br />

<strong>David</strong> <strong>Cronk</strong> 80


TAKE<br />

A<br />

BREAK<br />

<strong>David</strong> <strong>Cronk</strong> 81


Day 2<br />

Course Outline (cont)<br />

Morning – Lecture<br />

Communication Modes<br />

Collective communication<br />

Afternoon – <strong>Lab</strong><br />

Hands on exercises using various<br />

communication methods in MPI<br />

<strong>David</strong> <strong>Cronk</strong> 82


Collective Communication<br />

OUTLINE<br />

› Introduction<br />

› Synchronization<br />

› Global Collective Communication<br />

› Reduction<br />

• Reduction routines<br />

• User defined operations<br />

› Performance issues<br />

<strong>David</strong> <strong>Cronk</strong> 83


Collective Communication<br />

Amount <strong>of</strong> data sent must exactly match the amount <strong>of</strong><br />

data received<br />

Collective routines are collective across an entire<br />

communicator and must be called in the same order<br />

from all processors within the communicator<br />

Collective routines are all blocking<br />

This simply means buffers can be re-used upon return<br />

Collective routines may return as soon as the calling<br />

process’ participation is complete<br />

Does not say anything about the other processors<br />

Collective routines may or may not be synchronizing<br />

No mixing <strong>of</strong> collective and point-to-point communication<br />

<strong>David</strong> <strong>Cronk</strong> 84


Collective Communication<br />

Synchronization<br />

Barrier: MPI_BARRIER (comm, ierr)<br />

Only collective routine which provides explicit<br />

synchronization<br />

Returns at any processor only after all processes<br />

have entered the call<br />

Barrier can be used to ensure all processes have<br />

reached a certain point in the computation<br />

<strong>David</strong> <strong>Cronk</strong> 85


Collective Communication<br />

Global Communication Routines:<br />

› Except broadcast, each routine has 2 variants:<br />

• Standard variant: All messages are the same size<br />

• Vector Variant: Each item is a vector <strong>of</strong> possibly varying length<br />

› If there is a single origin or destination, it is referred to as the<br />

root<br />

› Each routine (except broadcast) has distinct send and<br />

receive arguments<br />

› Send and receive buffers must be disjoint<br />

› Each can use MPI_IN_PLACE, which allows the user to<br />

specify that data contributed by the caller is already in its<br />

final location.<br />

<strong>David</strong> <strong>Cronk</strong> 86


Collective Communication: Bcast<br />

MPI_BCAST (buffer, count, datatype, root, comm, ierr)<br />

This routine copies count elements <strong>of</strong> type datatype from<br />

buffer on the process with rank root into the location<br />

specified by buffer on all other processes in the group<br />

referenced by the communicator comm<br />

All processes must supply the same value for the argument<br />

root<br />

MPI_BCAST is strictly in-place, not data is moved at the root<br />

REMEMBER: A broadcast need not be synchronizing.<br />

Returning from a broadcast tells you nothing about the<br />

status <strong>of</strong> the other processes involved in a broadcast.<br />

Furthermore, though MPI does not require MPI_BCAST to<br />

be synchronizing, it neither prohibits synchronous behavior.<br />

<strong>David</strong> <strong>Cronk</strong> 87


BCAST<br />

If (myrank == root) {<br />

fp = fopen (filename, ‘r’);<br />

fscanf (fp, ‘%d’, &iters);<br />

fclose (fp);<br />

MPI_Bcast (&iters, 1, MPI_INT,<br />

root, MPI_COMM_WORLD);<br />

}<br />

else {<br />

MPI_Recv (&iters, 1, MPI_INT,<br />

root, tag, MPI_COMM_WORLD,<br />

&status);<br />

}<br />

If (myrank == root) {<br />

fp = fopen (filename, ‘r’);<br />

fscanf (fp, ‘%d’, &iters);<br />

fclose (fp);<br />

}<br />

MPI_Bcast (&iters, 1, MPI_INT,<br />

root, MPI_COMM_WORLD);<br />

cont<br />

THAT’S BETTER<br />

OOPS!<br />

<strong>David</strong> <strong>Cronk</strong> 88


Collective Communication:<br />

Gather<br />

A Gather operation has data from all processes<br />

collected, or “gathered”, at a central process,<br />

referred to as the “root”<br />

Even the root process contributes data<br />

The root process can be any process, it does<br />

not have to have any particular rank<br />

Every process must pass the same value for the<br />

root argument<br />

Each process must send the same amount <strong>of</strong><br />

data<br />

<strong>David</strong> <strong>Cronk</strong> 89


Collective Communication:<br />

Gather<br />

MPI_GATHER (sendbuf, sendcount, sendtype, recvbuf,<br />

recvcount, recvtype, root, comm, ierr)<br />

› Receive arguments are only meaningful at the root<br />

› recvcount is the number <strong>of</strong> elements received from each<br />

process<br />

› Data received at root in rank order<br />

› Root can use MPI_IN_PLACE for sendbuf:<br />

• data is assumed to be in the correct place in the recvbuf<br />

P1 = root<br />

P2<br />

P3<br />

P2<br />

MPI_GATHER<br />

root<br />

<strong>David</strong> <strong>Cronk</strong> 90


MPI_Gather<br />

for (i = 0; i < 20; i++) {<br />

do some computation<br />

tmp[i] = some value;<br />

}<br />

MPI_Gather (tmp, 20, MPI_INT, res,<br />

20, MPI_INT, 0, MPI_COMM_WORLD);<br />

if (myrank == 0)<br />

write out results<br />

WORKS<br />

int tmp[20];<br />

int res[320];<br />

for (i = 0; i < 20; i++) {<br />

do some computation<br />

if (myrank == 0)<br />

res[i] = some value<br />

else tmp[i] = some value<br />

}<br />

if (myrank == 0)<br />

MPI_Gather (MPI_IN_PLACE,<br />

20, MPI_INT, res, 20, MPI_INT,<br />

0, MPI_COMM_WORLD);<br />

write out results<br />

else<br />

MPI_Gather (tmp, 20, MPI_INT,<br />

tmp, 320, MPI_REAL, 0<br />

MPI_COMM_WORLD);<br />

A OK<br />

<strong>David</strong> <strong>Cronk</strong> 91


Collective Communication:<br />

Gatherv<br />

MPI_GATHERV (sendbuf, sendcount, sendtype,<br />

recvbuf, recvcounts, displs, recvtype, root, comm,ierr)<br />

› Vector variant <strong>of</strong> MPI_GATHER<br />

› Allows a varying amount <strong>of</strong> data from each proc<br />

› allows root to specify where data from each proc<br />

goes<br />

› No portion <strong>of</strong> the receive buffer may be written<br />

more than once<br />

› The amount <strong>of</strong> data specified to be received at the<br />

root must match amount <strong>of</strong> data sent by non-roots<br />

› Displacements are in terms <strong>of</strong> recvtype<br />

› MPI_IN_PLACE may be used by root.<br />

<strong>David</strong> <strong>Cronk</strong> 92


Collective Communication:<br />

Gatherv (cont)<br />

1 2 3 4 counts<br />

9 7 4 0 displs<br />

P1 = root<br />

P2<br />

MPI_GATHERV<br />

P3<br />

P4<br />

<strong>David</strong> <strong>Cronk</strong> 93


Collective Communication:<br />

Gatherv (cont)<br />

sbuffs<br />

rbuff<br />

stride = 105;<br />

root = 0;<br />

for (i = 0; i < nprocs; i++) {<br />

displs[i] = i*stride<br />

counts[i] = 100;<br />

}<br />

MPI_Gatherv (sbuff, 100, MPI_INT,<br />

rbuff, counts, displs, MPI_INT,<br />

root, MPI_COMM_WORLD);<br />

<strong>David</strong> <strong>Cronk</strong> 94


Collective Communication:<br />

Gatherv (cont)<br />

nprocs<br />

….<br />

nprocs<br />

CALL MPI_COMM_SIZE(MPI_COMM_WORLD, nprocs, ierr)<br />

CALL MPI_COMM_RANK(MPI_COMM_WORLD, myrank, ierr)<br />

scount = myrank+1<br />

displs(1) = 0<br />

rcounts(1) = 1<br />

DO I=2,nprocs<br />

displs(I) = displs(I-1) + I – 1<br />

rcounts(I) = I<br />

ENDDO<br />

CALL MPI_GATHERV(sbuff, scount, MPI_INT, rbuff, rcounts,<br />

displs, MPI_INT, root, MPI_COMM_WORL, ierr)<br />

<strong>David</strong> <strong>Cronk</strong> 95


Collective Communication:<br />

Scatter<br />

MPI_SCATTER (sendbuf, sendcount, sendtype, recvbuf,<br />

recvcount, recvtype, root, comm, ierr)<br />

› Opposite <strong>of</strong> MPI_GATHER<br />

› Send arguments only meaningful at root<br />

› Root can use MPI_IN_PLACE for recvbuf<br />

P1<br />

MPI_SCATTER<br />

P2<br />

B (on root)<br />

P3<br />

P4<br />

<strong>David</strong> <strong>Cronk</strong> 96


MPI_SCATTER<br />

IF (MYPE .EQ. ROOT) THEN<br />

OPEN (25, FILE=‘filename’)<br />

READ (25, *) nprocs, nboxes<br />

READ (25, *) mat(i,j) (i=1,nboxes)(j=1,nprocs)<br />

CLOSE (25)<br />

ENDIF<br />

CALL MPI_BCAST (nboxes, 1, MPI_INTEGER,<br />

& ROOT, MPI_COMM_WORLD, ierr)<br />

CALL MPI_SCATTER (mat, nboxes, MPI_INT,<br />

& lboxes, nboxes, MPI_INT, ROOT,<br />

& MPI_COMM_WORLD, ierr)<br />

<strong>David</strong> <strong>Cronk</strong> 97


Collective Communication:<br />

Scatterv<br />

MPI_SCATTERV (sendbuf, scounts, displs, sendtype,<br />

recvbuf, recvcount, recvtype, ierr)<br />

› Opposite <strong>of</strong> MPI_GATHERV<br />

› Send arguments only meaningful at root<br />

› Root can use MPI_IN_PLACE for recvbuf<br />

› No location <strong>of</strong> the sendbuf can be read more than<br />

once<br />

<strong>David</strong> <strong>Cronk</strong> 98


Collective Communication:<br />

Scatterv (cont)<br />

P1<br />

MPI_SCATTERV<br />

P2<br />

B (on root)<br />

P3<br />

counts<br />

1 2 3 4<br />

dislps<br />

9 7 4 0<br />

P4<br />

<strong>David</strong> <strong>Cronk</strong> 99


MPI_SCATTERV<br />

C mnb = max number <strong>of</strong> boxes<br />

IF (MYPE .EQ. ROOT) THEN<br />

OPEN (25, FILE=‘filename’)<br />

READ (25, *) nprocs<br />

READ (25, *) (nboxes(I), I=1,nprocs)<br />

READ (25, *) mat(I,J) (I=1,nboxes(I))(J=1,nprocs)<br />

CLOSE (25)<br />

DO I = 1,nprocs<br />

displs(I) = (I-1)*mnb<br />

ENDDO<br />

ENDIF<br />

CALL MPI_SCATTER (nboxes, 1, MPI_INT,<br />

nb, 1, MPI_INT, ROOT, MPI_COMM_WORLD, ierr)<br />

CALL MPI_SCATTERV (mat, nboxes, displs, MPI_INT,<br />

lboxes, nb, MPI_INT, ROOT, MPI_COMM_WORLD, ierr)<br />

<strong>David</strong> <strong>Cronk</strong> 100


Collective Communication:<br />

Allgather<br />

MPI_ALLGATHER (sendbuf, sendcount,<br />

sendtype, recvbuf, recvcount, recvtype,<br />

comm, ierr)<br />

› Same as MPI_GATHER, except all processors get<br />

the result<br />

› MPI_IN_PLACE may be used for sendbuf <strong>of</strong> all<br />

processors<br />

› Equivalent to a gather followed by a bcast<br />

<strong>David</strong> <strong>Cronk</strong> 101


Collective Communication:<br />

Allgatherv<br />

MPI_ALLGATHERV (sendbuf, sendcount,<br />

sendtype, recvbuf, recvcounts, displs,<br />

recvtype, comm, ierr)<br />

› Same as MPI_GATHERV, except all processes<br />

get the result<br />

› MPI_IN_PLACE may be used for sendbuf <strong>of</strong> all<br />

processors<br />

› Similar to a gatherv followed by a bcast<br />

• If there are “holes” in the receive buffer, bcast would<br />

overwrite the “holes”<br />

• displs need not be the same on each PE<br />

<strong>David</strong> <strong>Cronk</strong> 102


Allgatherv<br />

int mycount; /* inited to # local ints */<br />

int counts[4]; /* inited to proper values */<br />

int displs[4];<br />

displs[0] = 0;<br />

for (I = 1; I < 4; I++)<br />

displs[I] = displs[I-1] + counts[I-1];<br />

MPI_Allgatherv(sbuff, mycount, MPI_INT,<br />

rbuff, counts, displs, MPI_INT,<br />

MPI_COMM_WORLD);<br />

<strong>David</strong> <strong>Cronk</strong> 103


Allgatherv<br />

sbuffs<br />

rbuff<br />

stride = 105;<br />

root = 0;<br />

for (i = 0; i < nprocs; i++) {<br />

displs[i] = i*stride<br />

counts[I] = 100;<br />

}<br />

MPI_Allgatherv (sbuff, 100, MPI_INT,<br />

rbuff, counts, displs, MPI_INT,<br />

MPI_COMM_WORLD);<br />

<strong>David</strong> <strong>Cronk</strong> 104


Allgatherv<br />

p1 p2 p3 p4<br />

MPI_Comm_rank (MPI_COMM_WORLD, &myrank);<br />

MPI_Comm_size (MPI_COMM_WORLD, &nprocs);<br />

p1<br />

p2<br />

p3<br />

p4<br />

for (i=0; i


Collective Communication:<br />

Alltoall (scatter/gather)<br />

MPI_ALLTOALL (sendbuf, sendcount, sendtype,<br />

recvbuf, recvcount, recvtype, comm, ierr)<br />

<strong>David</strong> <strong>Cronk</strong> 106


Collective Communication:<br />

Alltoallv<br />

MPI_ALLTOALLV (sendbuf, sendcounts, sdispls,<br />

sendtype, recvbuf, recvcounts, rdispls, recvtype,<br />

comm, ierr)<br />

› Same as MPI_ALLTOALL, but the vector variant<br />

• Can specify how many blocks to send to each processor,<br />

location <strong>of</strong> blocks to send, how many blocks to receive from<br />

each processor, and where to place the received blocks<br />

• No location in the sendbuf can be read more than once and no<br />

location in the recvbuf can be written to more than once<br />

<strong>David</strong> <strong>Cronk</strong> 107


Collective Communication:<br />

Alltoallw<br />

MPI_ALLTOALLW (sendbuf, sendcounts, sdispls,<br />

sendtypes, recvbuf, recvcounts, rdispls, recvtypes,<br />

comm, ierr)<br />

› Same as MPI_ALLTOALLV, except different<br />

datatypes can be specified for data scattered as<br />

well as data gathered<br />

• Can specify how many blocks to send to each processor,<br />

location and type <strong>of</strong> blocks to send, how many blocks to receive<br />

from each processor, the type <strong>of</strong> the blocks received, and<br />

where to place the received blocks<br />

• Displacements are now in terms <strong>of</strong> bytes rather that types<br />

• No location in the sendbuf can be read more than once and no<br />

location in the recvbuf can be written to more than once<br />

<strong>David</strong> <strong>Cronk</strong> 108


Example<br />

subroutine System_Change_init ( dq, ierror)<br />

!------------------------------------------------------------------------------<br />

! Subroutine for data exchange on all six boundaries<br />

!<br />

! This routine initiates the operations, has to be finished by according<br />

! Wait/Waitall<br />

!------------------------------------------------------------------------------<br />

!<br />

USE globale_daten<br />

USE comm<br />

implicit none<br />

include 'mpif.h'<br />

double precision, dimension (0:n1+1,0:n2+1,0:n3+1,nc) :: dq<br />

! local variables<br />

integer :: handnum, info, position<br />

integer :: j, k, n, ni<br />

integer :: ierror<br />

integer :: size2, size4, size6<br />

! /* Fortran90 */<br />

integer, dimension (MPI_STATUS_SIZE,6) :: sendstatusfeld<br />

integer, dimension (MPI_STATUS_SIZE) :: status<br />

double precision, allocatable, dimension (:) :: global_dq<br />

size2 = (n2+2)*(n3+2)*nc * SIZE_OF_REALx<br />

size4 = (n1+2)*(n3+2)*nc * SIZE_OF_REALx<br />

size6 = (n1+2)*(n2+2)*nc * SIZE_OF_REALx<br />

if (.not. rand_ab) then<br />

call MPI_IRECV(dq(1,1,1,1), recvcount(tid_io),<br />

& recvtype(tid_io), tid_io, 10001,<br />

& MPI_COMM_WORLD, recvhandle(1), info)<br />

else<br />

recvhandle(1) = MPI_REQUEST_NULL<br />

endif<br />

if (.not. rand_sing) then<br />

call MPI_IRECV(dq(1,1,1,1), recvcount(tid_iu),<br />

& recvtype(tid_iu), tid_iu, 10002,<br />

& MPI_COMM_WORLD, recvhandle(2), info)<br />

else<br />

recvhandle(2) = MPI_REQUEST_NULL<br />

endif<br />

<strong>David</strong> <strong>Cronk</strong> 109


Example (cont)<br />

if (.not. rand_zu) then<br />

call MPI_IRECV(dq(1,1,1,1), recvcount(tid_jo),<br />

& recvtype(tid_jo), tid_jo, 10003,<br />

& MPI_COMM_WORLD, recvhandle(3), info)<br />

else<br />

recvhandle(3) = MPI_REQUEST_NULL<br />

endif<br />

if (.not. rand_festk) then<br />

call MPI_IRECV(dq(1,1,1,1), recvcount(tid_ju),<br />

& recvtype(tid_ju), tid_ju, 10004,<br />

& MPI_COMM_WORLD, recvhandle(4), info)<br />

else<br />

recvhandle(4) = MPI_REQUEST_NULL<br />

endif<br />

if (.not. rand_symo) then<br />

call MPI_IRECV(dq(1,1,1,1), recvcount(tid_ko),<br />

& recvtype(tid_ko), tid_ko, 10005,<br />

& MPI_COMM_WORLD, recvhandle(5), info)<br />

else<br />

recvhandle(5) = MPI_REQUEST_NULL<br />

endif<br />

if (.not. rand_symu) then<br />

call MPI_IRECV(dq(1,1,1,1), recvcount(tid_ku),<br />

& recvtype(tid_ku), tid_ku, 10006,<br />

& MPI_COMM_WORLD, recvhandle(6), info)<br />

else<br />

recvhandle(6) = MPI_REQUEST_NULL<br />

endif<br />

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!<br />

if (.not. rand_sing) then<br />

call MPI_ISEND(dq(1,1,1,1), sendcount(tid_iu),<br />

& sendtype(tid_iu), tid_iu, 10001,<br />

& MPI_COMM_WORLD, sendhandle(1), info)<br />

else<br />

sendhandle(1) = MPI_REQUEST_NULL<br />

endif<br />

if (.not. rand_ab) then<br />

call MPI_ISEND(dq(1,1,1,1), sendcount(tid_io),<br />

& sendtype(tid_io), tid_io, 10002,<br />

& MPI_COMM_WORLD, sendhandle(2), info)<br />

else<br />

sendhandle(2) = MPI_REQUEST_NULL<br />

endif<br />

<strong>David</strong> <strong>Cronk</strong> 110


Example (cont)<br />

if (.not. rand_festk) then<br />

call MPI_ISEND(dq(1,1,1,1), sendcount(tid_ju),<br />

& sendtype(tid_ju), tid_ju, 10003,<br />

& MPI_COMM_WORLD, sendhandle(3), info)<br />

else<br />

sendhandle(3) = MPI_REQUEST_NULL<br />

endif<br />

if (.not. rand_zu) then<br />

call MPI_ISEND(dq(1,1,1,1), sendcount(tid_jo),<br />

& sendtype(tid_jo), tid_jo, 10004,<br />

& MPI_COMM_WORLD, sendhandle(4), info)<br />

else<br />

sendhandle(4) = MPI_REQUEST_NULL<br />

endif<br />

if (.not. rand_symo) then<br />

call MPI_ISEND(dq(1,1,1,1), sendcount(tid_ko),<br />

& sendtype(tid_ko), tid_ko, 10006,<br />

& MPI_COMM_WORLD, sendhandle(6), info)<br />

else<br />

sendhandle(6) = MPI_REQUEST_NULL<br />

endif<br />

!... Waitall for the Isends/we have to force to finish them..<br />

call MPI_WAITALL(6, sendhandle, sendstatusfeld, info)<br />

ierror = 0<br />

return<br />

end<br />

if (.not. rand_symu) then<br />

call MPI_ISEND(dq(1,1,1,1), sendcount(tid_ku),<br />

& sendtype(tid_ku), tid_ku, 10005,<br />

& MPI_COMM_WORLD, sendhandle(5), info)<br />

else<br />

sendhandle(5) = MPI_REQUEST_NULL<br />

endif<br />

<strong>David</strong> <strong>Cronk</strong> 111


Example (Alltoallw)<br />

subroutine System_Change ( dq, ierror)<br />

!------------------------------------------------------------------------------<br />

!<br />

! Subroutine for data exchange on all six boundaries<br />

!<br />

! uses the MPI-2 function MPI_Alltoallw<br />

!------------------------------------------------------------------------------<br />

!<br />

USE globale_daten<br />

implicit none<br />

include 'mpif.h'<br />

double precision, dimension (0:n1+1,0:n2+1,0:n3+1,nc) :: dq<br />

integer :: ierror<br />

call MPI_Alltoallw ( dq(1,1,1,1), sendcount, senddisps, sendtype, &<br />

dq(1,1,1,1), recvcount, recvdisps, recvtype, &<br />

MPI_COMM_WORLD, ierror )<br />

end subroutine System_Change<br />

<strong>David</strong> <strong>Cronk</strong> 112


Collective Communication:<br />

Reduction<br />

› Global reduction across all members <strong>of</strong> a group<br />

› Can us predefined operations or user defined<br />

operations<br />

› Can be used on single elements or arrays <strong>of</strong><br />

elements<br />

› Counts and types must be the same on all<br />

processors<br />

› Operations are assumed to be associative<br />

› All pre-defined operations are commutative<br />

› User defined operations can be different on each<br />

processor, but not recommended<br />

<strong>David</strong> <strong>Cronk</strong> 113


Collective Communication:<br />

Reduction (reduce)<br />

MPI_REDUCE (sendbuf, recvbuf, count, datatype, op,<br />

root, comm, ierr)<br />

› recvbuf only meaningful on root<br />

› Combines elements (on an element by element basis) in<br />

sendbuf according to op<br />

› Results <strong>of</strong> the reduction are returned to root in recvbuf<br />

› MPI_IN_PLACE can be used for sendbuf on root<br />

<strong>David</strong> <strong>Cronk</strong> 114


MPI_REDUCE<br />

REAL a(n), b(n,m), c(m)<br />

REAL sum(m)<br />

DO j=1,m<br />

sum(j) = 0.0<br />

DO i = 1,n<br />

sum(j) = sum(j) + a(i)*b(i,j)<br />

ENDDO<br />

ENDDO<br />

CALL MPI_REDUCE(sum, c, m, MPI_REAL,<br />

MPI_SUM, 0, MPI_COMM_WORLD, ierr)<br />

<strong>David</strong> <strong>Cronk</strong> 115


Collective Communication:<br />

Reduction (cont)<br />

› MPI_ALLREDUCE (sendbuf, recvbuf,<br />

count, datatype, op, comm, ierr)<br />

› Same as MPI_REDUCE, except all<br />

processors get the result<br />

› MPI_REDUCE_SCATTER (sendbuf,<br />

recv_buff, recvcounts, datatype, op,<br />

comm, ierr)<br />

› Acts like it does a reduce followed by a<br />

scatterv<br />

<strong>David</strong> <strong>Cronk</strong> 116


MPI_ALLREDUCE<br />

REAL a(n), b(n,m), c(m)<br />

REAL sum(m)<br />

DO j=1,m<br />

sum(j) = 0.0<br />

DO i = 1,n<br />

sum(j) = sum(j) + a(i)*b(i,j)<br />

ENDDO<br />

ENDDO<br />

CALL MPI_ALLREDUCE(sum, c, m, MPI_REAL,<br />

MPI_SUM, MPI_COMM_WORLD, ierr)<br />

<strong>David</strong> <strong>Cronk</strong> 117


MPI_REDUCE_SCATTER<br />

DO j=1,nprocs<br />

counts(j) = n<br />

DO j=1,m<br />

sum(j) = 0.0<br />

DO i = 1,n<br />

sum(j) = sum(j) + a(i)*b(i,j)<br />

ENDDO<br />

ENDDO<br />

CALL MPI_REDUCE_SCATTER(sum, c, counts, MPI_REAL,<br />

MPI_SUM, MPI_COMM_WORLD, ierr)<br />

<strong>David</strong> <strong>Cronk</strong> 118


Collective Communication: Prefix<br />

Reduction<br />

MPI_SCAN (sendbuf, recvbuf, count,<br />

datatype, op, comm, ierr)<br />

Performs an inclusive element-wise prefix<br />

reduction<br />

MPI_EXSCAN (sendbuf, recvbuf, count,<br />

datatype, op, comm, ierr)<br />

› Performs an exclusive prefix reduction<br />

› Results are undefined at process 0<br />

<strong>David</strong> <strong>Cronk</strong> 119


MPI_SCAN<br />

MPI_SCAN (sbuf, rbuf, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD)<br />

MPI_EXSCAN (sbuf, rbuf, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD)<br />

<strong>David</strong> <strong>Cronk</strong> 120


Collective Communication:<br />

Reduction - user defined ops<br />

MPI_OP_CREATE (function, commute, op, ierr)<br />

› if commute is true, operation is assumed to be<br />

commutative<br />

› Function is a user defined function with 4 arguments<br />

• invec: input vector<br />

• inoutvec: input and output value<br />

• len: number <strong>of</strong> elements<br />

• datatype: MPI_DATATYPE<br />

• Returns invec[i] op inoutvec[i], i = 0..len-1<br />

› MPI_OP_FREE (op, ierr)<br />

<strong>David</strong> <strong>Cronk</strong> 121


Create a non-commutative sum<br />

Void my_add (void *in, void *out, int *len, MPI_Datatype *dtype)<br />

{<br />

int i;<br />

int *iarray1, *iarray2;<br />

float *farray1, *farray2;<br />

if (*dtype == MPI_INT) {<br />

iarray1 = in; iarray2 = out;<br />

for (i = 0; i < *len; i++)<br />

iarray2[i] = iarra2[i] + iarray1[i];<br />

} else {<br />

farray1 = in; farray2 = out;<br />

for (i = 0; i < *len; i++)<br />

iarray2[i] = iarra2[i] + iarray1[i];<br />

}<br />

}<br />

…<br />

MPI_Op myop;<br />

MPI_Op_create ((MPI_User_function*)my_add, False, &myop);<br />

MPI_Reduce (inbuf, outbuf, num, MPI_FLOAT, myop, 0, MPI_COMM_WORLD);<br />

<strong>David</strong> <strong>Cronk</strong> 122


Collective Communication:<br />

Performance Issues<br />

Collective operations should have much better<br />

performance than simply sending messages directly<br />

› Broadcast may make use <strong>of</strong> a broadcast tree (or other<br />

mechanism)<br />

› All collective operations can potentially make use <strong>of</strong> a tree<br />

(or other) mechanism to improve performance<br />

Important to use the simplest collective operations<br />

which still achieve the needed results<br />

Use MPI_IN_PLACE whenever appropriate and<br />

supported<br />

Reduces unnecessary memory usage and redundant data<br />

movement<br />

<strong>David</strong> <strong>Cronk</strong> 123


Course Outline (cont)<br />

Day 3<br />

Morning – Lecture<br />

Derived Datatypes<br />

What else is there<br />

Groups and communicators<br />

MPI-2<br />

Dynamic process management<br />

One-sided communication<br />

MPI-I/O<br />

Afternoon – <strong>Lab</strong><br />

Hands on exercises creating and using derived datatypes<br />

<strong>David</strong> <strong>Cronk</strong> 124


Derived Datatypes<br />

› Introduction and definitions<br />

› Datatype constructors<br />

› Committing derived datatypes<br />

› Pack and Unpack<br />

› Performance issues<br />

<strong>David</strong> <strong>Cronk</strong> 125


Derived Datatypes<br />

› A derived datatype is a sequence <strong>of</strong> primitive<br />

datatypes and displacements<br />

› Derived datatypes are created by building on<br />

primitive datatypes<br />

› A derived datatype’s typemap is the sequence <strong>of</strong><br />

(primitive type, disp) pairs that defines the derived<br />

datatype<br />

› These displacements need not be positive, unique, or<br />

increasing.<br />

› A datatype’s type signature is just the sequence <strong>of</strong><br />

primitive datatypes<br />

› A messages type signature is the type signature <strong>of</strong><br />

the datatype being sent, repeated count times<br />

<strong>David</strong> <strong>Cronk</strong> 126


Derived Datatypes (cont)<br />

Typemap =<br />

(MPI_INT, 0) (MPI_INT, 12) (MPI_INT, 16) (MPI_INT, 20) (MPI_INT, 36)<br />

Type Signature =<br />

{MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT}<br />

Type Signature =<br />

{MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_INT}<br />

In collective communication, the type signature <strong>of</strong> data sent must<br />

match the type signature <strong>of</strong> data received!<br />

<strong>David</strong> <strong>Cronk</strong> 127


Derived Datatypes (cont)<br />

Lower Bound: The lowest displacement <strong>of</strong> an entry <strong>of</strong><br />

this datatype<br />

Upper Bound: Relative address <strong>of</strong> the last byte<br />

occupied by entries <strong>of</strong> this datatype, rounded up to<br />

satisfy alignment requirements<br />

Extent: The span from lower to upper bound<br />

MPI_GET_EXTENT (datatype, lb, extent, ierr)<br />

MPI_TYPE_SIZE (datatype, size, ierr)<br />

MPI_GET_ADDRESS (location, address, ierr)<br />

Lb, extent, and address are <strong>of</strong> type MPI_Aint in C and<br />

INTEGER(KIND=MPI_ADDRESS_KIND) in Fortran<br />

<strong>David</strong> <strong>Cronk</strong> 128


Datatype Constructors<br />

MPI_TYPE_DUP (oldtype, newtype, ierr)<br />

› Simply duplicates an existing type<br />

› Not useful to regular users<br />

MPI_TYPE_CONTIGUOUS(count,oldtype,newtype,ierr)<br />

› Creates a new type representing count contiguous<br />

occurrences <strong>of</strong> oldtype (uses extent(oldtype))<br />

› ex: MPI_TYPE_CONTIGUOUS (2, MPI_INT, 2INT)<br />

• creates a new datatype 2INT which represents<br />

an array <strong>of</strong> 2 integers<br />

Datatype 2INT<br />

<strong>David</strong> <strong>Cronk</strong> 129


CONTIGUOUS DATATYPE<br />

P1 sends 100 integers to P2<br />

P1<br />

int buff[100];<br />

MPI_Datatype dtype;<br />

...<br />

...<br />

MPI_Type_contiguous (100,<br />

MPI_INT, &dtype);<br />

MPI_Type_commit (&dtype);<br />

P2<br />

int buff[100]<br />

MPI_Recv (buff, 100, MPI_INT, 1, tag,<br />

MPI_COMM_WORLD, &status)<br />

MPI_Send (buff, 1, dtype, 2, tag,<br />

MPI_COMM_WORLD)<br />

<strong>David</strong> <strong>Cronk</strong> 130


Datatype Constructors (cont)<br />

MPI_TYPE_VECTOR (count, blocklength, stride,<br />

oldtype, newtype, ierr)<br />

› Creates a datatype representing count regularly spaced<br />

occurrences <strong>of</strong> blocklength contiguous oldtypes<br />

› stride is in terms <strong>of</strong> elements <strong>of</strong> oldtype (may be negative)<br />

› ex: MPI_TYPE_VECTOR (4, 2, 3, 2INT, AINT)<br />

AINT<br />

<strong>David</strong> <strong>Cronk</strong> 131


Datatype Constructors (cont)<br />

MPI_TYPE_CREATE_HVECTOR (count, blocklength,<br />

stride, oldtype, newtype, ierr)<br />

› Identical to MPI_TYPE_VECTOR, except stride is given in<br />

bytes rather than elements.<br />

› In C, stride is <strong>of</strong> type MPI_Aint<br />

› In Fortran, stride is integer(kind=MPI_ADDRESS_KIND)<br />

› ex: MPI_TYPE_CREATE_HVECTOR (4, 2, 20, 2INT, BINT)<br />

BINT<br />

<strong>David</strong> <strong>Cronk</strong> 132


EXAMPLE<br />

REAL a(100,100), B(100,100)<br />

CALL MPI_COMM_RANK (MPI_COMM_WORLD, myrank, ierr)<br />

CALL MPI_TYPE_SIZE (MPI_REAL, size<strong>of</strong>real, ierr)<br />

CALL MPI_TYPE_VECTOR (100, 1, 100,MPI_REAL, rtype, ierr)<br />

CALL MPI_TYPE_CREATE_HVECTOR (100, 1, size<strong>of</strong>real, rtype,<br />

xpose, ierr)<br />

CALL MPI_TYPE_COMMIT (xpose, ierr)<br />

CALL MPI_SENDRECV (a, 1, xpose, myrank, 0, b, 100*100,<br />

MPI_REAL, myrank, 0, MPI_COMM_WORLD, status, ierr)<br />

<strong>David</strong> <strong>Cronk</strong> 133


HVECTOR<br />

struct particles<br />

{<br />

char class;<br />

double coord[4];<br />

char other[5];<br />

}<br />

void sendparts ()<br />

{<br />

struct particles parts[1000];<br />

int dest, tag;<br />

MPI_Datatype dtype;<br />

size = size<strong>of</strong> (struct particles);<br />

MPI_Type_create_hvector (1000, 2, size,<br />

MPI_DOUBLE, &loctype);<br />

MPI_Type_commit(&loctype);<br />

MPI_Send(parts[0].coord, 1, loctype, dest, tag, comm);<br />

<strong>David</strong> <strong>Cronk</strong> 134


Datatype Constructors (cont)<br />

MPI_TYPE_INDEXED (count, blocklengths, displs, oldtype, newtype, ierr)<br />

•Allows specification <strong>of</strong> non-contiguous data layout<br />

•Good for irregular problems<br />

•ex: MPI_TYPE_INDEXED (3, lengths, displs, 2INT, CINT)<br />

•lengths = (2, 4, 3) displs = (0,3,8)<br />

CINT<br />

•Most <strong>of</strong>ten, block sizes are all the same (typically 1)<br />

•MPI-2 introduced a new constructor<br />

<strong>David</strong> <strong>Cronk</strong> 135


Datatype Constructors (cont)<br />

MPI_TYPE_CREATE_INDEXED_BLOCK (count,<br />

blocklength, displs, oldtype, newtype, ierr)<br />

› Same as MPI_TYPE_INDEXED, except all blocks are the<br />

same length (blocklength)<br />

› ex: MPI_TYPE_INDEXED_BLOCK (7, 1, displs, MPI_INT,<br />

DINT)<br />

• displs = (1, 3, 4, 6, 9, 13, 14)<br />

DINT<br />

•displs = (14, 3, 4, 9, 6, 13, 1)<br />

DINT<br />

<strong>David</strong> <strong>Cronk</strong> 136


Datatype Constructors (cont)<br />

MPI_TYPE_CREATE_HINDEXED (count, blocklengths, displs,<br />

oldtype, newtype, ierr)<br />

Identical to MPI_TYPE_INDEXED except displacements are in bytes<br />

rather then elements<br />

Displs are <strong>of</strong> type MPI_Aint in C and<br />

integer(KIND=MPI_ADDRESS_KIND) in Fortran<br />

MPI_TYPE_CREATE_STRUCT (count, lengths, displs, types,<br />

newtype, ierr)<br />

› Used mainly for sending arrays <strong>of</strong> structures<br />

› count is number <strong>of</strong> fields in the structure<br />

› lengths is number <strong>of</strong> elements in each field<br />

› displs should be calculated (portability) and are <strong>of</strong> type MPI_Aint in<br />

C and integer(KIND=MPI_ADDRESS_KIND) in Fortran<br />

<strong>David</strong> <strong>Cronk</strong> 137


MPI_TYPE_CREATE_STRUCT<br />

MPI_Datatype stype;<br />

MPI_Datatype types[3] =<br />

{MPI_CHAR, MPI_DOUBLE,<br />

MPI_CHAR};<br />

int lens[3] = {1, 6, 7};<br />

MPI_Aint displs[3] = {0,<br />

size<strong>of</strong>(double), 7*size<strong>of</strong>(double)};<br />

MPI_Type_create_struct (3, lens,<br />

displs, types, &stype);<br />

Non-portable<br />

struct s1 {<br />

char class;<br />

double d[6];<br />

char b[7];<br />

};<br />

struct s1 sarray[100];<br />

MPI_Datatype stype;<br />

MPI_Datatype types[3] =<br />

{MPI_CHAR, MPI_DOUBLE,<br />

MPI_CHAR};<br />

int lens[3] = {1, 6, 7};<br />

MPI_Aint displs[3];<br />

MPI_Get_address (&sarray[0].class,<br />

&displs[0]);<br />

MPI_Get_address (&sarray[0].d,<br />

&displs[1]);<br />

MPI_Get_address (&sarray[0].b,<br />

&displs[2]);<br />

for (i=2;i>=0;i--) displs[i] -=displs[0]<br />

MPI_Type_create_struct (3, lens,<br />

displs, types, &stype);<br />

Semi-portable<br />

<strong>David</strong> <strong>Cronk</strong> 138


MPI_TYPE_CREATE_STRUCT<br />

int i;<br />

char c[100];<br />

float f[3];<br />

int a;<br />

MPI_Aint disp[4];<br />

int lens[4] = {1, 100, 3, 1};<br />

MPI_Datatype types[4] = {MPI_INT, MPI_CHAR, MPI_FLOAT, MPI_INT};<br />

MPI_Datatype stype;<br />

MPI_Get_address(&i, &disp[0]);<br />

MPI_Get_address(c, &disp[1]);<br />

MPI_Get_address(f, &disp[2]);<br />

MPI_Get_address(&a, &disp[3]);<br />

MPI_Type_create_struct(4, lens, disp, types, &stype);<br />

MPI_Type_commit (&stype);<br />

MPI_Send (MPI_BOTTOM, 1, stype, ……..);<br />

<strong>David</strong> <strong>Cronk</strong> 139


Derived Datatypes (cont)<br />

MPI_TYPE_CREATE_RESIZED<br />

(oldtype, lb, extent, newtype, ierr)<br />

› sets a new lower bound and extent for<br />

oldtype<br />

› Does NOT change amount <strong>of</strong> data sent in<br />

a message<br />

• only changes data access pattern<br />

› lb and extent are <strong>of</strong> type MPI_Aint in C and<br />

integer(KIND=MPI_ADDRESS_KIND) in<br />

Fortran<br />

<strong>David</strong> <strong>Cronk</strong> 140


MPI_TYPE_CREATE_RESIZED<br />

Struct s1 {<br />

char class;<br />

double d[2];<br />

char b[3];<br />

};<br />

struct s1 sarray[100];<br />

MPI_Datatype stype, ntype;<br />

MPI_Datatype types[3] =<br />

{MPI_CHAR, MPI_DOUBLE,<br />

MPI_CHAR};<br />

int lens[3] = {1, 6, 7};<br />

MPI_Aint displs[3];<br />

MPI_Get_address (&sarray[0].class,<br />

&displs[0];<br />

MPI_Get_address (&sarray[0].d,<br />

&displs[1];<br />

MPI_Get_address (&sarray[0].b,<br />

&displs[2];<br />

for (i=2;i>=0;i--) displs[i] -=displs[0]<br />

MPI_Type_create_struct (3, lens,<br />

displs, types, &stype);<br />

MPI_Type_create_resized (stype, 0,<br />

size<strong>of</strong>(struct s1), &ntype);<br />

Really Portable<br />

<strong>David</strong> <strong>Cronk</strong> 141


MPI_TYPE_CREATE_RESIZED<br />

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35<br />

P 0<br />

Send to P 1<br />

Send to P 2<br />

Send to P 3<br />

MPI_Type_vector (2, 4, 6, MPI_INT, &my_type);<br />

What if I want to send all purple portions at once<br />

MPI_Send (outbuff, 3, my_type, target, tag, comm);<br />

This would send 0, 1, 2, 3, 6, 7, 8, 9, 10,11, 12, 13, 16, 17, 18, 19,..<br />

MPI_Type_create_resized (MY_TYPE, 0, 12*size<strong>of</strong>(int), &new_type);<br />

We can now send all elements in one call<br />

We could even use a scatter now to send to P 1 , P 2 , and P 3<br />

<strong>David</strong> <strong>Cronk</strong> 142


Datatype Constructors (cont)<br />

MPI_TYPE_CREATE_SUBARRAY (ndims, sizes,<br />

subsizes, starts, order, oldtype, newtype, ierr)<br />

› Creates a newtype which represents a contiguous<br />

subsection <strong>of</strong> an array with ndims dimensions<br />

• This sub-array is only contiguous conceptually, it may not be<br />

stored contiguously in memory!<br />

› ndims is the number <strong>of</strong> array dimensions<br />

› sizes is an integer array is magnitude <strong>of</strong> array in each<br />

dimension<br />

› Subsizes is integer array <strong>of</strong> magnitude <strong>of</strong> the subarray in<br />

each dimension<br />

› starts is an integer array specifying starting coordinates <strong>of</strong><br />

subarray<br />

› Arrays are assumed to be indexed starting a zero!!!<br />

› Order must be MPI_ORDER_C or MPI_ORDER_FORTRAN<br />

• C programs may specify Fortran ordering, and vice-versa<br />

<strong>David</strong> <strong>Cronk</strong> 143


Datatype Constructors: Subarrays<br />

(1,1)<br />

(10,10)<br />

MPI_TYPE_CREATE_SUBARRAY (2, sizes, subsizes,<br />

starts, MPI_ORDER_FORTRAN, MPI_INT, sarray)<br />

sizes = (10, 10)<br />

subsizes = (6,6)<br />

starts = (3, 3)<br />

<strong>David</strong> <strong>Cronk</strong> 144


Datatype Constructors: Subarrays<br />

(1,1)<br />

(10,10)<br />

MPI_TYPE_CREATE_SUBARRAY (2, sizes, subsizes,<br />

starts, MPI_ORDER_FORTRAN, MPI_INT, sarray)<br />

sizes = (10, 10)<br />

subsizes = (6,6)<br />

starts = (2,2)<br />

<strong>David</strong> <strong>Cronk</strong> 145


Datatype Constructors: Darrays<br />

MPI_TYPE_CREATE_DARRAY (size, rank, dims,<br />

gsizes, distribs, dargs, psizes, order, oldt, newtype,<br />

ierr)<br />

› Used with arrays that are distributed in HPF-like fashion on<br />

Cartesian process grids<br />

› Generates datatypes corresponding to the sub-arrays stored<br />

on each processor<br />

› Returns in newtype a datatype specific to the sub-array<br />

stored on process rank<br />

<strong>David</strong> <strong>Cronk</strong> 146


Datatype Constructors (cont)<br />

Derived datatypes must be committed before<br />

they can be used<br />

› MPI_TYPE_COMMIT (datatype, ierr)<br />

› Performs a “compilation” <strong>of</strong> the datatype<br />

description into an efficient representation<br />

Derived datatypes should be freed when they<br />

are no longer needed<br />

› MPI_TYPE_FREE (datatype, ierr)<br />

› Does not effect datatypes derived from the freed<br />

datatype or current communication<br />

<strong>David</strong> <strong>Cronk</strong> 147


Pack and Unpack<br />

MPI_PACK (inbuf, incount, datatype, outbuf, outsize,<br />

position, comm, ierr)<br />

MPI_UNPACK (inbuf, insize, position, outbuf, outcount,<br />

datatype, comm, ierr)<br />

MPI_PACK_SIZE (incount, datatype, comm, size, ierr)<br />

› Packed messages must be sent with the type MPI_PACKED<br />

› Packed messages can be received with any matching<br />

datatype<br />

› Unpacked messages can be received with the type<br />

MPI_PACKED<br />

› Receives must use type MPI_PACKED if the messages are<br />

to be unpacked<br />

<strong>David</strong> <strong>Cronk</strong> 148


int i;<br />

char c[100];<br />

MPI_Aint disp[2];<br />

int lens[2] = {1, 100];<br />

MPI_Datatype types[2] = {MPI_INT, MPI_CHAR};<br />

MPI_Datatype type1;<br />

MPI_Get_address (&i, &(disp[0]);<br />

MPI_Get_address(c, &(disp[1]);<br />

MPI_Type_create_struct (2, lens, disp, types, &type1);<br />

MPI_Type_commit (&type1);<br />

MPI_Send (MPI_BOTTOM, 1, type1, 1, 0, MPI_COMM_WORLD)<br />

int i;<br />

char c[100];<br />

char buf[110];<br />

int pos = 0;<br />

Pack and Unpack<br />

MPI_Pack(&i, 1, MPI_INT, buf, 110, &pos, MPI_COMM_WORLD);<br />

MPI_Pack(c, 100, MPI_CHAR, buf, 110, &pos, MPI_COMM_WORLD);<br />

MPI_Send(buf, pos, MPI_PACKED, 1, 0, MPI_COMM_WORLD);<br />

Char c[100];<br />

MPI_Status status;<br />

int i, comm;<br />

MPI_Aint disp[2];<br />

int len[2] = {1, 100};<br />

MPI_Datatype types[2] = {MPI_INT, MPI_CHAR};<br />

MPI_Datatype type1;<br />

MPI_Get_address (&i, &(disp[0]);<br />

MPI_Get_address(c, &(disp[1]);<br />

MPI_Type_create_struct (2, lens, disp, types, &type1);<br />

MPI_Type_commit (&type1);<br />

comm = MPI_COMM_WORLD;<br />

MPI_Recv (MPI_BOTTOM, 1, type1, 0, 0, comm, &status);<br />

int i, comm;<br />

char c[100];<br />

MPI_Status status;<br />

char buf[110]<br />

int pos = 0;<br />

comm = MPI_COMM_WORLD;<br />

MPI_Recv (buf, 110, MPI_PACKED, 1, 0, comm, &status);<br />

MPI_Unpack (buf, &pos, &i, 1, MPI_INT, comm);<br />

MPI_Unpack (buf, 110, &pos, c, 100, MPI_CHAR, comm);<br />

<strong>David</strong> <strong>Cronk</strong> 149


Derived Datatypes: Performance<br />

Issues<br />

› May allow the user to send fewer or smaller<br />

messages<br />

› System dependant on how well this <strong>works</strong><br />

› May be able to significantly reduce memory copies<br />

› Not all implementations have done a good job<br />

› can make I/O much more efficient<br />

› Data packing may be more efficient if it reduces the<br />

number <strong>of</strong> send operations by packing meta-data at<br />

the front <strong>of</strong> the message<br />

› This is <strong>of</strong>ten possible (and advantageous) for data layouts<br />

that are runtime dependant<br />

<strong>David</strong> <strong>Cronk</strong> 150


TAKE<br />

A<br />

BREAK<br />

<strong>David</strong> <strong>Cronk</strong> 151


Course Outline (cont)<br />

Day 3<br />

Morning – Lecture<br />

Derived Datatypes<br />

What else is there<br />

Groups and communicators<br />

MPI-2<br />

Dynamic process management<br />

One-sided communication<br />

MPI-I/O<br />

Afternoon – <strong>Lab</strong><br />

Hands on exercises creating and using derived datatypes<br />

<strong>David</strong> <strong>Cronk</strong> 152


Communicators and Groups<br />

Many MPI users are only familiar with<br />

MPI_COMM_WORLD<br />

A communicator can be thought <strong>of</strong> as a handle to a<br />

group<br />

A group is an ordered set <strong>of</strong> processes<br />

Each process is associated with a rank<br />

Ranks are contiguous and start from zero<br />

For many applications (dual level parallelism)<br />

maintaining different groups is appropriate<br />

Groups allow collective operations to work on a subset<br />

<strong>of</strong> processes<br />

Information can be added onto communicators to be<br />

passed into routines<br />

<strong>David</strong> <strong>Cronk</strong> 153


Communicators and Groups(cont)<br />

While we think <strong>of</strong> a communicator as spanning<br />

processes, it is actually unique to a process<br />

A communicator can be thought <strong>of</strong> as a handle<br />

to an object (group attribute) that describes a<br />

group <strong>of</strong> processes<br />

An intracommunicator is used for<br />

communication within a single group<br />

An intercommunicator is used for<br />

communication between 2 disjoint groups<br />

<strong>David</strong> <strong>Cronk</strong> 154


Communicators and Groups(cont)<br />

P 2<br />

P 1<br />

P 3<br />

MPI_COMM_WORLD<br />

Comm1<br />

Comm2<br />

<strong>David</strong> <strong>Cronk</strong> 155


Communicators and Groups(cont)<br />

Refer to previous slide<br />

There are 3 distinct groups<br />

These are associated with MPI_COMM_WORLD,<br />

comm1, and comm2<br />

P 3 is a member <strong>of</strong> all 3 groups and may have<br />

different ranks in each group(say 0, 3 , & 4)<br />

If P 2 wants to send a message to P 1 it must use<br />

MPI_COMM_WORLD<br />

If P 2 wants to send a message to P 3 it can use<br />

MPI_COMM_WORLD (send to rank 0) or comm1<br />

(send to rank 3)<br />

<strong>David</strong> <strong>Cronk</strong> 156


Group Management<br />

You can access information about groups<br />

Size, rank within, translate ranks between 2<br />

groups, compare 2 groups<br />

You can create new groups<br />

Get a group associated with a comm<br />

Set operations, include or exclude lists<br />

<strong>David</strong> <strong>Cronk</strong> 157


Communicator management<br />

You can access information about<br />

communicators<br />

Size <strong>of</strong> group associated with, rank within<br />

group associated with, compare 2<br />

You can create new communicators<br />

Create a new comm for a group<br />

Split a group into disjoint set <strong>of</strong> groups, and<br />

create new comms<br />

Can create intercommunicators<br />

<strong>David</strong> <strong>Cronk</strong> 158


Course Outline (cont)<br />

Day 3<br />

Morning – Lecture<br />

Derived Datatypes<br />

What else is there<br />

Groups and communicators<br />

MPI-2<br />

One-sided communication<br />

Dynamic process management<br />

MPI-I/O<br />

Afternoon – <strong>Lab</strong><br />

Hands on exercises creating and using derived datatypes<br />

<strong>David</strong> <strong>Cronk</strong> 159


One Sided Communication<br />

One sided communication allows shmem style<br />

gets and puts<br />

Only one process need actively participate in<br />

one sided operations<br />

With sufficient hardware support, remote<br />

memory operations can <strong>of</strong>fer greater<br />

performance and functionality over the<br />

message passing model<br />

MPI remote memory operations do not make<br />

use <strong>of</strong> a shared address space<br />

<strong>David</strong> <strong>Cronk</strong> 160


One Sided Communication<br />

By requiring only one process to<br />

participate, significant performance<br />

improvements are possible<br />

› No implicit ordering <strong>of</strong> data delivery<br />

› No implicit synchronization<br />

Some programs are more easily written<br />

with the remote memory access (RMA)<br />

model<br />

› Global counter<br />

<strong>David</strong> <strong>Cronk</strong> 161


One Sided Communication<br />

RMA operations require 3 steps<br />

1. Define an area <strong>of</strong> memory that can be<br />

used for RMA operations (window)<br />

2. Specify the data to be moved and<br />

where to move it<br />

3. Specify a way <strong>of</strong> to know the data is<br />

available<br />

<strong>David</strong> <strong>Cronk</strong> 162


One Sided Communication<br />

Get<br />

Put<br />

Address space<br />

Windows<br />

<strong>David</strong> <strong>Cronk</strong> 163


One Sided Communication<br />

Memory Windows<br />

A memory window defines an area <strong>of</strong> memory that<br />

can be used for RMA operations<br />

A memory window must be a contiguous block <strong>of</strong><br />

memory<br />

Described by a base address and number <strong>of</strong> bytes<br />

Window creation is collective across a communicator<br />

A window object is returned. This window object is<br />

used for all subsequent RMA calls<br />

<strong>David</strong> <strong>Cronk</strong> 164


One Sided Communication<br />

Data movement<br />

MPI_PUT<br />

MPI_GET<br />

MPI_ACCUMULATE<br />

All data movement routines are nonblocking<br />

Synchronization call is required to ensure<br />

operation completion<br />

<strong>David</strong> <strong>Cronk</strong> 165


Dynamic Process Management<br />

Standard manner <strong>of</strong> starting processes in<br />

PVM<br />

Useful in assembling complex distributed<br />

applications<br />

Of questionable value with batch queuing<br />

systems and resource managers<br />

Processes are started during runtime<br />

<strong>David</strong> <strong>Cronk</strong> 166


Dynamic Process Management<br />

Spawning new processes<br />

Collective over a group<br />

New processes form their own group with their own<br />

MPI_COMM_WORLD<br />

Spawning processes are returned an<br />

intercommunicator with the spawning processes<br />

part <strong>of</strong> the local group and spawned processes<br />

part <strong>of</strong> the remote group<br />

Spawned processes can get this intercommunicator<br />

with call to MPI_Comm_get_parent<br />

<strong>David</strong> <strong>Cronk</strong> 167


Dynamic Process Management<br />

Two running MPI programs may connect<br />

with each other<br />

One program announces a willingness to<br />

accept connections while another<br />

attempts to establish a connection<br />

Once a connection has been established,<br />

the two parallel programs share an<br />

intercommunicator<br />

<strong>David</strong> <strong>Cronk</strong> 168


MPI-I/O<br />

Introduction<br />

› What is parallel I/O<br />

› Why do we need parallel I/O<br />

› What is MPI-I/O<br />

<strong>David</strong> <strong>Cronk</strong> 169


What is parallel I/O<br />

INTRODUCTION<br />

› Multiple processes accessing a single file<br />

<strong>David</strong> <strong>Cronk</strong> 170


What is parallel I/O<br />

INTRODUCTION<br />

› Multiple processes accessing a single file<br />

› Often, both data and file access is noncontiguous<br />

• Ghost cells cause non-contiguous data access<br />

• Block or cyclic distributions cause noncontiguous<br />

file access<br />

<strong>David</strong> <strong>Cronk</strong> 171


Non-Contiguous Access<br />

Local Mem<br />

File layout<br />

<strong>David</strong> <strong>Cronk</strong> 172


What is parallel I/O<br />

INTRODUCTION<br />

› Multiple processes accessing a single file<br />

› Often, both data and file access is noncontiguous<br />

• Ghost cells cause non-contiguous data access<br />

• Block or cyclic distributions cause noncontiguous<br />

file access<br />

› Want to access data and files with as few<br />

I/O calls as possible<br />

<strong>David</strong> <strong>Cronk</strong> 173


INTRODUCTION (cont)<br />

Why use parallel I/O<br />

› Many users do not have time to learn the<br />

complexities <strong>of</strong> I/O optimization<br />

<strong>David</strong> <strong>Cronk</strong> 174


INTRODUCTION (cont)<br />

Integer dim<br />

parameter (dim=10000)<br />

Integer*4 out_array(dim)<br />

OPEN (fh,filename,UNFORMATTED)<br />

WRITE(fh) (out_array(I), I=1,dim)<br />

rl = 4*dim<br />

OPEN (fh, filename, DIRECT, RECL=rl)<br />

WRITE (fh, REC=1) out_array<br />

<strong>David</strong> <strong>Cronk</strong> 175


INTRODUCTION (cont)<br />

Why use parallel I/O<br />

› Many users do not have time to learn the<br />

complexities <strong>of</strong> I/O optimization<br />

› Use <strong>of</strong> parallel I/O can simplify coding<br />

• Single read/write operation vs. multiple<br />

read/write operations<br />

<strong>David</strong> <strong>Cronk</strong> 176


INTRODUCTION (cont)<br />

Why use parallel I/O<br />

› Many users do not have time to learn the<br />

complexities <strong>of</strong> I/O optimization<br />

› Use <strong>of</strong> parallel I/O can simplify coding<br />

• Single read/write operation vs. multiple<br />

read/write operations<br />

› Parallel I/O potentially <strong>of</strong>fers significant<br />

performance improvement over traditional<br />

approaches<br />

<strong>David</strong> <strong>Cronk</strong> 177


INTRODUCTION (cont)<br />

Traditional approaches<br />

› Each process writes to a separate file<br />

• Often requires an additional post-processing<br />

step<br />

• Without post-processing, restarts must use<br />

same number <strong>of</strong> processor<br />

› Result sent to a master processor, which<br />

collects results and writes out to disk<br />

› Each processor calculates position in file<br />

and writes individually<br />

<strong>David</strong> <strong>Cronk</strong> 178


INTRODUCTION (cont)<br />

What is MPI-I/O<br />

› MPI-I/O is a set <strong>of</strong> extensions to the<br />

original MPI standard<br />

› This is an interface specification: <strong>It</strong> does<br />

NOT give implementation specifics<br />

› <strong>It</strong> provides routines for file manipulation<br />

and data access<br />

› Calls to MPI-I/O routines are portable<br />

across a large number <strong>of</strong> architectures<br />

<strong>David</strong> <strong>Cronk</strong> 179


MPI-I/O<br />

Makes extensive use <strong>of</strong> derived datatypes<br />

Allows non-contiguous memory and or disk data<br />

to be read/written with a single I/O call<br />

Can simplify programming and maintenance<br />

May allow for overlap <strong>of</strong> computation and I/O<br />

Collective I/O allows for performance<br />

optimization through marshaling<br />

Significant performance improvement is<br />

possible<br />

<strong>David</strong> <strong>Cronk</strong> 180


Recommended references<br />

MPI - The Complete Reference Volume 1, The<br />

MPI Core<br />

MPI - The Complete Reference Volume 2, The<br />

MPI Extensions<br />

USING MPI: Portable Parallel Programming<br />

with the Message-Passing Interface<br />

Using MPI-2: Advanced Features <strong>of</strong> the<br />

Message-Passing Interface<br />

<strong>David</strong> <strong>Cronk</strong> 181


Other Useful Information<br />

https://okc.erdc.hpc.mil<br />

Computational Environments (CE)<br />

Under “Papers/Pubs”<br />

– Using MPI-I/O<br />

– Guidelines for writing portable MPI programs<br />

MPI-CHECK<br />

A decent free () debugger for MPI<br />

programs<br />

http://andrew.ait.iastate.edu/HPC/MPI-<br />

CHECK.htm<br />

<strong>David</strong> <strong>Cronk</strong> 182

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!