MPI IO Example

We have covered only a few of the many MPI IO procedures available, but enough to write a working example so we can see how they fit together. We will assign a single-character upper-case letter, starting with A, to each process. We will have each process write its character to a file for N repetitions. So in particular, if we have 4 processes and we ask for 3 repetitions, the file should contain

ABCDABCDABCD

Each character occupies a byte (so for Python we will use the MPI_BYTE type) which simplifies computing the offset. We will use MPI_File_write_at since this is a small write, and the overhead of a collective write might be excessive.

We will then have each process read the file created and print it to verify that it is as expected.

We can illustrate the file layout with offsets

File layout diagram with offsets for the MPI Write example
Each process writes its assigned letter with offset depending on rank and number of processes

The offset is 4 bytes for each processes and repetition. If we loop over a variable i, then some thought shows that the offset for each process is

offset=rank+(i-1)*nprocs

where i is the loop index over the number of repetitions.

Examples for each language

C++

Contents of mpi_io_example.cxx

#include <cstring>
#include <cstdio>
#include <iostream>
#include <fstream>
#include <string>
#include <mpi.h>

using namespace std;

int main (int argc, char *argv[]) {

    // Declarations for MPI
    int rank, nprocs;
    int errcode;
    MPI_Status mpi_stat;
    MPI_Info info;
    MPI_Offset offset;
    MPI_File fh;
    int root=0, tag=0;
    int mpi_err;

    // Check number of parameters and read in filename
    if (argc < 2) {
       printf ("USAGE:  %s output-file\n", argv[0]);
    exit(1);
    }
    const char *fname=argv[1];

    //Initialize MPI
    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD,&nprocs);
    MPI_Comm_rank(MPI_COMM_WORLD,&rank);

    int ord=int('A')+rank;
    char my_char=(char)ord;

    //Fun with pointers (sometimes fh is dereferenced, sometimes not)
    int amode=MPI_MODE_CREATE | MPI_MODE_WRONLY;
    mpi_err=MPI_File_open(MPI_COMM_WORLD,fname,amode,MPI_INFO_NULL,&fh);

    if (mpi_err != MPI_SUCCESS) {
        MPI_Finalize();
        exit(2);
    }

    int nreps=20;
    for (int i=0;i<nreps;i++) {
        offset=rank+i*nprocs;
        MPI_File_write_at(fh,offset,&my_char,1,MPI_CHAR,&mpi_stat);
    }
    MPI_File_close(&fh);

    // Read back in as ordinary file
    // We don't care about efficiency here
    if (rank==root) {
       ifstream fp(fname, ios::in);
       string sstr((istreambuf_iterator<char>(fp)), istreambuf_iterator<char>());
    cout<<sstr<<endl;
    fp.close();
    }

    //All processes read entire file
    //Blocking so will wait for root to finish above read
    amode=MPI_MODE_RDONLY;
    mpi_err=MPI_File_open(MPI_COMM_WORLD,fname,amode,MPI_INFO_NULL,&fh);
    if ( mpi_err != MPI_SUCCESS) {
       MPI_Finalize();
       cout<<"Unable to open MPI file for reading\n";
       exit(2);
    }
    MPI_Offset fsize;
    int tsize;
    MPI_File_get_size(fh,&fsize);
    MPI_Type_size(MPI_CHAR,&tsize);
    if (rank==root) {
        cout<<"File size is "<<fsize<<" Type size is "<<tsize<<" bytes\n";
    }
    int nchar=fsize/tsize;
    char fbuf[nchar];

    MPI_File_read_all(fh, fbuf, nchar, MPI_CHAR, &mpi_stat);
    MPI_File_close(&fh);
    cout<<"Rank "<<rank<<" ";
    for (int i=0; i<nchar; ++i) {
        cout<<fbuf[i];
    }
    cout<<endl;

    //Read back in as MPI file
    amode=MPI_MODE_RDONLY;
    mpi_err=MPI_File_open(MPI_COMM_WORLD,fname,amode,MPI_INFO_NULL,&fh);

    if (mpi_err != MPI_SUCCESS) {
        MPI_Finalize();
        cout<<"Unable to open MPI file for reading\n";
        exit(2);
    }

    char rbuf[nreps];
    offset=0;
    for (int i=0;i<nreps;i++) {
        offset=rank+i*nprocs;
        MPI_File_read_at(fh,offset,&rbuf[i],1,MPI_CHAR,&mpi_stat);
    }

    cout<<"Rank "<<rank<<" ";
    for (int i=0; i<nreps; ++i) {
        cout<<rbuf[i];
    }
    cout<<endl;

    MPI_File_close(&fh);

    MPI_Finalize();

}

Download mpi_io_example.cxx file

Fortran

Contents of mpi_io_example.f90

