next up previous index
Next: The Discussion Up: Writing Sequential Files with Previous: Writing Sequential Files with

Program mkrandpfiles

Here is the program itself:

/*
 * %Id: mkrandpfiles.c,v 1.2 2003/10/19 19:20:14 gustav Exp %
 *
 * %Log: mkrandpfiles.c,v %
 * Revision 1.2  2003/10/19 19:20:14  gustav
 * Indented the program with Emacs.
 *
 * Revision 1.1  2003/10/19 18:51:41  gustav
 * Initial revision
 *
 *
 */

#include <stdio.h>   /* all IO stuff lives here */
#include <stdlib.h>  /* exit lives here */
#include <unistd.h>  /* getopt lives here */
#include <errno.h>   /* UNIX error handling lives here */
#include <string.h>  /* strcpy lives here */
#include <mpi.h>     /* MPI and MPI-IO live here */

#define MASTER_RANK 0
#define TRUE 1
#define FALSE 0
#define BOOLEAN int
#define BLOCK_SIZE 1048576
#define MBYTE 1048576
#define SYNOPSIS printf ("synopsis: %s -f <file> -l <blocks>\n", argv[0])

int main(argc, argv)
     int argc;
     char *argv[];
{
  /* my variables */

  int my_rank, pool_size, number_of_blocks = 0, i;
  int number_of_integers, number_of_bytes;
  long long total_number_of_integers, total_number_of_bytes;
  BOOLEAN i_am_the_master = FALSE, input_error = FALSE, 
    my_file_open_error = FALSE, file_open_error = FALSE,
    my_write_error = FALSE, write_error = FALSE;
  char *basename = NULL, file_name[BUFSIZ], message[BUFSIZ];
  int basename_length, *junk;
  MPI_File fh;
  double start, finish, io_time, longest_io_time;
  char error_string[BUFSIZ];
  int length_of_error_string, error_class;
  MPI_Status  status;

  /* getopt variables */

  extern char *optarg;
  int c;

  /* error handling variables */

  extern int errno;

  /* ACTION */

  MPI_Init(&argc, &argv);
  MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
  MPI_Comm_size(MPI_COMM_WORLD, &pool_size);
  if (my_rank == MASTER_RANK) i_am_the_master = TRUE;

  if (i_am_the_master) {

    /* read the command line */

    while ((c = getopt(argc, argv, "f:l:h")) != EOF)
      switch(c) {
      case 'f': 
        basename = optarg;
	break;
      case 'l': 
	if ((sscanf (optarg, "%d", &number_of_blocks) != 1) ||
	    (number_of_blocks < 1)) 
	  input_error = TRUE;
	break;
      case 'h':
	input_error = TRUE;
	break;
      case '?':
	input_error = TRUE;
	break;
      }

    /* Check if the command line has initialized both the basename and
     * the number_of_blocks.
     */

    if ((basename == NULL) || (number_of_blocks == 0)) input_error = TRUE;

    if (input_error)
      SYNOPSIS;
    else {
      basename_length = strlen(basename) + 1;
#ifdef DEBUG
      printf("basename         = %s\n", basename);
      printf("basename_length  = %d\n", basename_length);
      printf("number_of_blocks = %d\n", number_of_blocks);
#endif
    }
  } /* end of if(i_am_the_master) { <read the command line> } */

  /* Transmit the effect of reading the command line to other
     processes. */

  MPI_Bcast(&input_error, 1, MPI_INT, MASTER_RANK, MPI_COMM_WORLD);

  if (! input_error) {

    /* If we managed to get here, data read from the command line
       is probably OK. */

    MPI_Bcast(&number_of_blocks, 1, MPI_INT, MASTER_RANK, MPI_COMM_WORLD);
    MPI_Bcast(&basename_length, 1, MPI_INT, MASTER_RANK, MPI_COMM_WORLD);
    if (! i_am_the_master) basename = (char*) malloc(basename_length);
    MPI_Bcast(basename, basename_length, MPI_CHAR, MASTER_RANK, MPI_COMM_WORLD);

#ifdef DEBUG
    printf("%3d: basename = %s, number_of_blocks = %d\n", 
	   my_rank, basename, number_of_blocks);
#endif

    /* Allocate space needed to generate the integers */

    number_of_integers = number_of_blocks * BLOCK_SIZE;
    number_of_bytes = sizeof(int) * number_of_integers;
    total_number_of_integers = (long long) number_of_integers
      * (long long) pool_size;
    total_number_of_bytes = (long long) number_of_bytes
      * (long long) pool_size;
    junk = (int*) malloc(number_of_bytes);

    /* Now every process creates its own file name and attempts
       to open the file. */

    sprintf(file_name, "%s.%d", basename, my_rank);

#ifdef DEBUG
    printf("%3d: opening file %s\n", my_rank, file_name);
#endif

    my_file_open_error =
      MPI_File_open(MPI_COMM_SELF, file_name, 
		    MPI_MODE_CREATE | MPI_MODE_WRONLY, MPI_INFO_NULL, &fh);

    if (my_file_open_error != MPI_SUCCESS) {

      MPI_Error_class(my_file_open_error, &error_class);
      MPI_Error_string(error_class, error_string, &length_of_error_string);
      printf("%3d: %s\n", my_rank, error_string);

      MPI_Error_string(my_file_open_error, error_string, 
		       &length_of_error_string);
      printf("%3d: %s\n", my_rank, error_string);

      my_file_open_error = TRUE;

    }

    /* Now we must ALL check that NOBODY had problems
       with opening the file. */

    MPI_Allreduce (&my_file_open_error, &file_open_error, 1, MPI_INT, 
		   MPI_LOR, MPI_COMM_WORLD);

#ifdef DEBUG
    if (i_am_the_master)
      if (file_open_error)
	fprintf(stderr, "problem opening output files\n");
#endif

    /* If all files are open for writing, write to them */

    if (! file_open_error) {
      srand(28 + my_rank);
      for (i = 0; i < number_of_integers; i++) *(junk + i) = rand();
      start = MPI_Wtime();
      my_write_error = 
	MPI_File_write(fh, junk, number_of_integers, MPI_INT, &status);
      if (my_write_error != MPI_SUCCESS) {
	MPI_Error_class(my_write_error, &error_class);
	MPI_Error_string(error_class, error_string, &length_of_error_string);
	printf("%3d: %s\n", my_rank, error_string);
	MPI_Error_string(my_write_error, error_string, &length_of_error_string);
	printf("%3d: %s\n", my_rank, error_string);
	my_write_error = TRUE;
      }
      else {
	finish = MPI_Wtime();
	io_time = finish - start;
	printf("%3d: io_time = %f\n", my_rank, io_time);
      }

      /* Check if anybody had problems writing on the file */

      MPI_Allreduce (&my_write_error, &write_error, 1, MPI_INT,
		     MPI_LOR, MPI_COMM_WORLD);

#ifdef DEBUG
      if (i_am_the_master)
	if (write_error)
	  fprintf(stderr, "problem writing on files\n");
#endif

    } /* of if(! file_open_error) { <write on the file> } */

    /* Only processes that were successful opening the files
       need do close them here */

    if (!my_file_open_error) {
      MPI_File_close(&fh);
#ifdef DEBUG
      printf ("%3d: closed %s\n", my_rank, file_name);
#endif
    }

    /* If we have either write errors or file open errors,
       then processes that managed to open their files
       are requested to throw them away */

    if (write_error || file_open_error) {
      if (! my_file_open_error) {
        MPI_File_delete(file_name, MPI_INFO_NULL);
#ifdef DEBUG
        printf("%3d: deleted %s\n", my_rank, file_name);
#endif
      }
    }
    else {
      MPI_Reduce(&io_time, &longest_io_time, 1, MPI_DOUBLE, MPI_MAX,
		 MASTER_RANK, MPI_COMM_WORLD);
      if (i_am_the_master) {
	printf("longest_io_time       = %f seconds\n", longest_io_time);
	printf("total_number_of_bytes = %lld\n", total_number_of_bytes);
	printf("transfer rate         = %f MB/s\n", 
	       total_number_of_bytes / longest_io_time / MBYTE);
      }

    } /* end of if (write_error || file_open_error) {<delete open files>} */
       
  } /* end of if(! input_error) { <open the file and write on it> } */

  MPI_Finalize();
  exit(0);
}

