diff options
author | cvs2svn <no_author@cvs2svn> | 2002-01-23 21:30:34 (GMT) |
---|---|---|
committer | cvs2svn <no_author@cvs2svn> | 2002-01-23 21:30:34 (GMT) |
commit | 9627cb625db48ace93542ec136cfa85a28d1448e (patch) | |
tree | b9fb21dfc64689cab0c48291a109b308c0538b76 | |
parent | c2bca116ddeaed0ff5aa938378e4dc1b5f460eb1 (diff) | |
download | hdf5-9627cb625db48ace93542ec136cfa85a28d1448e.zip hdf5-9627cb625db48ace93542ec136cfa85a28d1448e.tar.gz hdf5-9627cb625db48ace93542ec136cfa85a28d1448e.tar.bz2 |
[svn-r4852] This commit was manufactured by cvs2svn to create branch 'hdf5_1_4'.
-rw-r--r-- | c++/config/irix6.x | 34 | ||||
-rw-r--r-- | perform/pio_engine.c | 1092 | ||||
-rw-r--r-- | perform/pio_timer.c | 143 | ||||
-rw-r--r-- | test/tmisc.c | 150 |
4 files changed, 1419 insertions, 0 deletions
diff --git a/c++/config/irix6.x b/c++/config/irix6.x new file mode 100644 index 0000000..dad44c5 --- /dev/null +++ b/c++/config/irix6.x @@ -0,0 +1,34 @@ +# -*- shell-script -*- +# +# This file is part of the HDF5 build script. It is processed shortly +# after configure starts and defines, among other things, flags for +# the various compile modes. +# +# See BlankForm in this directory for details + +# The default compiler is `MIPSpro CC' +if test -z "$CXX"; then + CXX=CC + CXX_BASENAME=CC +fi + +# Try native compiler flags +if test -z "$cxx_flags_set"; then +# -LANG:std required for std use; -ptused causes templates used to be +# instantiated + CPPFLAGS="-LANG:std -ptused" + +# libCio is a default library, since libtool before 1.5 doesn't fully +# support C++ yet, default libraries must be explicitly specified. +# A new macro is used for this temporary and specific task so it +# won't polute the existing configuration + DEFAULT_LIBS="-lCio" + + DEBUG_CXXFLAGS=-g + DEBUG_CPPFLAGS= + PROD_CXXFLAGS="-O -s" + PROD_CPPFLAGS= + PROFILE_CXXFLAGS=-xpg + PROFILE_CPPFLAGS= + cxx_flags_set=yes +fi diff --git a/perform/pio_engine.c b/perform/pio_engine.c new file mode 100644 index 0000000..d1ea6d3 --- /dev/null +++ b/perform/pio_engine.c @@ -0,0 +1,1092 @@ +/* + * Copyright (C) 2001, 2002 + * National Center for Supercomputing Applications + * All rights reserved. + * + * Author: Albert Cheng of NCSA, Oct 24, 2001. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> + +#include "hdf5.h" + +#ifdef H5_HAVE_PARALLEL + +#include <mpi.h> + +#ifndef MPI_FILE_NULL /*MPIO may be defined in mpi.h already */ +# include <mpio.h> +#endif /* !MPI_FILE_NULL */ + +#include "pio_perf.h" +#include "pio_timer.h" + +/* Macro definitions */ + +/* sizes of various items. these sizes won't change during program execution */ +#define ELMT_SIZE ((int)sizeof(int)) /* we're doing ints */ + +#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, "*** 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, "(%s) at line %4d in %s\n", \ + mesg, (int)__LINE__, __FILE__); \ +} + +/* verify: if val is false (0), print mesg. */ +#define VRFY(val, mesg) do { \ + if (!val) { \ + ERRMSG(mesg); \ + GOTOERROR(FAIL); \ + } \ +} while(0) + +#ifndef HDopen +# ifdef O_BINARY +# define HDopen(S,F,M) open(S,F|_O_BINARY,M) +# else /* O_BINARY */ +# define HDopen(S,F,M) open(S,F,M) +# endif /* !O_BINARY */ +#endif /* !HDopen */ + +#ifndef HDclose +# define HDclose(F) close(F) +#endif /* !HDclose */ + +#ifndef HDseek +# define HDseek(F,L,W) lseek(F,L,W) +#endif /* !HDseek */ + +#ifndef HDwrite +# define HDwrite(F,B,S) write(F,B,S) +#endif /* !HDwrite */ + +#ifndef HDread +# define HDread(F,B,S) read(F,B,S) +#endif /* !HDread */ + +/* Raw I/O macros */ +#define RAWCREATE(fn) HDopen(fn, O_CREAT|O_TRUNC|O_RDWR, 0600) +#define RAWOPEN(fn, F) HDopen(fn, F, 0600) +#define RAWCLOSE(F) HDclose(F) +#define RAWSEEK(F,L) HDseek(F,(off_t) L,SEEK_SET) +#define RAWWRITE(F,B,S) HDwrite(F,B,S) +#define RAWREAD(F,B,S) HDread(F,B,S) + +enum { + PIO_CREATE = 1, + PIO_WRITE = 2, + PIO_READ = 4 +}; + +/* Global variables */ +static int clean_file_g = -1; /*whether to cleanup temporary test */ + /*files. -1 is not defined; */ + /*0 is no cleanup; 1 is do cleanup */ + + + +/* + * In a parallel machine, the filesystem suitable for compiling is + * unlikely a parallel file system that is suitable for parallel I/O. + * There is no standard pathname for the parallel file system. /tmp + * is about the best guess. + */ +#ifndef HDF5_PARAPREFIX +# ifdef __PUMAGON__ + /* For the PFS of TFLOPS */ +# define HDF5_PARAPREFIX "pfs:/pfs_grande/multi/tmp_1" +# else +# define HDF5_PARAPREFIX "/tmp" +# endif /* __PUMAGON__ */ +#endif /* !HDF5_PARAPREFIX */ + +#ifndef MIN +#define MIN(a,b) (a < b ? a : b) +#endif /* !MIN */ + +/* the different types of file descriptors we can expect */ +typedef union _file_descr { + int rawfd; /* raw/Unix file */ + MPI_File mpifd; /* MPI file */ + hid_t h5fd; /* HDF5 file */ +} file_descr; + +/* local functions */ +static char *pio_create_filename(iotype iot, const char *base_name, + char *fullname, size_t size); +static herr_t do_write(file_descr *fd, iotype iot, long ndsets, + long nelmts, long buf_size, void *buffer); +static herr_t do_read(file_descr *fd, iotype iot, long ndsets, + long nelmts, long buf_size, void *buffer /*out*/); +static herr_t do_fopen(iotype iot, char *fname, file_descr *fd /*out*/, + int flags); +static herr_t do_fclose(iotype iot, file_descr *fd); +static void do_cleanupfile(iotype iot, char *fname); + +/* + * Function: do_pio + * Purpose: PIO Engine where Parallel IO are executed. + * Return: results + * Programmer: Albert Cheng, Bill Wendling 2001/12/12 + * Modifications: + */ +results +do_pio(parameters param) +{ + /* return codes */ + herr_t ret_code = 0; /*return code */ + results res; + + file_descr fd; + iotype iot; + + char fname[FILENAME_MAX]; + int maxprocs; + int nfiles, nf; + long ndsets, nelmts; + char *buffer = NULL; /*data buffer pointer */ + long buf_size; /*data buffer size in bytes */ + + /* HDF5 variables */ + herr_t hrc; /*HDF5 return code */ + + /* Sanity check parameters */ + + /* IO type */ + iot = param.io_type; + + switch (iot) { + case MPIO: + fd.mpifd = MPI_FILE_NULL; + res.timers = pio_time_new(MPI_TIMER); + break; + case RAW: + fd.rawfd = -1; + res.timers = pio_time_new(SYS_TIMER); + break; + case PHDF5: + fd.h5fd = -1; + res.timers = pio_time_new(SYS_TIMER); + break; + default: + /* unknown request */ + fprintf(stderr, "Unknown IO type request (%d)\n", iot); + GOTOERROR(FAIL); + } + + 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.num_procs; /* max number of mpi-processes to use */ + buf_size = param.buf_size; + + if (nfiles < 0 ) { + fprintf(stderr, + "number of files must be >= 0 (%d)\n", + nfiles); + GOTOERROR(FAIL); + } + + if (ndsets < 0 ) { + fprintf(stderr, + "number of datasets per file must be >= 0 (%ld)\n", + ndsets); + GOTOERROR(FAIL); + } + + if (nelmts <= 0 ) { + fprintf(stderr, + "number of elements per dataset must be > 0 (%ld)\n", + nelmts); + GOTOERROR(FAIL); + } + + if (maxprocs <= 0 ) { + fprintf(stderr, + "maximum number of process to use must be > 0 (%d)\n", + maxprocs); + GOTOERROR(FAIL); + } + + if (buf_size <= 0 ){ + fprintf(stderr, + "buffer size must be > 0 (%ld)\n", buf_size); + GOTOERROR(FAIL); + } + +#if AKCDEBUG +/* DEBUG*/ +fprintf(stderr, "nfiles=%d\n", nfiles); +fprintf(stderr, "ndsets=%ld\n", ndsets); +fprintf(stderr, "nelmts=%ld\n", nelmts); +fprintf(stderr, "maxprocs=%d\n", maxprocs); +fprintf(stderr, "buffer size=%ld\n", buf_size); +fprintf(stderr, "total data size=%ld\n", ndsets*nelmts*sizeof(int)); +nfiles=MIN(3, nfiles); +/*ndsets=MIN(5, ndsets);*/ +/*nelmts=MIN(1000, nelmts);*/ +buf_size=MIN(1024*1024, buf_size); +/* DEBUG END */ +#endif + + /* allocate data buffer */ + buffer = malloc((size_t)buf_size); + + if (buffer == NULL){ + fprintf(stderr, "malloc for data buffer size (%ld) failed\n", + buf_size); + GOTOERROR(FAIL); + } + + for (nf = 1; nf <= nfiles; nf++) { + /* + * Write performance measurement + */ + /* Open file for write */ + char base_name[256]; + + MPI_Barrier(pio_comm_g); + + sprintf(base_name, "#pio_tmp_%u", nf); + pio_create_filename(iot, base_name, fname, sizeof(fname)); +#if AKCDEBUG +fprintf(stderr, "filename=%s\n", fname); +#endif + + set_time(res.timers, HDF5_GROSS_WRITE_FIXED_DIMS, START); + + hrc = do_fopen(iot, fname, &fd, PIO_CREATE | PIO_WRITE); + + VRFY((hrc == SUCCESS), "do_fopen failed"); + + set_time(res.timers, HDF5_FINE_WRITE_FIXED_DIMS, START); + hrc = do_write(&fd, iot, ndsets, nelmts, buf_size, buffer); + set_time(res.timers, HDF5_FINE_WRITE_FIXED_DIMS, STOP); + + VRFY((hrc == SUCCESS), "do_write failed"); + + /* Close file for write */ + hrc = do_fclose(iot, &fd); + + set_time(res.timers, HDF5_GROSS_WRITE_FIXED_DIMS, STOP); + + VRFY((hrc == SUCCESS), "do_fclose failed"); + + MPI_Barrier(pio_comm_g); + + /* + * Read performance measurement + */ + /* Open file for read */ + set_time(res.timers, HDF5_GROSS_READ_FIXED_DIMS, START); + + hrc = do_fopen(iot, fname, &fd, PIO_READ); + + VRFY((hrc == SUCCESS), "do_fopen failed"); + + set_time(res.timers, HDF5_FINE_READ_FIXED_DIMS, START); + hrc = do_read(&fd, iot, ndsets, nelmts, buf_size, buffer); + set_time(res.timers, HDF5_FINE_READ_FIXED_DIMS, STOP); + + VRFY((hrc == SUCCESS), "do_read failed"); + + /* Close file for read */ + hrc = do_fclose(iot, &fd); + + set_time(res.timers, HDF5_GROSS_READ_FIXED_DIMS, STOP); + + VRFY((hrc == SUCCESS), "do_fclose failed"); + + MPI_Barrier(pio_comm_g); + + do_cleanupfile(iot, fname); + } + +done: + /* clean up */ + /* release HDF5 objects */ + + /* close any opened files */ + /* no remove(fname) because that should have happened normally. */ + switch (iot) { + case RAW: + if (fd.rawfd != -1) + hrc = do_fclose(iot, &fd); + break; + case MPIO: + if (fd.mpifd != MPI_FILE_NULL) + hrc = do_fclose(iot, &fd); + break; + case PHDF5: + if (fd.h5fd != -1) + hrc = do_fclose(iot, &fd); + break; + } + + /* release generic resources */ + free(buffer); + res.ret_code = ret_code; + return res; +} + +/* + * Function: pio_create_filename + * Purpose: Create a new filename to write to. Determine the correct + * suffix to append to the filename by the type of I/O we're + * doing. Also, place in the /tmp/{$USER,$LOGIN} directory if + * USER or LOGIN are specified in the environment. + * Return: Pointer to filename or NULL + * Programmer: Bill Wendling, 21. November 2001 + * Modifications: + */ +static char * +pio_create_filename(iotype iot, const char *base_name, char *fullname, size_t size) +{ + const char *prefix, *suffix; + char *ptr, last = '\0'; + size_t i, j; + + if (!base_name || !fullname || size < 1) + return NULL; + + memset(fullname, 0, size); + + switch (iot) { + case RAW: + suffix = ".raw"; + break; + case MPIO: + suffix = ".mpio"; + break; + case PHDF5: + suffix = ".h5"; + break; + } + + /* First use the environment variable and then try the constant */ + prefix = getenv("HDF5_PARAPREFIX"); + +#ifdef HDF5_PARAPREFIX + if (!prefix) + prefix = HDF5_PARAPREFIX; +#endif /* HDF5_PARAPREFIX */ + + /* Prepend the prefix value to the base name */ + if (prefix && *prefix) { + /* If the prefix specifies the HDF5_PARAPREFIX directory, then + * default to using the "/tmp/$USER" or "/tmp/$LOGIN" + * directory instead. */ + register char *user, *login, *subdir; + + user = getenv("USER"); + login = getenv("LOGIN"); + subdir = (user ? user : login); + + if (subdir) { + for (i = 0; i < size && prefix[i]; i++) + fullname[i] = prefix[i]; + + fullname[i++] = '/'; + + for (j = 0; i < size && subdir[j]; i++, j++) + fullname[i] = subdir[j]; + } else { + /* We didn't append the prefix yet */ + strncpy(fullname, prefix, MIN(strlen(prefix), size)); + } + + if ((strlen(fullname) + strlen(base_name) + 1) < size) { + /* Append the base_name with a slash first. Multiple slashes are + * handled below. */ + struct stat buf; + + if (stat(fullname, &buf) < 0) + /* The directory doesn't exist just yet */ + if (mkdir(fullname, (mode_t)0755) < 0 && errno != EEXIST) { + /* We couldn't make the "/tmp/${USER,LOGIN}" subdirectory. + * Default to PREFIX's original prefix value. */ + strcpy(fullname, prefix); + } + + strcat(fullname, "/"); + strcat(fullname, base_name); + } else { + /* Buffer is too small */ + return NULL; + } + } else if (strlen(base_name) >= size) { + /* Buffer is too small */ + return NULL; + } else { + strcpy(fullname, base_name); + } + + /* Append a suffix */ + if (suffix) { + if (strlen(fullname) + strlen(suffix) >= size) + return NULL; + + strcat(fullname, suffix); + } + + /* Remove any double slashes in the filename */ + for (ptr = fullname, i = j = 0; ptr && i < size; i++, ptr++) { + if (*ptr != '/' || last != '/') + fullname[j++] = *ptr; + + last = *ptr; + } + + return fullname; +} + +/* + * Function: do_write + * Purpose: Write the required amount of data to the file. + * Return: SUCCESS or FAIL + * Programmer: Albert Cheng, Bill Wendling, 2001/12/13 + * Modifications: + */ +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 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 */ + + /* 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 */ + +#if AKCDEBUG +fprintf(stderr, "In do_write\n"); +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; + + /* hdf5 data space setup */ + if (iot == PHDF5){ + /* define a contiquous dataset of nelmts native ints */ + h5dims[0] = nelmts; + h5dset_space_id = H5Screate_simple(1, h5dims, NULL); + VRFY((h5dset_space_id >= 0), "H5Screate_simple"); + + /* create the memory dataspace that corresponds to the xfer buffer */ + h5dims[0] = nelmts_in_buf; + h5mem_space_id = H5Screate_simple(1, h5dims, NULL); + VRFY((h5mem_space_id >= 0), "H5Screate_simple"); + } + + for (ndset = 1; ndset <= ndsets; ++ndset) { + + /* Calculate dataset offset within a file */ + + /* create dataset */ + switch (iot) { + case RAW: + case MPIO: + /* both raw and mpi io just need dataset offset in file*/ + dset_offset = (ndset - 1) * dset_size; + break; + + case PHDF5: + sprintf(dname, "Dataset_%ld", ndset); + h5ds_id = H5Dcreate(fd->h5fd, dname, H5T_NATIVE_INT, + h5dset_space_id, H5P_DEFAULT); + + if (h5ds_id < 0) { + fprintf(stderr, "HDF5 Dataset Create failed\n"); + GOTOERROR(FAIL); + } + + 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; + +#if AKCDEBUG +fprintf(stderr, "proc %d: elmts_begin=%ld, elmts_count=%ld\n", + pio_mpi_rank_g, elmts_begin, elmts_count); +#endif + + nelmts_written = 0 ; + + while (nelmts_written < elmts_count){ + nelmts_towrite = elmts_count - nelmts_written; + + if (elmts_count - nelmts_written >= nelmts_in_buf) { + nelmts_towrite = nelmts_in_buf; + } else { + /* last write of a partial buffer */ + nelmts_towrite = elmts_count - nelmts_written; + } + +#if AKCDEBUG + /*Prepare write data*/ + { + int *intptr = (int *)buffer; + register int i; + + for (i = 0; i < nelmts_towrite; ++i) + *intptr++ = nelmts_towrite + i; + } +#endif + + /* Write */ + /* Calculate offset of write within a dataset/file */ + switch (iot) { + case RAW: + 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); +#endif + + rc = RAWSEEK(fd->rawfd, file_offset); + VRFY((rc>=0), "RAWSEEK"); + rc = RAWWRITE(fd->rawfd, buffer, (size_t)(nelmts_towrite * ELMT_SIZE)); + VRFY((rc == (nelmts_towrite*ELMT_SIZE)), "RAWWRITE"); + break; + + case MPIO: + 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); +#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; + 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"); + break; + } + + nelmts_written += nelmts_towrite; + } + + /* Calculate write time */ + + /* Close dataset. Only HDF5 needs to do an explicit close. */ + if (iot == PHDF5){ + hrc = H5Dclose(h5ds_id); + + if (hrc < 0) { + fprintf(stderr, "HDF5 Dataset Close failed\n"); + GOTOERROR(FAIL); + } + + h5ds_id = -1; + } + } + +done: + /* release HDF5 objects */ + if (h5dset_space_id != -1) { + hrc = H5Sclose(h5dset_space_id); + if (hrc < 0){ + fprintf(stderr, "HDF5 Dataset Space Close failed\n"); + ret_code = FAIL; + } else { + h5dset_space_id = -1; + } + } + + if (h5mem_space_id != -1) { + hrc = H5Sclose(h5mem_space_id); + if (hrc < 0) { + fprintf(stderr, "HDF5 Memory Space Close failed\n"); + ret_code = FAIL; + } else { + h5mem_space_id = -1; + } + } + + return ret_code; +} + +/* + * Function: do_read + * Purpose: read the required amount of data from the file. + * Return: SUCCESS or FAIL + * Programmer: Albert Cheng 2001/12/13 + * Modifications: + */ +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 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 */ + + /* 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 */ + +#if AKCDEBUG +fprintf(stderr, "In do_read\n"); +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; + + /* hdf5 data space setup */ + if (iot == PHDF5){ + /* define a contiquous dataset of nelmts native ints */ + h5dims[0] = nelmts; + h5dset_space_id = H5Screate_simple(1, h5dims, NULL); + VRFY((h5dset_space_id >= 0), "H5Screate_simple"); + + /* create the memory dataspace that corresponds to the xfer buffer */ + h5dims[0] = nelmts_in_buf; + h5mem_space_id = H5Screate_simple(1, h5dims, NULL); + VRFY((h5mem_space_id >= 0), "H5Screate_simple"); + } + + for (ndset = 1; ndset <= ndsets; ++ndset) { + /* Calculate dataset offset within a file */ + + /* create dataset */ + switch (iot) { + case RAW: + case MPIO: + /* both raw and mpi io just need dataset offset in file*/ + dset_offset = (ndset - 1) * dset_size; + break; + + case PHDF5: + sprintf(dname, "Dataset_%ld", ndset); + h5ds_id = H5Dopen(fd->h5fd, dname); + if (h5ds_id < 0) { + fprintf(stderr, "HDF5 Dataset open failed\n"); + GOTOERROR(FAIL); + } + + 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; + +#if AKCDEBUG +fprintf(stderr, "proc %d: elmts_begin=%ld, elmts_count=%ld\n", + 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) + nelmts_toread = nelmts_in_buf; + 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; + +#if AKCDEBUG +fprintf(stderr, "proc %d: read %ld bytes at file-offset %ld\n", + pio_mpi_rank_g, nelmts_toread*ELMT_SIZE, file_offset); +#endif + + rc = RAWSEEK(fd->rawfd, file_offset); + VRFY((rc>=0), "RAWSEEK"); + rc = RAWREAD(fd->rawfd, buffer, (size_t)(nelmts_toread*ELMT_SIZE)); + VRFY((rc==(nelmts_toread*ELMT_SIZE)), "RAWREAD"); + break; + + case MPIO: + 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; + + 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"); + break; + } + +#if AKCDEBUG & 0 + /*verify read data*/ + { + int *intptr = (int *)buffer; + register int i; + + for (i = 0; i < nelmts_towrite; ++i) + /* TO BE IMPLEMENTED */ + ; + } +#endif + + nelmts_read += nelmts_toread; + } + + /* Calculate read time */ + + /* Close dataset. Only HDF5 needs to do an explicit close. */ + if (iot == PHDF5){ + hrc = H5Dclose(h5ds_id); + + if (hrc < 0) { + fprintf(stderr, "HDF5 Dataset Close failed\n"); + GOTOERROR(FAIL); + } + + h5ds_id = -1; + } + } + +done: + /* release HDF5 objects */ + if (h5dset_space_id != -1) { + hrc = H5Sclose(h5dset_space_id); + if (hrc < 0){ + fprintf(stderr, "HDF5 Dataset Space Close failed\n"); + ret_code = FAIL; + } else { + h5dset_space_id = -1; + } + } + + if (h5mem_space_id != -1) { + hrc = H5Sclose(h5mem_space_id); + if (hrc < 0) { + fprintf(stderr, "HDF5 Memory Space Close failed\n"); + ret_code = FAIL; + } else { + h5mem_space_id = -1; + } + } + + return ret_code; +} + +/* + * Function: do_fopen + * Purpose: Open the specified file. + * Return: SUCCESS or FAIL + * Programmer: Albert Cheng, Bill Wendling, 2001/12/13 + * Modifications: + */ +static herr_t +do_fopen(iotype iot, char *fname, file_descr *fd /*out*/, int flags) +{ + int ret_code = SUCCESS, mrc; + herr_t hrc; + hid_t acc_tpl = -1; /* file access templates */ + + switch (iot) { + case RAW: + if (flags & (PIO_CREATE | PIO_WRITE)) + fd->rawfd = RAWCREATE(fname); + else + fd->rawfd = RAWOPEN(fname, O_RDONLY); + + if (fd->rawfd < 0 ) { + fprintf(stderr, "Raw File Open failed(%s)\n", fname); + GOTOERROR(FAIL); + } + + break; + + case MPIO: + if (flags & (PIO_CREATE | PIO_WRITE)) { + 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, (MPI_Offset)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); + } + } + + break; + + case PHDF5: + acc_tpl = H5Pcreate(H5P_FILE_ACCESS); + + if (acc_tpl < 0) { + fprintf(stderr, "HDF5 Property List Create failed\n"); + GOTOERROR(FAIL); + } + + hrc = H5Pset_fapl_mpio(acc_tpl, pio_comm_g, MPI_INFO_NULL); + + if (hrc < 0) { + fprintf(stderr, "HDF5 Property List Set failed\n"); + GOTOERROR(FAIL); + } + + /* create the parallel file */ + if (flags & (PIO_CREATE | PIO_WRITE)) { + fd->h5fd = H5Fcreate(fname, H5F_ACC_TRUNC, H5P_DEFAULT, acc_tpl); + } else { + fd->h5fd = H5Fopen(fname, H5P_DEFAULT, acc_tpl); + } + + hrc = H5Pclose(acc_tpl); + + if (fd->h5fd < 0) { + fprintf(stderr, "HDF5 File Create failed(%s)\n", fname); + GOTOERROR(FAIL); + } + + /* verifying the close of the acc_tpl */ + if (hrc < 0) { + fprintf(stderr, "HDF5 Property List Close failed\n"); + GOTOERROR(FAIL); + } + + break; + } + +done: + return ret_code; +} + +/* + * Function: do_fclose + * Purpose: Close the specified file descriptor. + * Return: SUCCESS or FAIL + * Programmer: Albert Cheng, Bill Wendling, 2001/12/13 + * Modifications: + */ +static herr_t +do_fclose(iotype iot, file_descr *fd /*out*/) +{ + herr_t ret_code = SUCCESS, hrc; + int mrc = 0, rc = 0; + + switch (iot) { + case RAW: + rc = RAWCLOSE(fd->rawfd); + + if (rc != 0){ + fprintf(stderr, "Raw File Close failed\n"); + GOTOERROR(FAIL); + } + + fd->rawfd = -1; + break; + + case MPIO: + mrc = MPI_File_close(&fd->mpifd); + + if (mrc != MPI_SUCCESS){ + fprintf(stderr, "MPI File close failed\n"); + GOTOERROR(FAIL); + } + + fd->mpifd = MPI_FILE_NULL; + break; + + case PHDF5: + hrc = H5Fclose(fd->h5fd); + + if (hrc < 0) { + fprintf(stderr, "HDF5 File Close failed\n"); + GOTOERROR(FAIL); + } + + fd->h5fd = -1; + break; + } + +done: + return ret_code; +} + + +/* + * Function: do_fclose + * Purpose: Cleanup temporary file unless HDF5_NOCLEANUP is set. + * Only Proc 0 of the PIO communicator will do the cleanup. + * Other processes just return. + * Return: void + * Programmer: Albert Cheng 2001/12/12 + * Modifications: + */ +static void +do_cleanupfile(iotype iot, char *fname) +{ + if (pio_mpi_rank_g != 0) + return; + + if (clean_file_g == -1) + 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; + } + } +} +#endif /* H5_HAVE_PARALLEL */ diff --git a/perform/pio_timer.c b/perform/pio_timer.c new file mode 100644 index 0000000..2ebdbce --- /dev/null +++ b/perform/pio_timer.c @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2001 + * National Center for Supercomputing Applications + * All rights reserved. + */ + +/* + * Purpose: + * + * This is a module of useful timing functions for performance testing. + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "pio_timer.h" + +#ifdef H5_HAVE_PARALLEL + +#include <mpi.h> + +/* + * The number to divide the tv_usec field with to get a nice decimal to add to + * the number of seconds. + */ +#define MILLISECOND 1000000.0 + +/* + * Function: pio_time_new + * Purpose: Build us a brand, spankin', new performance time object. + * The object is a black box to the user. They just tell us + * what type of timer they want (MPI_TIMER for MPI_Wtime or + * SYS_TIMER for system time). + * Return: Pointer to pio_time object + * Programmer: Bill Wendling, 01. October 2001 + * Modifications: + */ +pio_time * +pio_time_new(unsigned int type) +{ + pio_time *pt = (pio_time *)calloc(1, sizeof(struct pio_time_)); + register int i; + + for (i = 0; i < NUM_TIMERS; ++i) + pt->total_time[i] = 0.0; + + pt->type = type; + return pt; +} + +/* + * Function: pio_time_destroy + * Purpose: Remove the memory allocated for the pio_time object. Only + * need to call on a pointer allocated with the ``pio_time_new'' + * function. + * Return: Nothing + * Programmer: Bill Wendling, 01. October 2001 + * Modifications: + */ +void +pio_time_destroy(pio_time *pt) +{ + free(pt); +} + +/* + * Function: set_timer_type + * Purpose: Set the type of the timer to either MPI_TIMER or SYS_TIMER. + * This really only needs to be called if you didn't construct a + * timer with the pio_timer_new function (shame!). + * Return: Nothing + * Programmer: Bill Wendling, 04. October 2001 + * Modifications: + */ +void +set_timer_type(pio_time *pt, timer_type type) +{ + pt->type = type; +} + +/* + * Function: get_timer_type + * Purpose: Get the type of the timer. + * Return: MPI_TIMER or SYS_TIMER. + * Programmer: Bill Wendling, 04. October 2001 + * Modifications: + */ +timer_type +get_timer_type(pio_time *pt) +{ + return pt->type; +} + +/* + * Function: set_time + * Purpose: Set the time in a ``pio_time'' object. + * Return: Pointer to the passed in ``pio_time'' object. + * Programmer: Bill Wendling, 01. October 2001 + * Modifications: + */ +pio_time * +set_time(pio_time *pt, timer_type t, int start_stop) +{ + if (pt) { + if (pt->type == MPI_TIMER) { + if (start_stop == START) { + pt->mpi_timer[t] = MPI_Wtime(); + } else { + pt->total_time[t] += MPI_Wtime() - pt->mpi_timer[t]; + } + } else { + if (start_stop == START) { + gettimeofday(&pt->sys_timer[t], NULL); + } else { + struct timeval sys_t; + + gettimeofday(&sys_t, NULL); + pt->total_time[t] = + ((double)sys_t.tv_sec + + ((double)sys_t.tv_usec) / MILLISECOND) - + ((double)pt->sys_timer[t].tv_sec + + ((double)pt->sys_timer[t].tv_usec) / MILLISECOND); + } + } + } + + return pt; +} + +/* + * Function: get_time + * Purpose: Get the time from a ``pio_time'' object. + * Return: The number of seconds as a DOUBLE. + * Programmer: Bill Wendling, 01. October 2001 + * Modifications: + */ +double +get_time(pio_time *pt, timer_type t) +{ + return pt->total_time[t]; +} + +#endif /* H5_HAVE_PARALLEL */ diff --git a/test/tmisc.c b/test/tmisc.c new file mode 100644 index 0000000..6476c32 --- /dev/null +++ b/test/tmisc.c @@ -0,0 +1,150 @@ +/**************************************************************************** + * NCSA HDF * + * Software Development Group * + * National Center for Supercomputing Applications * + * University of Illinois at Urbana-Champaign * + * 605 E. Springfield, Champaign IL 61820 * + * * + * For conditions of distribution and use, see the accompanying * + * hdf/COPYING file. * + * * + ****************************************************************************/ + +/* $Id$ */ + +/*********************************************************** +* +* Test program: tmisc +* +* Test miscellaneous features not tested elsewhere. Generally +* regression tests for bugs that are reported and don't +* have an existing test to add them to. +* +*************************************************************/ + +#include "hdf5.h" +#include "testhdf5.h" + +#define FILE "tmisc.h5" + +/* Definitions for misc. test #1 */ +#define MISC1_VAL (13417386) /* 0xccbbaa */ +#define MISC1_VAL2 (15654348) /* 0xeeddcc */ +#define MISC1_DSET_NAME "/scalar_set" + +/**************************************************************** +** +** test_misc1(): test unlinking a dataset from a group and immediately +** re-using the dataset name +** +****************************************************************/ +static void +test_misc1(void) +{ + int i; + int i_check; + hid_t file, dataspace, dataset; + herr_t ret; + + /* Output message about test being performed */ + MESSAGE(5, ("Testing Unlinking Dataset and Re-creating It\n")); + + file = H5Fcreate(FILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fcreate"); + + dataspace = H5Screate(H5S_SCALAR); + CHECK(dataspace, FAIL, "H5Screate"); + + /* Write the dataset the first time. */ + dataset = H5Dcreate(file, MISC1_DSET_NAME, H5T_NATIVE_INT, dataspace, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate"); + + i = MISC1_VAL; + ret = H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &i); + CHECK(ret, FAIL, "H5Dwrite"); + + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + /* Remove the dataset. */ + ret = H5Gunlink(file, MISC1_DSET_NAME); + CHECK(ret, FAIL, "H5Gunlink"); + + /* Write the dataset for the second time with a different value. */ + dataset = H5Dcreate(file, MISC1_DSET_NAME, H5T_NATIVE_INT, dataspace, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate"); + + i = MISC1_VAL2; + ret = H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &i); + CHECK(ret, FAIL, "H5Dwrite"); + + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Sclose(dataspace); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + + /* Now, check the value written to the dataset, after it was re-created */ + file = H5Fopen(FILE, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fopen"); + + dataspace = H5Screate(H5S_SCALAR); + CHECK(dataspace, FAIL, "H5Screate"); + + dataset = H5Dopen(file, MISC1_DSET_NAME); + CHECK(dataset, FAIL, "H5Dopen"); + + ret = H5Dread(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &i_check); + CHECK(ret, FAIL, "H5Dread"); + VERIFY(i_check,MISC1_VAL2,"H5Dread"); + + ret = H5Sclose(dataspace); + CHECK(ret, FAIL, "H5Sclose"); + + ret = H5Dclose(dataset); + CHECK(ret, FAIL, "H5Dclose"); + + ret = H5Fclose(file); + CHECK(ret, FAIL, "H5Fclose"); + +} /* end test_misc1() */ + +/**************************************************************** +** +** test_misc(): Main misc. test routine. +** +****************************************************************/ +void +test_misc(void) +{ + /* Output message about test being performed */ + MESSAGE(5, ("Testing Miscellaneous Routines\n")); + + /* Various tests, using the same test file */ + test_misc1(); /* Test unlinking a dataset & immediately re-using name */ + +} /* test_misc() */ + + +/*------------------------------------------------------------------------- + * Function: cleanup_misc + * + * Purpose: Cleanup temporary test files + * + * Return: none + * + * Programmer: Albert Cheng + * July 2, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void +cleanup_misc(void) +{ + remove(FILE); +} |