program mpiwrite
   use mpi_f08
   implicit none

   integer            :: i
   character(len=80)  :: arg
   integer            :: numargs

   integer            :: rank, nprocs
   integer            :: mpi_err
   integer, parameter :: root=0
   type(MPI_Status)   :: mpi_stat
   type(MPI_File)     :: fh
   integer            :: amode
   integer            :: tsize
   INTEGER(KIND=MPI_OFFSET_KIND) :: fsize, offset
   character(len=24)  :: fname
   character(len=1)   :: my_char
   integer            :: nreps

   character(len=:), allocatable :: gu,u
   character(len=256) :: rbuf

   ! check number of parameters and read in filename
   ! all ranks do this, avoids broadcast
   numargs=command_argument_count()
   if (numargs .lt. 1) then
      stop 'USAGE: output-file'
   else
      call get_command_argument(1,fname)
   endif

   !Initialize MPI
   call MPI_INIT()
   call MPI_COMM_SIZE(MPI_COMM_WORLD,nprocs)
   call MPI_COMM_RANK(MPI_COMM_WORLD,rank)

   my_char=char(iachar('A')+rank)

   amode=ior(MPI_MODE_CREATE, MPI_MODE_WRONLY)
   call MPI_FILE_OPEN(MPI_COMM_WORLD,trim(fname),amode,MPI_INFO_NULL,fh,mpi_err)

   if ( mpi_err /= MPI_SUCCESS) then
       call MPI_FINALIZE()
       stop "Unable to open MPI file for reading"
   endif

   nreps=20
   do i=1,nreps
      ! Explcit cast for offset not really necessary
      offset=int(rank+(i-1)*nprocs,kind=MPI_OFFSET_KIND)
      call MPI_FILE_WRITE_AT(fh, offset, my_char, 1, MPI_CHARACTER, mpi_stat)
   enddo

   call MPI_FILE_CLOSE(fh)

   ! Read as ordinary file
   ! Still can't read variable-length strings in Fortran
   if (rank==root) then
       rbuf=' '
       open(unit=10,file=fname,status='unknown')
       read(10,*) rbuf
       gu=trim(rbuf)
       write(*,'(a,a)') "Read at root ",gu
       close(10)
   endif

   !All processes read entire file
   !Blocking so will wait for root to finish above read
   amode=MPI_MODE_RDONLY
   call MPI_FILE_OPEN(MPI_COMM_WORLD,trim(fname),amode,MPI_INFO_NULL,fh,mpi_err)
   if ( mpi_err /= MPI_SUCCESS) then
       call MPI_FINALIZE()
       stop "Unable to open MPI file for reading"
   endif

   !Reading into "big enough" buffer means we don't need to get the size,
   !but this is the syntax.  Note type of fsize in declarations
   call MPI_FILE_GET_SIZE(fh,fsize)
   call MPI_TYPE_SIZE(MPI_CHARACTER,tsize)
   if (rank==root) then
       write(*,*) "File size is ",fsize," Type size is ",tsize," bytes"
   endif

   rbuf=' '
   call MPI_FILE_READ_ALL(fh, rbuf, len(rbuf), MPI_CHARACTER, mpi_stat)
   gu=trim(rbuf)
   write(*,'(a,i4.4,a,a)') 'Full file at rank ',rank,' ',gu

   !Read back the MPI file portion for reach rank
   rbuf=' '
   amode=MPI_MODE_RDONLY
   call MPI_FILE_OPEN(MPI_COMM_WORLD,trim(fname),amode,MPI_INFO_NULL,fh,mpi_err)
   if ( mpi_err /= MPI_SUCCESS) then
       call MPI_FINALIZE()
       stop "Unable to open MPI file for reading"
   else
       do i=1,nreps
          call MPI_FILE_READ_AT(fh, offset, rbuf(i:i), 1, MPI_CHARACTER, mpi_stat)
       enddo
   endif
   write(*,'(a,i4.4,a,a)') 'Rank ',rank,' ',trim(rbuf)

   call MPI_FILE_CLOSE(fh)

   call MPI_Finalize()

end program

Download mpi_io_example.f90 file

Python

Contents of mpi_io_example.py

import sys
import numpy as np
from mpi4py import MPI

if len(sys.argv)<2:
    print("Usage: filename")
    exit()
else:
    filename=sys.argv[1]

comm=MPI.COMM_WORLD
rank=comm.Get_rank()
nprocs=comm.Get_size()

root=0

my_char=chr(ord('A') + rank).encode('ascii')

# Set up the buffer to contain a one-byte character (consistent with C char)
buf=np.array([my_char])

status=MPI.Status()
#Info is used for "hints" to various MPI routines.  Usually we don't need it.
info=MPI.Info()

amode=MPI.MODE_CREATE | MPI.MODE_WRONLY
fh=MPI.File.Open(comm,filename,amode,info)

#Use MPI Byte type since Python doesn't really support characters
nreps=20
for i in range(nreps):
    offset=rank+i*nprocs
    fh.Write_at(offset, [buf, MPI.BYTE],status=status)

fh.Close()

if rank==0:
    #First read back with ordinary IO
    with open(filename,'rb') as fp:
        array=np.fromfile(fp,dtype='byte')
    array=[chr(array[i]) for i in range(array.size)]
    print("Read at root "+"".join(array))
    fp.close()

#All processes read entire file
#Blocking so will wait for root to finish above read
amode=MPI.MODE_RDONLY
fh=MPI.File.Open(comm,filename,amode)
fsize=fh.Get_size()
itembytes=MPI.BYTE.Get_size()
if rank==root:
    print("File size is "+str(fsize)+" type size is "+str(itembytes)+" bytes")
nbytes=fsize//itembytes
rbuf=np.empty((nbytes,),dtype='byte')
fh.Read_all([rbuf,MPI.BYTE])
all_chars=[chr(rbuf[i]) for i in range(rbuf.size)]
print("Entire file at rank "+str(rank)+" "+''.join(all_chars))
fh.Close()

#Read back the MPI file portion for each rank
amode=MPI.MODE_RDONLY
fh=MPI.File.Open(comm,filename,amode)

my_vals=[]
offset=0
for i in range(nreps):
    offset=rank+i*nprocs
    fh.Read_at(offset, [buf, MPI.BYTE])
    my_vals.append(buf[0].decode())
fh.Close()
my_string=''.join(my_vals)
print(str(rank)+' '+my_string)

Download mpi_io_example.py file

Previous
Next
© 2026 The Rector and Visitors of the University of Virginia