Here is how this program is made:

gustav@bh1 $ pwd
/N/B/gustav/src/I590/mkrandpfiles
gustav@bh1 $ make install
co  RCS/Makefile,v Makefile
RCS/Makefile,v  -->  Makefile
revision 1.1
done
co  RCS/mkrandpfiles.c,v mkrandpfiles.c
RCS/mkrandpfiles.c,v  -->  mkrandpfiles.c
revision 1.2
done
mpicc -DDEBUG -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -o mkrandpfiles mkrandpfiles.c
install mkrandpfiles /N/B/gustav/bin
gustav@bh1 $

And now let us have a look at how it runs. We'll check for error handling first.

gustav@bh1 $ pwd
/N/gpfs/gustav/mkrandpfiles
gustav@bh1 $ mpiexec -n 8 mkrandpfiles -l 8
synopsis: mkrandpfiles -f <file> -l <blocks>
gustav@bh1 $ mpiexec -n 8 mkrandpfiles -f test
synopsis: mkrandpfiles -f <file> -l <blocks>
gustav@bh1 $ touch test.4 
gustav@bh1 $ chmod 444 test.4
gustav@bh1 $ mpiexec -n 8 mkrandpfiles -f test -l 8
basename         = test
basename_length  = 5
number_of_blocks = 8
  0: basename = test, number_of_blocks = 8
  0: opening file test.0
  2: basename = test, number_of_blocks = 8
  2: opening file test.2
  4: basename = test, number_of_blocks = 8
  4: opening file test.4
  6: basename = test, number_of_blocks = 8
  6: opening file test.6
  7: basename = test, number_of_blocks = 8
  7: opening file test.7
  3: basename = test, number_of_blocks = 8
  3: opening file test.3
  5: basename = test, number_of_blocks = 8
  5: opening file test.5
  1: basename = test, number_of_blocks = 8
  1: opening file test.1
  4: Other I/O error 
  4: Other I/O error Permission denied
