/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *										 *
 *  Copyright (C) 2019, Northwestern University					 *  Copyright (C) 2019, Northwestern University
 *  See COPYRIGHT notice in top-level directory.				 *  See COPYRIGHT notice in top-level directory.
 *										 *
 * This program shows an example of calling MPI_File_set_view(), which sets      * This program shows an example of calling MPI_File_set_view(), which sets
 * a visible file region to the calling MPI process. With such fileview set,     * a visible file region to the calling MPI process. With such fileview set,
 * all successive MPI read and write function calls will read and write only     * all successive MPI read and write function calls will read and write only
 * the visible region. In this example program, the visible region to process    * the visible region. In this example program, the visible region to process
 * rank i starts from file offset (rank * 10 * sizeof(int)).			 * rank i starts from file offset (rank * 10 * sizeof(int)).
 *										 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */    * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include <stdio.h>								#include <stdio.h>
#include <stdlib.h>								#include <stdlib.h>
#include <mpi.h>								#include <mpi.h>

#define CHECK_ERR(func) { \							#define CHECK_ERR(func) { \
    if (err != MPI_SUCCESS) { \							    if (err != MPI_SUCCESS) { \
        int errorStringLen; \							        int errorStringLen; \
        char errorString[MPI_MAX_ERROR_STRING]; \				        char errorString[MPI_MAX_ERROR_STRING]; \
        MPI_Error_string(err, errorString, &errorStringLen); \			        MPI_Error_string(err, errorString, &errorStringLen); \
        printf("Error at line %d: calling %s (%s)\n",__LINE__, #func, errorSt           printf("Error at line %d: calling %s (%s)\n",__LINE__, #func, errorSt
    } \										    } \
}										}

/*----< main() >------------------------------------------------------------*   /*----< main() >------------------------------------------------------------*
int main(int argc, char **argv) {						int main(int argc, char **argv) {
    char *filename;								    char *filename;
    int i, err, cmode, rank, buf[10];						    int i, err, cmode, rank, buf[10];
    MPI_Offset offset;								    MPI_Offset offset;
    MPI_File fh;								    MPI_File fh;
									      >     MPI_Info info;
    MPI_Status status;								    MPI_Status status;

    MPI_Init(&argc, &argv);							    MPI_Init(&argc, &argv);

    err = MPI_Comm_rank(MPI_COMM_WORLD, &rank);					    err = MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    CHECK_ERR(MPI_Comm_rank);							    CHECK_ERR(MPI_Comm_rank);

    filename = "testfile.out";							    filename = "testfile.out";
    if (argc > 1) filename = argv[1];						    if (argc > 1) filename = argv[1];

    /* open a file (create if the file does not exist) */			    /* open a file (create if the file does not exist) */
    cmode = MPI_MODE_CREATE | MPI_MODE_RDWR;					    cmode = MPI_MODE_CREATE | MPI_MODE_RDWR;
    err = MPI_File_open(MPI_COMM_WORLD, filename, cmode, MPI_INFO_NULL, &fh);       err = MPI_File_open(MPI_COMM_WORLD, filename, cmode, MPI_INFO_NULL, &fh);
    CHECK_ERR(MPI_File_open);							    CHECK_ERR(MPI_File_open);

    /* initialize write buffer contents */					    /* initialize write buffer contents */
    for (i=0; i<10; i++) buf[i] = 100 * rank + i;				    for (i=0; i<10; i++) buf[i] = 100 * rank + i;

    /* set file offset for this calling process */				    /* set file offset for this calling process */
    offset = (MPI_Offset)rank * 10 * sizeof(int);				    offset = (MPI_Offset)rank * 10 * sizeof(int);

									      >     /* Set "view is local" info key for MPI_File_set_view() call */
									      >     MPI_Info_create(&info);
									      >     MPI_Info_set(info, "view_is_local", "true");
									      >
    /* MPI_File_set_view() sets the file visible region to this process start       /* MPI_File_set_view() sets the file visible region to this process start
     * at offset. Setting etype argument to MPI_INT means this file will be          * at offset. Setting etype argument to MPI_INT means this file will be
     * accessed in the units of integer size. Setting filetype argument to           * accessed in the units of integer size. Setting filetype argument to
     * MPI_INT means a contiguous 4-byte region (assuming integer size if 4          * MPI_INT means a contiguous 4-byte region (assuming integer size if 4
     * bytes) is recursively applied to the file to form the visible region t        * bytes) is recursively applied to the file to form the visible region t
     * the calling process, starting from its "offset" set in the offset	     * the calling process, starting from its "offset" set in the offset
     * argument. In this example, the "file view" of a process is the entire         * argument. In this example, the "file view" of a process is the entire
     * file starting from its offset.						     * file starting from its offset.
     */										     */
    err = MPI_File_set_view(fh, offset, MPI_INT, MPI_INT, "native", MPI_INFO_ |     err = MPI_File_set_view(fh, offset, MPI_INT, MPI_INT, "native", info);
    CHECK_ERR(MPI_File_set_view);						    CHECK_ERR(MPI_File_set_view);

    /* Each process writes 3 integers to the file region visible to it.		    /* Each process writes 3 integers to the file region visible to it.
     * Note the file pointer will advance 3x4 bytes after this call.		     * Note the file pointer will advance 3x4 bytes after this call.
     */										     */
    err = MPI_File_write_all(fh, &buf[0], 3, MPI_INT, &status);		      |     err = MPI_File_write(fh, &buf[0], 3, MPI_INT, &status);
    CHECK_ERR(MPI_File_set_view);						    CHECK_ERR(MPI_File_set_view);

    /* Each process continues to write next 7 integers to the file region           /* Each process continues to write next 7 integers to the file region
     * visible to it, starting from the file pointer updated from the previou        * visible to it, starting from the file pointer updated from the previou
     * write call.								     * write call.
     */										     */
    err = MPI_File_write_all(fh, &buf[3], 7, MPI_INT, &status);			    err = MPI_File_write_all(fh, &buf[3], 7, MPI_INT, &status);
    CHECK_ERR(MPI_File_set_view);						    CHECK_ERR(MPI_File_set_view);

    /* close the file collectively */						    /* close the file collectively */
    err = MPI_File_close(&fh);							    err = MPI_File_close(&fh);
    CHECK_ERR(MPI_File_set_view);						    CHECK_ERR(MPI_File_set_view);

    MPI_Finalize();								    MPI_Finalize();
    return 0;									    return 0;
}										}


