summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--perform/benchpar.c476
1 files changed, 476 insertions, 0 deletions
diff --git a/perform/benchpar.c b/perform/benchpar.c
new file mode 100644
index 0000000..86f6526
--- /dev/null
+++ b/perform/benchpar.c
@@ -0,0 +1,476 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "hdf5.h"
+
+/* Local macros */
+
+/* defines for type of VFL driver to use */
+#define FACC_DEFAULT 0
+#define FACC_MPIO 1
+#define FACC_MPIPOSIX 2
+
+/* Defines for computing performance information */
+#define ONE_KB 1024
+#define ONE_MB (ONE_KB * ONE_KB)
+#define ONE_GB (ONE_MB * ONE_KB)
+/* report 0.0 in case t is zero too */
+#define MB_PER_SEC(bytes,t) (((t)==0.0) ? 0.0 : ((((double)bytes) / ONE_MB) / (t)))
+
+/* Control default behavior (with no command line arguments) */
+#define DEFAULT_RANK 3
+#define DEFAULT_DIM 1024
+#define DEFAULT_PREFIX "/tmp"
+#define DEFAULT_USERNAME "koziol"
+#define DEFAULT_FILENAME "benchpar.h5"
+#define DEFAULT_SLICE 0
+#define DEFAULT_C_TYPE int
+#define DEFAULT_HDF5_DATATYPE H5T_NATIVE_INT /* Keep this in sync with the DEFAULT_C_TYPE */
+#define DEFAULT_DATASET_NAME "Dataset"
+#define DEFAULT_VFL_DRIVER FACC_MPIO
+#define DEFAULT_PAR_MODE H5FD_MPIO_COLLECTIVE
+#define DEFAULT_CHUNK_STORAGE 0
+#define DEFAULT_ITER 3
+
+/* MPI info */
+int mpi_rank, mpi_size;
+int mpi_namelen;
+char mpi_name[MPI_MAX_PROCESSOR_NAME];
+
+/* Usage information */
+static void usage(void)
+{
+ printf("usage: benchpar [-d <# of dims>] [-s <dim_size>] [-f <file name>] [-h]\n");
+ printf(" [-S <slice dim>] [-p] [-I] [-c] [-i <# of iterations>\n");
+ printf(" -c - Use chunked storage for dataset with 1-1 exact\n");
+ printf(" mapping of chunks to hyperslabs\n");
+ printf(" Default: off (i.e. contiguous storage)\n");
+ printf(" -d <# of dims> - Number of dimensions of the dataset\n");
+ printf(" Default: 3\n");
+ printf(" -f <file name> - Set the name of the test file\n");
+ printf(" Default: /tmp/<login>/benchpar.h5\n");
+ printf(" -h - Prints usage information\n");
+ printf(" -i <# of iters> - Set the number of test iterations to perform\n");
+ printf(" Default: 3\n");
+ printf(" -I - Use independent parallel I/O\n");
+ printf(" Default: use collective parallel I/O\n");
+ printf(" -p - Use MPI-posix VFL driver\n");
+ printf(" Default: use MPI-I/O VFL driver\n");
+ printf(" -s <dim_size> - Set the size of each of the dataset's dimensions\n");
+ printf(" Default: 1024\n");
+ printf(" -S <slice dim> - Set the dimension to slice the dataset along\n");
+ printf(" Default: 0\n");
+} /* end usage() */
+
+/* Create & initialize file creation property list with appropriate properties */
+static hid_t create_fcpl(void)
+{
+ hid_t fcpl; /* File creation property list */
+
+ fcpl=H5Pcreate(H5P_FILE_CREATE);
+ assert(fcpl>0);
+
+ return(fcpl);
+} /* end create_fcpl() */
+
+/* Create & initialize file access property list with appropriate properties */
+static hid_t create_fapl(MPI_Comm comm, MPI_Info info, int acc_type )
+{
+ hid_t fapl; /* File access property list */
+ herr_t ret; /* Generic return value */
+
+ fapl = H5Pcreate (H5P_FILE_ACCESS);
+ assert(fapl>0);
+
+ /* set parallel access with communicator, using MPI-I/O driver */
+ if (acc_type == FACC_MPIO) {
+ ret = H5Pset_fapl_mpio(fapl, comm, info);
+ assert(ret>=0);
+ } /* end if */
+
+ /* set parallel access with communicator, using MPI-posix driver */
+ if (acc_type == FACC_MPIPOSIX) {
+ ret = H5Pset_fapl_mpiposix(fapl, comm);
+ assert(ret>=0);
+ } /* end if */
+
+ return (fapl);
+} /* end create_fapl() */
+
+/* Create & initialize dataset creation property list with appropriate properties */
+static hid_t create_dcpl(unsigned use_chunks, int rank, hsize_t *dims)
+{
+ hid_t dcpl; /* Dataset creation property list */
+ herr_t ret; /* Generic return value */
+
+ dcpl=H5Pcreate(H5P_DATASET_CREATE);
+ assert(dcpl>0);
+
+ /* Check if the dataset should be chunked */
+ if(use_chunks) {
+ ret = H5Pset_chunk(dcpl, rank, dims);
+ assert(ret>=0);
+ } /* end if */
+
+ return(dcpl);
+} /* end create_dcpl() */
+
+/* Create & initialize dataset transfer property list with appropriate properties */
+static hid_t create_dxpl(H5FD_mpio_xfer_t par_mode)
+{
+ hid_t dxpl; /* Dataset creation property list */
+ herr_t ret; /* Generic return value */
+
+ dxpl=H5Pcreate(H5P_DATASET_XFER);
+ assert(dxpl>0);
+
+ /* Set collective I/O on this transfer */
+ ret=H5Pset_dxpl_mpio(dxpl, par_mode);
+ assert(ret>=0);
+
+ return(dxpl);
+} /* end create_dcpl() */
+
+int main(int argc, char *argv[])
+{
+ int curr_arg; /* Current command line argument being processed */
+ int rank; /* Number of dimensions of the dataset */
+ hsize_t dim_size; /* Dimension size of each dimension */
+ hsize_t *dims; /* Pointer to array of dimensions */
+ hssize_t *start; /* Pointer to array of starting locations for hyperslab selection */
+ hsize_t *count; /* Pointer to array of counts for hyperslab selection */
+ unsigned slice_dim; /* Dimension to slice up */
+ char *file_name=NULL; /* Name of file to put data into */
+ hid_t fcpl; /* HDF5 File creation property list ID */
+ hid_t fapl; /* HDF5 File access property list ID */
+ hid_t dcpl; /* HDF5 Dataset creation property list ID */
+ hid_t dxpl; /* HDF5 Dataset transfer property list ID */
+ hid_t fid; /* HDF5 file ID */
+ hid_t dsid; /* HDF5 dataset ID */
+ hid_t file_sid; /* HDF5 dataspace ID for dataset on disk */
+ hid_t mem_sid; /* HDF5 dataspace ID for dataset in memory */
+ DEFAULT_C_TYPE *buf; /* Buffer to write out */
+ hsize_t buf_size; /* Size of buffer to write */
+ int i; /* Local index variable */
+ herr_t ret; /* Generic return value */
+ double start_write_time, end_write_time, elap_write_time; /* Start, end and elapsed time to write raw data */
+ double tmp_max_write_time; /* Temporary holders for maximum time for all nodes to perform raw data I/O */
+ double max_write_time=-DBL_MAX, min_write_time=DBL_MAX; /* Minimum & maximum time for all nodes to perform raw data I/O */
+ double start_file_time, end_file_time, elap_file_time; /* Start, end and elapsed time from file open to file close */
+ double tmp_max_file_time; /* Temporary holders for maximum time for all nodes from file open to file close */
+ double max_file_time=-DBL_MAX, min_file_time=DBL_MAX; /* Minimum & maximum time for all nodes from file open to file close */
+ int vfl_type; /* Type of VFL driver to use */
+ H5FD_mpio_xfer_t par_mode; /* Type of parallel I/O to perform */
+ unsigned use_chunks; /* Whether to use chunks for dataset or not */
+ unsigned num_iter; /* Number of iterations to perform */
+ unsigned u; /* Local index variable */
+
+ /* Un-buffer the stdout and stderr */
+ setbuf(stderr, NULL);
+ setbuf(stdout, NULL);
+
+ /* MPI initialization */
+ MPI_Init(&argc,&argv);
+ MPI_Comm_size(MPI_COMM_WORLD,&mpi_size);
+ MPI_Comm_rank(MPI_COMM_WORLD,&mpi_rank);
+ MPI_Get_processor_name(mpi_name,&mpi_namelen);
+
+ /* Set some defaults */
+ rank=DEFAULT_RANK;
+ dim_size=DEFAULT_DIM;
+ slice_dim=DEFAULT_SLICE;
+ vfl_type=DEFAULT_VFL_DRIVER;
+ par_mode=DEFAULT_PAR_MODE;
+ use_chunks=DEFAULT_CHUNK_STORAGE;
+ num_iter=DEFAULT_ITER;
+
+ /* Parse command line arguments */
+ if(argc>1) {
+ curr_arg=1;
+ while(curr_arg<argc) {
+ /* Trap any unknown command line parameters */
+ if(argv[curr_arg][0]!='-') {
+ printf("unknown command line parameter: %s\n",argv[curr_arg]);
+ goto done;
+ } /* end if */
+
+ /* Skip over command line flag */
+ curr_arg++;
+
+ switch(argv[curr_arg-1][1]) {
+ case 'c': /* Use chunked storage for dataset */
+ use_chunks=1;
+ break;
+
+ case 'd': /* Change number of dimensions */
+ /* Get new number of dimensions */
+ rank=atoi(argv[curr_arg]);
+ curr_arg++; /* Skip over number of dimensions */
+
+ /* Sanity check */
+ if(rank<=0) {
+ printf("rank=%d, invalid number of dimensions: %d\n",mpi_rank,rank);
+ goto done;
+ } /* end if */
+ break;
+
+ case 'f': /* Change test file name */
+ /* Get new file name */
+ file_name=strdup(argv[curr_arg]);
+ curr_arg++; /* Skip over file name from command line */
+ break;
+
+ case 'h': /* Print usage information */
+ usage();
+ goto done;
+ break;
+
+ case 'i': /* Change number of iterations */
+ /* Get new number of dimensions */
+ num_iter=atoi(argv[curr_arg]);
+ curr_arg++; /* Skip over number of iterations */
+
+ /* Sanity check */
+ if(num_iter<1) {
+ printf("rank=%d, invalid number of iterations: %u\n",mpi_rank,num_iter);
+ goto done;
+ } /* end if */
+ break;
+
+ case 'I': /* Use independent I/O for parallel I/O */
+ par_mode=H5FD_MPIO_INDEPENDENT;
+ break;
+
+ case 'p': /* Use MPI-posix VFL driver */
+ vfl_type=FACC_MPIPOSIX;
+ break;
+
+ case 's': /* Change dimension size */
+ /* Get new dimension size */
+ dim_size=atoi(argv[curr_arg]);
+ curr_arg++; /* Skip over dimension size from command line */
+
+ /* Sanity check */
+ if(dim_size<=0) {
+ printf("rank=%d, invalid dimension size: %ld\n",mpi_rank,(long)dim_size);
+ goto done;
+ } /* end if */
+ break;
+
+ case 'S': /* Change dimension to slice */
+ /* Get new dimension to slice */
+ slice_dim=atoi(argv[curr_arg]);
+ curr_arg++; /* Skip over slice dimension from command line */
+ break;
+
+ default:
+ printf("rank=%d, unknown command line parameter: %s\n",mpi_rank,argv[curr_arg-1]);
+ goto done;
+ } /* end switch */
+ } /* end while */
+ } /* end if */
+
+ /* Sanity check */
+ if(slice_dim>=rank) {
+ printf("rank=%d, error, slice dim larger than rank: slice_dim=%d, rank=%d\n",mpi_rank,slice_dim,rank);
+ goto done;
+ } /* end if */
+
+ /* Set rest of defaults */
+ if(file_name==NULL) {
+ char *login; /* Pointer to login name */
+
+ /* Get the login name for this user */
+ login=getlogin();
+ if(login==NULL)
+ login=DEFAULT_USERNAME;
+
+ /* Allocate enough room for the prefix, the login name, two '/'s, the filename and the string terminator */
+ file_name=malloc(strlen(DEFAULT_PREFIX)+1+strlen(login)+1+strlen(DEFAULT_FILENAME)+1);
+ strcpy(file_name,DEFAULT_PREFIX);
+ strcat(file_name,"/");
+ strcat(file_name,login);
+ strcat(file_name,"/");
+ strcat(file_name,DEFAULT_FILENAME);
+ } /* end if */
+
+ /* Allocate memory for this process's portion of dataset */
+ buf_size=sizeof(DEFAULT_C_TYPE);
+ for(i=0; i<rank; i++)
+ buf_size *= dim_size;
+ buf_size /= mpi_size;
+
+ /* Sanity check for overflow */
+ assert((hsize_t)((size_t)buf_size)==buf_size);
+
+ buf=malloc((size_t)buf_size);
+ assert(buf);
+
+ /* Initialize dataset portion to something unique for each process */
+ memset(buf,mpi_rank,(size_t)buf_size);
+
+ for(u=0; u<num_iter; u++) {
+ /* Create file creation property list */
+ fcpl=create_fcpl();
+ assert(fcpl>0);
+
+ /* Create file access property list */
+ fapl=create_fapl(MPI_COMM_WORLD,MPI_INFO_NULL,vfl_type);
+ assert(fapl>0);
+
+ /* Get file start time */
+ start_file_time = MPI_Wtime();
+
+ /* Create file */
+ fid=H5Fcreate(file_name,H5F_ACC_TRUNC,fcpl,fapl);
+ assert(fid>0);
+
+ /* Close file creation property list */
+ ret=H5Pclose(fcpl);
+ assert(ret>=0);
+
+ /* Close file access property list */
+ ret=H5Pclose(fapl);
+ assert(ret>=0);
+
+ /* Create dataspace for dataset on disk */
+ dims=malloc(sizeof(hsize_t)*rank);
+ assert(dims);
+ for(i=0; i<rank; i++)
+ dims[i]=dim_size;
+
+ file_sid=H5Screate_simple(rank,dims,NULL);
+ assert(file_sid>0);
+
+ /* Create dataspace for buffer in memory */
+ for(i=0; i<rank; i++)
+ dims[i]=dim_size;
+ dims[slice_dim] /= mpi_size;
+
+ mem_sid=H5Screate_simple(rank,dims,NULL);
+ assert(mem_sid>0);
+
+ /* Create dataset creation property list */
+ dcpl=create_dcpl(use_chunks,rank,dims);
+ assert(dcpl>0);
+
+ /* Create dataset */
+ dsid=H5Dcreate(fid,DEFAULT_DATASET_NAME,DEFAULT_HDF5_DATATYPE,file_sid,dcpl);
+ assert(dsid>0);
+
+ /* Close dataset creation property list */
+ ret=H5Pclose(dcpl);
+ assert(ret>=0);
+
+ /* Select hyperslab for file dataspace */
+ start=malloc(sizeof(hssize_t)*rank);
+ assert(start);
+ count=malloc(sizeof(hsize_t)*rank);
+ assert(count);
+ for(i=0; i<rank; i++) {
+ start[i]=0;
+ count[i]=dim_size;
+ } /* end for */
+ start[slice_dim]=mpi_rank*(dim_size/mpi_size);
+ count[slice_dim]=dim_size/mpi_size;
+
+ ret = H5Sselect_hyperslab(file_sid,H5S_SELECT_SET,start,NULL,count,NULL);
+ assert(ret>=0);
+
+ /* Create dataset transfer property list */
+ dxpl=create_dxpl(par_mode);
+ assert(dxpl>0);
+
+ /* Get raw data start time */
+ start_write_time = MPI_Wtime();
+
+ /* Write hyperslab to dataset */
+ ret = H5Dwrite(dsid, DEFAULT_HDF5_DATATYPE, mem_sid,
+ file_sid, dxpl, buf);
+ assert(ret>=0);
+
+ /* Get stop time for raw data timer */
+ end_write_time = MPI_Wtime();
+
+ /* Close dataset transfer property list */
+ ret=H5Pclose(dxpl);
+ assert(ret>=0);
+
+ /* Close memory dataspace */
+ ret=H5Sclose(mem_sid);
+ assert(ret>=0);
+
+ /* Close file dataspace */
+ ret=H5Sclose(file_sid);
+ assert(ret>=0);
+
+ /* Close dataset */
+ ret=H5Dclose(dsid);
+ assert(ret>=0);
+
+ /* Close file */
+ ret=H5Fclose(fid);
+ assert(ret>=0);
+
+ /* Get stop time for file timer */
+ end_file_time = MPI_Wtime();
+
+ /* Compute timing results */
+ elap_write_time=end_write_time-start_write_time;
+ elap_file_time=end_file_time-start_file_time;
+
+ /* Collect the minimum and maximum times by MPI reduces */
+ MPI_Allreduce(&elap_write_time, &tmp_max_write_time, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
+ MPI_Allreduce(&elap_file_time, &tmp_max_file_time, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
+
+ /* Track the fastest & slowest total runs */
+ if(tmp_max_write_time>max_write_time)
+ max_write_time=tmp_max_write_time;
+ if(tmp_max_write_time<min_write_time)
+ min_write_time=tmp_max_write_time;
+ if(tmp_max_file_time>max_file_time)
+ max_file_time=tmp_max_file_time;
+ if(tmp_max_file_time<min_file_time)
+ min_file_time=tmp_max_file_time;
+ } /* end for */
+
+ /* Only print information from one node */
+ if(mpi_rank==0) {
+ /* Print information about test */
+ printf("File driver used: %s\n",vfl_type==FACC_MPIO ? "MPI-I/O" : "MPI-posix");
+ printf("Type of parallel access: %s\n",par_mode==H5FD_MPIO_COLLECTIVE ? "Collective" : "Independent");
+ printf("Type of dataset storage: %s\n",use_chunks ? "Chunked" : "Contiguous");
+ printf("Number of processes: %d\n",mpi_size);
+ printf("Element size: %u\n",(unsigned)sizeof(DEFAULT_C_TYPE));
+ printf("# of dimensions: %d\n",rank);
+ printf("Dimension size: %ld\n",(long)dim_size);
+ printf("Dimension sliced: %u\n",slice_dim);
+ printf("Number of elements: %lu\n",(unsigned long)((buf_size/sizeof(DEFAULT_C_TYPE))*mpi_size));
+ printf("Total dataset size (bytes): %lu\n",(unsigned long)(buf_size*mpi_size));
+ printf("Dataset size per process (bytes): %lu\n",(unsigned long)buf_size);
+
+ /* Print timing results */
+ printf("# of iterations: %u\n",num_iter);
+ printf("Maximum raw data write throughput=%6.2f MB/s (%7.3f s)\n",MB_PER_SEC((buf_size*mpi_size),min_write_time),min_write_time);
+ printf("Minimum raw data write throughput=%6.2f MB/s (%7.3f s)\n",MB_PER_SEC((buf_size*mpi_size),max_write_time),max_write_time);
+ printf("Maximum file throughput=%6.2f MB/s (%7.3f s)\n",MB_PER_SEC((buf_size*mpi_size),min_file_time),min_file_time);
+ printf("Minimum file throughput=%6.2f MB/s (%7.3f s)\n",MB_PER_SEC((buf_size*mpi_size),max_file_time),max_file_time);
+ } /* end if */
+
+done:
+ /* Free buffers allocated */
+ if(file_name)
+ free(file_name);
+ if(buf)
+ free(buf);
+ if(dims)
+ free(dims);
+ if(start)
+ free(start);
+ if(count)
+ free(count);
+
+ /* MPI termination */
+ MPI_Finalize();
+ return(0);
+} /* end main() */