problem opening output files
  0: closed test.0
  2: closed test.2
  6: closed test.6
  1: closed test.1
  5: closed test.5
  3: closed test.3
  7: closed test.7
  6: deleted test.6
  0: deleted test.0
  2: deleted test.2
  3: deleted test.3
  7: deleted test.7
  5: deleted test.5
  1: deleted test.1
gustav@bh1 $

And now a real run:

gustav@bh1 $ rm -f test.4
gustav@bh1 $ mpiexec -n 8 mkrandpfiles -f test -l 10
basename         = test
basename_length  = 5
number_of_blocks = 10
  0: basename = test, number_of_blocks = 10
  0: opening file test.0
  1: basename = test, number_of_blocks = 10
  1: opening file test.1
  2: basename = test, number_of_blocks = 10
  2: opening file test.2
  6: basename = test, number_of_blocks = 10
  6: opening file test.6
  4: basename = test, number_of_blocks = 10
  4: opening file test.4
  7: basename = test, number_of_blocks = 10
  7: opening file test.7
  3: basename = test, number_of_blocks = 10
  3: opening file test.3
  5: basename = test, number_of_blocks = 10
  5: opening file test.5
  7: io_time = 3.383798
  3: io_time = 3.461928
  5: io_time = 3.508230
  2: io_time = 3.523316
  4: io_time = 3.783771
  1: io_time = 3.955147
  6: io_time = 4.276280
  0: io_time = 5.050947
  1: closed test.1
  2: closed test.2
  3: closed test.3
  4: closed test.4
  7: closed test.7
  5: closed test.5
  6: closed test.6
  0: closed test.0
longest_io_time       = 5.050947 seconds
total_number_of_bytes = 335544320
transfer rate         = 63.354455 MB/s
gustav@bh1 $



Zdzislaw Meglicki
2004-04-29