home *** CD-ROM | disk | FTP | other *** search
/ ftp.parl.clemson.edu / 2015-02-07.ftp.parl.clemson.edu.tar / ftp.parl.clemson.edu / pub / pvfs2 / tests / mpi-io-test.c next >
C/C++ Source or Header  |  2006-07-28  |  13KB  |  443 lines

  1. /*
  2.  * (C) 1995-2001 Clemson University and Argonne National Laboratory.
  3.  *
  4.  * See COPYING in top-level directory.
  5.  */
  6.  
  7. /* mpi-io-test.c
  8.  *
  9.  * This is derived from code given to me by Rajeev Thakur.  Dunno where
  10.  * it originated.
  11.  *
  12.  * It's purpose is to produce aggregate bandwidth numbers for varying
  13.  * block sizes, number of processors, an number of iterations.
  14.  *
  15.  * This is strictly an MPI program - it is used to test the MPI I/O
  16.  * functionality implemented by Romio.
  17.  *
  18.  * Compiling is usually easiest with something like:
  19.  * mpicc -Wall -Wstrict-prototypes mpi-io-test.c -o mpi-io-test
  20.  *
  21.  * NOTE: This code assumes that all command line arguments make it out to all
  22.  * the processes that make up the parallel job, which isn't always the case.
  23.  * So if it doesn't work on some platform, that might be why.
  24.  */
  25.  
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <fcntl.h>
  29. #include <unistd.h>
  30. #include <string.h>
  31. #include <sys/time.h>
  32. #include <mpi.h>
  33. #include <errno.h>
  34. #include <getopt.h>
  35.  
  36. /* DEFAULT VALUES FOR OPTIONS */
  37. static int64_t opt_block     = 16*1024*1024;
  38. static int     opt_iter      = 1;
  39. static int     opt_coll      = 0;
  40. static int     opt_correct   = 0;
  41. static int     opt_sync      = 0;
  42. static int     opt_single    = 0;
  43. static int     opt_verbose   = 0;
  44. static int     opt_rdonly    = 0;
  45. static int     opt_wronly    = 0;
  46. static char    opt_file[256] = "test.out";
  47. static char    opt_pvfs2tab[256] = "notset";
  48. static int     opt_pvfstab_set = 0;
  49.  
  50. /* function prototypes */
  51. static int parse_args(int argc, char **argv);
  52. static void usage(void);
  53. static void handle_error(int errcode, char *str);
  54.  
  55. /* global vars */
  56. static int mynod = 0;
  57. static int nprocs = 1;
  58.  
  59. int main(int argc, char **argv)
  60. {
  61.    char *buf, *tmp=NULL, *check;
  62.    int i, j, v, err, sync_err=0, my_correct = 1, correct, myerrno;
  63.    double stim, etim;
  64.    double write_tim = 0;
  65.    double read_tim = 0;
  66.    double read_bw, write_bw;
  67.    double max_read_tim, max_write_tim;
  68.    double min_read_tim, min_write_tim;
  69.    double ave_read_tim, ave_write_tim;
  70.    double sum_read_tim, sum_write_tim;
  71.    double sq_write_tim, sq_read_tim;
  72.    double sumsq_write_tim, sumsq_read_tim;
  73.    double var_read_tim, var_write_tim;
  74.    int64_t iter_jump = 0;
  75.    int64_t seek_position = 0;
  76.    MPI_File fh;
  77.    MPI_Status status;
  78.     MPI_Comm comm;
  79.    int nchars=0;
  80.    int namelen;
  81.    char processor_name[MPI_MAX_PROCESSOR_NAME];
  82.  
  83.    /* startup MPI and determine the rank of this process */
  84.    MPI_Init(&argc,&argv);
  85.    MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
  86.    MPI_Comm_rank(MPI_COMM_WORLD, &mynod);
  87.    MPI_Get_processor_name(processor_name, &namelen); 
  88.    
  89.    /* parse the command line arguments */
  90.    parse_args(argc, argv);
  91.  
  92.    if (opt_verbose) fprintf(stdout,"Process %d of %d is on %s\n",
  93.                                      mynod, nprocs, processor_name);
  94.  
  95.    if (mynod == 0) printf("# Using mpi-io calls.\n");
  96.  
  97.    
  98.    /* kindof a weird hack- if the location of the pvfstab file was 
  99.     * specified on the command line, then spit out this location into
  100.     * the appropriate environment variable: */
  101.    
  102.    if (opt_pvfstab_set) {
  103.       if ((setenv("PVFS2TAB_FILE", opt_pvfs2tab, 1)) < 0) {
  104.          perror("setenv");
  105.          goto die_jar_jar_die;
  106.       }
  107.    }
  108.    
  109.    /* this is how much of the file data is covered on each iteration of
  110.     * the test.  used to help determine the seek offset on each
  111.     * iteration */
  112.    iter_jump = nprocs * opt_block;
  113.       
  114.    /* setup a buffer of data to write */
  115.    if (!(tmp = malloc((size_t) opt_block + 256))) {
  116.       perror("malloc");
  117.       goto die_jar_jar_die;
  118.    }
  119.    buf = tmp + 128 - (((long)tmp) % 128);  /* align buffer */
  120.  
  121.    /* open the file for writing */
  122.     if (opt_coll) {
  123.         comm = MPI_COMM_WORLD;
  124.     }
  125.     else {
  126.         comm = MPI_COMM_SELF;
  127.     }
  128.    err = MPI_File_open(comm, opt_file, 
  129.                               MPI_MODE_CREATE | MPI_MODE_RDWR, MPI_INFO_NULL, &fh);
  130.    if (err != MPI_SUCCESS) {
  131.       handle_error(err, "MPI_File_open");
  132.       goto die_jar_jar_die;
  133.    } 
  134.     
  135.     nchars = (int) (opt_block/sizeof(char));
  136.     if (!opt_rdonly) {
  137.  
  138.    /* now repeat the seek and write operations the number of times
  139.     * specified on the command line */
  140.    for (j=0; j < opt_iter; j++) {
  141.  
  142.       /* reading and writing to the same block is cheating, but sometimes
  143.        * we want to measure cached performance of file servers */
  144.       if (opt_single == 1)
  145.             seek_position = 0;
  146.       else
  147.             /* seek to an appropriate position depending on the iteration 
  148.              * and rank of the current process */
  149.             seek_position = (j*iter_jump)+(mynod*opt_block);
  150.  
  151.       MPI_File_seek(fh, seek_position, MPI_SEEK_SET);
  152.  
  153.       if (opt_correct) /* fill in buffer for iteration */ {
  154.          for (i=0, v=mynod+j, check=buf; i<opt_block; i++, v++, check++) 
  155.             *check = (char) v;
  156.       }
  157.  
  158.       /* discover the starting time of the operation */
  159.       MPI_Barrier(MPI_COMM_WORLD);
  160.       stim = MPI_Wtime();
  161.  
  162.       /* write out the data */
  163.         if (opt_coll) {
  164.             err = MPI_File_write_all(fh, buf, nchars, MPI_CHAR, &status);
  165.         }
  166.         else {
  167.             err = MPI_File_write(fh, buf, nchars, MPI_CHAR, &status);
  168.         }
  169.       if(err){
  170.          fprintf(stderr, "node %d, write error: %s\n", mynod, 
  171.          strerror(errno));
  172.       }
  173.       if (opt_sync) sync_err = MPI_File_sync(fh);
  174.       if (sync_err) {
  175.          fprintf(stderr, "node %d, sync error: %s\n", mynod, 
  176.                       strerror(errno));
  177.       }
  178.  
  179.       /* discover the ending time of the operation */
  180.       etim = MPI_Wtime();
  181.  
  182.       write_tim += (etim - stim);
  183.       
  184.       /* we are done with this "write" iteration */
  185.    }
  186.     } /* ! opt_rdonly */
  187.  
  188.    err = MPI_File_close(&fh);
  189.    if(err){
  190.       fprintf(stderr, "node %d, close error after write\n", mynod);
  191.    }
  192.     
  193.    /* wait for everyone to synchronize at this point */
  194.    MPI_Barrier(MPI_COMM_WORLD);
  195.  
  196.    /* reopen the file to read the data back out */
  197.    err = MPI_File_open(comm, opt_file, 
  198.                MPI_MODE_CREATE | MPI_MODE_RDWR, MPI_INFO_NULL, &fh);
  199.    if (err < 0) {
  200.       fprintf(stderr, "node %d, open error: %s\n", mynod, strerror(errno));
  201.       goto die_jar_jar_die;
  202.    }
  203.  
  204.     if (!opt_wronly) {
  205.    /* we are going to repeat the read operation the number of iterations
  206.     * specified */
  207.    for (j=0; j < opt_iter; j++) {
  208.       /* reading and writing to the same block is cheating, but sometimes
  209.        * we want to measure cached performance of file servers */
  210.       if (opt_single == 1) {
  211.             seek_position = 0;
  212.         }
  213.       else {
  214.             /* seek to an appropriate position depending on the iteration 
  215.              * and rank of the current process */
  216.             seek_position = (j*iter_jump)+(mynod*opt_block);
  217.         }
  218.  
  219.       MPI_File_seek(fh, seek_position, MPI_SEEK_SET);
  220.  
  221.       /* discover the start time */
  222.       MPI_Barrier(MPI_COMM_WORLD);
  223.       stim = MPI_Wtime();
  224.  
  225.       /* read in the file data */
  226.         if (opt_coll) {
  227.             err = MPI_File_read_all(fh, buf, nchars, MPI_CHAR, &status);
  228.         }
  229.         else {
  230.             err = MPI_File_read(fh, buf, nchars, MPI_CHAR, &status);
  231.         }
  232.       myerrno = errno;
  233.  
  234.       /* discover the end time */
  235.       etim = MPI_Wtime();
  236.       read_tim += (etim - stim);
  237.  
  238.       if (err < 0) {
  239.             fprintf(stderr, "node %d, read error, loc = %lld: %s\n",
  240.                 mynod, (long long) mynod*opt_block, strerror(myerrno));
  241.         }
  242.  
  243.       /* if the user wanted to check correctness, compare the write
  244.        * buffer to the read buffer */
  245.       if (opt_correct) {
  246.          int badct = 0;
  247.  
  248.          for (i=0, v=mynod+j, check=buf;
  249.               i < opt_block && badct < 10;
  250.               i++, v++, check++)
  251.          {
  252.             if (*check != (char) v) {
  253.                my_correct = 0;
  254.                if (badct < 10) {
  255.                   badct++;
  256.                   fprintf(stderr, "buf[%d] = %d, should be %d\n", 
  257.                           i, *check, (char) v);
  258.                }
  259.             }
  260.          }
  261.          MPI_Allreduce(&my_correct, &correct, 1, MPI_INT, MPI_MIN,
  262.                        MPI_COMM_WORLD);
  263.          if (badct == 10) fprintf(stderr, "...\n");
  264.       }
  265.  
  266.       /* we are done with this read iteration */
  267.    }
  268.     } /* !opt_wronly */
  269.  
  270.    /* close the file */
  271.    err = MPI_File_close(&fh);
  272.    if (err) {
  273.       fprintf(stderr, "node %d, close error after write\n", mynod);
  274.    }
  275.  
  276.    /* compute the read and write times */
  277.    MPI_Allreduce(&read_tim, &max_read_tim, 1, MPI_DOUBLE, MPI_MAX,
  278.       MPI_COMM_WORLD);
  279.    MPI_Allreduce(&read_tim, &min_read_tim, 1, MPI_DOUBLE, MPI_MIN,
  280.       MPI_COMM_WORLD);
  281.    MPI_Allreduce(&read_tim, &sum_read_tim, 1, MPI_DOUBLE, MPI_SUM,
  282.       MPI_COMM_WORLD);
  283.  
  284.    /* calculate our part of the summation used for variance */
  285.    sq_read_tim = read_tim - (sum_read_tim / nprocs);
  286.    sq_read_tim = sq_read_tim * sq_read_tim;
  287.    MPI_Allreduce(&sq_read_tim, &sumsq_read_tim, 1, MPI_DOUBLE, 
  288.                    MPI_SUM, MPI_COMM_WORLD);
  289.  
  290.  
  291.    MPI_Allreduce(&write_tim, &max_write_tim, 1, MPI_DOUBLE, MPI_MAX,
  292.       MPI_COMM_WORLD);
  293.    MPI_Allreduce(&write_tim, &min_write_tim, 1, MPI_DOUBLE, MPI_MIN,
  294.       MPI_COMM_WORLD);
  295.    MPI_Allreduce(&write_tim, &sum_write_tim, 1, MPI_DOUBLE, MPI_SUM,
  296.       MPI_COMM_WORLD);
  297.  
  298.    /* calculate our part of the summation used for variance */
  299.    sq_write_tim = write_tim - (sum_write_tim / nprocs );
  300.    sq_write_tim = sq_write_tim * sq_write_tim;
  301.    MPI_Allreduce(&sq_write_tim, &sumsq_write_tim, 1, MPI_DOUBLE, 
  302.                    MPI_SUM, MPI_COMM_WORLD);
  303.  
  304.    /* calculate the average from the sum */
  305.    ave_read_tim  = sum_read_tim / nprocs; 
  306.    ave_write_tim = sum_write_tim / nprocs; 
  307.  
  308.    /* and finally compute variance */
  309.    if (nprocs > 1) {
  310.         var_read_tim  = sumsq_read_tim / (nprocs-1);
  311.         var_write_tim = sumsq_write_tim / (nprocs-1);
  312.    }
  313.    else {
  314.         var_read_tim = 0;
  315.         var_write_tim = 0;
  316.    }
  317.    
  318.    /* print out the results on one node */
  319.    if (mynod == 0) {
  320.       read_bw = (opt_block*nprocs*opt_iter)/(max_read_tim*1.0e6);
  321.       write_bw = (opt_block*nprocs*opt_iter)/(max_write_tim*1.0e6);
  322.       
  323.         printf("nr_procs = %d, nr_iter = %d, blk_sz = %lld, coll = %d\n",
  324.                  nprocs, opt_iter, (long long) opt_block, opt_coll);
  325.         
  326.         printf("# total_size = %lld\n",
  327.                  (long long) opt_block*nprocs*opt_iter);
  328.         printf("# Write: min_t = %f, max_t = %f, mean_t = %f, var_t = %f\n", 
  329.                  min_write_tim, max_write_tim, ave_write_tim, var_write_tim);
  330.         printf("# Read:  min_t = %f, max_t = %f, mean_t = %f, var_t = %f\n", 
  331.                  min_read_tim, max_read_tim, ave_read_tim, var_read_tim);
  332.       
  333.       printf("Write bandwidth = %f Mbytes/sec\n", write_bw);
  334.       printf("Read bandwidth = %f Mbytes/sec\n", read_bw);
  335.       
  336.       if (opt_correct) {
  337.          printf("Correctness test %s.\n", correct ? "passed" : "failed");
  338.       }
  339.    }
  340.  
  341.  
  342. die_jar_jar_die:   
  343.  
  344.    free(tmp);
  345.    MPI_Finalize();
  346.    return(0);
  347. }
  348.  
  349. static int parse_args(int argc, char **argv)
  350. {
  351.    int c;
  352.    
  353.    while ((c = getopt(argc, argv, "b:i:f:p:CcyShvrw")) != EOF) {
  354.       switch (c) {
  355.          case 'b': /* block size */
  356.             opt_block = atoi(optarg);
  357.             break;
  358.          case 'i': /* iterations */
  359.             opt_iter = atoi(optarg);
  360.             break;
  361.          case 'f': /* filename */
  362.             strncpy(opt_file, optarg, 255);
  363.             break;
  364.          case 'p': /* pvfstab file */
  365.             strncpy(opt_pvfs2tab, optarg, 255);
  366.             opt_pvfstab_set = 1;
  367.             break;
  368.          case 'c': /* correctness */
  369.             opt_correct = 1;
  370.             break;
  371.          case 'C': /* collective I/O */
  372.             opt_coll = 1;
  373.             break;
  374.          case 'y': /* sYnc */
  375.             opt_sync = 1;
  376.             break;
  377.          case 'S': /* Single region */
  378.             opt_single = 1;
  379.             break;
  380.          case 'v': /* verbose */
  381.             opt_verbose = 1;
  382.             break;
  383.             case 'r': /* read-only */
  384.                 opt_rdonly = 1;
  385.                 break;
  386.             case 'w': /* write-only */
  387.                 opt_wronly = 1;
  388.                 break;
  389.          case 'h':
  390.             if (mynod == 0)
  391.                 usage();
  392.             exit(0);
  393.          case '?': /* unknown */
  394.             if (mynod == 0)
  395.                 usage();
  396.             exit(1);
  397.          default:
  398.             break;
  399.       }
  400.    }
  401.    return(0);
  402. }
  403.  
  404. static void usage(void)
  405. {
  406.     printf("Usage: mpi-io-test [<OPTIONS>...]\n");
  407.     printf("\n<OPTIONS> is one of\n");
  408.     printf(" -b       block size (in bytes) [default: 16777216]\n");
  409.     printf(" -c       verify correctness of file data [default: off]\n");
  410.     printf(" -C       perform operations Collectively [default: off]\n");
  411.     printf(" -i       iterations [default: 1]\n");
  412.     printf(" -f       filename [default: /foo/test.out]\n");
  413.     printf(" -p       path to pvfs2tab file to use [default: notset]\n");
  414.     printf(" -S       all process write to same Single region of file [default: off]\n");
  415.      printf(" -r       read-only.  do no writes.  file must already exist\n");
  416.      printf(" -w       write-only. do no reads.\n");
  417.     printf(" -v       be more verbose\n");
  418.     printf(" -y       sYnc the file after each write [default: off]\n");
  419.     printf(" -h       print this help\n");
  420. }
  421.  
  422. static void handle_error(int errcode, char *str)
  423. {
  424.     char msg[MPI_MAX_ERROR_STRING];
  425.     int resultlen;
  426.  
  427.     MPI_Error_string(errcode, msg, &resultlen);
  428.     fprintf(stderr, "%s: %s\n", str, msg);
  429.     MPI_Abort(MPI_COMM_WORLD, 1);
  430. }
  431.  
  432. /*
  433.  * Local variables:
  434.  *  c-indent-level: 3
  435.  *  c-basic-offset: 3
  436.  *  tab-width: 3
  437.  *
  438.  * vim: ts=3
  439.  * End:
  440.  */ 
  441.  
  442.  
  443.