From d1d532069bd98ad37afb130fc9fba76be92d098b Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 18 Dec 2001 15:12:21 -0500 Subject: [svn-r4733] Purpose: Feature Changes Description: Okay, I needed to add in more parameters so that the user can modify how things are supposed to work with the PIO programs. Also needed to change the algorithm a bit to make these work. And needed to add in timing for the READ option. Solution: Added the above things. The parameters took a major rewrite of the command-line parsing stuff. Here's the usage statement: usage: pio_perf [OPTIONS] OPTIONS -h, --help Print a usage message and exit -d N, --num-dsets=N Number of datasets per file [default:1] -f S, --file-size=S Size of a single file [default: 64M] -F N, --num-files=N Number of files [default: 1] -H, --hdf5 Run HDF5 performance test -i, --num-iterations Number of iterations to perform [default: 1] -m, --mpiio Run MPI/IO performance test -o F, --output=F Output raw data into file F [default: none] -P N, --max-num-processes=N Maximum number of processes to use [default: 1] -p N, --min-num-processes=N Minimum number of processes to use [default: 1] -r, --raw Run raw (UNIX) performance test -X S, --max-xfer-size=S Maximum transfer buffer size [default: 1M] -x S, --min-xfer-size=S Minimum transfer buffer size [default: 1K] F - is a filename. N - is an integer >=0. S - is a size specifier, an integer >=0 followed by a size indicator: K - Kilobyte M - Megabyte G - Gigabyte Example: 37M = 37 Megabytes Platforms tested: Linux, but not fully finished... --- perform/pio_engine.c | 415 +++++++++++++++++++++++++++------------------------ perform/pio_perf.c | 383 +++++++++++++++++++++++++++++++++++++---------- perform/pio_perf.h | 12 +- 3 files changed, 531 insertions(+), 279 deletions(-) diff --git a/perform/pio_engine.c b/perform/pio_engine.c index f3530fc..c2e7ac4 100644 --- a/perform/pio_engine.c +++ b/perform/pio_engine.c @@ -35,13 +35,13 @@ #define GOTOERROR(errcode) { ret_code = errcode; goto done; } #define GOTODONE { goto done; } #define ERRMSG(mesg) { \ - fprintf(stderr, "Proc %d: ", pio_mpi_rank_g); \ + fprintf(stderr, "Proc %d: ", pio_mpi_rank_g); \ fprintf(stderr, "*** Assertion failed (%s) at line %4d in %s\n", \ mesg, (int)__LINE__, __FILE__); \ } #define MSG(mesg) { \ - fprintf(stderr, "Proc %d: ", pio_mpi_rank_g); \ + fprintf(stderr, "Proc %d: ", pio_mpi_rank_g); \ fprintf(stderr, "(%s) at line %4d in %s\n", \ mesg, (int)__LINE__, __FILE__); \ } @@ -93,13 +93,13 @@ enum { }; /* Global variables */ -MPI_Comm pio_comm_g; /* Communicator to run the PIO */ -int pio_mpi_rank_g; /* MPI rank of pio_comm_g */ -int pio_mpi_nprocs_g; /* number of processes of pio_comm_g */ +MPI_Comm pio_comm_g; /* Communicator to run the PIO */ +int pio_mpi_rank_g; /* MPI rank of pio_comm_g */ +int pio_mpi_nprocs_g; /* number of processes of pio_comm_g */ -static int clean_file_g = -1; /*whether to cleanup temporary test */ - /*files. -1 is not defined; */ - /*0 is no cleanup; 1 is do cleanup */ +static int clean_file_g = -1; /*whether to cleanup temporary test */ + /*files. -1 is not defined; */ + /*0 is no cleanup; 1 is do cleanup */ @@ -152,7 +152,7 @@ results do_pio(parameters param) { /* return codes */ - int rc; /*routine return code */ + int rc; /*routine return code */ int mrc; /*MPI return code */ herr_t ret_code = 0; /*return code */ results res; @@ -166,33 +166,34 @@ do_pio(parameters param) long ndsets, nelmts; int color; /*for communicator creation */ char *buffer = NULL; /*data buffer pointer */ - long buf_size; /*data buffer size in bytes */ + long buf_size; /*data buffer size in bytes */ /* HDF5 variables */ - herr_t hrc; /*HDF5 return code */ + herr_t hrc; /*HDF5 return code */ /* MPI variables */ int myrank, nprocs = 1; pio_comm_g = MPI_COMM_NULL; - /* parameters sanity check */ + /* Sanity check parameters */ + + /* IO type */ iot = param.io_type; switch (iot) { case MPIO: - fd.mpifd = MPI_FILE_NULL; + fd.mpifd = MPI_FILE_NULL; res.timers = pio_time_new(MPI_TIMER); break; case RAW: - fd.rawfd = -1; + fd.rawfd = -1; res.timers = pio_time_new(SYS_TIMER); - break; + break; case PHDF5: - fd.h5fd = -1; + fd.h5fd = -1; res.timers = pio_time_new(SYS_TIMER); break; - default: /* unknown request */ fprintf(stderr, "Unknown IO type request (%d)\n", iot); @@ -202,7 +203,7 @@ do_pio(parameters param) nfiles = param.num_files; /* number of files */ ndsets = param.num_dsets; /* number of datasets per file */ nelmts = param.num_elmts; /* number of elements per dataset */ - maxprocs = param.max_num_procs; /* max number of mpi-processes to use */ + maxprocs = param.num_procs; /* max number of mpi-processes to use */ buf_size = param.buf_size; if (nfiles < 0 ) { @@ -295,7 +296,7 @@ buf_size=MIN(1024*1024, buf_size); for (nf = 1; nf <= nfiles; nf++) { /* - * Wirte performance measurement + * Write performance measurement */ /* Open file for write */ char base_name[256]; @@ -329,15 +330,25 @@ fprintf(stderr, "filename=%s\n", fname); * Read performance measurement */ /* Open file for read */ + set_time(res.timers, HDF5_FILE_OPENCLOSE, START); hrc = do_fopen(iot, fname, &fd, PIO_READ); + set_time(res.timers, HDF5_FILE_OPENCLOSE, STOP); + VRFY((hrc == SUCCESS), "do_fopen failed"); - hrc = do_read(&fd, iot, ndsets, nelmts, buf_size, buffer); - VRFY((hrc == SUCCESS), "do_read failed"); + set_time(res.timers, HDF5_READ_FIXED_DIMS, START); + hrc = do_read(&fd, iot, ndsets, nelmts, buf_size, buffer); + set_time(res.timers, HDF5_READ_FIXED_DIMS, STOP); + + VRFY((hrc == SUCCESS), "do_read failed"); /* Close file for read */ + set_time(res.timers, HDF5_FILE_OPENCLOSE, START); hrc = do_fclose(iot, &fd); + set_time(res.timers, HDF5_FILE_OPENCLOSE, STOP); + VRFY((hrc == SUCCESS), "do_fclose failed"); + do_cleanupfile(iot, fname); } @@ -349,26 +360,27 @@ done: /* no remove(fname) because that should have happened normally. */ switch (iot) { case RAW: - if (fd.rawfd != -1) - hrc = do_fclose(iot, &fd); + if (fd.rawfd != -1) + hrc = do_fclose(iot, &fd); break; case MPIO: if (fd.mpifd != MPI_FILE_NULL) - hrc = do_fclose(iot, &fd); + hrc = do_fclose(iot, &fd); break; case PHDF5: if (fd.h5fd != -1) - hrc = do_fclose(iot, &fd); + hrc = do_fclose(iot, &fd); break; } /* release MPI resources */ if (pio_comm_g != MPI_COMM_NULL){ mrc = MPI_Comm_free(&pio_comm_g); - if (mrc != MPI_SUCCESS) { - fprintf(stderr, "MPI_Comm_free failed\n"); - ret_code = FAIL; - } + + if (mrc != MPI_SUCCESS) { + fprintf(stderr, "MPI_Comm_free failed\n"); + ret_code = FAIL; + } } /* release generic resources */ @@ -499,27 +511,27 @@ static herr_t do_write(file_descr *fd, iotype iot, long ndsets, long nelmts, long buf_size, void *buffer) { - int ret_code = SUCCESS; - int rc; /*routine return code */ + int ret_code = SUCCESS; + int rc; /*routine return code */ int mrc; /*MPI return code */ MPI_Offset mpi_offset; MPI_Status mpi_status; - long ndset; - long nelmts_towrite, nelmts_written; - char dname[64]; - off_t dset_offset; /*dataset offset in a file */ - off_t file_offset; /*file offset of the next transfer */ - long dset_size; /*one dataset size in bytes */ - long nelmts_in_buf; - long elmts_begin; /*first elmt this process transfer */ - long elmts_count; /*number of elmts this process transfer */ + long ndset; + long nelmts_towrite, nelmts_written; + char dname[64]; + off_t dset_offset; /*dataset offset in a file */ + off_t file_offset; /*file offset of the next transfer */ + long dset_size; /*one dataset size in bytes */ + long nelmts_in_buf; + long elmts_begin; /*first elmt this process transfer */ + long elmts_count; /*number of elmts this process transfer */ /* HDF5 variables */ herr_t hrc; /*HDF5 return code */ hsize_t h5dims[1]; /*dataset dim sizes */ hid_t h5dset_space_id = -1; /*dataset space ID */ hid_t h5mem_space_id = -1; /*memory dataspace ID */ - hid_t h5ds_id = -1; /* dataset handle */ + hid_t h5ds_id = -1; /*dataset handle */ #if AKCDEBUG fprintf(stderr, "In do_write\n"); @@ -527,6 +539,7 @@ fprintf(stderr, "ndsets=%ld\n", ndsets); fprintf(stderr, "nelmts=%ld\n", nelmts); fprintf(stderr, "buffer size=%ld\n", buf_size); #endif + /* calculate dataset parameters. data type is always native C int */ dset_size = nelmts * ELMT_SIZE; nelmts_in_buf = buf_size/ELMT_SIZE; @@ -569,19 +582,19 @@ fprintf(stderr, "buffer size=%ld\n", buf_size); break; } - /* Calculate the first element and how many elements this process - * transfer. First calculate the beginning element of this process - * and the next process. Count of elements is the difference between - * these two beginnings. This way, it avoids any rounding errors. - */ - elmts_begin = (nelmts*1.0)/pio_mpi_nprocs_g*pio_mpi_rank_g; - if (pio_mpi_rank_g < (pio_mpi_nprocs_g - 1)){ - elmts_count = ((nelmts*1.0)/pio_mpi_nprocs_g*(pio_mpi_rank_g+1)) - - elmts_begin; - }else{ - /* last process. Take whatever are left */ - elmts_count = nelmts - elmts_begin; - } + /* Calculate the first element and how many elements this process + * transfer. First calculate the beginning element of this process + * and the next process. Count of elements is the difference between + * these two beginnings. This way, it avoids any rounding errors. + */ + elmts_begin = (nelmts*1.0)/pio_mpi_nprocs_g*pio_mpi_rank_g; + + if (pio_mpi_rank_g < (pio_mpi_nprocs_g - 1)) + elmts_count = ((nelmts * 1.0) / pio_mpi_nprocs_g * (pio_mpi_rank_g + 1)) + - elmts_begin; + else + /* last process. Take whatever are left */ + elmts_count = nelmts - elmts_begin; #if AKCDEBUG fprintf(stderr, "proc %d: elmts_begin=%ld, elmts_count=%ld\n", @@ -589,6 +602,7 @@ fprintf(stderr, "proc %d: elmts_begin=%ld, elmts_count=%ld\n", #endif nelmts_written = 0 ; + while (nelmts_written < elmts_count){ nelmts_towrite = elmts_count - nelmts_written; @@ -612,56 +626,60 @@ fprintf(stderr, "proc %d: elmts_begin=%ld, elmts_count=%ld\n", /* Write */ /* Calculate offset of write within a dataset/file */ - switch (iot){ + switch (iot) { case RAW: - file_offset = dset_offset + - (elmts_begin + nelmts_written)*ELMT_SIZE; + file_offset = dset_offset + (elmts_begin + nelmts_written)*ELMT_SIZE; + #if AKCDEBUG fprintf(stderr, "proc %d: writes %ld bytes at file-offset %ld\n", - pio_mpi_rank_g, nelmts_towrite*ELMT_SIZE, file_offset); + pio_mpi_rank_g, nelmts_towrite*ELMT_SIZE, file_offset); #endif + rc = RAWSEEK(fd->rawfd, file_offset); - VRFY((rc>=0), "RAWSEEK"); + VRFY((rc>=0), "RAWSEEK"); rc = RAWWRITE(fd->rawfd, buffer, nelmts_towrite*ELMT_SIZE); - VRFY((rc==(nelmts_towrite*ELMT_SIZE)), "RAWWRITE"); + VRFY((rc==(nelmts_towrite*ELMT_SIZE)), "RAWWRITE"); break; case MPIO: - mpi_offset = dset_offset + - (elmts_begin + nelmts_written)*ELMT_SIZE; + mpi_offset = dset_offset + (elmts_begin + nelmts_written)*ELMT_SIZE; + #if AKCDEBUG fprintf(stderr, "proc %d: writes %ld bytes at mpi-offset %ld\n", - pio_mpi_rank_g, nelmts_towrite*ELMT_SIZE, mpi_offset); + pio_mpi_rank_g, nelmts_towrite*ELMT_SIZE, mpi_offset); #endif - mrc = MPI_File_write_at(fd->mpifd, mpi_offset, buffer, - nelmts_towrite*ELMT_SIZE, MPI_CHAR, &mpi_status); - VRFY((mrc==MPI_SUCCESS), "MPIO_WRITE"); - break; + + mrc = MPI_File_write_at(fd->mpifd, mpi_offset, buffer, + nelmts_towrite * ELMT_SIZE, MPI_CHAR, + &mpi_status); + VRFY((mrc==MPI_SUCCESS), "MPIO_WRITE"); + break; case PHDF5: - /*set up the dset space id to select the segment to process */ - { - hsize_t block[1], stride[1], count[1]; - hssize_t start[1]; - - start[0] = elmts_begin + nelmts_written; - stride[0] = block[0] = nelmts_towrite; - count[0] = 1; - hrc = H5Sselect_hyperslab(h5dset_space_id, H5S_SELECT_SET, - start, stride, count, block); - VRFY((hrc >= 0), "H5Sset_hyperslab"); - - /*setup the memory space id too. Only start is different */ - start[0] = 0; - hrc = H5Sselect_hyperslab(h5mem_space_id, H5S_SELECT_SET, - start, stride, count, block); - VRFY((hrc >= 0), "H5Sset_hyperslab"); - } - MPI_Barrier(pio_comm_g); - - /* set write time here */ - hrc = H5Dwrite(h5ds_id, H5T_NATIVE_INT, h5mem_space_id, - h5dset_space_id, H5P_DEFAULT, buffer); - VRFY((hrc >= 0), "H5Dwrite"); + /*set up the dset space id to select the segment to process */ + { + hsize_t block[1], stride[1], count[1]; + hssize_t start[1]; + + start[0] = elmts_begin + nelmts_written; + stride[0] = block[0] = nelmts_towrite; + count[0] = 1; + hrc = H5Sselect_hyperslab(h5dset_space_id, H5S_SELECT_SET, + start, stride, count, block); + VRFY((hrc >= 0), "H5Sset_hyperslab"); + + /*setup the memory space id too. Only start is different */ + start[0] = 0; + hrc = H5Sselect_hyperslab(h5mem_space_id, H5S_SELECT_SET, + start, stride, count, block); + VRFY((hrc >= 0), "H5Sset_hyperslab"); + } + + MPI_Barrier(pio_comm_g); + + /* set write time here */ + hrc = H5Dwrite(h5ds_id, H5T_NATIVE_INT, h5mem_space_id, + h5dset_space_id, H5P_DEFAULT, buffer); + VRFY((hrc >= 0), "H5Dwrite"); break; } @@ -708,7 +726,6 @@ done: return ret_code; } - /* * Function: do_read * Purpose: read the required amount of data from the file. @@ -720,27 +737,27 @@ static herr_t do_read(file_descr *fd, iotype iot, long ndsets, long nelmts, long buf_size, void *buffer /*out*/) { - int ret_code = SUCCESS; - int rc; /*routine return code */ + int ret_code = SUCCESS; + int rc; /*routine return code */ int mrc; /*MPI return code */ - MPI_Offset mpi_offset; - MPI_Status mpi_status; - long ndset; - long nelmts_toread, nelmts_read; - char dname[64]; - off_t dset_offset; /*dataset offset in a file */ - off_t file_offset; /*file offset of the next transfer */ - long dset_size; /*one dataset size in bytes */ - long nelmts_in_buf; - long elmts_begin; /*first elmt this process transfer */ - long elmts_count; /*number of elmts this process transfer */ + MPI_Offset mpi_offset; + MPI_Status mpi_status; + long ndset; + long nelmts_toread, nelmts_read; + char dname[64]; + off_t dset_offset; /*dataset offset in a file */ + off_t file_offset; /*file offset of the next transfer */ + long dset_size; /*one dataset size in bytes */ + long nelmts_in_buf; + long elmts_begin; /*first elmt this process transfer */ + long elmts_count; /*number of elmts this process transfer */ /* HDF5 variables */ - herr_t hrc; /*HDF5 return code */ - hsize_t h5dims[1]; /*dataset dim sizes */ - hid_t h5dset_space_id = -1; /*dataset space ID */ - hid_t h5mem_space_id = -1; /*memory dataspace ID */ - hid_t h5ds_id = -1; /* dataset handle */ + herr_t hrc; /*HDF5 return code */ + hsize_t h5dims[1]; /*dataset dim sizes */ + hid_t h5dset_space_id = -1; /*dataset space ID */ + hid_t h5mem_space_id = -1; /*memory dataspace ID */ + hid_t h5ds_id = -1; /*dataset handle */ #if AKCDEBUG fprintf(stderr, "In do_read\n"); @@ -748,6 +765,7 @@ fprintf(stderr, "ndsets=%ld\n", ndsets); fprintf(stderr, "nelmts=%ld\n", nelmts); fprintf(stderr, "buffer size=%ld\n", buf_size); #endif + /* calculate dataset parameters. data type is always native C int */ dset_size = nelmts * ELMT_SIZE; nelmts_in_buf = buf_size/ELMT_SIZE; @@ -766,7 +784,6 @@ fprintf(stderr, "buffer size=%ld\n", buf_size); } for (ndset = 1; ndset <= ndsets; ++ndset) { - /* Calculate dataset offset within a file */ /* create dataset */ @@ -788,88 +805,94 @@ fprintf(stderr, "buffer size=%ld\n", buf_size); break; } - /* Calculate the first element and how many elements this process - * transfer. First calculate the beginning element of this process - * and the next process. Count of elements is the difference between - * these two beginnings. This way, it avoids any rounding errors. - */ - elmts_begin = (nelmts*1.0)/pio_mpi_nprocs_g*pio_mpi_rank_g; - if (pio_mpi_rank_g < (pio_mpi_nprocs_g - 1)){ - elmts_count = ((nelmts*1.0)/pio_mpi_nprocs_g*(pio_mpi_rank_g+1)) - - elmts_begin; - }else{ - /* last process. Take whatever are left */ - elmts_count = nelmts - elmts_begin; - } + /* + * Calculate the first element and how many elements this process + * transfer. First calculate the beginning element of this process + * and the next process. Count of elements is the difference between + * these two beginnings. This way, it avoids any rounding errors. + */ + elmts_begin = (nelmts*1.0)/pio_mpi_nprocs_g*pio_mpi_rank_g; + + if (pio_mpi_rank_g < (pio_mpi_nprocs_g - 1)) + elmts_count = ((nelmts * 1.0) / pio_mpi_nprocs_g * (pio_mpi_rank_g + 1)) - + elmts_begin; + else + /* last process. Take whatever are left */ + elmts_count = nelmts - elmts_begin; #if AKCDEBUG fprintf(stderr, "proc %d: elmts_begin=%ld, elmts_count=%ld\n", - pio_mpi_rank_g, elmts_begin, elmts_count); + pio_mpi_rank_g, elmts_begin, elmts_count); #endif nelmts_read = 0 ; + while (nelmts_read < elmts_count){ nelmts_toread = elmts_count - nelmts_read; - if (elmts_count - nelmts_read >= nelmts_in_buf) { + if (elmts_count - nelmts_read >= nelmts_in_buf) nelmts_toread = nelmts_in_buf; - } else { + else /* last read of a partial buffer */ nelmts_toread = elmts_count - nelmts_read; - } /* read */ /* Calculate offset of read within a dataset/file */ switch (iot){ case RAW: - file_offset = dset_offset + - (elmts_begin + nelmts_read)*ELMT_SIZE; + file_offset = dset_offset + (elmts_begin + nelmts_read)*ELMT_SIZE; + #if AKCDEBUG fprintf(stderr, "proc %d: read %ld bytes at file-offset %ld\n", - pio_mpi_rank_g, nelmts_toread*ELMT_SIZE, file_offset); + pio_mpi_rank_g, nelmts_toread*ELMT_SIZE, file_offset); #endif + rc = RAWSEEK(fd->rawfd, file_offset); - VRFY((rc>=0), "RAWSEEK"); + VRFY((rc>=0), "RAWSEEK"); rc = RAWREAD(fd->rawfd, buffer, nelmts_toread*ELMT_SIZE); - VRFY((rc==(nelmts_toread*ELMT_SIZE)), "RAWREAD"); + VRFY((rc==(nelmts_toread*ELMT_SIZE)), "RAWREAD"); break; case MPIO: - mpi_offset = dset_offset + - (elmts_begin + nelmts_read)*ELMT_SIZE; + mpi_offset = dset_offset + (elmts_begin + nelmts_read)*ELMT_SIZE; + #if AKCDEBUG fprintf(stderr, "proc %d: read %ld bytes at mpi-offset %ld\n", pio_mpi_rank_g, nelmts_toread*ELMT_SIZE, mpi_offset); #endif - mrc = MPI_File_read_at(fd->mpifd, mpi_offset, buffer, - nelmts_toread*ELMT_SIZE, MPI_CHAR, &mpi_status); - VRFY((mrc==MPI_SUCCESS), "MPIO_read"); - break; + + mrc = MPI_File_read_at(fd->mpifd, mpi_offset, buffer, + nelmts_toread*ELMT_SIZE, MPI_CHAR, + &mpi_status); + VRFY((mrc==MPI_SUCCESS), "MPIO_read"); + break; + case PHDF5: - /*set up the dset space id to select the segment to process */ - { - hsize_t block[1], stride[1], count[1]; - hssize_t start[1]; - - start[0] = elmts_begin + nelmts_read; - stride[0] = block[0] = nelmts_toread; - count[0] = 1; - hrc = H5Sselect_hyperslab(h5dset_space_id, H5S_SELECT_SET, - start, stride, count, block); - VRFY((hrc >= 0), "H5Sset_hyperslab"); - - /*setup the memory space id too. Only start is different */ - start[0] = 0; - hrc = H5Sselect_hyperslab(h5mem_space_id, H5S_SELECT_SET, - start, stride, count, block); - VRFY((hrc >= 0), "H5Sset_hyperslab"); - } - MPI_Barrier(pio_comm_g); - - /* set read time here */ - hrc = H5Dread(h5ds_id, H5T_NATIVE_INT, h5mem_space_id, - h5dset_space_id, H5P_DEFAULT, buffer); - VRFY((hrc >= 0), "H5Dread"); + /*set up the dset space id to select the segment to process */ + { + hsize_t block[1], stride[1], count[1]; + hssize_t start[1]; + + start[0] = elmts_begin + nelmts_read; + stride[0] = block[0] = nelmts_toread; + count[0] = 1; + hrc = H5Sselect_hyperslab(h5dset_space_id, H5S_SELECT_SET, + start, stride, count, block); + VRFY((hrc >= 0), "H5Sset_hyperslab"); + + /*setup the memory space id too. Only start is different */ + start[0] = 0; + hrc = H5Sselect_hyperslab(h5mem_space_id, H5S_SELECT_SET, + start, stride, count, block); + VRFY((hrc >= 0), "H5Sset_hyperslab"); + } + + MPI_Barrier(pio_comm_g); + + /* set read time here */ + hrc = H5Dread(h5ds_id, H5T_NATIVE_INT, h5mem_space_id, + h5dset_space_id, H5P_DEFAULT, buffer); + VRFY((hrc >= 0), "H5Dread"); break; } @@ -880,7 +903,7 @@ fprintf(stderr, "proc %d: read %ld bytes at mpi-offset %ld\n", register int i; for (i = 0; i < nelmts_towrite; ++i) - /* TO BE IMPLEMENTED */ + /* TO BE IMPLEMENTED */ ; } #endif @@ -928,7 +951,6 @@ done: return ret_code; } - /* * Function: do_fopen * Purpose: Open the specified file. @@ -945,11 +967,10 @@ do_fopen(iotype iot, char *fname, file_descr *fd /*out*/, int flags) switch (iot) { case RAW: - if (flags & (PIO_CREATE | PIO_WRITE)) { + if (flags & (PIO_CREATE | PIO_WRITE)) fd->rawfd = RAWCREATE(fname); - } else { + else fd->rawfd = RAWOPEN(fname, O_RDONLY); - } if (fd->rawfd < 0 ) { fprintf(stderr, "Raw File Open failed(%s)\n", fname); @@ -960,30 +981,32 @@ do_fopen(iotype iot, char *fname, file_descr *fd /*out*/, int flags) case MPIO: if (flags & (PIO_CREATE | PIO_WRITE)) { - MPI_File_delete(fname, MPI_INFO_NULL); + MPI_File_delete(fname, MPI_INFO_NULL); mrc = MPI_File_open(pio_comm_g, fname, MPI_MODE_CREATE | MPI_MODE_RDWR, MPI_INFO_NULL, &fd->mpifd); - if (mrc != MPI_SUCCESS) { - fprintf(stderr, "MPI File Open failed(%s)\n", fname); - GOTOERROR(FAIL); - } - /*since MPI_File_open with MPI_MODE_CREATE does not truncate */ - /*filesize , set size to 0 explicitedly. */ - mrc = MPI_File_set_size(fd->mpifd, 0); - if (mrc != MPI_SUCCESS) { - fprintf(stderr, "MPI_File_set_size failed\n"); - GOTOERROR(FAIL); - } + if (mrc != MPI_SUCCESS) { + fprintf(stderr, "MPI File Open failed(%s)\n", fname); + GOTOERROR(FAIL); + } + + /*since MPI_File_open with MPI_MODE_CREATE does not truncate */ + /*filesize , set size to 0 explicitedly. */ + mrc = MPI_File_set_size(fd->mpifd, 0); + + if (mrc != MPI_SUCCESS) { + fprintf(stderr, "MPI_File_set_size failed\n"); + GOTOERROR(FAIL); + } } else { mrc = MPI_File_open(pio_comm_g, fname, MPI_MODE_RDONLY, MPI_INFO_NULL, &fd->mpifd); - if (mrc != MPI_SUCCESS) { - fprintf(stderr, "MPI File Open failed(%s)\n", fname); - GOTOERROR(FAIL); - } - } + if (mrc != MPI_SUCCESS) { + fprintf(stderr, "MPI File Open failed(%s)\n", fname); + GOTOERROR(FAIL); + } + } break; @@ -1095,21 +1118,21 @@ static void do_cleanupfile(iotype iot, char *fname) { if (pio_mpi_rank_g != 0) - return; + return; if (clean_file_g == -1) - clean_file_g = (getenv("HDF5_NOCLEANUP")==NULL) ? 1 : 0; + clean_file_g = (getenv("HDF5_NOCLEANUP")==NULL) ? 1 : 0; if (clean_file_g){ - switch (iot){ - case RAW: - remove(fname); - break; - case MPIO: - case PHDF5: - MPI_File_delete(fname, MPI_INFO_NULL); - break; - } + switch (iot){ + case RAW: + remove(fname); + break; + case MPIO: + case PHDF5: + MPI_File_delete(fname, MPI_INFO_NULL); + break; + } } } #endif /* H5_HAVE_PARALLEL */ diff --git a/perform/pio_perf.c b/perform/pio_perf.c index a195d25..a4602f8 100644 --- a/perform/pio_perf.c +++ b/perform/pio_perf.c @@ -71,6 +71,10 @@ #define ONE_MB (ONE_KB * ONE_KB) #define ONE_GB (ONE_MB * ONE_KB) +#define PIO_RAW 020 +#define PIO_MPI 040 +#define PIO_HDF5 060 + #define MB_PER_SEC(bytes,t) (((bytes) / ONE_MB) / t) #define MIN_HDF5_BUF_SIZE (ONE_MB >> 1) @@ -85,9 +89,9 @@ static const char *progname = "pio_perf"; * adding more, make sure that they don't clash with each other. */ #if 1 -static const char *s_opts = "ho:m:"; +static const char *s_opts = "hf:HP:p:X:x:md:F:i:o:r"; #else -static const char *s_opts = "hbo:m:"; +static const char *s_opts = "hbf:HP:p:X:x:md:F:i:o:r"; #endif /* 1 */ static struct long_options l_opts[] = { { "help", no_arg, 'h' }, @@ -101,28 +105,102 @@ static struct long_options l_opts[] = { { "bin", no_arg, 'b' }, { "bi", no_arg, 'b' }, #endif /* 0 */ - { "max-size", require_arg, 'm' }, - { "max-siz", require_arg, 'm' }, - { "max-si", require_arg, 'm' }, - { "max-s", require_arg, 'm' }, - { "max", require_arg, 'm' }, - { "ma", require_arg, 'm' }, + { "file-size", require_arg, 'f' }, + { "file-siz", require_arg, 'f' }, + { "file-si", require_arg, 'f' }, + { "file-s", require_arg, 'f' }, + { "file", require_arg, 'f' }, + { "fil", require_arg, 'f' }, + { "fi", require_arg, 'f' }, + { "hdf5", no_arg, 'H' }, + { "hdf", no_arg, 'H' }, + { "hd", no_arg, 'H' }, + { "max-num-processes", require_arg, 'P' }, + { "max-num-processe", require_arg, 'P' }, + { "max-num-process", require_arg, 'P' }, + { "max-num-proces", require_arg, 'P' }, + { "max-num-proce", require_arg, 'P' }, + { "max-num-proc", require_arg, 'P' }, + { "max-num-pro", require_arg, 'P' }, + { "max-num-pr", require_arg, 'P' }, + { "max-num-p", require_arg, 'P' }, + { "min-num-processes", require_arg, 'p' }, + { "min-num-processe", require_arg, 'p' }, + { "min-num-process", require_arg, 'p' }, + { "min-num-proces", require_arg, 'p' }, + { "min-num-proce", require_arg, 'p' }, + { "min-num-proc", require_arg, 'p' }, + { "min-num-pro", require_arg, 'p' }, + { "min-num-pr", require_arg, 'p' }, + { "min-num-p", require_arg, 'p' }, + { "max-xfer-size", require_arg, 'X' }, + { "max-xfer-siz", require_arg, 'X' }, + { "max-xfer-si", require_arg, 'X' }, + { "max-xfer-s", require_arg, 'X' }, + { "max-xfer", require_arg, 'X' }, + { "max-xfe", require_arg, 'X' }, + { "max-xf", require_arg, 'X' }, + { "max-x", require_arg, 'X' }, + { "min-xfer-size", require_arg, 'x' }, + { "min-xfer-siz", require_arg, 'x' }, + { "min-xfer-si", require_arg, 'x' }, + { "min-xfer-s", require_arg, 'x' }, + { "min-xfer", require_arg, 'x' }, + { "min-xfe", require_arg, 'x' }, + { "min-xf", require_arg, 'x' }, + { "min-x", require_arg, 'x' }, + { "mpiio", no_arg, 'm' }, + { "mpii", no_arg, 'm' }, + { "mpi", no_arg, 'm' }, + { "mp", no_arg, 'm' }, + { "num-dsets", require_arg, 'd' }, + { "num-dset", require_arg, 'd' }, + { "num-dse", require_arg, 'd' }, + { "num-ds", require_arg, 'd' }, + { "num-d", require_arg, 'd' }, + { "num-files", require_arg, 'F' }, + { "num-file", require_arg, 'F' }, + { "num-fil", require_arg, 'F' }, + { "num-fi", require_arg, 'F' }, + { "num-f", require_arg, 'F' }, + { "num-iterations", require_arg, 'i' }, + { "num-iteration", require_arg, 'i' }, + { "num-iteratio", require_arg, 'i' }, + { "num-iterati", require_arg, 'i' }, + { "num-iterat", require_arg, 'i' }, + { "num-itera", require_arg, 'i' }, + { "num-iter", require_arg, 'i' }, + { "num-ite", require_arg, 'i' }, + { "num-it", require_arg, 'i' }, + { "num-i", require_arg, 'i' }, { "output", require_arg, 'o' }, { "outpu", require_arg, 'o' }, { "outp", require_arg, 'o' }, { "out", require_arg, 'o' }, { "ou", require_arg, 'o' }, + { "raw", no_arg, 'r' }, + { "ra", no_arg, 'r' }, { NULL, 0, '\0' } }; struct options { + long io_types; /* bitmask of which I/O types to test */ const char *output_file; /* file to print report to */ - long max_size; /* maximum size of file in gigabytes */ + long file_size; /* size of file */ + long num_dsets; /* number of datasets */ + long num_files; /* number of files */ + long num_iters; /* number of iterations */ + long max_num_procs; /* maximum number of processes to use */ + long min_num_procs; /* minimum number of processes to use */ + long max_xfer_size; /* maximum transfer buffer size */ + long min_xfer_size; /* minimum transfer buffer size */ }; /* local functions */ +static long parse_size_directive(const char *size); static struct options *parse_command_line(int argc, char *argv[]); -static void run_test_loop(FILE *output, int max_num_procs, long max_size); +static void run_test_loop(FILE *output, struct options *options); +static void run_test(FILE *output, iotype iot, parameters parms); static void print_indent(register FILE *output, register int indent); static void usage(const char *prog); @@ -168,7 +246,7 @@ main(int argc, char **argv) goto cheese_and; } - run_test_loop(output, world_size, opts->max_size); + run_test_loop(output, opts); cheese_and: MPI_Finalize(); @@ -199,96 +277,116 @@ onions: * Modifications: */ static void -run_test_loop(FILE *output, int max_num_procs, long max_size) +run_test_loop(FILE *output, struct options *opts) { parameters parms; + long num_procs; + int io_runs = PIO_HDF5 | PIO_MPI | PIO_RAW; /* default to run all tests */ + + if (opts->io_types & ~07) { + /* we want to run only a select subset of these tests */ + opts->io_types = 0; + + if (opts->io_types | PIO_HDF5) + io_runs |= PIO_HDF5; + + if (opts->io_types | PIO_MPI) + io_runs |= PIO_MPI; + + if (opts->io_types | PIO_RAW) + io_runs |= PIO_RAW; + } - /* num_files stays ``1'' for now but may change later */ - parms.num_files = 1; - parms.num_iters = 1; + parms.num_files = opts->num_files; + parms.num_dsets = opts->num_dsets; + parms.num_iters = opts->num_iters; /* divide the maximum number of processors by 2 for each loop iter */ - for (; max_num_procs > 0; max_num_procs /= 2) { - register iotype i; + for (num_procs = opts->min_num_procs; + num_procs <= opts->max_num_procs; num_procs <<= 1) { + register long j; - parms.max_num_procs = max_num_procs; - fprintf(output, "Number of processors = %u\n", parms.max_num_procs); + parms.num_procs = num_procs; + fprintf(output, "Number of processors = %u\n", parms.num_procs); - for (i = RAW; i <= PHDF5; ++i) { - register unsigned long j; + for (j = opts->min_xfer_size; j <= opts->max_xfer_size; j <<= 1) { + parms.buf_size = j; + parms.num_elmts = opts->file_size / (parms.num_dsets * sizeof(int)); - parms.io_type = i; print_indent(output, TAB_SPACE * 1); - fprintf(output, "Type of IO = "); - - if (i == RAW) - fprintf(output, "Raw\n"); - else if (i == MPIO) - fprintf(output, "MPIO\n"); - else - fprintf(output, "PHDF5\n"); - - for (j = MIN_HDF5_BUF_SIZE; j <= MAX_HDF5_BUF_SIZE; j <<= 1) { - results res; - - parms.buf_size = j; - parms.num_dsets = MAX_HDF5_BUF_SIZE / j; - parms.num_dsets = (parms.num_dsets ? parms.num_dsets : 1); - parms.num_elmts = max_size / (parms.num_dsets * sizeof(int)); - - print_indent(output, TAB_SPACE * 2); - fprintf(output, - "# of files: %u, # of dsets: %lu, Elements per dset: %lu\n", - parms.num_files, parms.num_dsets, parms.num_elmts); - - /* call Albert's testing here */ - res = do_pio(parms); - - print_indent(output, TAB_SPACE * 3); - fprintf(output, "Write Results = %.2f MB/s\n", - MB_PER_SEC(parms.num_dsets * parms.num_elmts * sizeof(int), - get_time(res.timers, HDF5_WRITE_FIXED_DIMS))); - - pio_time_destroy(res.timers); - } + fprintf(output, + "# of files: %u, # of dsets: %lu, Elements per dset: %lu\n", + parms.num_files, parms.num_dsets, parms.num_elmts); + + if (io_runs | PIO_RAW) + run_test(output, RAW, parms); + + if (io_runs | PIO_MPI) + run_test(output, MPIO, parms); + + if (io_runs | PIO_HDF5) + run_test(output, PHDF5, parms); } } } /* - * Function: print_indent - * Purpose: Print spaces to indent a new line of text for pretty printing - * things. + * Function: run_test + * Purpose: Inner loop call to actually run the I/O test. * Return: Nothing - * Programmer: Bill Wendling, 29. October 2001 + * Programmer: Bill Wendling, 18. December 2001 * Modifications: */ static void -print_indent(register FILE *output, register int indent) +run_test(FILE *output, iotype iot, parameters parms) { - for (; indent > 0; --indent) - fputc(' ', output); + results res; + + parms.io_type = iot; + print_indent(output, TAB_SPACE * 2); + fprintf(output, "Type of IO = "); + + switch (iot) { + case RAW: + fprintf(output, "Raw\n"); + break; + case MPIO: + fprintf(output, "MPIO\n"); + break; + case PHDF5: + fprintf(output, "PHDF5\n"); + break; + } + + /* call Albert's testing here */ + res = do_pio(parms); + + print_indent(output, TAB_SPACE * 3); + fprintf(output, "Write Results = %.2f MB/s\n", + MB_PER_SEC(parms.num_dsets * parms.num_elmts * sizeof(int), + get_time(res.timers, HDF5_WRITE_FIXED_DIMS))); + + print_indent(output, TAB_SPACE * 3); + fprintf(output, "Read Results = %.2f MB/s\n", + MB_PER_SEC(parms.num_dsets * parms.num_elmts * sizeof(int), + get_time(res.timers, HDF5_READ_FIXED_DIMS))); + + pio_time_destroy(res.timers); } /* - * Function: usage - * Purpose: Print a usage message and then exit. + * Function: print_indent + * Purpose: Print spaces to indent a new line of text for pretty printing + * things. * Return: Nothing - * Programmer: Bill Wendling, 31. October 2001 + * Programmer: Bill Wendling, 29. October 2001 * Modifications: */ static void -usage(const char *prog) +print_indent(register FILE *output, register int indent) { - fflush(stdout); - fprintf(stdout, "usage: %s [OPTIONS]\n", prog); - fprintf(stdout, " OPTIONS\n"); - fprintf(stdout, " -h, --help Print a usage message and exit\n"); - fprintf(stdout, " -m #, --max-size=# Maximum size of file in megabytes [default: 512]\n"); - fprintf(stdout, " -o F, --output=F Output raw data into file F\n"); - fprintf(stdout, "\n"); - fprintf(stdout, " F - is a filename.\n"); - fprintf(stdout, "\n"); + for (; indent > 0; --indent) + fputc(' ', output); } /* @@ -305,8 +403,18 @@ parse_command_line(int argc, char *argv[]) int opt; struct options *cl_opts; - cl_opts = (struct options *)calloc(1, sizeof(struct options)); - cl_opts->max_size = 512 * ONE_MB; + cl_opts = (struct options *)malloc(sizeof(struct options)); + + cl_opts->output_file = NULL; + cl_opts->file_size = 64 * ONE_MB; + cl_opts->io_types = 07; /* bottom bits indicate default type to run */ + cl_opts->num_dsets = 1; + cl_opts->num_files = 1; + cl_opts->num_iters = 1; + cl_opts->max_num_procs = 1; + cl_opts->min_num_procs = 1; + cl_opts->max_xfer_size = 1 * ONE_MB; + cl_opts->min_xfer_size = 1 * ONE_KB; while ((opt = get_option(argc, (const char **)argv, s_opts, l_opts)) != EOF) { switch ((char)opt) { @@ -315,12 +423,45 @@ parse_command_line(int argc, char *argv[]) /* the future "binary" option */ break; #endif /* 0 */ + case 'd': + cl_opts->num_dsets = strtol(opt_arg, NULL, 10); + break; + case 'f': + cl_opts->file_size = parse_size_directive(opt_arg); + break; + case 'F': + cl_opts->num_files = strtol(opt_arg, NULL, 10); + break; + case 'H': + cl_opts->io_types &= ~07; + cl_opts->io_types |= PIO_HDF5; + break; + case 'i': + cl_opts->num_iters = strtol(opt_arg, NULL, 10); + break; case 'm': - cl_opts->max_size = atol(opt_arg) * ONE_MB; + cl_opts->io_types &= ~07; + cl_opts->io_types |= PIO_MPI; break; case 'o': cl_opts->output_file = opt_arg; break; + case 'p': + cl_opts->min_num_procs = strtol(opt_arg, NULL, 10); + break; + case 'P': + cl_opts->max_num_procs = strtol(opt_arg, NULL, 10); + break; + case 'r': + cl_opts->io_types &= ~07; + cl_opts->io_types |= PIO_RAW; + break; + case 'x': + cl_opts->min_xfer_size = parse_size_directive(opt_arg); + break; + case 'X': + cl_opts->max_xfer_size = parse_size_directive(opt_arg); + break; case 'h': usage(progname); exit(EXIT_SUCCESS); @@ -335,6 +476,94 @@ parse_command_line(int argc, char *argv[]) return cl_opts; } +/* + * Function: parse_size_directive + * Purpose: Parse the size directive passed on the commandline. The size + * directive is an integer followed by a size indicator: + * + * K, k - Kilobyte + * M, m - Megabyte + * G, g - Gigabyte + * + * Return: The size as a LONG. If an unknown size indicator is used, then + * the program will exit with EXIT_FAILURE as the return value. + * Programmer: Bill Wendling, 18. December 2001 + * Modifications: + */ +static long +parse_size_directive(const char *size) +{ + long s; + char *endptr; + + s = strtol(size, &endptr, 10); + + if (endptr && *endptr) { + while (*endptr != '\0' && (*endptr == ' ' || *endptr == '\t')) + ++endptr; + + switch (*endptr) { + case 'K': + case 'k': + s *= ONE_KB; + break; + case 'M': + case 'm': + s *= ONE_MB; + break; + case 'G': + case 'g': + s *= ONE_GB; + break; + default: + fprintf(stderr, "Illegal size specifier '%c'\n", *endptr); + exit(EXIT_FAILURE); + } + } + + return s; +} + +/* + * Function: usage + * Purpose: Print a usage message and then exit. + * Return: Nothing + * Programmer: Bill Wendling, 31. October 2001 + * Modifications: + */ +static void +usage(const char *prog) +{ + fflush(stdout); + fprintf(stdout, "usage: %s [OPTIONS]\n", prog); + fprintf(stdout, " OPTIONS\n"); + fprintf(stdout, " -h, --help Print a usage message and exit\n"); + fprintf(stdout, " -d N, --num-dsets=N Number of datasets per file [default:1]\n"); + fprintf(stdout, " -f S, --file-size=S Size of a single file [default: 64M]\n"); + fprintf(stdout, " -F N, --num-files=N Number of files [default: 1]\n"); + fprintf(stdout, " -H, --hdf5 Run HDF5 performance test\n"); + fprintf(stdout, " -i, --num-iterations Number of iterations to perform [default: 1]\n"); + fprintf(stdout, " -m, --mpiio Run MPI/IO performance test\n"); + fprintf(stdout, " -o F, --output=F Output raw data into file F [default: none]\n"); + fprintf(stdout, " -P N, --max-num-processes=N Maximum number of processes to use [default: 1]\n"); + fprintf(stdout, " -p N, --min-num-processes=N Minimum number of processes to use [default: 1]\n"); + fprintf(stdout, " -r, --raw Run raw (UNIX) performance test\n"); + fprintf(stdout, " -X S, --max-xfer-size=S Maximum transfer buffer size [default: 1M]\n"); + fprintf(stdout, " -x S, --min-xfer-size=S Minimum transfer buffer size [default: 1K]\n"); + fprintf(stdout, "\n"); + fprintf(stdout, " F - is a filename.\n"); + fprintf(stdout, " N - is an integer >=0.\n"); + fprintf(stdout, " S - is a size specifier, an integer >=0 followed by a size indicator:\n"); + fprintf(stdout, "\n"); + fprintf(stdout, " K - Kilobyte\n"); + fprintf(stdout, " M - Megabyte\n"); + fprintf(stdout, " G - Gigabyte\n"); + fprintf(stdout, "\n"); + fprintf(stdout, " Example: 37M = 37 Megabytes\n"); + fprintf(stdout, "\n"); + fflush(stdout); +} + #else /* H5_HAVE_PARALLEL */ /* diff --git a/perform/pio_perf.h b/perform/pio_perf.h index fb25f62..d954591 100644 --- a/perform/pio_perf.h +++ b/perform/pio_perf.h @@ -17,12 +17,12 @@ typedef enum iotype_ { } iotype; typedef struct parameters_ { - int max_num_procs; /* Maximum number of processes to use */ - iotype io_type; /* The type of IO test to perform */ - int num_files; /* Number of files to create */ - long num_dsets; /* Number of datasets to create */ - long num_elmts; /* Number of native ints in each dset */ - int num_iters; /* Number of times to loop doing the IO */ + iotype io_type; /* The type of IO test to perform */ + int num_procs; /* Maximum number of processes to use */ + int num_files; /* Number of files to create */ + long num_dsets; /* Number of datasets to create */ + long num_elmts; /* Number of native ints in each dset */ + int num_iters; /* Number of times to loop doing the IO */ long buf_size; /* Buffer size */ } parameters; -- cgit v0.12