From fdf38bb5f4763ad9a9a0cd7ac7502d298b437a94 Mon Sep 17 00:00:00 2001 From: "M. Scot Breitenfeld" Date: Wed, 12 Dec 2018 15:39:18 -0600 Subject: HDFFV-10652 Implemented a process-0 read and then broadcast for collective read of full datasets (H5S_ALL) by all the processes in the file communicator. --- src/H5Dmpio.c | 69 +++++++++++----- src/H5FDmpio.c | 77 +++++++++++------- src/H5Ppublic.h | 6 ++ src/H5private.h | 4 + testpar/t_dset.c | 2 +- testpar/t_mdset.c | 118 ++++++++++++++++------------ testpar/t_pread.c | 230 +++++++++++++++++++++++++++++++++++++++++++++++++----- 7 files changed, 388 insertions(+), 118 deletions(-) diff --git a/src/H5Dmpio.c b/src/H5Dmpio.c index 2c06800..3c4eab2 100644 --- a/src/H5Dmpio.c +++ b/src/H5Dmpio.c @@ -37,7 +37,7 @@ #include "H5Eprivate.h" /* Error handling */ #include "H5Fprivate.h" /* File access */ #include "H5FDprivate.h" /* File drivers */ -#include "H5FDmpi.h" /* MPI-based file drivers */ +#include "H5FDmpi.h" /* MPI-based file drivers */ #include "H5Iprivate.h" /* IDs */ #include "H5MMprivate.h" /* Memory management */ #include "H5Oprivate.h" /* Object headers */ @@ -47,6 +47,8 @@ #ifdef H5_HAVE_PARALLEL +hbool_t H5FD_MPIO_Proc0_BCast_g; /* Flag if dataset is both: H5S_ALL and < 2GB */ + /****************/ /* Local Macros */ /****************/ @@ -281,8 +283,9 @@ H5D__mpio_opt_possible(const H5D_io_info_t *io_info, const H5S_t *file_space, const H5S_t *mem_space, const H5D_type_info_t *type_info) { H5FD_mpio_xfer_t io_xfer_mode; /* MPI I/O transfer mode */ - unsigned local_cause = 0; /* Local reason(s) for breaking collective mode */ - unsigned global_cause = 0; /* Global reason(s) for breaking collective mode */ + unsigned local_cause[2] = {0,0}; /* [0] Local reason(s) for breaking collective mode */ + /* [1] Flag if dataset is both: H5S_ALL and small */ + unsigned global_cause[2] = {0,0}; /* Global reason(s) for breaking collective mode */ htri_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE @@ -298,34 +301,34 @@ H5D__mpio_opt_possible(const H5D_io_info_t *io_info, const H5S_t *file_space, if(H5CX_get_io_xfer_mode(&io_xfer_mode) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get MPI-I/O transfer mode") if(io_xfer_mode == H5FD_MPIO_INDEPENDENT) - local_cause |= H5D_MPIO_SET_INDEPENDENT; + local_cause[0] |= H5D_MPIO_SET_INDEPENDENT; /* Optimized MPI types flag must be set */ /* (based on 'HDF5_MPI_OPT_TYPES' environment variable) */ if(!H5FD_mpi_opt_types_g) - local_cause |= H5D_MPIO_MPI_OPT_TYPES_ENV_VAR_DISABLED; + local_cause[0] |= H5D_MPIO_MPI_OPT_TYPES_ENV_VAR_DISABLED; /* Don't allow collective operations if datatype conversions need to happen */ if(!type_info->is_conv_noop) - local_cause |= H5D_MPIO_DATATYPE_CONVERSION; + local_cause[0] |= H5D_MPIO_DATATYPE_CONVERSION; /* Don't allow collective operations if data transform operations should occur */ if(!type_info->is_xform_noop) - local_cause |= H5D_MPIO_DATA_TRANSFORMS; + local_cause[0] |= H5D_MPIO_DATA_TRANSFORMS; /* Check whether these are both simple or scalar dataspaces */ if(!((H5S_SIMPLE == H5S_GET_EXTENT_TYPE(mem_space) || H5S_SCALAR == H5S_GET_EXTENT_TYPE(mem_space)) && (H5S_SIMPLE == H5S_GET_EXTENT_TYPE(file_space) || H5S_SCALAR == H5S_GET_EXTENT_TYPE(file_space)))) - local_cause |= H5D_MPIO_NOT_SIMPLE_OR_SCALAR_DATASPACES; + local_cause[0] |= H5D_MPIO_NOT_SIMPLE_OR_SCALAR_DATASPACES; /* Dataset storage must be contiguous or chunked */ if(!(io_info->dset->shared->layout.type == H5D_CONTIGUOUS || io_info->dset->shared->layout.type == H5D_CHUNKED)) - local_cause |= H5D_MPIO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET; + local_cause[0] |= H5D_MPIO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET; /* check if external-file storage is used */ if(io_info->dset->shared->dcpl_cache.efl.nused > 0) - local_cause |= H5D_MPIO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET; + local_cause[0] |= H5D_MPIO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET; /* The handling of memory space is different for chunking and contiguous * storage. For contiguous storage, mem_space and file_space won't change @@ -343,28 +346,56 @@ H5D__mpio_opt_possible(const H5D_io_info_t *io_info, const H5S_t *file_space, if (io_info->op_type == H5D_IO_OP_WRITE && io_info->dset->shared->layout.type == H5D_CHUNKED && io_info->dset->shared->dcpl_cache.pline.nused > 0) - local_cause |= H5D_MPIO_PARALLEL_FILTERED_WRITES_DISABLED; + local_cause[0] |= H5D_MPIO_PARALLEL_FILTERED_WRITES_DISABLED; #endif + H5FD_MPIO_Proc0_BCast_g = FALSE; + /* Check to see if all the processes are reading the same data */ + if((H5S_GET_SELECT_TYPE(file_space) != H5S_SEL_ALL)) { + /* Flag to do a MPI_Bcast of the data from one proc instead of + * having all the processes involved in the persistent I/O. + */ + local_cause[1] |= H5D_MPIO_NOT_H5S_ALL; + } + else { + + /* If the size of the dataset is less than 2GB then do an MPI_Bcast + * of the data from one process instead of having all the processes + * involved in the persistent I/O. + */ + + hsize_t dset_storage_size; + H5D__get_storage_size(io_info->dset, &dset_storage_size); + + if(dset_storage_size > ((hsize_t)(H5_2GB) - 1) ) { + local_cause[1] |= H5D_MPIO_GREATER_THAN_2GB; + } + } + /* Check for independent I/O */ - if(local_cause & H5D_MPIO_SET_INDEPENDENT) - global_cause = local_cause; + if(local_cause[0] & H5D_MPIO_SET_INDEPENDENT) + global_cause[0] = local_cause[0]; else { int mpi_code; /* MPI error code */ /* Form consensus opinion among all processes about whether to perform * collective I/O */ - if(MPI_SUCCESS != (mpi_code = MPI_Allreduce(&local_cause, &global_cause, 1, MPI_UNSIGNED, MPI_BOR, io_info->comm))) + if(MPI_SUCCESS != (mpi_code = MPI_Allreduce(&local_cause, &global_cause, 2, MPI_UNSIGNED, MPI_BOR, io_info->comm))) HMPI_GOTO_ERROR(FAIL, "MPI_Allreduce failed", mpi_code) + } /* end else */ /* Set the local & global values of no-collective-cause in the API context */ - H5CX_set_mpio_local_no_coll_cause(local_cause); - H5CX_set_mpio_global_no_coll_cause(global_cause); + H5CX_set_mpio_local_no_coll_cause(local_cause[0]); + H5CX_set_mpio_global_no_coll_cause(global_cause[0]); /* Set the return value, based on the global cause */ - ret_value = global_cause > 0 ? FALSE : TRUE; + ret_value = global_cause[0] > 0 ? FALSE : TRUE; + + /* read-proc0-and-bcast if collective and H5S_ALL */ + if(global_cause[0] == 0 && global_cause[1] == 0) + H5FD_MPIO_Proc0_BCast_g = TRUE; done: FUNC_LEAVE_NOAPI(ret_value) @@ -3069,8 +3100,8 @@ H5D__filtered_collective_chunk_entry_io(H5D_filtered_collective_io_info_t *chunk chunk_entry->chunk_states.new_chunk.length = chunk_entry->chunk_states.chunk_current.length; /* Currently, these chunk reads are done independently and will likely - * cause issues with collective metadata reads enabled. In the future, - * this should be refactored to use collective chunk reads - JTH */ + * cause issues with collective metadata reads enabled. In the future, + * this should be refactored to use collective chunk reads - JTH */ /* Get the original state of parallel I/O transfer mode */ if(H5CX_get_io_xfer_mode(&xfer_mode) < 0) diff --git a/src/H5FDmpio.c b/src/H5FDmpio.c index 87f8b6a..28bffc6 100644 --- a/src/H5FDmpio.c +++ b/src/H5FDmpio.c @@ -1414,31 +1414,32 @@ static herr_t H5FD_mpio_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr, size_t size, void *buf/*out*/) { - H5FD_mpio_t *file = (H5FD_mpio_t*)_file; - MPI_Offset mpi_off; - MPI_Status mpi_stat; /* Status from I/O operation */ - int mpi_code; /* mpi return code */ - MPI_Datatype buf_type = MPI_BYTE; /* MPI description of the selection in memory */ - int size_i; /* Integer copy of 'size' to read */ + H5FD_mpio_t *file = (H5FD_mpio_t*)_file; + MPI_Offset mpi_off; + MPI_Status mpi_stat; /* Status from I/O operation */ + int mpi_code; /* mpi return code */ + MPI_Datatype buf_type = MPI_BYTE; /* MPI description of the selection in memory */ + int size_i; /* Integer copy of 'size' to read */ #if MPI_VERSION >= 3 - MPI_Count bytes_read; /* Number of bytes read in */ + MPI_Count bytes_read = 0; /* Number of bytes read in */ MPI_Count type_size; /* MPI datatype used for I/O's size */ MPI_Count io_size; /* Actual number of bytes requested */ MPI_Count n; #else - int bytes_read; /* Number of bytes read in */ + int bytes_read = 0; /* Number of bytes read in */ int type_size; /* MPI datatype used for I/O's size */ int io_size; /* Actual number of bytes requested */ - int n; + int n; #endif - hbool_t use_view_this_time = FALSE; - herr_t ret_value = SUCCEED; + hbool_t use_view_this_time = FALSE; + hbool_t Proc0_BCast_enabled = FALSE; /* If read-proc0-and-bcast option was used */ + herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI_NOINIT #ifdef H5FDmpio_DEBUG if (H5FD_mpio_Debug[(int)'t']) - fprintf(stdout, "Entering H5FD_mpio_read\n" ); + fprintf(stdout, "Entering H5FD_mpio_read\n" ); #endif HDassert(file); HDassert(H5FD_MPIO==file->pub.driver_id); @@ -1457,12 +1458,12 @@ H5FD_mpio_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, #ifdef H5FDmpio_DEBUG if (H5FD_mpio_Debug[(int)'r']) fprintf(stdout, "in H5FD_mpio_read mpi_off=%ld size_i=%d\n", - (long)mpi_off, size_i ); + (long)mpi_off, size_i ); #endif /* Only look for MPI views for raw data transfers */ if(type == H5FD_MEM_DRAW) { - H5FD_mpio_xfer_t xfer_mode; /* I/O transfer mode */ + H5FD_mpio_xfer_t xfer_mode; /* I/O transfer mode */ /* Get the transfer mode from the API context */ if(H5CX_get_io_xfer_mode(&xfer_mode) < 0) @@ -1475,7 +1476,7 @@ H5FD_mpio_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, * could mean "use MPI_BYTE" by convention). */ if(xfer_mode==H5FD_MPIO_COLLECTIVE) { - MPI_Datatype file_type; + MPI_Datatype file_type; /* Remember that views are used */ use_view_this_time = TRUE; @@ -1502,8 +1503,8 @@ H5FD_mpio_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, H5FD_mpio_collective_opt_t coll_opt_mode; #ifdef H5FDmpio_DEBUG - if (H5FD_mpio_Debug[(int)'t']) - fprintf(stdout, "H5FD_mpio_read: using MPIO collective mode\n"); + if (H5FD_mpio_Debug[(int)'t']) + fprintf(stdout, "H5FD_mpio_read: using MPIO collective mode\n"); #endif /* Get the collective_opt property to check whether the application wants to do IO individually. */ if(H5CX_get_mpio_coll_opt(&coll_opt_mode) < 0) @@ -1514,8 +1515,23 @@ H5FD_mpio_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, if(H5FD_mpio_Debug[(int)'t']) fprintf(stdout, "H5FD_mpio_read: doing MPI collective IO\n"); #endif - if(MPI_SUCCESS != (mpi_code = MPI_File_read_at_all(file->f, mpi_off, buf, size_i, buf_type, &mpi_stat))) + if(H5FD_MPIO_Proc0_BCast_g) { +#ifdef H5FDmpio_DEBUG + if(H5FD_mpio_Debug[(int)'t']) + fprintf(stdout, "H5FD_mpio_read: doing Proc0-read-and-MPI_Bcast\n"); +#endif + if(file->mpi_rank == 0) { + if(MPI_SUCCESS != (mpi_code = MPI_File_read_at(file->f, mpi_off, buf, size_i, buf_type, &mpi_stat))) + HMPI_GOTO_ERROR(FAIL, "MPI_File_read_at failed", mpi_code) + } + if(MPI_SUCCESS != (mpi_code = MPI_Bcast(buf, size_i, buf_type, 0, file->comm))) + HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed", mpi_code) + Proc0_BCast_enabled = TRUE; + } + else { + if(MPI_SUCCESS != (mpi_code = MPI_File_read_at_all(file->f, mpi_off, buf, size_i, buf_type, &mpi_stat))) HMPI_GOTO_ERROR(FAIL, "MPI_File_read_at_all failed", mpi_code) + } } /* end if */ else { #ifdef H5FDmpio_DEBUG @@ -1534,24 +1550,31 @@ H5FD_mpio_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, HMPI_GOTO_ERROR(FAIL, "MPI_File_set_view failed", mpi_code) } else { if(MPI_SUCCESS != (mpi_code = MPI_File_read_at(file->f, mpi_off, buf, size_i, buf_type, &mpi_stat))) - HMPI_GOTO_ERROR(FAIL, "MPI_File_read_at failed", mpi_code) + HMPI_GOTO_ERROR(FAIL, "MPI_File_read_at failed", mpi_code) } - /* How many bytes were actually read? */ + if( !Proc0_BCast_enabled || (Proc0_BCast_enabled && file->mpi_rank == 0) ) { + /* How many bytes were actually read? */ #if MPI_VERSION >= 3 - if (MPI_SUCCESS != (mpi_code = MPI_Get_elements_x(&mpi_stat, buf_type, &bytes_read))) + if(MPI_SUCCESS != (mpi_code = MPI_Get_elements_x(&mpi_stat, buf_type, &bytes_read))) #else - if (MPI_SUCCESS != (mpi_code = MPI_Get_elements(&mpi_stat, MPI_BYTE, &bytes_read))) + if(MPI_SUCCESS != (mpi_code = MPI_Get_elements(&mpi_stat, MPI_BYTE, &bytes_read))) #endif HMPI_GOTO_ERROR(FAIL, "MPI_Get_elements failed", mpi_code) + } + + if(Proc0_BCast_enabled ) { + if(MPI_SUCCESS != MPI_Bcast(&bytes_read, 1, MPI_LONG_LONG, 0, file->comm)) + HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed", 0) + } /* Get the type's size */ #if MPI_VERSION >= 3 - if (MPI_SUCCESS != (mpi_code = MPI_Type_size_x(buf_type, &type_size))) + if(MPI_SUCCESS != (mpi_code = MPI_Type_size_x(buf_type, &type_size))) #else - if (MPI_SUCCESS != (mpi_code = MPI_Type_size(buf_type, &type_size))) + if(MPI_SUCCESS != (mpi_code = MPI_Type_size(buf_type, &type_size))) #endif - HMPI_GOTO_ERROR(FAIL, "MPI_Type_size failed", mpi_code) + HMPI_GOTO_ERROR(FAIL, "MPI_Type_size failed", mpi_code) /* Compute the actual number of bytes requested */ io_size=type_size*size_i; @@ -1564,12 +1587,12 @@ H5FD_mpio_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, * This gives us zeroes beyond end of physical MPI file. */ if ((n=(io_size-bytes_read)) > 0) - HDmemset((char*)buf+bytes_read, 0, (size_t)n); + HDmemset((char*)buf+bytes_read, 0, (size_t)n); done: #ifdef H5FDmpio_DEBUG if (H5FD_mpio_Debug[(int)'t']) - fprintf(stdout, "Leaving H5FD_mpio_read\n" ); + fprintf(stdout, "Leaving H5FD_mpio_read\n" ); #endif FUNC_LEAVE_NOAPI(ret_value) diff --git a/src/H5Ppublic.h b/src/H5Ppublic.h index 86c6687..6f41ecd 100644 --- a/src/H5Ppublic.h +++ b/src/H5Ppublic.h @@ -170,6 +170,12 @@ typedef enum H5D_mpio_no_collective_cause_t { H5D_MPIO_NO_COLLECTIVE_MAX_CAUSE = 0x80 } H5D_mpio_no_collective_cause_t; +typedef enum H5D_mpio_no_proc0_bcast_cause_t { + H5D_MPIO_PROC0_BCAST = 0x00, + H5D_MPIO_NOT_H5S_ALL = 0x01, + H5D_MPIO_GREATER_THAN_2GB = 0x02 +} H5D_mpio_no_proc0_bcast_cause_t; + /********************/ /* Public Variables */ /********************/ diff --git a/src/H5private.h b/src/H5private.h index b654bae..3fc1d7a 100644 --- a/src/H5private.h +++ b/src/H5private.h @@ -568,6 +568,9 @@ #define H5_PB (1024.0F * 1024.0F * 1024.0F * 1024.0F * 1024.0F) #define H5_EB (1024.0F * 1024.0F * 1024.0F * 1024.0F * 1024.0F * 1024.0F) +/* Define 2GB -- Used for 2GB limitation checks */ +#define H5_2GB (2.0F * 1024.0F * 1024.0F * 1024.0F) + #ifndef H5_HAVE_FLOCK /* flock() operations. Used in the source so we have to define them when * the call is not available (e.g.: Windows). These should NOT be used @@ -1735,6 +1738,7 @@ typedef struct H5_debug_t { #ifdef H5_HAVE_PARALLEL extern hbool_t H5_coll_api_sanity_check_g; +extern hbool_t H5FD_MPIO_Proc0_BCast_g; /* Meets read-proc0-and-bcast requirements*/ #endif /* H5_HAVE_PARALLEL */ extern H5_debug_t H5_debug_g; diff --git a/testpar/t_dset.c b/testpar/t_dset.c index 281d027..35501d8 100644 --- a/testpar/t_dset.c +++ b/testpar/t_dset.c @@ -2649,7 +2649,7 @@ compress_readAll(void) /* Try reading the data */ ret = H5Dread(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, xfer_plist, data_read); - VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + VRFY((ret >= 0), "H5Dread succeeded"); /* Verify data read */ for(u=0; u= 0), "H5Dread succeeded"); - /* Verify all data read are the fill value 0 */ - trdata = rdata; - err_num = 0; - for(i = 0; i < (int)dset_dims[0]; i++) + /* Create DXPL for I/O */ + dxpl = H5Pcreate(H5P_DATASET_XFER); + VRFY((dxpl >= 0), "H5Pcreate succeeded"); + + for(ii = 0; ii < 2; ii++) { + if(ii == 0) + ret = H5Pset_dxpl_mpio(dxpl, H5FD_MPIO_INDEPENDENT); + else + ret = H5Pset_dxpl_mpio(dxpl, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + + /* set entire read buffer with the constant 2 */ + HDmemset(rdata,2,(size_t)(dset_size*sizeof(int))); + /* Read the entire dataset back */ + ret = H5Dread(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, dxpl, rdata); + VRFY((ret >= 0), "H5Dread succeeded"); + + /* Verify all data read are the fill value 0 */ + trdata = rdata; + err_num = 0; + for(i = 0; i < (int)dset_dims[0]; i++) for(j = 0; j < (int)dset_dims[1]; j++) - for(k = 0; k < (int)dset_dims[2]; k++) - for(l = 0; l < (int)dset_dims[3]; l++, twdata++, trdata++) - if(*trdata != 0) - if(err_num++ < MAX_ERR_REPORT || VERBOSE_MED) - printf("Dataset Verify failed at [%d][%d][%d][%d]: expect 0, got %d\n", i, j, k, l, *trdata); - if(err_num > MAX_ERR_REPORT && !VERBOSE_MED) + for(k = 0; k < (int)dset_dims[2]; k++) + for(l = 0; l < (int)dset_dims[3]; l++, twdata++, trdata++) + if(*trdata != 0) + if(err_num++ < MAX_ERR_REPORT || VERBOSE_MED) + printf("Dataset Verify failed at [%d][%d][%d][%d]: expect 0, got %d\n", i, j, k, l, *trdata); + if(err_num > MAX_ERR_REPORT && !VERBOSE_MED) printf("[more errors ...]\n"); - if(err_num){ + if(err_num){ printf("%d errors found in check_value\n", err_num); - nerrors++; + nerrors++; + } } /* Barrier to ensure all processes have completed the above test. */ @@ -681,10 +694,6 @@ void dataset_fillvalue(void) ret = H5Sselect_hyperslab(memspace, H5S_SELECT_SET, req_start, NULL, req_count, NULL); VRFY((ret >= 0), "H5Sselect_hyperslab succeeded on memory dataspace"); - /* Create DXPL for collective I/O */ - dxpl = H5Pcreate(H5P_DATASET_XFER); - VRFY((dxpl >= 0), "H5Pcreate succeeded"); - ret = H5Pset_dxpl_mpio(dxpl, H5FD_MPIO_COLLECTIVE); VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); if(dxfer_coll_type == DXFER_INDEPENDENT_IO) { @@ -711,37 +720,46 @@ void dataset_fillvalue(void) /* * Read dataset after partial write. */ - /* set entire read buffer with the constant 2 */ - HDmemset(rdata,2,(size_t)(dset_size*sizeof(int))); - /* Independently read the entire dataset back */ - ret = H5Dread(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); - VRFY((ret >= 0), "H5Dread succeeded"); - /* Verify correct data read */ - twdata=wdata; - trdata=rdata; - err_num=0; - for(i=0; i<(int)dset_dims[0]; i++) + for(ii = 0; ii < 2; ii++) { + if(ii == 0) + ret = H5Pset_dxpl_mpio(dxpl, H5FD_MPIO_INDEPENDENT); + else + ret = H5Pset_dxpl_mpio(dxpl, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + + /* set entire read buffer with the constant 2 */ + HDmemset(rdata,2,(size_t)(dset_size*sizeof(int))); + /* Read the entire dataset back */ + ret = H5Dread(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, dxpl, rdata); + VRFY((ret >= 0), "H5Dread succeeded"); + + /* Verify correct data read */ + twdata=wdata; + trdata=rdata; + err_num=0; + for(i=0; i<(int)dset_dims[0]; i++) for(j=0; j<(int)dset_dims[1]; j++) - for(k=0; k<(int)dset_dims[2]; k++) - for(l=0; l<(int)dset_dims[3]; l++, twdata++, trdata++) - if(i MAX_ERR_REPORT && !VERBOSE_MED) + for(k=0; k<(int)dset_dims[2]; k++) + for(l=0; l<(int)dset_dims[3]; l++, twdata++, trdata++) + if(i MAX_ERR_REPORT && !VERBOSE_MED) printf("[more errors ...]\n"); - if(err_num){ + if(err_num){ printf("%d errors found in check_value\n", err_num); - nerrors++; + nerrors++; + } } - + /* Close all file objects */ ret = H5Dclose(dataset); VRFY((ret >= 0), "H5Dclose succeeded"); @@ -856,7 +874,7 @@ void collective_group_write(void) if(!((m+1) % 10)) { printf("created %d groups\n", m+1); MPI_Barrier(MPI_COMM_WORLD); - } + } #endif /* BARRIER_CHECKS */ } diff --git a/testpar/t_pread.c b/testpar/t_pread.c index 0905d44..a6a6a7d 100644 --- a/testpar/t_pread.c +++ b/testpar/t_pread.c @@ -46,7 +46,7 @@ completely foolproof is to underestimate the ingenuity of complete\n\ fools.\n"; static int generate_test_file(MPI_Comm comm, int mpi_rank, int group); -static int test_parallel_read(MPI_Comm comm, int mpi_rank, int group); +static int test_parallel_read(MPI_Comm comm, int mpi_rank, int mpi_size, int group); static char *test_argv0 = NULL; @@ -413,7 +413,7 @@ generate_test_file( MPI_Comm comm, int mpi_rank, int group_id ) * Function: test_parallel_read * * Purpose: This actually tests the superblock optimization - * and covers the two primary cases we're interested in. + * and covers the three primary cases we're interested in. * 1). That HDF5 files can be opened in parallel by * the rank 0 process and that the superblock * offset is correctly broadcast to the other @@ -423,6 +423,10 @@ generate_test_file( MPI_Comm comm, int mpi_rank, int group_id ) * subgroups of MPI_COMM_WORLD and that each * subgroup operates as described in (1) to * collectively read the data. + * 3). Testing proc0-read-and-MPI_Bcast using + * sub-communicators, and reading into + * a memory space that is different from the + * file space. * * The global MPI rank is used for reading and * writing data for process specific data in the @@ -444,7 +448,7 @@ generate_test_file( MPI_Comm comm, int mpi_rank, int group_id ) *------------------------------------------------------------------------- */ static int -test_parallel_read(MPI_Comm comm, int mpi_rank, int group_id) +test_parallel_read(MPI_Comm comm, int mpi_rank, int mpi_size, int group_id) { const char *failure_mssg; const char *fcn_name = "test_parallel_read()"; @@ -457,8 +461,12 @@ test_parallel_read(MPI_Comm comm, int mpi_rank, int group_id) hid_t fapl_id = -1; hid_t file_id = -1; hid_t dset_id = -1; + hid_t dxpl_id = H5P_DEFAULT; hid_t memspace = -1; hid_t filespace = -1; + hid_t filetype = -1; + size_t filetype_size; + hssize_t dset_size; hsize_t i; hsize_t offset; hsize_t count = COUNT; @@ -606,14 +614,6 @@ test_parallel_read(MPI_Comm comm, int mpi_rank, int group_id) } } - /* close file, etc. */ - if ( pass || (dset_id != -1) ) { - if ( H5Dclose(dset_id) < 0 ) { - pass = false; - failure_mssg = "H5Dclose(dset_id) failed.\n"; - } - } - if ( pass || (memspace != -1) ) { if ( H5Sclose(memspace) < 0 ) { pass = false; @@ -628,6 +628,202 @@ test_parallel_read(MPI_Comm comm, int mpi_rank, int group_id) } } + /* free data_slice if it has been allocated */ + if ( data_slice != NULL ) { + HDfree(data_slice); + data_slice = NULL; + } + + /* + * Test reading proc0-read-and-bcast with sub-communicators + */ + + /* Don't test with more than 6 processes to avoid memory issues */ + + if( group_size <= 6 ) { + + if ( (filespace = H5Dget_space(dset_id )) < 0 ) { + pass = FALSE; + failure_mssg = "H5Dget_space failed.\n"; + } + + if ( (dset_size = H5Sget_simple_extent_npoints(filespace)) < 0 ) { + pass = FALSE; + failure_mssg = "H5Sget_simple_extent_npoints failed.\n"; + } + + if ( (filetype = H5Dget_type(dset_id)) < 0 ) { + pass = FALSE; + failure_mssg = "H5Dget_type failed.\n"; + } + + if ( (filetype_size = H5Tget_size(filetype)) == 0 ) { + pass = FALSE; + failure_mssg = "H5Tget_size failed.\n"; + } + + if ( H5Tclose(filetype) < 0 ) { + pass = FALSE; + failure_mssg = "H5Tclose failed.\n"; + }; + + if ( (data_slice = (float *)HDmalloc((size_t)dset_size*filetype_size)) == NULL ) { + pass = FALSE; + failure_mssg = "malloc of data_slice failed.\n"; + } + + if ( pass ) { + if ( (dxpl_id = H5Pcreate(H5P_DATASET_XFER)) < 0 ) { + pass = FALSE; + failure_mssg = "H5Pcreate(H5P_DATASET_XFER) failed.\n"; + } + } + + if ( pass ) { + if ( (H5Pset_dxpl_mpio(dxpl_id, H5FD_MPIO_COLLECTIVE)) < 0 ) { + pass = FALSE; + failure_mssg = "H5Pset_dxpl_mpio() failed.\n"; + } + } + + /* read H5S_ALL section */ + if ( pass ) { + if ( (H5Dread(dset_id, H5T_NATIVE_FLOAT, H5S_ALL, + H5S_ALL, dxpl_id, data_slice)) < 0 ) { + pass = FALSE; + failure_mssg = "H5Dread() failed\n"; + } + } + + /* verify the data */ + if ( pass ) { + + if ( comm == MPI_COMM_WORLD ) /* test 1 */ + nextValue = 0; + else if ( group_id == 0 ) /* test 2 group 0 */ + nextValue = 0; + else /* test 2 group 1 */ + nextValue = (float)((hsize_t)( mpi_size / 2 )*count); + + i = 0; + while ( ( pass ) && ( i < (hsize_t)dset_size ) ) { + /* what we really want is data_slice[i] != nextValue -- + * the following is a circumlocution to shut up the + * the compiler. + */ + if ( ( data_slice[i] > nextValue ) || + ( data_slice[i] < nextValue ) ) { + pass = FALSE; + failure_mssg = "Unexpected dset contents.\n"; + } + nextValue += 1; + i++; + } + } + + if ( pass || (filespace != -1) ) { + if ( H5Sclose(filespace) < 0 ) { + pass = false; + failure_mssg = "H5Sclose(filespace) failed.\n"; + } + } + + /* free data_slice if it has been allocated */ + if ( data_slice != NULL ) { + HDfree(data_slice); + data_slice = NULL; + } + + /* + * Read an H5S_ALL filespace into a hyperslab defined memory space + */ + + if ( (data_slice = (float *)HDmalloc((size_t)(dset_size*2)*filetype_size)) == NULL ) { + pass = FALSE; + failure_mssg = "malloc of data_slice failed.\n"; + } + + /* setup memspace */ + if ( pass ) { + dims[0] = (hsize_t)dset_size*2; + if ( (memspace = H5Screate_simple(1, dims, NULL)) < 0 ) { + pass = FALSE; + failure_mssg = "H5Screate_simple(1, dims, NULL) failed\n"; + } + } + if ( pass ) { + offset = (hsize_t)dset_size; + if ( (H5Sselect_hyperslab(memspace, H5S_SELECT_SET, + &offset, NULL, &offset, NULL)) < 0 ) { + pass = FALSE; + failure_mssg = "H5Sselect_hyperslab() failed\n"; + } + } + + /* read this processes section of the data */ + if ( pass ) { + if ( (H5Dread(dset_id, H5T_NATIVE_FLOAT, memspace, + H5S_ALL, dxpl_id, data_slice)) < 0 ) { + pass = FALSE; + failure_mssg = "H5Dread() failed\n"; + } + } + + /* verify the data */ + if ( pass ) { + + if ( comm == MPI_COMM_WORLD ) /* test 1 */ + nextValue = 0; + else if ( group_id == 0 ) /* test 2 group 0 */ + nextValue = 0; + else /* test 2 group 1 */ + nextValue = (float)((hsize_t)(mpi_size / 2)*count); + + i = (hsize_t)dset_size; + while ( ( pass ) && ( i < (hsize_t)dset_size ) ) { + /* what we really want is data_slice[i] != nextValue -- + * the following is a circumlocution to shut up the + * the compiler. + */ + if ( ( data_slice[i] > nextValue ) || + ( data_slice[i] < nextValue ) ) { + pass = FALSE; + failure_mssg = "Unexpected dset contents.\n"; + } + nextValue += 1; + i++; + } + } + + if ( pass || (memspace != -1) ) { + if ( H5Sclose(memspace) < 0 ) { + pass = false; + failure_mssg = "H5Sclose(memspace) failed.\n"; + } + } + + /* free data_slice if it has been allocated */ + if ( data_slice != NULL ) { + HDfree(data_slice); + data_slice = NULL; + } + + if ( pass || (dxpl_id != -1) ) { + if ( H5Pclose(dxpl_id) < 0 ) { + pass = false; + failure_mssg = "H5Pclose(dxpl_id) failed.\n"; + } + } + } + + /* close file, etc. */ + if ( pass || (dset_id != -1) ) { + if ( H5Dclose(dset_id) < 0 ) { + pass = false; + failure_mssg = "H5Dclose(dset_id) failed.\n"; + } + } + if ( pass || (file_id != -1) ) { if ( H5Fclose(file_id) < 0 ) { pass = false; @@ -668,17 +864,9 @@ test_parallel_read(MPI_Comm comm, int mpi_rank, int group_id) HDfprintf(stdout, "%s: failure_mssg = \"%s\"\n", fcn_name, failure_mssg); } - HDremove(reloc_data_filename); } - /* free data_slice if it has been allocated */ - if ( data_slice != NULL ) { - HDfree(data_slice); - data_slice = NULL; - } - - return( ! pass ); } /* test_parallel_read() */ @@ -803,7 +991,7 @@ main( int argc, char **argv) } /* Now read the generated test file (stil using MPI_COMM_WORLD) */ - nerrs += test_parallel_read( MPI_COMM_WORLD, mpi_rank, which_group); + nerrs += test_parallel_read( MPI_COMM_WORLD, mpi_rank, mpi_size, which_group); if ( nerrs > 0 ) { if ( mpi_rank == 0 ) { @@ -819,7 +1007,7 @@ main( int argc, char **argv) } /* run the 2nd set of tests */ - nerrs += test_parallel_read(group_comm, mpi_rank, which_group); + nerrs += test_parallel_read(group_comm, mpi_rank, mpi_size, which_group); if ( nerrs > 0 ) { if ( mpi_rank == 0 ) { -- cgit v0.12 From f772ef9f2e12f2407bd6d3f72ddd996ea721f9b8 Mon Sep 17 00:00:00 2001 From: "M. Scot Breitenfeld" Date: Mon, 31 Dec 2018 15:06:16 -0600 Subject: switched to using CX instead of a global var. --- src/H5CX.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/H5CXprivate.h | 2 ++ src/H5Dmpio.c | 10 ++++++---- src/H5FDmpio.c | 2 +- src/H5private.h | 1 - 5 files changed, 65 insertions(+), 6 deletions(-) diff --git a/src/H5CX.c b/src/H5CX.c index 1d9cf3d..756dc03 100644 --- a/src/H5CX.c +++ b/src/H5CX.c @@ -198,6 +198,7 @@ typedef struct H5CX_t { MPI_Datatype btype; /* MPI datatype for buffer, when using collective I/O */ MPI_Datatype ftype; /* MPI datatype for file, when using collective I/O */ hbool_t mpi_file_flushing; /* Whether an MPI-opened file is being flushed */ + hbool_t mpio_Proc0_BCast; /* Whether a dataset meets read-proc0-and-bcast requirements */ #endif /* H5_HAVE_PARALLEL */ /* Cached DXPL properties */ @@ -1537,6 +1538,33 @@ done: /*------------------------------------------------------------------------- + * Function: H5CX_get_mpio_Proc0_BCast + * + * Purpose: Retrieves if the dataset meets read-proc0-and-bcast requirements for the current API call context. + * + * Return: Non-negative on success / Negative on failure + * + * Programmer: M. Breitenfeld + * December 31, 2018 + * + *------------------------------------------------------------------------- + */ +hbool_t +H5CX_get_mpio_Proc0_BCast(void) +{ + H5CX_node_t **head = H5CX_get_my_context(); /* Get the pointer to the head of the API context, for this thread */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Sanity check */ + HDassert(head && *head); + + FUNC_LEAVE_NOAPI((*head)->ctx.mpio_Proc0_BCast) + +} /* end H5CX_get_mpio_Proc0_BCast() */ + + +/*------------------------------------------------------------------------- * Function: H5CX_get_mpio_chunk_opt_mode * * Purpose: Retrieves the collective chunk optimization mode for the current API call context. @@ -2320,6 +2348,34 @@ H5CX_set_mpio_global_no_coll_cause(uint32_t mpio_global_no_coll_cause) FUNC_LEAVE_NOAPI_VOID } /* end H5CX_set_mpio_global_no_coll_cause() */ + +/*------------------------------------------------------------------------- + * Function: H5CX_set_mpio_Proc0_BCast + * + * Purpose: Sets if the dataset meets read-proc0-and-bcast requirements for the current API call context. + * + * Return: + * + * Programmer: M. Breitenfeld + * December 31, 2018 + * + *------------------------------------------------------------------------- + */ +void +H5CX_set_mpio_Proc0_BCast(hbool_t mpio_Proc0_BCast) +{ + H5CX_node_t **head = H5CX_get_my_context(); /* Get the pointer to the head of the API context, for this thread */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Sanity checks */ + HDassert(head && *head); + + (*head)->ctx.mpio_Proc0_BCast = mpio_Proc0_BCast; + + FUNC_LEAVE_NOAPI_VOID +} /* end H5CX_set_mpio_Proc0_BCast */ + #ifdef H5_HAVE_INSTRUMENTED_LIBRARY /*------------------------------------------------------------------------- diff --git a/src/H5CXprivate.h b/src/H5CXprivate.h index 57ca5cd..f93121c 100644 --- a/src/H5CXprivate.h +++ b/src/H5CXprivate.h @@ -75,6 +75,7 @@ H5_DLL H5AC_ring_t H5CX_get_ring(void); H5_DLL hbool_t H5CX_get_coll_metadata_read(void); H5_DLL herr_t H5CX_get_mpi_coll_datatypes(MPI_Datatype *btype, MPI_Datatype *ftype); H5_DLL hbool_t H5CX_get_mpi_file_flushing(void); +H5_DLL hbool_t H5CX_get_mpio_Proc0_BCast(void); #endif /* H5_HAVE_PARALLEL */ /* "Getter" routines for DXPL properties cached in API context */ @@ -128,6 +129,7 @@ H5_DLL void H5CX_set_mpio_actual_chunk_opt(H5D_mpio_actual_chunk_opt_mode_t chun H5_DLL void H5CX_set_mpio_actual_io_mode(H5D_mpio_actual_io_mode_t actual_io_mode); H5_DLL void H5CX_set_mpio_local_no_coll_cause(uint32_t mpio_local_no_coll_cause); H5_DLL void H5CX_set_mpio_global_no_coll_cause(uint32_t mpio_global_no_coll_cause); +H5_DLL void H5CX_set_mpio_Proc0_BCast(hbool_t mpio_Proc0_BCast); #ifdef H5_HAVE_INSTRUMENTED_LIBRARY H5_DLL herr_t H5CX_test_set_mpio_coll_chunk_link_hard(int mpio_coll_chunk_link_hard); H5_DLL herr_t H5CX_test_set_mpio_coll_chunk_multi_hard(int mpio_coll_chunk_multi_hard); diff --git a/src/H5Dmpio.c b/src/H5Dmpio.c index 3c4eab2..df2cc9e 100644 --- a/src/H5Dmpio.c +++ b/src/H5Dmpio.c @@ -47,8 +47,6 @@ #ifdef H5_HAVE_PARALLEL -hbool_t H5FD_MPIO_Proc0_BCast_g; /* Flag if dataset is both: H5S_ALL and < 2GB */ - /****************/ /* Local Macros */ /****************/ @@ -287,6 +285,7 @@ H5D__mpio_opt_possible(const H5D_io_info_t *io_info, const H5S_t *file_space, /* [1] Flag if dataset is both: H5S_ALL and small */ unsigned global_cause[2] = {0,0}; /* Global reason(s) for breaking collective mode */ htri_t ret_value = SUCCEED; /* Return value */ + hbool_t H5FD_MPIO_Proc0_BCast; /* Flag if dataset is both: H5S_ALL and < 2GB */ FUNC_ENTER_PACKAGE @@ -349,7 +348,7 @@ H5D__mpio_opt_possible(const H5D_io_info_t *io_info, const H5S_t *file_space, local_cause[0] |= H5D_MPIO_PARALLEL_FILTERED_WRITES_DISABLED; #endif - H5FD_MPIO_Proc0_BCast_g = FALSE; + H5FD_MPIO_Proc0_BCast = FALSE; /* Check to see if all the processes are reading the same data */ if((H5S_GET_SELECT_TYPE(file_space) != H5S_SEL_ALL)) { /* Flag to do a MPI_Bcast of the data from one proc instead of @@ -395,7 +394,10 @@ H5D__mpio_opt_possible(const H5D_io_info_t *io_info, const H5S_t *file_space, /* read-proc0-and-bcast if collective and H5S_ALL */ if(global_cause[0] == 0 && global_cause[1] == 0) - H5FD_MPIO_Proc0_BCast_g = TRUE; + H5FD_MPIO_Proc0_BCast = TRUE; + + /* Set Flag if dataset is both: H5S_ALL and < 2GB in the API context */ + H5CX_set_mpio_Proc0_BCast(H5FD_MPIO_Proc0_BCast); done: FUNC_LEAVE_NOAPI(ret_value) diff --git a/src/H5FDmpio.c b/src/H5FDmpio.c index 28bffc6..a4b9ef3 100644 --- a/src/H5FDmpio.c +++ b/src/H5FDmpio.c @@ -1515,7 +1515,7 @@ H5FD_mpio_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, if(H5FD_mpio_Debug[(int)'t']) fprintf(stdout, "H5FD_mpio_read: doing MPI collective IO\n"); #endif - if(H5FD_MPIO_Proc0_BCast_g) { + if(H5CX_get_mpio_Proc0_BCast()) { #ifdef H5FDmpio_DEBUG if(H5FD_mpio_Debug[(int)'t']) fprintf(stdout, "H5FD_mpio_read: doing Proc0-read-and-MPI_Bcast\n"); diff --git a/src/H5private.h b/src/H5private.h index 3fc1d7a..05bfc63 100644 --- a/src/H5private.h +++ b/src/H5private.h @@ -1738,7 +1738,6 @@ typedef struct H5_debug_t { #ifdef H5_HAVE_PARALLEL extern hbool_t H5_coll_api_sanity_check_g; -extern hbool_t H5FD_MPIO_Proc0_BCast_g; /* Meets read-proc0-and-bcast requirements*/ #endif /* H5_HAVE_PARALLEL */ extern H5_debug_t H5_debug_g; -- cgit v0.12 From 55f7fe7f1b236bbe496ff1af79331166df4b7e83 Mon Sep 17 00:00:00 2001 From: "M. Scot Breitenfeld" Date: Wed, 2 Jan 2019 09:39:03 -0600 Subject: Removed reason for breaking read-proc0-and-bcast --- src/H5Dmpio.c | 4 ++-- src/H5Pprivate.h | 1 - src/H5Ppublic.h | 6 ------ 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/H5Dmpio.c b/src/H5Dmpio.c index df2cc9e..e1c0edb 100644 --- a/src/H5Dmpio.c +++ b/src/H5Dmpio.c @@ -354,7 +354,7 @@ H5D__mpio_opt_possible(const H5D_io_info_t *io_info, const H5S_t *file_space, /* Flag to do a MPI_Bcast of the data from one proc instead of * having all the processes involved in the persistent I/O. */ - local_cause[1] |= H5D_MPIO_NOT_H5S_ALL; + local_cause[1] |= 0x01; } else { @@ -367,7 +367,7 @@ H5D__mpio_opt_possible(const H5D_io_info_t *io_info, const H5S_t *file_space, H5D__get_storage_size(io_info->dset, &dset_storage_size); if(dset_storage_size > ((hsize_t)(H5_2GB) - 1) ) { - local_cause[1] |= H5D_MPIO_GREATER_THAN_2GB; + local_cause[1] |= 0x02; } } diff --git a/src/H5Pprivate.h b/src/H5Pprivate.h index 866f088..7007635 100644 --- a/src/H5Pprivate.h +++ b/src/H5Pprivate.h @@ -44,7 +44,6 @@ typedef struct H5P_genplist_t H5P_genplist_t; #define H5_COLL_MD_READ_FLAG_NAME "collective_metadata_read" - /****************************/ /* Library Private Typedefs */ /****************************/ diff --git a/src/H5Ppublic.h b/src/H5Ppublic.h index 6f41ecd..86c6687 100644 --- a/src/H5Ppublic.h +++ b/src/H5Ppublic.h @@ -170,12 +170,6 @@ typedef enum H5D_mpio_no_collective_cause_t { H5D_MPIO_NO_COLLECTIVE_MAX_CAUSE = 0x80 } H5D_mpio_no_collective_cause_t; -typedef enum H5D_mpio_no_proc0_bcast_cause_t { - H5D_MPIO_PROC0_BCAST = 0x00, - H5D_MPIO_NOT_H5S_ALL = 0x01, - H5D_MPIO_GREATER_THAN_2GB = 0x02 -} H5D_mpio_no_proc0_bcast_cause_t; - /********************/ /* Public Variables */ /********************/ -- cgit v0.12 From 58decdbd88f6f6c273c65a37dc54ac1bff6f1b2b Mon Sep 17 00:00:00 2001 From: "M. Scot Breitenfeld" Date: Wed, 12 Dec 2018 15:39:18 -0600 Subject: HDFFV-10652 Implemented a process-0 read and then broadcast for collective read of full datasets (H5S_ALL) by all the processes in the file communicator. --- src/H5CX.c | 56 +++++++++++++ src/H5CXprivate.h | 2 + src/H5Dmpio.c | 71 ++++++++++++----- src/H5FDmpio.c | 77 +++++++++++------- src/H5Pprivate.h | 1 - src/H5private.h | 3 + testpar/t_dset.c | 2 +- testpar/t_mdset.c | 118 ++++++++++++++++------------ testpar/t_pread.c | 230 +++++++++++++++++++++++++++++++++++++++++++++++++----- 9 files changed, 441 insertions(+), 119 deletions(-) diff --git a/src/H5CX.c b/src/H5CX.c index 1d9cf3d..756dc03 100644 --- a/src/H5CX.c +++ b/src/H5CX.c @@ -198,6 +198,7 @@ typedef struct H5CX_t { MPI_Datatype btype; /* MPI datatype for buffer, when using collective I/O */ MPI_Datatype ftype; /* MPI datatype for file, when using collective I/O */ hbool_t mpi_file_flushing; /* Whether an MPI-opened file is being flushed */ + hbool_t mpio_Proc0_BCast; /* Whether a dataset meets read-proc0-and-bcast requirements */ #endif /* H5_HAVE_PARALLEL */ /* Cached DXPL properties */ @@ -1537,6 +1538,33 @@ done: /*------------------------------------------------------------------------- + * Function: H5CX_get_mpio_Proc0_BCast + * + * Purpose: Retrieves if the dataset meets read-proc0-and-bcast requirements for the current API call context. + * + * Return: Non-negative on success / Negative on failure + * + * Programmer: M. Breitenfeld + * December 31, 2018 + * + *------------------------------------------------------------------------- + */ +hbool_t +H5CX_get_mpio_Proc0_BCast(void) +{ + H5CX_node_t **head = H5CX_get_my_context(); /* Get the pointer to the head of the API context, for this thread */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Sanity check */ + HDassert(head && *head); + + FUNC_LEAVE_NOAPI((*head)->ctx.mpio_Proc0_BCast) + +} /* end H5CX_get_mpio_Proc0_BCast() */ + + +/*------------------------------------------------------------------------- * Function: H5CX_get_mpio_chunk_opt_mode * * Purpose: Retrieves the collective chunk optimization mode for the current API call context. @@ -2320,6 +2348,34 @@ H5CX_set_mpio_global_no_coll_cause(uint32_t mpio_global_no_coll_cause) FUNC_LEAVE_NOAPI_VOID } /* end H5CX_set_mpio_global_no_coll_cause() */ + +/*------------------------------------------------------------------------- + * Function: H5CX_set_mpio_Proc0_BCast + * + * Purpose: Sets if the dataset meets read-proc0-and-bcast requirements for the current API call context. + * + * Return: + * + * Programmer: M. Breitenfeld + * December 31, 2018 + * + *------------------------------------------------------------------------- + */ +void +H5CX_set_mpio_Proc0_BCast(hbool_t mpio_Proc0_BCast) +{ + H5CX_node_t **head = H5CX_get_my_context(); /* Get the pointer to the head of the API context, for this thread */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Sanity checks */ + HDassert(head && *head); + + (*head)->ctx.mpio_Proc0_BCast = mpio_Proc0_BCast; + + FUNC_LEAVE_NOAPI_VOID +} /* end H5CX_set_mpio_Proc0_BCast */ + #ifdef H5_HAVE_INSTRUMENTED_LIBRARY /*------------------------------------------------------------------------- diff --git a/src/H5CXprivate.h b/src/H5CXprivate.h index 57ca5cd..f93121c 100644 --- a/src/H5CXprivate.h +++ b/src/H5CXprivate.h @@ -75,6 +75,7 @@ H5_DLL H5AC_ring_t H5CX_get_ring(void); H5_DLL hbool_t H5CX_get_coll_metadata_read(void); H5_DLL herr_t H5CX_get_mpi_coll_datatypes(MPI_Datatype *btype, MPI_Datatype *ftype); H5_DLL hbool_t H5CX_get_mpi_file_flushing(void); +H5_DLL hbool_t H5CX_get_mpio_Proc0_BCast(void); #endif /* H5_HAVE_PARALLEL */ /* "Getter" routines for DXPL properties cached in API context */ @@ -128,6 +129,7 @@ H5_DLL void H5CX_set_mpio_actual_chunk_opt(H5D_mpio_actual_chunk_opt_mode_t chun H5_DLL void H5CX_set_mpio_actual_io_mode(H5D_mpio_actual_io_mode_t actual_io_mode); H5_DLL void H5CX_set_mpio_local_no_coll_cause(uint32_t mpio_local_no_coll_cause); H5_DLL void H5CX_set_mpio_global_no_coll_cause(uint32_t mpio_global_no_coll_cause); +H5_DLL void H5CX_set_mpio_Proc0_BCast(hbool_t mpio_Proc0_BCast); #ifdef H5_HAVE_INSTRUMENTED_LIBRARY H5_DLL herr_t H5CX_test_set_mpio_coll_chunk_link_hard(int mpio_coll_chunk_link_hard); H5_DLL herr_t H5CX_test_set_mpio_coll_chunk_multi_hard(int mpio_coll_chunk_multi_hard); diff --git a/src/H5Dmpio.c b/src/H5Dmpio.c index 2c06800..e1c0edb 100644 --- a/src/H5Dmpio.c +++ b/src/H5Dmpio.c @@ -37,7 +37,7 @@ #include "H5Eprivate.h" /* Error handling */ #include "H5Fprivate.h" /* File access */ #include "H5FDprivate.h" /* File drivers */ -#include "H5FDmpi.h" /* MPI-based file drivers */ +#include "H5FDmpi.h" /* MPI-based file drivers */ #include "H5Iprivate.h" /* IDs */ #include "H5MMprivate.h" /* Memory management */ #include "H5Oprivate.h" /* Object headers */ @@ -281,9 +281,11 @@ H5D__mpio_opt_possible(const H5D_io_info_t *io_info, const H5S_t *file_space, const H5S_t *mem_space, const H5D_type_info_t *type_info) { H5FD_mpio_xfer_t io_xfer_mode; /* MPI I/O transfer mode */ - unsigned local_cause = 0; /* Local reason(s) for breaking collective mode */ - unsigned global_cause = 0; /* Global reason(s) for breaking collective mode */ + unsigned local_cause[2] = {0,0}; /* [0] Local reason(s) for breaking collective mode */ + /* [1] Flag if dataset is both: H5S_ALL and small */ + unsigned global_cause[2] = {0,0}; /* Global reason(s) for breaking collective mode */ htri_t ret_value = SUCCEED; /* Return value */ + hbool_t H5FD_MPIO_Proc0_BCast; /* Flag if dataset is both: H5S_ALL and < 2GB */ FUNC_ENTER_PACKAGE @@ -298,34 +300,34 @@ H5D__mpio_opt_possible(const H5D_io_info_t *io_info, const H5S_t *file_space, if(H5CX_get_io_xfer_mode(&io_xfer_mode) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get MPI-I/O transfer mode") if(io_xfer_mode == H5FD_MPIO_INDEPENDENT) - local_cause |= H5D_MPIO_SET_INDEPENDENT; + local_cause[0] |= H5D_MPIO_SET_INDEPENDENT; /* Optimized MPI types flag must be set */ /* (based on 'HDF5_MPI_OPT_TYPES' environment variable) */ if(!H5FD_mpi_opt_types_g) - local_cause |= H5D_MPIO_MPI_OPT_TYPES_ENV_VAR_DISABLED; + local_cause[0] |= H5D_MPIO_MPI_OPT_TYPES_ENV_VAR_DISABLED; /* Don't allow collective operations if datatype conversions need to happen */ if(!type_info->is_conv_noop) - local_cause |= H5D_MPIO_DATATYPE_CONVERSION; + local_cause[0] |= H5D_MPIO_DATATYPE_CONVERSION; /* Don't allow collective operations if data transform operations should occur */ if(!type_info->is_xform_noop) - local_cause |= H5D_MPIO_DATA_TRANSFORMS; + local_cause[0] |= H5D_MPIO_DATA_TRANSFORMS; /* Check whether these are both simple or scalar dataspaces */ if(!((H5S_SIMPLE == H5S_GET_EXTENT_TYPE(mem_space) || H5S_SCALAR == H5S_GET_EXTENT_TYPE(mem_space)) && (H5S_SIMPLE == H5S_GET_EXTENT_TYPE(file_space) || H5S_SCALAR == H5S_GET_EXTENT_TYPE(file_space)))) - local_cause |= H5D_MPIO_NOT_SIMPLE_OR_SCALAR_DATASPACES; + local_cause[0] |= H5D_MPIO_NOT_SIMPLE_OR_SCALAR_DATASPACES; /* Dataset storage must be contiguous or chunked */ if(!(io_info->dset->shared->layout.type == H5D_CONTIGUOUS || io_info->dset->shared->layout.type == H5D_CHUNKED)) - local_cause |= H5D_MPIO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET; + local_cause[0] |= H5D_MPIO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET; /* check if external-file storage is used */ if(io_info->dset->shared->dcpl_cache.efl.nused > 0) - local_cause |= H5D_MPIO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET; + local_cause[0] |= H5D_MPIO_NOT_CONTIGUOUS_OR_CHUNKED_DATASET; /* The handling of memory space is different for chunking and contiguous * storage. For contiguous storage, mem_space and file_space won't change @@ -343,28 +345,59 @@ H5D__mpio_opt_possible(const H5D_io_info_t *io_info, const H5S_t *file_space, if (io_info->op_type == H5D_IO_OP_WRITE && io_info->dset->shared->layout.type == H5D_CHUNKED && io_info->dset->shared->dcpl_cache.pline.nused > 0) - local_cause |= H5D_MPIO_PARALLEL_FILTERED_WRITES_DISABLED; + local_cause[0] |= H5D_MPIO_PARALLEL_FILTERED_WRITES_DISABLED; #endif + H5FD_MPIO_Proc0_BCast = FALSE; + /* Check to see if all the processes are reading the same data */ + if((H5S_GET_SELECT_TYPE(file_space) != H5S_SEL_ALL)) { + /* Flag to do a MPI_Bcast of the data from one proc instead of + * having all the processes involved in the persistent I/O. + */ + local_cause[1] |= 0x01; + } + else { + + /* If the size of the dataset is less than 2GB then do an MPI_Bcast + * of the data from one process instead of having all the processes + * involved in the persistent I/O. + */ + + hsize_t dset_storage_size; + H5D__get_storage_size(io_info->dset, &dset_storage_size); + + if(dset_storage_size > ((hsize_t)(H5_2GB) - 1) ) { + local_cause[1] |= 0x02; + } + } + /* Check for independent I/O */ - if(local_cause & H5D_MPIO_SET_INDEPENDENT) - global_cause = local_cause; + if(local_cause[0] & H5D_MPIO_SET_INDEPENDENT) + global_cause[0] = local_cause[0]; else { int mpi_code; /* MPI error code */ /* Form consensus opinion among all processes about whether to perform * collective I/O */ - if(MPI_SUCCESS != (mpi_code = MPI_Allreduce(&local_cause, &global_cause, 1, MPI_UNSIGNED, MPI_BOR, io_info->comm))) + if(MPI_SUCCESS != (mpi_code = MPI_Allreduce(&local_cause, &global_cause, 2, MPI_UNSIGNED, MPI_BOR, io_info->comm))) HMPI_GOTO_ERROR(FAIL, "MPI_Allreduce failed", mpi_code) + } /* end else */ /* Set the local & global values of no-collective-cause in the API context */ - H5CX_set_mpio_local_no_coll_cause(local_cause); - H5CX_set_mpio_global_no_coll_cause(global_cause); + H5CX_set_mpio_local_no_coll_cause(local_cause[0]); + H5CX_set_mpio_global_no_coll_cause(global_cause[0]); /* Set the return value, based on the global cause */ - ret_value = global_cause > 0 ? FALSE : TRUE; + ret_value = global_cause[0] > 0 ? FALSE : TRUE; + + /* read-proc0-and-bcast if collective and H5S_ALL */ + if(global_cause[0] == 0 && global_cause[1] == 0) + H5FD_MPIO_Proc0_BCast = TRUE; + + /* Set Flag if dataset is both: H5S_ALL and < 2GB in the API context */ + H5CX_set_mpio_Proc0_BCast(H5FD_MPIO_Proc0_BCast); done: FUNC_LEAVE_NOAPI(ret_value) @@ -3069,8 +3102,8 @@ H5D__filtered_collective_chunk_entry_io(H5D_filtered_collective_io_info_t *chunk chunk_entry->chunk_states.new_chunk.length = chunk_entry->chunk_states.chunk_current.length; /* Currently, these chunk reads are done independently and will likely - * cause issues with collective metadata reads enabled. In the future, - * this should be refactored to use collective chunk reads - JTH */ + * cause issues with collective metadata reads enabled. In the future, + * this should be refactored to use collective chunk reads - JTH */ /* Get the original state of parallel I/O transfer mode */ if(H5CX_get_io_xfer_mode(&xfer_mode) < 0) diff --git a/src/H5FDmpio.c b/src/H5FDmpio.c index 87f8b6a..a4b9ef3 100644 --- a/src/H5FDmpio.c +++ b/src/H5FDmpio.c @@ -1414,31 +1414,32 @@ static herr_t H5FD_mpio_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, hid_t H5_ATTR_UNUSED dxpl_id, haddr_t addr, size_t size, void *buf/*out*/) { - H5FD_mpio_t *file = (H5FD_mpio_t*)_file; - MPI_Offset mpi_off; - MPI_Status mpi_stat; /* Status from I/O operation */ - int mpi_code; /* mpi return code */ - MPI_Datatype buf_type = MPI_BYTE; /* MPI description of the selection in memory */ - int size_i; /* Integer copy of 'size' to read */ + H5FD_mpio_t *file = (H5FD_mpio_t*)_file; + MPI_Offset mpi_off; + MPI_Status mpi_stat; /* Status from I/O operation */ + int mpi_code; /* mpi return code */ + MPI_Datatype buf_type = MPI_BYTE; /* MPI description of the selection in memory */ + int size_i; /* Integer copy of 'size' to read */ #if MPI_VERSION >= 3 - MPI_Count bytes_read; /* Number of bytes read in */ + MPI_Count bytes_read = 0; /* Number of bytes read in */ MPI_Count type_size; /* MPI datatype used for I/O's size */ MPI_Count io_size; /* Actual number of bytes requested */ MPI_Count n; #else - int bytes_read; /* Number of bytes read in */ + int bytes_read = 0; /* Number of bytes read in */ int type_size; /* MPI datatype used for I/O's size */ int io_size; /* Actual number of bytes requested */ - int n; + int n; #endif - hbool_t use_view_this_time = FALSE; - herr_t ret_value = SUCCEED; + hbool_t use_view_this_time = FALSE; + hbool_t Proc0_BCast_enabled = FALSE; /* If read-proc0-and-bcast option was used */ + herr_t ret_value = SUCCEED; FUNC_ENTER_NOAPI_NOINIT #ifdef H5FDmpio_DEBUG if (H5FD_mpio_Debug[(int)'t']) - fprintf(stdout, "Entering H5FD_mpio_read\n" ); + fprintf(stdout, "Entering H5FD_mpio_read\n" ); #endif HDassert(file); HDassert(H5FD_MPIO==file->pub.driver_id); @@ -1457,12 +1458,12 @@ H5FD_mpio_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, #ifdef H5FDmpio_DEBUG if (H5FD_mpio_Debug[(int)'r']) fprintf(stdout, "in H5FD_mpio_read mpi_off=%ld size_i=%d\n", - (long)mpi_off, size_i ); + (long)mpi_off, size_i ); #endif /* Only look for MPI views for raw data transfers */ if(type == H5FD_MEM_DRAW) { - H5FD_mpio_xfer_t xfer_mode; /* I/O transfer mode */ + H5FD_mpio_xfer_t xfer_mode; /* I/O transfer mode */ /* Get the transfer mode from the API context */ if(H5CX_get_io_xfer_mode(&xfer_mode) < 0) @@ -1475,7 +1476,7 @@ H5FD_mpio_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, * could mean "use MPI_BYTE" by convention). */ if(xfer_mode==H5FD_MPIO_COLLECTIVE) { - MPI_Datatype file_type; + MPI_Datatype file_type; /* Remember that views are used */ use_view_this_time = TRUE; @@ -1502,8 +1503,8 @@ H5FD_mpio_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, H5FD_mpio_collective_opt_t coll_opt_mode; #ifdef H5FDmpio_DEBUG - if (H5FD_mpio_Debug[(int)'t']) - fprintf(stdout, "H5FD_mpio_read: using MPIO collective mode\n"); + if (H5FD_mpio_Debug[(int)'t']) + fprintf(stdout, "H5FD_mpio_read: using MPIO collective mode\n"); #endif /* Get the collective_opt property to check whether the application wants to do IO individually. */ if(H5CX_get_mpio_coll_opt(&coll_opt_mode) < 0) @@ -1514,8 +1515,23 @@ H5FD_mpio_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, if(H5FD_mpio_Debug[(int)'t']) fprintf(stdout, "H5FD_mpio_read: doing MPI collective IO\n"); #endif - if(MPI_SUCCESS != (mpi_code = MPI_File_read_at_all(file->f, mpi_off, buf, size_i, buf_type, &mpi_stat))) + if(H5CX_get_mpio_Proc0_BCast()) { +#ifdef H5FDmpio_DEBUG + if(H5FD_mpio_Debug[(int)'t']) + fprintf(stdout, "H5FD_mpio_read: doing Proc0-read-and-MPI_Bcast\n"); +#endif + if(file->mpi_rank == 0) { + if(MPI_SUCCESS != (mpi_code = MPI_File_read_at(file->f, mpi_off, buf, size_i, buf_type, &mpi_stat))) + HMPI_GOTO_ERROR(FAIL, "MPI_File_read_at failed", mpi_code) + } + if(MPI_SUCCESS != (mpi_code = MPI_Bcast(buf, size_i, buf_type, 0, file->comm))) + HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed", mpi_code) + Proc0_BCast_enabled = TRUE; + } + else { + if(MPI_SUCCESS != (mpi_code = MPI_File_read_at_all(file->f, mpi_off, buf, size_i, buf_type, &mpi_stat))) HMPI_GOTO_ERROR(FAIL, "MPI_File_read_at_all failed", mpi_code) + } } /* end if */ else { #ifdef H5FDmpio_DEBUG @@ -1534,24 +1550,31 @@ H5FD_mpio_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, HMPI_GOTO_ERROR(FAIL, "MPI_File_set_view failed", mpi_code) } else { if(MPI_SUCCESS != (mpi_code = MPI_File_read_at(file->f, mpi_off, buf, size_i, buf_type, &mpi_stat))) - HMPI_GOTO_ERROR(FAIL, "MPI_File_read_at failed", mpi_code) + HMPI_GOTO_ERROR(FAIL, "MPI_File_read_at failed", mpi_code) } - /* How many bytes were actually read? */ + if( !Proc0_BCast_enabled || (Proc0_BCast_enabled && file->mpi_rank == 0) ) { + /* How many bytes were actually read? */ #if MPI_VERSION >= 3 - if (MPI_SUCCESS != (mpi_code = MPI_Get_elements_x(&mpi_stat, buf_type, &bytes_read))) + if(MPI_SUCCESS != (mpi_code = MPI_Get_elements_x(&mpi_stat, buf_type, &bytes_read))) #else - if (MPI_SUCCESS != (mpi_code = MPI_Get_elements(&mpi_stat, MPI_BYTE, &bytes_read))) + if(MPI_SUCCESS != (mpi_code = MPI_Get_elements(&mpi_stat, MPI_BYTE, &bytes_read))) #endif HMPI_GOTO_ERROR(FAIL, "MPI_Get_elements failed", mpi_code) + } + + if(Proc0_BCast_enabled ) { + if(MPI_SUCCESS != MPI_Bcast(&bytes_read, 1, MPI_LONG_LONG, 0, file->comm)) + HMPI_GOTO_ERROR(FAIL, "MPI_Bcast failed", 0) + } /* Get the type's size */ #if MPI_VERSION >= 3 - if (MPI_SUCCESS != (mpi_code = MPI_Type_size_x(buf_type, &type_size))) + if(MPI_SUCCESS != (mpi_code = MPI_Type_size_x(buf_type, &type_size))) #else - if (MPI_SUCCESS != (mpi_code = MPI_Type_size(buf_type, &type_size))) + if(MPI_SUCCESS != (mpi_code = MPI_Type_size(buf_type, &type_size))) #endif - HMPI_GOTO_ERROR(FAIL, "MPI_Type_size failed", mpi_code) + HMPI_GOTO_ERROR(FAIL, "MPI_Type_size failed", mpi_code) /* Compute the actual number of bytes requested */ io_size=type_size*size_i; @@ -1564,12 +1587,12 @@ H5FD_mpio_read(H5FD_t *_file, H5FD_mem_t H5_ATTR_UNUSED type, * This gives us zeroes beyond end of physical MPI file. */ if ((n=(io_size-bytes_read)) > 0) - HDmemset((char*)buf+bytes_read, 0, (size_t)n); + HDmemset((char*)buf+bytes_read, 0, (size_t)n); done: #ifdef H5FDmpio_DEBUG if (H5FD_mpio_Debug[(int)'t']) - fprintf(stdout, "Leaving H5FD_mpio_read\n" ); + fprintf(stdout, "Leaving H5FD_mpio_read\n" ); #endif FUNC_LEAVE_NOAPI(ret_value) diff --git a/src/H5Pprivate.h b/src/H5Pprivate.h index 866f088..7007635 100644 --- a/src/H5Pprivate.h +++ b/src/H5Pprivate.h @@ -44,7 +44,6 @@ typedef struct H5P_genplist_t H5P_genplist_t; #define H5_COLL_MD_READ_FLAG_NAME "collective_metadata_read" - /****************************/ /* Library Private Typedefs */ /****************************/ diff --git a/src/H5private.h b/src/H5private.h index b654bae..05bfc63 100644 --- a/src/H5private.h +++ b/src/H5private.h @@ -568,6 +568,9 @@ #define H5_PB (1024.0F * 1024.0F * 1024.0F * 1024.0F * 1024.0F) #define H5_EB (1024.0F * 1024.0F * 1024.0F * 1024.0F * 1024.0F * 1024.0F) +/* Define 2GB -- Used for 2GB limitation checks */ +#define H5_2GB (2.0F * 1024.0F * 1024.0F * 1024.0F) + #ifndef H5_HAVE_FLOCK /* flock() operations. Used in the source so we have to define them when * the call is not available (e.g.: Windows). These should NOT be used diff --git a/testpar/t_dset.c b/testpar/t_dset.c index 281d027..35501d8 100644 --- a/testpar/t_dset.c +++ b/testpar/t_dset.c @@ -2649,7 +2649,7 @@ compress_readAll(void) /* Try reading the data */ ret = H5Dread(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, xfer_plist, data_read); - VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + VRFY((ret >= 0), "H5Dread succeeded"); /* Verify data read */ for(u=0; u= 0), "H5Dread succeeded"); - /* Verify all data read are the fill value 0 */ - trdata = rdata; - err_num = 0; - for(i = 0; i < (int)dset_dims[0]; i++) + /* Create DXPL for I/O */ + dxpl = H5Pcreate(H5P_DATASET_XFER); + VRFY((dxpl >= 0), "H5Pcreate succeeded"); + + for(ii = 0; ii < 2; ii++) { + if(ii == 0) + ret = H5Pset_dxpl_mpio(dxpl, H5FD_MPIO_INDEPENDENT); + else + ret = H5Pset_dxpl_mpio(dxpl, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + + /* set entire read buffer with the constant 2 */ + HDmemset(rdata,2,(size_t)(dset_size*sizeof(int))); + /* Read the entire dataset back */ + ret = H5Dread(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, dxpl, rdata); + VRFY((ret >= 0), "H5Dread succeeded"); + + /* Verify all data read are the fill value 0 */ + trdata = rdata; + err_num = 0; + for(i = 0; i < (int)dset_dims[0]; i++) for(j = 0; j < (int)dset_dims[1]; j++) - for(k = 0; k < (int)dset_dims[2]; k++) - for(l = 0; l < (int)dset_dims[3]; l++, twdata++, trdata++) - if(*trdata != 0) - if(err_num++ < MAX_ERR_REPORT || VERBOSE_MED) - printf("Dataset Verify failed at [%d][%d][%d][%d]: expect 0, got %d\n", i, j, k, l, *trdata); - if(err_num > MAX_ERR_REPORT && !VERBOSE_MED) + for(k = 0; k < (int)dset_dims[2]; k++) + for(l = 0; l < (int)dset_dims[3]; l++, twdata++, trdata++) + if(*trdata != 0) + if(err_num++ < MAX_ERR_REPORT || VERBOSE_MED) + printf("Dataset Verify failed at [%d][%d][%d][%d]: expect 0, got %d\n", i, j, k, l, *trdata); + if(err_num > MAX_ERR_REPORT && !VERBOSE_MED) printf("[more errors ...]\n"); - if(err_num){ + if(err_num){ printf("%d errors found in check_value\n", err_num); - nerrors++; + nerrors++; + } } /* Barrier to ensure all processes have completed the above test. */ @@ -681,10 +694,6 @@ void dataset_fillvalue(void) ret = H5Sselect_hyperslab(memspace, H5S_SELECT_SET, req_start, NULL, req_count, NULL); VRFY((ret >= 0), "H5Sselect_hyperslab succeeded on memory dataspace"); - /* Create DXPL for collective I/O */ - dxpl = H5Pcreate(H5P_DATASET_XFER); - VRFY((dxpl >= 0), "H5Pcreate succeeded"); - ret = H5Pset_dxpl_mpio(dxpl, H5FD_MPIO_COLLECTIVE); VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); if(dxfer_coll_type == DXFER_INDEPENDENT_IO) { @@ -711,37 +720,46 @@ void dataset_fillvalue(void) /* * Read dataset after partial write. */ - /* set entire read buffer with the constant 2 */ - HDmemset(rdata,2,(size_t)(dset_size*sizeof(int))); - /* Independently read the entire dataset back */ - ret = H5Dread(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, rdata); - VRFY((ret >= 0), "H5Dread succeeded"); - /* Verify correct data read */ - twdata=wdata; - trdata=rdata; - err_num=0; - for(i=0; i<(int)dset_dims[0]; i++) + for(ii = 0; ii < 2; ii++) { + if(ii == 0) + ret = H5Pset_dxpl_mpio(dxpl, H5FD_MPIO_INDEPENDENT); + else + ret = H5Pset_dxpl_mpio(dxpl, H5FD_MPIO_COLLECTIVE); + VRFY((ret >= 0), "H5Pset_dxpl_mpio succeeded"); + + /* set entire read buffer with the constant 2 */ + HDmemset(rdata,2,(size_t)(dset_size*sizeof(int))); + /* Read the entire dataset back */ + ret = H5Dread(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, dxpl, rdata); + VRFY((ret >= 0), "H5Dread succeeded"); + + /* Verify correct data read */ + twdata=wdata; + trdata=rdata; + err_num=0; + for(i=0; i<(int)dset_dims[0]; i++) for(j=0; j<(int)dset_dims[1]; j++) - for(k=0; k<(int)dset_dims[2]; k++) - for(l=0; l<(int)dset_dims[3]; l++, twdata++, trdata++) - if(i MAX_ERR_REPORT && !VERBOSE_MED) + for(k=0; k<(int)dset_dims[2]; k++) + for(l=0; l<(int)dset_dims[3]; l++, twdata++, trdata++) + if(i MAX_ERR_REPORT && !VERBOSE_MED) printf("[more errors ...]\n"); - if(err_num){ + if(err_num){ printf("%d errors found in check_value\n", err_num); - nerrors++; + nerrors++; + } } - + /* Close all file objects */ ret = H5Dclose(dataset); VRFY((ret >= 0), "H5Dclose succeeded"); @@ -856,7 +874,7 @@ void collective_group_write(void) if(!((m+1) % 10)) { printf("created %d groups\n", m+1); MPI_Barrier(MPI_COMM_WORLD); - } + } #endif /* BARRIER_CHECKS */ } diff --git a/testpar/t_pread.c b/testpar/t_pread.c index 0905d44..a6a6a7d 100644 --- a/testpar/t_pread.c +++ b/testpar/t_pread.c @@ -46,7 +46,7 @@ completely foolproof is to underestimate the ingenuity of complete\n\ fools.\n"; static int generate_test_file(MPI_Comm comm, int mpi_rank, int group); -static int test_parallel_read(MPI_Comm comm, int mpi_rank, int group); +static int test_parallel_read(MPI_Comm comm, int mpi_rank, int mpi_size, int group); static char *test_argv0 = NULL; @@ -413,7 +413,7 @@ generate_test_file( MPI_Comm comm, int mpi_rank, int group_id ) * Function: test_parallel_read * * Purpose: This actually tests the superblock optimization - * and covers the two primary cases we're interested in. + * and covers the three primary cases we're interested in. * 1). That HDF5 files can be opened in parallel by * the rank 0 process and that the superblock * offset is correctly broadcast to the other @@ -423,6 +423,10 @@ generate_test_file( MPI_Comm comm, int mpi_rank, int group_id ) * subgroups of MPI_COMM_WORLD and that each * subgroup operates as described in (1) to * collectively read the data. + * 3). Testing proc0-read-and-MPI_Bcast using + * sub-communicators, and reading into + * a memory space that is different from the + * file space. * * The global MPI rank is used for reading and * writing data for process specific data in the @@ -444,7 +448,7 @@ generate_test_file( MPI_Comm comm, int mpi_rank, int group_id ) *------------------------------------------------------------------------- */ static int -test_parallel_read(MPI_Comm comm, int mpi_rank, int group_id) +test_parallel_read(MPI_Comm comm, int mpi_rank, int mpi_size, int group_id) { const char *failure_mssg; const char *fcn_name = "test_parallel_read()"; @@ -457,8 +461,12 @@ test_parallel_read(MPI_Comm comm, int mpi_rank, int group_id) hid_t fapl_id = -1; hid_t file_id = -1; hid_t dset_id = -1; + hid_t dxpl_id = H5P_DEFAULT; hid_t memspace = -1; hid_t filespace = -1; + hid_t filetype = -1; + size_t filetype_size; + hssize_t dset_size; hsize_t i; hsize_t offset; hsize_t count = COUNT; @@ -606,14 +614,6 @@ test_parallel_read(MPI_Comm comm, int mpi_rank, int group_id) } } - /* close file, etc. */ - if ( pass || (dset_id != -1) ) { - if ( H5Dclose(dset_id) < 0 ) { - pass = false; - failure_mssg = "H5Dclose(dset_id) failed.\n"; - } - } - if ( pass || (memspace != -1) ) { if ( H5Sclose(memspace) < 0 ) { pass = false; @@ -628,6 +628,202 @@ test_parallel_read(MPI_Comm comm, int mpi_rank, int group_id) } } + /* free data_slice if it has been allocated */ + if ( data_slice != NULL ) { + HDfree(data_slice); + data_slice = NULL; + } + + /* + * Test reading proc0-read-and-bcast with sub-communicators + */ + + /* Don't test with more than 6 processes to avoid memory issues */ + + if( group_size <= 6 ) { + + if ( (filespace = H5Dget_space(dset_id )) < 0 ) { + pass = FALSE; + failure_mssg = "H5Dget_space failed.\n"; + } + + if ( (dset_size = H5Sget_simple_extent_npoints(filespace)) < 0 ) { + pass = FALSE; + failure_mssg = "H5Sget_simple_extent_npoints failed.\n"; + } + + if ( (filetype = H5Dget_type(dset_id)) < 0 ) { + pass = FALSE; + failure_mssg = "H5Dget_type failed.\n"; + } + + if ( (filetype_size = H5Tget_size(filetype)) == 0 ) { + pass = FALSE; + failure_mssg = "H5Tget_size failed.\n"; + } + + if ( H5Tclose(filetype) < 0 ) { + pass = FALSE; + failure_mssg = "H5Tclose failed.\n"; + }; + + if ( (data_slice = (float *)HDmalloc((size_t)dset_size*filetype_size)) == NULL ) { + pass = FALSE; + failure_mssg = "malloc of data_slice failed.\n"; + } + + if ( pass ) { + if ( (dxpl_id = H5Pcreate(H5P_DATASET_XFER)) < 0 ) { + pass = FALSE; + failure_mssg = "H5Pcreate(H5P_DATASET_XFER) failed.\n"; + } + } + + if ( pass ) { + if ( (H5Pset_dxpl_mpio(dxpl_id, H5FD_MPIO_COLLECTIVE)) < 0 ) { + pass = FALSE; + failure_mssg = "H5Pset_dxpl_mpio() failed.\n"; + } + } + + /* read H5S_ALL section */ + if ( pass ) { + if ( (H5Dread(dset_id, H5T_NATIVE_FLOAT, H5S_ALL, + H5S_ALL, dxpl_id, data_slice)) < 0 ) { + pass = FALSE; + failure_mssg = "H5Dread() failed\n"; + } + } + + /* verify the data */ + if ( pass ) { + + if ( comm == MPI_COMM_WORLD ) /* test 1 */ + nextValue = 0; + else if ( group_id == 0 ) /* test 2 group 0 */ + nextValue = 0; + else /* test 2 group 1 */ + nextValue = (float)((hsize_t)( mpi_size / 2 )*count); + + i = 0; + while ( ( pass ) && ( i < (hsize_t)dset_size ) ) { + /* what we really want is data_slice[i] != nextValue -- + * the following is a circumlocution to shut up the + * the compiler. + */ + if ( ( data_slice[i] > nextValue ) || + ( data_slice[i] < nextValue ) ) { + pass = FALSE; + failure_mssg = "Unexpected dset contents.\n"; + } + nextValue += 1; + i++; + } + } + + if ( pass || (filespace != -1) ) { + if ( H5Sclose(filespace) < 0 ) { + pass = false; + failure_mssg = "H5Sclose(filespace) failed.\n"; + } + } + + /* free data_slice if it has been allocated */ + if ( data_slice != NULL ) { + HDfree(data_slice); + data_slice = NULL; + } + + /* + * Read an H5S_ALL filespace into a hyperslab defined memory space + */ + + if ( (data_slice = (float *)HDmalloc((size_t)(dset_size*2)*filetype_size)) == NULL ) { + pass = FALSE; + failure_mssg = "malloc of data_slice failed.\n"; + } + + /* setup memspace */ + if ( pass ) { + dims[0] = (hsize_t)dset_size*2; + if ( (memspace = H5Screate_simple(1, dims, NULL)) < 0 ) { + pass = FALSE; + failure_mssg = "H5Screate_simple(1, dims, NULL) failed\n"; + } + } + if ( pass ) { + offset = (hsize_t)dset_size; + if ( (H5Sselect_hyperslab(memspace, H5S_SELECT_SET, + &offset, NULL, &offset, NULL)) < 0 ) { + pass = FALSE; + failure_mssg = "H5Sselect_hyperslab() failed\n"; + } + } + + /* read this processes section of the data */ + if ( pass ) { + if ( (H5Dread(dset_id, H5T_NATIVE_FLOAT, memspace, + H5S_ALL, dxpl_id, data_slice)) < 0 ) { + pass = FALSE; + failure_mssg = "H5Dread() failed\n"; + } + } + + /* verify the data */ + if ( pass ) { + + if ( comm == MPI_COMM_WORLD ) /* test 1 */ + nextValue = 0; + else if ( group_id == 0 ) /* test 2 group 0 */ + nextValue = 0; + else /* test 2 group 1 */ + nextValue = (float)((hsize_t)(mpi_size / 2)*count); + + i = (hsize_t)dset_size; + while ( ( pass ) && ( i < (hsize_t)dset_size ) ) { + /* what we really want is data_slice[i] != nextValue -- + * the following is a circumlocution to shut up the + * the compiler. + */ + if ( ( data_slice[i] > nextValue ) || + ( data_slice[i] < nextValue ) ) { + pass = FALSE; + failure_mssg = "Unexpected dset contents.\n"; + } + nextValue += 1; + i++; + } + } + + if ( pass || (memspace != -1) ) { + if ( H5Sclose(memspace) < 0 ) { + pass = false; + failure_mssg = "H5Sclose(memspace) failed.\n"; + } + } + + /* free data_slice if it has been allocated */ + if ( data_slice != NULL ) { + HDfree(data_slice); + data_slice = NULL; + } + + if ( pass || (dxpl_id != -1) ) { + if ( H5Pclose(dxpl_id) < 0 ) { + pass = false; + failure_mssg = "H5Pclose(dxpl_id) failed.\n"; + } + } + } + + /* close file, etc. */ + if ( pass || (dset_id != -1) ) { + if ( H5Dclose(dset_id) < 0 ) { + pass = false; + failure_mssg = "H5Dclose(dset_id) failed.\n"; + } + } + if ( pass || (file_id != -1) ) { if ( H5Fclose(file_id) < 0 ) { pass = false; @@ -668,17 +864,9 @@ test_parallel_read(MPI_Comm comm, int mpi_rank, int group_id) HDfprintf(stdout, "%s: failure_mssg = \"%s\"\n", fcn_name, failure_mssg); } - HDremove(reloc_data_filename); } - /* free data_slice if it has been allocated */ - if ( data_slice != NULL ) { - HDfree(data_slice); - data_slice = NULL; - } - - return( ! pass ); } /* test_parallel_read() */ @@ -803,7 +991,7 @@ main( int argc, char **argv) } /* Now read the generated test file (stil using MPI_COMM_WORLD) */ - nerrs += test_parallel_read( MPI_COMM_WORLD, mpi_rank, which_group); + nerrs += test_parallel_read( MPI_COMM_WORLD, mpi_rank, mpi_size, which_group); if ( nerrs > 0 ) { if ( mpi_rank == 0 ) { @@ -819,7 +1007,7 @@ main( int argc, char **argv) } /* run the 2nd set of tests */ - nerrs += test_parallel_read(group_comm, mpi_rank, which_group); + nerrs += test_parallel_read(group_comm, mpi_rank, mpi_size, which_group); if ( nerrs > 0 ) { if ( mpi_rank == 0 ) { -- cgit v0.12 From ffff13f0f3fef61d98012983ea71659339fa502c Mon Sep 17 00:00:00 2001 From: "M. Scot Breitenfeld" Date: Wed, 2 Jan 2019 11:11:24 -0600 Subject: Documented HDFFV-10652 --- release_docs/RELEASE.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt index e386c8b..a92881e 100644 --- a/release_docs/RELEASE.txt +++ b/release_docs/RELEASE.txt @@ -132,7 +132,13 @@ New Features Parallel Library: ----------------- - - + - Changed the default behavior in parallel when reading the same dataset in its entirely + (i.e. H5S_ALL dataset selection) which is being read by all the processes collectively. + The new behavior is the HDF5 library will use an MPI_Bcast to pass the data read from + the disk by the root process to the remain processes in the MPI communicator associated + with the HDF5 file. + + (MSB - 2019/01/02, HDFFV-10652) Fortran Library: ---------------- -- cgit v0.12 From 774098afa6c27dc3800e36d4e6a0a5dc0988e30e Mon Sep 17 00:00:00 2001 From: "M. Scot Breitenfeld" Date: Wed, 2 Jan 2019 11:48:48 -0600 Subject: updated defined constants --- src/H5Dmpio.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/H5Dmpio.c b/src/H5Dmpio.c index e1c0edb..f6b1692 100644 --- a/src/H5Dmpio.c +++ b/src/H5Dmpio.c @@ -83,6 +83,10 @@ /* Macros to represent the regularity of the selection for multiple chunk IO case. */ #define H5D_CHUNK_SELECT_REG 1 +/* Macros for reason's to not enable read-proc-and-bcast. */ +#define H5D_MPIO_PROC0_BCAST 0x00 +#define H5D_MPIO_NOT_H5S_ALL 0x01 +#define H5D_MPIO_GREATER_THAN_2GB 0x02 /******************/ /* Local Typedefs */ @@ -281,9 +285,9 @@ H5D__mpio_opt_possible(const H5D_io_info_t *io_info, const H5S_t *file_space, const H5S_t *mem_space, const H5D_type_info_t *type_info) { H5FD_mpio_xfer_t io_xfer_mode; /* MPI I/O transfer mode */ - unsigned local_cause[2] = {0,0}; /* [0] Local reason(s) for breaking collective mode */ - /* [1] Flag if dataset is both: H5S_ALL and small */ - unsigned global_cause[2] = {0,0}; /* Global reason(s) for breaking collective mode */ + unsigned local_cause[2] = {0,H5D_MPIO_PROC0_BCAST}; /* [0] Local reason(s) for breaking collective mode */ + /* [1] Flag if dataset is both: H5S_ALL and small */ + unsigned global_cause[2] = {0,H5D_MPIO_PROC0_BCAST}; /* Global reason(s) for breaking collective mode */ htri_t ret_value = SUCCEED; /* Return value */ hbool_t H5FD_MPIO_Proc0_BCast; /* Flag if dataset is both: H5S_ALL and < 2GB */ @@ -354,7 +358,7 @@ H5D__mpio_opt_possible(const H5D_io_info_t *io_info, const H5S_t *file_space, /* Flag to do a MPI_Bcast of the data from one proc instead of * having all the processes involved in the persistent I/O. */ - local_cause[1] |= 0x01; + local_cause[1] |= H5D_MPIO_NOT_H5S_ALL; } else { @@ -367,7 +371,7 @@ H5D__mpio_opt_possible(const H5D_io_info_t *io_info, const H5S_t *file_space, H5D__get_storage_size(io_info->dset, &dset_storage_size); if(dset_storage_size > ((hsize_t)(H5_2GB) - 1) ) { - local_cause[1] |= 0x02; + local_cause[1] |= H5D_MPIO_GREATER_THAN_2GB; } } @@ -393,7 +397,7 @@ H5D__mpio_opt_possible(const H5D_io_info_t *io_info, const H5S_t *file_space, ret_value = global_cause[0] > 0 ? FALSE : TRUE; /* read-proc0-and-bcast if collective and H5S_ALL */ - if(global_cause[0] == 0 && global_cause[1] == 0) + if(global_cause[0] == 0 && global_cause[1] == H5D_MPIO_PROC0_BCAST) H5FD_MPIO_Proc0_BCast = TRUE; /* Set Flag if dataset is both: H5S_ALL and < 2GB in the API context */ -- cgit v0.12 From 422d6daf6bdee030d0ffac5fa6d7bbe37b1d5501 Mon Sep 17 00:00:00 2001 From: "M. Scot Breitenfeld" Date: Wed, 2 Jan 2019 11:53:41 -0600 Subject: typo --- src/H5Dmpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/H5Dmpio.c b/src/H5Dmpio.c index f6b1692..8850c59 100644 --- a/src/H5Dmpio.c +++ b/src/H5Dmpio.c @@ -83,7 +83,7 @@ /* Macros to represent the regularity of the selection for multiple chunk IO case. */ #define H5D_CHUNK_SELECT_REG 1 -/* Macros for reason's to not enable read-proc-and-bcast. */ +/* Macros for reasons to not enable read-proc-and-bcast. */ #define H5D_MPIO_PROC0_BCAST 0x00 #define H5D_MPIO_NOT_H5S_ALL 0x01 #define H5D_MPIO_GREATER_THAN_2GB 0x02 -- cgit v0.12 From b39960580ec27a95bbeb9e99a2c94358c923f70b Mon Sep 17 00:00:00 2001 From: "M. Scot Breitenfeld" Date: Wed, 2 Jan 2019 11:53:41 -0600 Subject: typo --- src/H5Dmpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/H5Dmpio.c b/src/H5Dmpio.c index f6b1692..8850c59 100644 --- a/src/H5Dmpio.c +++ b/src/H5Dmpio.c @@ -83,7 +83,7 @@ /* Macros to represent the regularity of the selection for multiple chunk IO case. */ #define H5D_CHUNK_SELECT_REG 1 -/* Macros for reason's to not enable read-proc-and-bcast. */ +/* Macros for reasons to not enable read-proc-and-bcast. */ #define H5D_MPIO_PROC0_BCAST 0x00 #define H5D_MPIO_NOT_H5S_ALL 0x01 #define H5D_MPIO_GREATER_THAN_2GB 0x02 -- cgit v0.12 From 390a3f67282e64752a14e2c1ed13545fde8712d1 Mon Sep 17 00:00:00 2001 From: "M. Scot Breitenfeld" Date: Thu, 3 Jan 2019 09:47:14 -0600 Subject: Added chunked dataset, H5S_ALL test --- testpar/t_pread.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 111 insertions(+), 3 deletions(-) diff --git a/testpar/t_pread.c b/testpar/t_pread.c index a6a6a7d..f3d4730 100644 --- a/testpar/t_pread.c +++ b/testpar/t_pread.c @@ -34,6 +34,8 @@ const char *FILENAMES[NFILENAME + 1]={"reloc_t_pread_data_file", #define COUNT 1000 +#define LIMIT_NPROC 6 + hbool_t pass = true; static const char *random_hdf5_text = "Now is the time for all first-time-users of HDF5 to read their \ @@ -108,6 +110,9 @@ generate_test_file( MPI_Comm comm, int mpi_rank, int group_id ) hid_t fapl_id = -1; hid_t dxpl_id = -1; hid_t dset_id = -1; + hid_t dset_id_ch = -1; + hid_t dcpl_id = H5P_DEFAULT; + hsize_t chunk[1]; float nextValue; float *data_slice = NULL; @@ -272,6 +277,55 @@ generate_test_file( MPI_Comm comm, int mpi_rank, int group_id ) } } + + /* create a chunked dataset */ + chunk[0] = COUNT/8; + + if ( pass ) { + if ( (dcpl_id = H5Pcreate (H5P_DATASET_CREATE)) < 0 ) { + pass = false; + failure_mssg = "H5Pcreate() failed.\n"; + } + } + + if ( pass ) { + if ( (H5Pset_chunk (dcpl_id, 1, chunk) ) < 0 ) { + pass = false; + failure_mssg = "H5Pset_chunk() failed.\n"; + } + } + + if ( pass ) { + + if ( (dset_id_ch = H5Dcreate2(file_id, "dataset0_chunked", H5T_NATIVE_FLOAT, + filespace, H5P_DEFAULT, dcpl_id, + H5P_DEFAULT)) < 0 ) { + pass = false; + failure_mssg = "H5Dcreate2() failed.\n"; + } + } + + if ( pass ) { + if ( (H5Dwrite(dset_id_ch, H5T_NATIVE_FLOAT, memspace, + filespace, dxpl_id, data_slice)) < 0 ) { + pass = false; + failure_mssg = "H5Dwrite() failed.\n"; + } + } + if ( pass || (dcpl_id != -1)) { + if ( H5Pclose(dcpl_id) < 0 ) { + pass = false; + failure_mssg = "H5Pclose(dcpl_id) failed.\n"; + } + } + + if ( pass || (dset_id_ch != -1)) { + if ( H5Dclose(dset_id_ch) < 0 ) { + pass = false; + failure_mssg = "H5Dclose(dset_id_ch) failed.\n"; + } + } + /* close file, etc. */ if ( pass || (dset_id != -1)) { if ( H5Dclose(dset_id) < 0 ) { @@ -426,7 +480,7 @@ generate_test_file( MPI_Comm comm, int mpi_rank, int group_id ) * 3). Testing proc0-read-and-MPI_Bcast using * sub-communicators, and reading into * a memory space that is different from the - * file space. + * file space, and chunked datasets. * * The global MPI rank is used for reading and * writing data for process specific data in the @@ -461,6 +515,7 @@ test_parallel_read(MPI_Comm comm, int mpi_rank, int mpi_size, int group_id) hid_t fapl_id = -1; hid_t file_id = -1; hid_t dset_id = -1; + hid_t dset_id_ch = -1; hid_t dxpl_id = H5P_DEFAULT; hid_t memspace = -1; hid_t filespace = -1; @@ -560,6 +615,14 @@ test_parallel_read(MPI_Comm comm, int mpi_rank, int mpi_size, int group_id) } } + /* open the chunked data set */ + if ( pass ) { + if ( (dset_id_ch = H5Dopen2(file_id, "dataset0_chunked", H5P_DEFAULT)) < 0 ) { + pass = FALSE; + failure_mssg = "H5Dopen2() failed\n"; + } + } + /* setup memspace */ if ( pass ) { dims[0] = count; @@ -638,9 +701,9 @@ test_parallel_read(MPI_Comm comm, int mpi_rank, int mpi_size, int group_id) * Test reading proc0-read-and-bcast with sub-communicators */ - /* Don't test with more than 6 processes to avoid memory issues */ + /* Don't test with more than LIMIT_NPROC processes to avoid memory issues */ - if( group_size <= 6 ) { + if( group_size <= LIMIT_NPROC ) { if ( (filespace = H5Dget_space(dset_id )) < 0 ) { pass = FALSE; @@ -721,6 +784,44 @@ test_parallel_read(MPI_Comm comm, int mpi_rank, int mpi_size, int group_id) } } + /* read H5S_ALL section for the chunked dataset */ + for ( i = 0; i < (hsize_t)dset_size; i++) { + data_slice[i] = 0; + } + if ( pass ) { + if ( (H5Dread(dset_id_ch, H5T_NATIVE_FLOAT, H5S_ALL, + H5S_ALL, dxpl_id, data_slice)) < 0 ) { + pass = FALSE; + failure_mssg = "H5Dread() failed\n"; + } + } + + /* verify the data */ + if ( pass ) { + + if ( comm == MPI_COMM_WORLD ) /* test 1 */ + nextValue = 0; + else if ( group_id == 0 ) /* test 2 group 0 */ + nextValue = 0; + else /* test 2 group 1 */ + nextValue = (float)((hsize_t)( mpi_size / 2 )*count); + + i = 0; + while ( ( pass ) && ( i < (hsize_t)dset_size ) ) { + /* what we really want is data_slice[i] != nextValue -- + * the following is a circumlocution to shut up the + * the compiler. + */ + if ( ( data_slice[i] > nextValue ) || + ( data_slice[i] < nextValue ) ) { + pass = FALSE; + failure_mssg = "Unexpected chunked dset contents.\n"; + } + nextValue += 1; + i++; + } + } + if ( pass || (filespace != -1) ) { if ( H5Sclose(filespace) < 0 ) { pass = false; @@ -824,6 +925,13 @@ test_parallel_read(MPI_Comm comm, int mpi_rank, int mpi_size, int group_id) } } + if ( pass || (dset_id_ch != -1) ) { + if ( H5Dclose(dset_id_ch) < 0 ) { + pass = false; + failure_mssg = "H5Dclose(dset_id_ch) failed.\n"; + } + } + if ( pass || (file_id != -1) ) { if ( H5Fclose(file_id) < 0 ) { pass = false; -- cgit v0.12 From b4d4d371a03158c39f120b1bde6c4bd51f1b2eb6 Mon Sep 17 00:00:00 2001 From: Scot Breitenfeld Date: Wed, 5 Dec 2018 10:45:54 -0600 Subject: HDFFV-10443: Add "field" parameter to H5Oinfo* and H5Ovisit* APIs. --- config/cmake_ext_mod/ConfigureChecks.cmake | 1 + configure.ac | 9 + fortran/src/H5Of.c | 48 ++-- fortran/src/H5Off.F90 | 98 ++++++-- fortran/src/H5_f.c | 11 + fortran/src/H5_ff.F90 | 73 +++++- fortran/src/H5f90global.F90 | 13 + fortran/src/H5f90proto.h | 10 +- fortran/src/H5match_types.c | 13 + fortran/src/hdf5_fortrandll.def.in | 1 + fortran/test/tH5O_F03.F90 | 390 +++++++++++++++++++++++++++-- src/H5Oint.c | 7 +- src/H5Pprivate.h | 1 + src/H5private.h | 3 - 14 files changed, 600 insertions(+), 78 deletions(-) diff --git a/config/cmake_ext_mod/ConfigureChecks.cmake b/config/cmake_ext_mod/ConfigureChecks.cmake index 0424ed6..c24c1f8 100644 --- a/config/cmake_ext_mod/ConfigureChecks.cmake +++ b/config/cmake_ext_mod/ConfigureChecks.cmake @@ -413,6 +413,7 @@ HDF_CHECK_TYPE_SIZE (off64_t ${HDF_PREFIX}_SIZEOF_OFF64_T) if (NOT ${HDF_PREFIX}_SIZEOF_OFF64_T) set (${HDF_PREFIX}_SIZEOF_OFF64_T 0) endif () +HDF_CHECK_TYPE_SIZE (time_t ${HDF_PREFIX}_SIZEOF_TIME_T) #----------------------------------------------------------------------------- # Extra C99 types diff --git a/configure.ac b/configure.ac index 21ad68b..1b12e57 100644 --- a/configure.ac +++ b/configure.ac @@ -1210,6 +1210,15 @@ EOF AC_CHECK_SIZEOF([bool]) fi +AC_CHECK_SIZEOF(time_t, [], [ +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_TIME_H +#include +#endif +]) + ## Checkpoint the cache AC_CACHE_SAVE diff --git a/fortran/src/H5Of.c b/fortran/src/H5Of.c index 45b7f09..7951c77 100644 --- a/fortran/src/H5Of.c +++ b/fortran/src/H5Of.c @@ -27,11 +27,15 @@ fill_h5o_info_t_f(H5O_info_t Oinfo, H5O_info_t_f *object_info); int_f fill_h5o_info_t_f(H5O_info_t Oinfo, H5O_info_t_f *object_info) { + /* This function does not used the field parameter because we want + * this function to fill the unfilled fields with C's default values. + */ + struct tm *ts; object_info->fileno = Oinfo.fileno; object_info->addr = (haddr_t_f)Oinfo.addr; - + object_info->type = (int_f)Oinfo.type; object_info->rc = (int_f)Oinfo.rc; @@ -96,6 +100,8 @@ fill_h5o_info_t_f(H5O_info_t Oinfo, H5O_info_t_f *object_info) { object_info->meta_size.obj.index_size = (hsize_t_f)Oinfo.meta_size.obj.index_size; object_info->meta_size.obj.heap_size = (hsize_t_f)Oinfo.meta_size.obj.heap_size; + object_info->meta_size.attr.index_size = (hsize_t_f)Oinfo.meta_size.attr.index_size; + object_info->meta_size.attr.heap_size = (hsize_t_f)Oinfo.meta_size.attr.heap_size; return 0; @@ -138,7 +144,7 @@ h5olink_c (hid_t_f *object_id, hid_t_f *new_loc_id, _fcd name, size_t_f *namelen * Call H5Olink function. */ if((hid_t_f)H5Olink((hid_t)*object_id, (hid_t)*new_loc_id, c_name, - (hid_t)*lcpl_id, (hid_t)*lapl_id) < 0) + (hid_t)*lcpl_id, (hid_t)*lapl_id) < 0) HGOTO_DONE(FAIL); done: @@ -229,6 +235,7 @@ h5oclose_c ( hid_t_f *object_id ) * idx - Iteration position at which to start * op - Callback function passing data regarding the link to the calling application * op_data - User-defined pointer to data required by the application for its processing of the link + * fields - Flags specifying the fields to include in object_info. * * OUTPUTS * idx - Position at which an interrupted iteration may be restarted @@ -241,7 +248,7 @@ h5oclose_c ( hid_t_f *object_id ) * SOURCE */ int_f -h5ovisit_c(hid_t_f *group_id, int_f *index_type, int_f *order, H5O_iterate_t op, void *op_data ) +h5ovisit_c(hid_t_f *group_id, int_f *index_type, int_f *order, H5O_iterate_t op, void *op_data, int_f *fields ) /******/ { int_f ret_value = -1; /* Return value */ @@ -250,7 +257,8 @@ h5ovisit_c(hid_t_f *group_id, int_f *index_type, int_f *order, H5O_iterate_t op, /* * Call H5Ovisit2 */ - func_ret_value = H5Ovisit2( (hid_t)*group_id, (H5_index_t)*index_type, (H5_iter_order_t)*order, op, op_data, H5O_INFO_ALL); + + func_ret_value = H5Ovisit2( (hid_t)*group_id, (H5_index_t)*index_type, (H5_iter_order_t)*order, op, op_data, (uint)*fields); ret_value = (int_f)func_ret_value; @@ -302,6 +310,7 @@ h5oopen_by_addr_c (hid_t_f *loc_id, haddr_t_f *addr, hid_t_f *obj_id) * name - Name of group, relative to loc_id. * namelen - Name length. * lapl_id - Link access property list. + * fields - Flags specifying the fields to include in object_info. * OUTPUTS * object_info - Buffer in which to return object information. * @@ -314,7 +323,7 @@ h5oopen_by_addr_c (hid_t_f *loc_id, haddr_t_f *addr, hid_t_f *obj_id) */ int_f h5oget_info_by_name_c (hid_t_f *loc_id, _fcd name, size_t_f *namelen, hid_t_f *lapl_id, - H5O_info_t_f *object_info) + H5O_info_t_f *object_info, int_f *fields) /******/ { char *c_name = NULL; /* Buffer to hold C string */ @@ -331,10 +340,10 @@ h5oget_info_by_name_c (hid_t_f *loc_id, _fcd name, size_t_f *namelen, hid_t_f *l * Call H5Oinfo_by_name function. */ if(H5Oget_info_by_name2((hid_t)*loc_id, c_name, - &Oinfo, H5O_INFO_ALL, (hid_t)*lapl_id) < 0) + &Oinfo, (uint)*fields, (hid_t)*lapl_id) < 0) HGOTO_DONE(FAIL); - ret_value = fill_h5o_info_t_f(Oinfo,object_info); + ret_value = fill_h5o_info_t_f(Oinfo, object_info); done: if(c_name) @@ -354,6 +363,7 @@ h5oget_info_by_name_c (hid_t_f *loc_id, _fcd name, size_t_f *namelen, hid_t_f *l * lapl_id - Link access property list. * OUTPUTS * object_info - Buffer in which to return object information. + * fields - Flags specifying the fields to include in object_info. * * RETURNS * 0 on success, -1 on failure @@ -364,7 +374,7 @@ h5oget_info_by_name_c (hid_t_f *loc_id, _fcd name, size_t_f *namelen, hid_t_f *l */ int_f h5oget_info_by_idx_c (hid_t_f *loc_id, _fcd group_name, size_t_f *namelen, - int_f *index_field, int_f *order, hsize_t_f *n, hid_t_f *lapl_id, H5O_info_t_f *object_info) + int_f *index_field, int_f *order, hsize_t_f *n, hid_t_f *lapl_id, H5O_info_t_f *object_info, int_f *fields) /******/ { char *c_group_name = NULL; /* Buffer to hold C string */ @@ -386,7 +396,7 @@ h5oget_info_by_idx_c (hid_t_f *loc_id, _fcd group_name, size_t_f *namelen, * Call H5Oinfo_by_idx function. */ if(H5Oget_info_by_idx2((hid_t)*loc_id, c_group_name, c_index_field, c_order, (hsize_t)*n, - &Oinfo, H5O_INFO_ALL, (hid_t)*lapl_id) < 0) + &Oinfo, (uint)*fields, (hid_t)*lapl_id) < 0) HGOTO_DONE(FAIL); ret_value = fill_h5o_info_t_f(Oinfo,object_info); @@ -404,6 +414,7 @@ h5oget_info_by_idx_c (hid_t_f *loc_id, _fcd group_name, size_t_f *namelen, * Calls H5Oget_info * INPUTS * object_id - Identifier for target object. + * fields - Flags specifying the fields to include in object_info. * OUTPUTS * object_info - Buffer in which to return object information. * @@ -415,7 +426,7 @@ h5oget_info_by_idx_c (hid_t_f *loc_id, _fcd group_name, size_t_f *namelen, * SOURCE */ int_f -h5oget_info_c (hid_t_f *object_id, H5O_info_t_f *object_info) +h5oget_info_c (hid_t_f *object_id, H5O_info_t_f *object_info, int_f *fields) /******/ { int_f ret_value = 0; /* Return value */ @@ -424,7 +435,7 @@ h5oget_info_c (hid_t_f *object_id, H5O_info_t_f *object_info) /* * Call H5Oinfo_by_name function. */ - if(H5Oget_info2((hid_t)*object_id, &Oinfo, H5O_INFO_ALL) < 0) + if(H5Oget_info2((hid_t)*object_id, &Oinfo, (uint)*fields) < 0) HGOTO_DONE(FAIL); ret_value = fill_h5o_info_t_f(Oinfo,object_info); @@ -457,8 +468,8 @@ h5oget_info_c (hid_t_f *object_id, H5O_info_t_f *object_info) */ int_f h5ocopy_c (hid_t_f *src_loc_id, _fcd src_name, size_t_f *src_name_len, - hid_t_f *dst_loc_id, _fcd dst_name, size_t_f *dst_name_len, - hid_t_f *ocpypl_id, hid_t_f *lcpl_id ) + hid_t_f *dst_loc_id, _fcd dst_name, size_t_f *dst_name_len, + hid_t_f *ocpypl_id, hid_t_f *lcpl_id ) /******/ { char *c_src_name = NULL; /* Buffer to hold C string */ @@ -478,7 +489,7 @@ h5ocopy_c (hid_t_f *src_loc_id, _fcd src_name, size_t_f *src_name_len, * Call H5Ocopy function. */ if(H5Ocopy( (hid_t)*src_loc_id, c_src_name, (hid_t)*dst_loc_id, c_dst_name, - (hid_t)*ocpypl_id, (hid_t)*lcpl_id) < 0) + (hid_t)*ocpypl_id, (hid_t)*lcpl_id) < 0) HGOTO_DONE(FAIL); done: @@ -503,6 +514,7 @@ h5ocopy_c (hid_t_f *src_loc_id, _fcd src_name, size_t_f *src_name_len, * idx - Iteration position at which to start * op - Callback function passing data regarding the link to the calling application * op_data - User-defined pointer to data required by the application for its processing of the link + * fields - Flags specifying the fields to include in object_info. * * OUTPUTS * idx - Position at which an interrupted iteration may be restarted @@ -516,7 +528,7 @@ h5ocopy_c (hid_t_f *src_loc_id, _fcd src_name, size_t_f *src_name_len, */ int_f h5ovisit_by_name_c(hid_t_f *loc_id, _fcd object_name, size_t_f *namelen, int_f *index_type, int_f *order, - H5O_iterate_t op, void *op_data, hid_t_f *lapl_id ) + H5O_iterate_t op, void *op_data, hid_t_f *lapl_id, int_f *fields ) /******/ { int_f ret_value = -1; /* Return value */ @@ -533,7 +545,7 @@ h5ovisit_by_name_c(hid_t_f *loc_id, _fcd object_name, size_t_f *namelen, int_f * Call H5Ovisit */ func_ret_value = H5Ovisit_by_name2( (hid_t)*loc_id, c_object_name, (H5_index_t)*index_type, (H5_iter_order_t)*order, - op, op_data, H5O_INFO_ALL, (hid_t)*lapl_id); + op, op_data, (uint)*fields, (hid_t)*lapl_id); ret_value = (int_f)func_ret_value; done: @@ -763,7 +775,7 @@ h5oset_comment_by_name_c (hid_t_f *object_id, _fcd name, size_t_f *namelen, _fc */ int_f h5oopen_by_idx_c (hid_t_f *loc_id, _fcd group_name, size_t_f *group_namelen, - int_f *index_type, int_f *order, hsize_t_f *n, hid_t_f *obj_id, hid_t_f *lapl_id) + int_f *index_type, int_f *order, hsize_t_f *n, hid_t_f *obj_id, hid_t_f *lapl_id) /******/ { char *c_group_name = NULL; /* Buffer to hold C string */ @@ -868,7 +880,7 @@ h5oget_comment_c (hid_t_f *object_id, _fcd comment, size_t_f *commentsize, hssi */ int_f h5oget_comment_by_name_c (hid_t_f *loc_id, _fcd name, size_t_f *name_size, - _fcd comment, size_t_f *commentsize, size_t_f *bufsize, hid_t_f *lapl_id) + _fcd comment, size_t_f *commentsize, size_t_f *bufsize, hid_t_f *lapl_id) /******/ { char *c_comment = NULL; /* Buffer to hold C string */ diff --git a/fortran/src/H5Off.F90 b/fortran/src/H5Off.F90 index 243ec29..13dcf01 100644 --- a/fortran/src/H5Off.F90 +++ b/fortran/src/H5Off.F90 @@ -83,7 +83,7 @@ MODULE H5O TYPE, BIND(C) :: h5o_info_t INTEGER(C_LONG) :: fileno ! File number that object is located in INTEGER(haddr_t) :: addr ! Object address in file - INTEGER(C_INT) :: type ! Basic object type (group, dataset, etc.) + INTEGER(C_INT) :: type ! Basic object type (group, dataset, etc.) INTEGER :: rc ! Reference count of object INTEGER, DIMENSION(8) :: atime ! Access time ! -- NOTE -- @@ -98,6 +98,28 @@ MODULE H5O TYPE(meta_size_t) :: meta_size END TYPE h5o_info_t +! C interoperable structure for h5o_info_t. The Fortran derived type returns the time +! values as an integer array as specified in the Fortran intrinsic DATE_AND_TIME(VALUES). +! Whereas, this derived type does not. + + TYPE, BIND(C) :: c_h5o_info_t + INTEGER(C_LONG) :: fileno ! File number that object is located in + INTEGER(haddr_t) :: addr ! Object address in file + INTEGER(C_INT) :: type ! Basic object type (group, dataset, etc.) + INTEGER(C_INT) :: rc ! Reference count of object + + INTEGER(KIND=TIME_T) :: atime ! Access time + INTEGER(KIND=TIME_T) :: mtime ! modify time + INTEGER(KIND=TIME_T) :: ctime ! create time + INTEGER(KIND=TIME_T) :: btime ! Access time + + INTEGER(hsize_t) :: num_attrs ! # of attributes attached to object + + TYPE(hdr_t) :: hdr + + TYPE(meta_size_t) :: meta_size + END TYPE c_h5o_info_t + !***** CONTAINS @@ -834,12 +856,16 @@ CONTAINS ! return_value - returns the return value of the first operator that returns a positive value, or ! zero if all members were processed with no operator returning non-zero. ! hdferr - Returns 0 if successful and -1 if fails +! +! Optional parameters: +! fields - Flags specifying the fields to include in object_info. +! ! AUTHOR ! M. Scot Breitenfeld ! November 19, 2008 ! ! Fortran2003 Interface: - SUBROUTINE h5ovisit_f(object_id, index_type, order, op, op_data, return_value, hdferr) + SUBROUTINE h5ovisit_f(object_id, index_type, order, op, op_data, return_value, hdferr, fields) IMPLICIT NONE INTEGER(HID_T), INTENT(IN) :: object_id INTEGER, INTENT(IN) :: index_type @@ -849,10 +875,12 @@ CONTAINS TYPE(C_PTR) :: op_data INTEGER, INTENT(OUT) :: return_value INTEGER, INTENT(OUT) :: hdferr + INTEGER, INTENT(IN), OPTIONAL :: fields !***** + INTEGER :: fields_c INTERFACE - INTEGER FUNCTION h5ovisit_c(object_id, index_type, order, op, op_data) & + INTEGER FUNCTION h5ovisit_c(object_id, index_type, order, op, op_data, fields) & BIND(C, NAME='h5ovisit_c') IMPORT :: C_FUNPTR, C_PTR IMPORT :: HID_T @@ -862,10 +890,14 @@ CONTAINS INTEGER, INTENT(IN) :: order TYPE(C_FUNPTR), VALUE :: op TYPE(C_PTR), VALUE :: op_data + INTEGER, INTENT(IN) :: fields END FUNCTION h5ovisit_c END INTERFACE - return_value = h5ovisit_c(object_id, index_type, order, op, op_data) + fields_c = H5O_INFO_ALL_F + IF(PRESENT(fields)) fields_c = fields + + return_value = h5ovisit_c(object_id, index_type, order, op, op_data, fields_c) IF(return_value.GE.0)THEN hdferr = 0 @@ -894,26 +926,29 @@ CONTAINS ! ! Optional parameters: ! lapl_id - Link access property list. +! fields - Flags specifying the fields to include in object_info. ! ! AUTHOR ! M. Scot Breitenfeld ! December 1, 2008 ! ! Fortran2003 Interface: - SUBROUTINE h5oget_info_by_name_f(loc_id, name, object_info, hdferr, lapl_id) + SUBROUTINE h5oget_info_by_name_f(loc_id, name, object_info, hdferr, lapl_id, fields) IMPLICIT NONE INTEGER(HID_T) , INTENT(IN) :: loc_id CHARACTER(LEN=*), INTENT(IN) :: name TYPE(h5o_info_t), INTENT(OUT), TARGET :: object_info INTEGER , INTENT(OUT) :: hdferr INTEGER(HID_T) , INTENT(IN) , OPTIONAL :: lapl_id + INTEGER , INTENT(IN) , OPTIONAL :: fields !***** INTEGER(SIZE_T) :: namelen INTEGER(HID_T) :: lapl_id_default TYPE(C_PTR) :: ptr + INTEGER :: fields_c INTERFACE - INTEGER FUNCTION h5oget_info_by_name_c(loc_id, name, namelen, lapl_id_default, object_info) & + INTEGER FUNCTION h5oget_info_by_name_c(loc_id, name, namelen, lapl_id_default, object_info, fields) & BIND(C, NAME='h5oget_info_by_name_c') IMPORT :: c_char, c_ptr IMPORT :: HID_T, SIZE_T @@ -923,10 +958,13 @@ CONTAINS INTEGER(SIZE_T) , INTENT(IN) :: namelen INTEGER(HID_T) , INTENT(IN) :: lapl_id_default TYPE(C_PTR),VALUE :: object_info - + INTEGER , INTENT(IN) :: fields END FUNCTION h5oget_info_by_name_c END INTERFACE + fields_c = H5O_INFO_ALL_F + IF(PRESENT(fields)) fields_c = fields + namelen = LEN(name) lapl_id_default = H5P_DEFAULT_F @@ -934,7 +972,7 @@ CONTAINS ptr = C_LOC(object_info) - hdferr = H5Oget_info_by_name_c(loc_id, name, namelen, lapl_id_default, ptr) + hdferr = H5Oget_info_by_name_c(loc_id, name, namelen, lapl_id_default, ptr, fields_c) END SUBROUTINE H5Oget_info_by_name_f @@ -953,34 +991,43 @@ CONTAINS ! object_info - Buffer in which to return object information. ! hdferr - Returns 0 if successful and -1 if fails. ! +! Optional parameters: +! fields - Flags specifying the fields to include in object_info. +! ! AUTHOR ! M. Scot Breitenfeld ! May 11, 2012 ! ! Fortran2003 Interface: - SUBROUTINE h5oget_info_f(object_id, object_info, hdferr) + SUBROUTINE h5oget_info_f(object_id, object_info, hdferr, fields) USE, INTRINSIC :: ISO_C_BINDING IMPLICIT NONE INTEGER(HID_T) , INTENT(IN) :: object_id TYPE(h5o_info_t), INTENT(OUT), TARGET :: object_info INTEGER , INTENT(OUT) :: hdferr + INTEGER , INTENT(IN), OPTIONAL :: fields !***** TYPE(C_PTR) :: ptr - + INTEGER :: fields_c + INTERFACE - INTEGER FUNCTION h5oget_info_c(object_id, object_info) & + INTEGER FUNCTION h5oget_info_c(object_id, object_info, fields) & BIND(C, NAME='h5oget_info_c') IMPORT :: C_PTR IMPORT :: HID_T IMPLICIT NONE INTEGER(HID_T), INTENT(IN) :: object_id TYPE(C_PTR), VALUE :: object_info + INTEGER, INTENT(IN) :: fields END FUNCTION h5oget_info_c END INTERFACE + fields_c = H5O_INFO_ALL_F + IF(PRESENT(fields)) fields_c = fields + ptr = C_LOC(object_info) - hdferr = H5Oget_info_c(object_id, ptr) + hdferr = H5Oget_info_c(object_id, ptr, fields_c) END SUBROUTINE H5Oget_info_f @@ -1006,6 +1053,7 @@ CONTAINS ! ! Optional parameters: ! lapl_id - Link access property list. (Not currently used.) +! fields - Flags specifying the fields to include in object_info. ! ! AUTHOR ! M. Scot Breitenfeld @@ -1013,7 +1061,7 @@ CONTAINS ! ! Fortran2003 Interface: SUBROUTINE h5oget_info_by_idx_f(loc_id, group_name, index_field, order, n, & - object_info, hdferr, lapl_id) + object_info, hdferr, lapl_id, fields) USE, INTRINSIC :: ISO_C_BINDING IMPLICIT NONE @@ -1025,14 +1073,16 @@ CONTAINS TYPE(h5o_info_t), INTENT(OUT), TARGET :: object_info INTEGER , INTENT(OUT) :: hdferr INTEGER(HID_T) , INTENT(IN) , OPTIONAL :: lapl_id + INTEGER , INTENT(IN) , OPTIONAL :: fields !***** INTEGER(SIZE_T) :: namelen INTEGER(HID_T) :: lapl_id_default TYPE(C_PTR) :: ptr + INTEGER :: fields_c INTERFACE INTEGER FUNCTION h5oget_info_by_idx_c(loc_id, group_name, namelen, & - index_field, order, n, lapl_id_default, object_info) BIND(C, NAME='h5oget_info_by_idx_c') + index_field, order, n, lapl_id_default, object_info, fields) BIND(C, NAME='h5oget_info_by_idx_c') IMPORT :: c_char, c_ptr, c_funptr IMPORT :: HID_T, SIZE_T, HSIZE_T INTEGER(HID_T) , INTENT(IN) :: loc_id @@ -1043,17 +1093,20 @@ CONTAINS INTEGER(HSIZE_T), INTENT(IN) :: n INTEGER(HID_T) , INTENT(IN) :: lapl_id_default TYPE(C_PTR), VALUE :: object_info - + INTEGER, INTENT(IN) :: fields END FUNCTION h5oget_info_by_idx_c END INTERFACE + fields_c = H5O_INFO_ALL_F + IF(PRESENT(fields)) fields_c = fields + namelen = LEN(group_name) lapl_id_default = H5P_DEFAULT_F IF(PRESENT(lapl_id)) lapl_id_default = lapl_id ptr = C_LOC(object_info) - hdferr = H5Oget_info_by_idx_c(loc_id, group_name, namelen, index_field, order, n, lapl_id_default, ptr) + hdferr = H5Oget_info_by_idx_c(loc_id, group_name, namelen, index_field, order, n, lapl_id_default, ptr, fields_c) END SUBROUTINE H5Oget_info_by_idx_f @@ -1086,6 +1139,7 @@ CONTAINS ! ! Optional parameters: ! lapl_id - Link access property list identifier. +! fields - Flags specifying the fields to include in object_info. ! ! AUTHOR ! M. Scot Breitenfeld @@ -1093,7 +1147,7 @@ CONTAINS ! ! Fortran2003 Interface: SUBROUTINE h5ovisit_by_name_f(loc_id, object_name, index_type, order, op, op_data, & - return_value, hdferr, lapl_id) + return_value, hdferr, lapl_id, fields) IMPLICIT NONE INTEGER(HID_T) , INTENT(IN) :: loc_id CHARACTER(LEN=*), INTENT(IN) :: object_name @@ -1105,14 +1159,16 @@ CONTAINS INTEGER , INTENT(OUT) :: return_value INTEGER , INTENT(OUT) :: hdferr INTEGER(HID_T) , INTENT(IN) , OPTIONAL :: lapl_id + INTEGER , INTENT(IN) , OPTIONAL :: fields !***** INTEGER(SIZE_T) :: namelen INTEGER(HID_T) :: lapl_id_default + INTEGER :: fields_c INTERFACE INTEGER FUNCTION h5ovisit_by_name_c(loc_id, object_name, namelen, index_type, order, & - op, op_data, lapl_id) BIND(C, NAME='h5ovisit_by_name_c') + op, op_data, lapl_id, fields) BIND(C, NAME='h5ovisit_by_name_c') IMPORT :: C_CHAR, C_PTR, C_FUNPTR IMPORT :: HID_T, SIZE_T IMPLICIT NONE @@ -1124,16 +1180,20 @@ CONTAINS TYPE(C_FUNPTR) , VALUE :: op TYPE(C_PTR) , VALUE :: op_data INTEGER(HID_T) , INTENT(IN) :: lapl_id + INTEGER , INTENT(IN) :: fields END FUNCTION h5ovisit_by_name_c END INTERFACE + fields_c = H5O_INFO_ALL_F + IF(PRESENT(fields)) fields_c = fields + namelen = LEN(object_name) lapl_id_default = H5P_DEFAULT_F IF(PRESENT(lapl_id)) lapl_id_default = lapl_id return_value = h5ovisit_by_name_c(loc_id, object_name, namelen, index_type, order, & - op, op_data, lapl_id_default) + op, op_data, lapl_id_default, fields_c) IF(return_value.GE.0)THEN hdferr = 0 diff --git a/fortran/src/H5_f.c b/fortran/src/H5_f.c index 352ffab..69ba8b3 100644 --- a/fortran/src/H5_f.c +++ b/fortran/src/H5_f.c @@ -556,6 +556,17 @@ h5init_flags_c( int_f *h5d_flags, size_t_f *h5d_size_flags, h5o_flags[24] = (int_f)H5O_TYPE_DATASET; /* Object is a dataset */ h5o_flags[25] = (int_f)H5O_TYPE_NAMED_DATATYPE; /* Object is a named data type */ h5o_flags[26] = (int_f)H5O_TYPE_NTYPES; /* Number of different object types */ + +/* Flags for H5Oget_info. + * These flags determine which fields will be filled in in the H5O_info_t + * struct. + */ + h5o_flags[27] = (int_f)H5O_INFO_ALL; /* (H5O_INFO_BASIC|H5O_INFO_TIME|H5O_INFO_NUM_ATTRS|H5O_INFO_HDR|H5O_INFO_META_SIZE) */ + h5o_flags[28] = (int_f)H5O_INFO_BASIC; /* Fill in the fileno, addr, type, and rc fields */ + h5o_flags[29] = (int_f)H5O_INFO_TIME; /* Fill in the atime, mtime, ctime, and btime fields */ + h5o_flags[30] = (int_f)H5O_INFO_NUM_ATTRS; /* Fill in the num_attrs field */ + h5o_flags[31] = (int_f)H5O_INFO_HDR; /* Fill in the hdr field */ + h5o_flags[32] = (int_f)H5O_INFO_META_SIZE; /* Fill in the meta_size field */ /* * H5P flags */ diff --git a/fortran/src/H5_ff.F90 b/fortran/src/H5_ff.F90 index f63e734..a66ac95 100644 --- a/fortran/src/H5_ff.F90 +++ b/fortran/src/H5_ff.F90 @@ -98,8 +98,8 @@ MODULE H5LIB ! ! H5O flags declaration ! - INTEGER, PARAMETER :: H5O_FLAGS_LEN = 27 - INTEGER, DIMENSION(1:H5O_FLAGS_LEN) :: H5o_flags + INTEGER, PARAMETER :: H5O_FLAGS_LEN = 33 + INTEGER, DIMENSION(1:H5O_FLAGS_LEN) :: H5O_flags ! ! H5P flags declaration ! @@ -139,8 +139,8 @@ MODULE H5LIB ! INTEGER, PARAMETER :: H5LIB_FLAGS_LEN = 2 INTEGER, DIMENSION(1:H5LIB_FLAGS_LEN) :: H5LIB_flags - - PUBLIC :: h5open_f, h5close_f, h5get_libversion_f, h5dont_atexit_f, h5kind_to_type, h5offsetof + + PUBLIC :: h5open_f, h5close_f, h5get_libversion_f, h5dont_atexit_f, h5kind_to_type, h5offsetof, h5gmtime PUBLIC :: h5garbage_collect_f, h5check_version_f CONTAINS @@ -488,7 +488,13 @@ CONTAINS H5O_TYPE_GROUP_F = h5o_flags(24) H5O_TYPE_DATASET_F = h5o_flags(25) H5O_TYPE_NAMED_DATATYPE_F = h5o_flags(26) - H5O_TYPE_NTYPES_F = h5o_flags(27) + H5O_TYPE_NTYPES_F = h5o_flags(27) + H5O_INFO_ALL_F = h5o_flags(28) + H5O_INFO_BASIC_F = h5o_flags(29) + H5O_INFO_TIME_F = h5o_flags(30) + H5O_INFO_NUM_ATTRS_F = h5o_flags(31) + H5O_INFO_HDR_F = h5o_flags(32) + H5O_INFO_META_SIZE_F = h5o_flags(33) ! ! H5P flags ! @@ -898,4 +904,61 @@ CONTAINS END FUNCTION h5offsetof +!****f* H5LIB_PROVISIONAL/h5gmtime +! +! NAME +! h5gmtime +! +! PURPOSE +! Convert time_t structure (C) to Fortran DATE AND TIME storage format. +! +! Inputs: +! stdtime_t - Object of type time_t that contains a time value +! +! Outputs: +! datetime - A date/time array using Fortran conventions: +! datetime(1) = year +! datetime(2) = month +! datetime(3) = day +! datetime(4) = 0 ! time is expressed as UTC (or GMT timezone) */ +! datetime(5) = hour +! datetime(6) = minute +! datetime(7) = second +! datetime(8) = millisecond -- not available, assigned - HUGE(0) +! +! AUTHOR +! M. Scot Breitenfeld +! January, 2019 +! +! Fortran Interface: + FUNCTION h5gmtime(stdtime_t) + IMPLICIT NONE + INTEGER(KIND=TIME_T), INTENT(IN) :: stdtime_t + INTEGER, DIMENSION(1:8) :: h5gmtime +!***** + TYPE(C_PTR) :: cptr + INTEGER(C_INT), DIMENSION(:), POINTER :: c_time + + INTERFACE + TYPE(C_PTR) FUNCTION gmtime(stdtime_t) BIND(C, NAME='gmtime') + IMPORT :: TIME_T, C_PTR + IMPLICIT NONE + INTEGER(KIND=TIME_T) :: stdtime_t + END FUNCTION gmtime + END INTERFACE + + cptr = gmtime(stdtime_t) + CALL C_F_POINTER(cptr, c_time, [9]) + + h5gmtime(1) = INT(c_time(6)+1900) ! year starts at 1900 + h5gmtime(2) = INT(c_time(5)+1) ! month starts at 0 in C + h5gmtime(3) = INT(c_time(4)) ! day + h5gmtime(4) = 0 ! time is expressed as UTC (or GMT timezone) + h5gmtime(5) = INT(c_time(3)) ! hour + h5gmtime(6) = INT(c_time(2)) ! minute + h5gmtime(7) = INT(c_time(1)) ! second + h5gmtime(8) = -32767 ! millisecond is not available, assign it -HUGE(0) + + END FUNCTION h5gmtime + END MODULE H5LIB diff --git a/fortran/src/H5f90global.F90 b/fortran/src/H5f90global.F90 index 078778a..b705cc1 100644 --- a/fortran/src/H5f90global.F90 +++ b/fortran/src/H5f90global.F90 @@ -493,6 +493,13 @@ MODULE H5GLOBAL !DEC$ATTRIBUTES DLLEXPORT :: H5O_TYPE_DATASET_F !DEC$ATTRIBUTES DLLEXPORT :: H5O_TYPE_NAMED_DATATYPE_F !DEC$ATTRIBUTES DLLEXPORT :: H5O_TYPE_NTYPES_F + !DEC$ATTRIBUTES DLLEXPORT :: H5O_INFO_ALL_F + !DEC$ATTRIBUTES DLLEXPORT :: H5O_INFO_BASIC_F + !DEC$ATTRIBUTES DLLEXPORT :: H5O_INFO_TIME_F + !DEC$ATTRIBUTES DLLEXPORT :: H5O_INFO_NUM_ATTRS_F + !DEC$ATTRIBUTES DLLEXPORT :: H5O_INFO_HDR_F + !DEC$ATTRIBUTES DLLEXPORT :: H5O_INFO_META_SIZE_F + ! !DEC$endif INTEGER :: H5O_COPY_SHALLOW_HIERARCHY_F ! *** THESE VARIABLES DO @@ -522,6 +529,12 @@ MODULE H5GLOBAL INTEGER :: H5O_TYPE_DATASET_F INTEGER :: H5O_TYPE_NAMED_DATATYPE_F INTEGER :: H5O_TYPE_NTYPES_F + INTEGER :: H5O_INFO_ALL_F + INTEGER :: H5O_INFO_BASIC_F + INTEGER :: H5O_INFO_TIME_F + INTEGER :: H5O_INFO_NUM_ATTRS_F + INTEGER :: H5O_INFO_HDR_F + INTEGER :: H5O_INFO_META_SIZE_F ! ! H5P flags declaration ! diff --git a/fortran/src/H5f90proto.h b/fortran/src/H5f90proto.h index 0884eb6..56b7f22 100644 --- a/fortran/src/H5f90proto.h +++ b/fortran/src/H5f90proto.h @@ -314,14 +314,14 @@ H5_FCDLL int_f h5oclose_c(hid_t_f *object_id ); H5_FCDLL int_f h5oopen_by_addr_c(hid_t_f *loc_id, haddr_t_f *addr, hid_t_f *obj_id); H5_FCDLL int_f h5olink_c(hid_t_f *object_id, hid_t_f *new_loc_id, _fcd name, size_t_f *namelen, hid_t_f *lcpl_id, hid_t_f *lapl_id); -H5_FCDLL int_f h5ovisit_c(hid_t_f *group_id, int_f *index_type, int_f *order, H5O_iterate_t op, void *op_data); +H5_FCDLL int_f h5ovisit_c(hid_t_f *group_id, int_f *index_type, int_f *order, H5O_iterate_t op, void *op_data, int_f *fields); H5_FCDLL int_f h5ovisit_by_name_c(hid_t_f *loc_id, _fcd object_name, size_t_f *namelen, int_f *index_type, int_f *order, - H5O_iterate_t op, void *op_data, hid_t_f *lapl_id ); -H5_FCDLL int_f h5oget_info_c(hid_t_f *object_id, H5O_info_t_f *object_info); + H5O_iterate_t op, void *op_data, hid_t_f *lapl_id, int_f *fields ); +H5_FCDLL int_f h5oget_info_c(hid_t_f *object_id, H5O_info_t_f *object_info, int_f *fields); H5_FCDLL int_f h5oget_info_by_idx_c(hid_t_f *loc_id, _fcd group_name, size_t_f *namelen, - int_f *index_field, int_f *order, hsize_t_f *n, hid_t_f *lapl_id, H5O_info_t_f *object_info); + int_f *index_field, int_f *order, hsize_t_f *n, hid_t_f *lapl_id, H5O_info_t_f *object_info, int_f *fields); H5_FCDLL int_f h5oget_info_by_name_c(hid_t_f *loc_id, _fcd name, size_t_f *namelen, hid_t_f *lapl_id, - H5O_info_t_f *object_info); + H5O_info_t_f *object_info, int_f *fields); H5_FCDLL int_f h5ocopy_c(hid_t_f *src_loc_id, _fcd src_name, size_t_f *src_name_len, hid_t_f *dst_loc_id, _fcd dst_name, size_t_f *dst_name_len, hid_t_f *ocpypl_id, hid_t_f *lcpl_id ); diff --git a/fortran/src/H5match_types.c b/fortran/src/H5match_types.c index 7e0b7e8..57f7dda 100644 --- a/fortran/src/H5match_types.c +++ b/fortran/src/H5match_types.c @@ -191,6 +191,8 @@ int main(void) } if(sizeof(size_t) == IntKinds_SizeOf[i]) writeTypedef("size_t", "size_t", IntKinds[i]); + if(sizeof(time_t) == IntKinds_SizeOf[i]) + writeTypedef("time_t", "time_t", IntKinds[i]); if(sizeof(hsize_t) == IntKinds_SizeOf[i]) writeTypedef("hsize_t", "hsize_t", IntKinds[i]); } @@ -306,6 +308,17 @@ int main(void) return -1; } + /* time_t */ + for(i=0;i< FORTRAN_NUM_INTEGER_KINDS;i++) { + if(IntKinds_SizeOf[i] == H5_SIZEOF_TIME_T) { + writeToFiles("time_t","TIME_T", "time_t_f", IntKinds[i]); + break; + } + if(i == (FORTRAN_NUM_INTEGER_KINDS-1) ) + /* Error: couldn't find a size for time_t */ + return -1; + } + /* int */ writeToFiles("int","Fortran_INTEGER", "int_f", H5_FORTRAN_NATIVE_INTEGER_KIND); diff --git a/fortran/src/hdf5_fortrandll.def.in b/fortran/src/hdf5_fortrandll.def.in index 2edba5a..81702fa 100644 --- a/fortran/src/hdf5_fortrandll.def.in +++ b/fortran/src/hdf5_fortrandll.def.in @@ -8,6 +8,7 @@ H5LIB_mp_H5GARBAGE_COLLECT_F H5LIB_mp_H5DONT_ATEXIT_F H5LIB_mp_H5KIND_TO_TYPE H5LIB_mp_H5OFFSETOF +H5LIB_mp_H5GMTIME ; H5A H5A_mp_H5AWRITE_CHAR_SCALAR H5A_mp_H5AREAD_CHAR_SCALAR diff --git a/fortran/test/tH5O_F03.F90 b/fortran/test/tH5O_F03.F90 index 44c4bff..d1a9ddb 100644 --- a/fortran/test/tH5O_F03.F90 +++ b/fortran/test/tH5O_F03.F90 @@ -58,21 +58,224 @@ MODULE visit_cb TYPE, bind(c) :: ovisit_ud_t INTEGER :: idx ! Index in object visit structure TYPE(obj_visit_t), DIMENSION(1:info_size) :: info ! Pointer to the object visit structure to use + INTEGER :: field END TYPE ovisit_ud_t CONTAINS - INTEGER FUNCTION visit_obj_cb( group_id, name, oinfo, op_data) bind(C) +! Compares the field values of a C h5O_info_t and a Fortran H5O_info_t. + + INTEGER FUNCTION compare_h5o_info_t( oinfo_f, oinfo_c, field, full_f_field ) RESULT(status) + + IMPLICIT NONE + TYPE(h5o_info_t) :: oinfo_f + TYPE(c_h5o_info_t) :: oinfo_c + INTEGER :: field + LOGICAL :: full_f_field ! All the fields of Fortran H5O_info_t where filled +! local + INTEGER(C_INT), DIMENSION(1:8) :: atime, btime, ctime, mtime + INTEGER :: i + + status = 0 + + IF( (field .EQ. H5O_INFO_BASIC_F).OR.(field .EQ. H5O_INFO_ALL_F) )THEN + IF( (oinfo_f%fileno.LE.0) .OR. (oinfo_c%fileno .NE. oinfo_f%fileno) )THEN + status = -1 + RETURN + ENDIF + IF( (oinfo_f%addr.LE.0) .OR. (oinfo_c%addr .NE. oinfo_f%addr) )THEN + status = -1 + RETURN + ENDIF + IF( (oinfo_f%type.LT.0) .OR. (oinfo_c%type .NE. oinfo_f%type) )THEN + status = -1 + RETURN + ENDIF + IF( (oinfo_f%rc.LT.0) .OR. (oinfo_c%rc .NE. oinfo_f%rc) )THEN + status = -1 + RETURN + ENDIF + + ENDIF + + IF((field .EQ. H5O_INFO_TIME_F).OR.(field .EQ. H5O_INFO_ALL_F))THEN + + atime(1:8) = h5gmtime(oinfo_c%atime) + btime(1:8) = h5gmtime(oinfo_c%btime) + ctime(1:8) = h5gmtime(oinfo_c%ctime) + mtime(1:8) = h5gmtime(oinfo_c%mtime) + + DO i = 1, 8 + IF( (atime(i) .NE. oinfo_f%atime(i)) )THEN + status = -1 + RETURN + ENDIF + + IF( (btime(i) .NE. oinfo_f%btime(i)) )THEN + status = -1 + RETURN + ENDIF + + IF( (ctime(i) .NE. oinfo_f%ctime(i)) )THEN + status = -1 + RETURN + ENDIF + + IF( (mtime(i) .NE. oinfo_f%mtime(i)) )THEN + status = -1 + RETURN + ENDIF + ENDDO + + ELSE IF(field .EQ. H5O_INFO_TIME_F.AND. full_f_field)THEN + ! check other field values are not filled (using only a small subset to check) + status = 0 + IF( oinfo_c%fileno .NE. oinfo_f%fileno) status = status + 1 + IF( oinfo_c%addr .NE. oinfo_f%addr) status = status + 1 + IF( oinfo_c%type .NE. oinfo_f%type) status = status + 1 + IF( oinfo_c%rc .NE. oinfo_f%rc) status = status + 1 + IF(status.EQ.0) THEN ! There was no difference found, which is only possible if the field was filled. + status = -1 + RETURN + ENDIF + status = 0 ! reset + ENDIF + + IF((field .EQ. H5O_INFO_NUM_ATTRS_F).OR.(field .EQ. H5O_INFO_ALL_F))THEN + IF( (oinfo_f%num_attrs.LT.0) .OR. (oinfo_c%num_attrs .NE. oinfo_f%num_attrs) )THEN + status = -1 + RETURN + ENDIF + ELSE IF( field .EQ. H5O_INFO_ALL_F.AND.full_f_field)THEN + ! check other field values are not filled (using only a small subset to check) + status = 0 + IF( oinfo_c%fileno .NE. oinfo_f%fileno) status = status + 1 + IF( oinfo_c%addr .NE. oinfo_f%addr) status = status + 1 + IF( oinfo_c%type .NE. oinfo_f%type) status = status + 1 + IF( oinfo_c%rc .NE. oinfo_f%rc) status = status + 1 + IF(status.EQ.0) THEN ! There was no difference found, which is only possible if the field was filled. + status = -1 + RETURN + ENDIF + status = 0 ! reset + + ENDIF + + IF((field).EQ.H5O_INFO_HDR_F.OR.(field .EQ. H5O_INFO_ALL_F))THEN + IF( (oinfo_f%hdr%version.LT.0) .OR. (oinfo_c%hdr%version .NE. oinfo_f%hdr%version) )THEN + status = -1 + RETURN + ENDIF + IF( (oinfo_f%hdr%nmesgs.LT.0) .OR. (oinfo_c%hdr%nmesgs .NE. oinfo_f%hdr%nmesgs) )THEN + status = -1 + RETURN + ENDIF + IF( (oinfo_f%hdr%nchunks.LT.0) .OR. (oinfo_c%hdr%nchunks .NE. oinfo_f%hdr%nchunks) )THEN + status = -1 + RETURN + ENDIF + IF( (oinfo_f%hdr%flags.LT.0) .OR. (oinfo_c%hdr%flags .NE. oinfo_f%hdr%flags) )THEN + status = -1 + RETURN + ENDIF + IF( (oinfo_f%hdr%space%total.LT.0) .OR. (oinfo_c%hdr%space%total .NE. oinfo_f%hdr%space%total) )THEN + status = -1 + RETURN + ENDIF + IF( (oinfo_f%hdr%space%meta.LT.0) .OR. (oinfo_c%hdr%space%meta .NE. oinfo_f%hdr%space%meta) )THEN + status = -1 + RETURN + ENDIF + IF( (oinfo_f%hdr%space%mesg.LT.0) .OR. (oinfo_c%hdr%space%mesg .NE. oinfo_f%hdr%space%mesg) )THEN + status = -1 + RETURN + ENDIF + IF( (oinfo_f%hdr%space%free.LT.0) .OR. (oinfo_c%hdr%space%free .NE. oinfo_f%hdr%space%free) )THEN + status = -1 + RETURN + ENDIF + IF( (oinfo_f%hdr%mesg%present.LT.0) .OR. (oinfo_c%hdr%mesg%present .NE. oinfo_f%hdr%mesg%present) )THEN + status = -1 + RETURN + ENDIF + IF( (oinfo_f%hdr%mesg%shared.LT.0) .OR. (oinfo_c%hdr%mesg%shared .NE. oinfo_f%hdr%mesg%shared) )THEN + status = -1 + RETURN + ENDIF + ELSE IF( field .EQ. H5O_INFO_HDR_F.AND.full_f_field)THEN + ! check other field values are not filled (using only a small subset to check) + status = 0 + IF( oinfo_c%fileno .NE. oinfo_f%fileno) status = status + 1 + IF( oinfo_c%addr .NE. oinfo_f%addr) status = status + 1 + IF( oinfo_c%type .NE. oinfo_f%type) status = status + 1 + IF( oinfo_c%rc .NE. oinfo_f%rc) status = status + 1 + IF(status.EQ.0) THEN ! There was no difference found, which is only possible if the field was filled. + status = -1 + RETURN + ENDIF + status = 0 ! reset + ENDIF + IF((field).EQ.H5O_INFO_META_SIZE_F.OR.(field .EQ. H5O_INFO_ALL_F))THEN + IF((oinfo_f%meta_size%obj%index_size.LT.0).OR.(oinfo_c%meta_size%obj%index_size.NE.oinfo_f%meta_size%obj%index_size))THEN + status = -1 + RETURN + ENDIF + IF((oinfo_f%meta_size%obj%heap_size.LT.0).OR.(oinfo_c%meta_size%obj%heap_size.NE.oinfo_f%meta_size%obj%heap_size))THEN + status = -1 + RETURN + ENDIF + IF((oinfo_f%meta_size%attr%index_size.LT.0).OR.(oinfo_c%meta_size%attr%index_size.NE.oinfo_f%meta_size%attr%index_size))THEN + status = -1 + RETURN + ENDIF + IF((oinfo_f%meta_size%attr%heap_size.LT.0).OR.(oinfo_c%meta_size%attr%heap_size.NE.oinfo_f%meta_size%attr%heap_size))THEN + status = -1 + RETURN + ENDIF + ELSE IF( field .EQ. H5O_INFO_META_SIZE_F.AND.full_f_field)THEN + ! check other field values are not filled (using only a small subset to check) + status = 0 + IF( oinfo_c%fileno .NE. oinfo_f%fileno) status = status + 1 + IF( oinfo_c%addr .NE. oinfo_f%addr) status = status + 1 + IF( oinfo_c%type .NE. oinfo_f%type) status = status + 1 + IF( oinfo_c%rc .NE. oinfo_f%rc) status = status + 1 + IF(status.EQ.0) THEN ! There was no difference found, which is only possible if the field was filled. + status = -1 + RETURN + ENDIF + status = 0 ! reset + ENDIF + + END FUNCTION compare_h5o_info_t + + INTEGER FUNCTION visit_obj_cb( group_id, name, oinfo_c, op_data) bind(C) IMPLICIT NONE INTEGER(HID_T), VALUE :: group_id CHARACTER(LEN=1), DIMENSION(1:180) :: name - TYPE(h5o_info_t) :: oinfo + CHARACTER(LEN=180) :: name2 + TYPE(c_h5o_info_t) :: oinfo_c TYPE(ovisit_ud_t) :: op_data - + TYPE(h5o_info_t) :: oinfo_f +! +! MEMBER | TYPE | MEANING | RANGE +! A(1) = tm_sec int seconds after the minute 0-61* +! A(2) = tm_min int minutes after the hour 0-59 +! A(3) = tm_hour int hours since midnight 0-23 +! A(4) = tm_mday int day of the month 1-31 +! A(5) = tm_mon int months since January 0-11 +! A(6) = tm_year int years since 1900 +! A(7) = tm_wday int days since Sunday 0-6 +! A(8) = tm_yday int days since January 1 0-365 +! A(9) = tm_isdst int Daylight Saving Time flag +! + INTEGER(C_INT), DIMENSION(:), POINTER :: c_atime, c_btime, c_ctime, c_mtime + INTEGER(C_INT), DIMENSION(1:8) :: atime, btime, ctime, mtime INTEGER :: len, i INTEGER :: idx + INTEGER :: ierr + TYPE(C_PTR) :: cptr visit_obj_cb = 0 @@ -87,21 +290,53 @@ CONTAINS len = len - 1 ! Check for correct object information + name2(1:180) = "" + DO i = 1, len + name2(i:i) = name(i)(1:1) + ENDDO - idx = op_data%idx + IF(op_data%field .EQ. H5O_INFO_ALL_F)THEN - DO i = 1, len - IF(op_data%info(idx)%path(i)(1:1) .NE. name(i)(1:1))THEN - visit_obj_cb = -1 - RETURN - ENDIF - - IF(op_data%info(idx)%type_obj .NE. oinfo%type)THEN - visit_obj_cb = -1 - RETURN - ENDIF + idx = op_data%idx + + DO i = 1, len + IF(op_data%info(idx)%path(i)(1:1) .NE. name(i)(1:1))THEN + visit_obj_cb = -1 + RETURN + ENDIF + + IF(op_data%info(idx)%type_obj .NE. oinfo_c%type)THEN + visit_obj_cb = -1 + RETURN + ENDIF + ENDDO - ENDDO + ENDIF + + ! Check H5Oget_info_by_name_f; if partial field values where filled correctly + CALL H5Oget_info_by_name_f(group_id, name2, oinfo_f, ierr); + visit_obj_cb = compare_h5o_info_t( oinfo_f, oinfo_c, op_data%field, .TRUE. ) + IF(visit_obj_cb.EQ.-1) RETURN + + ! Check H5Oget_info_by_name_f, only check field values + CALL H5Oget_info_by_name_f(group_id, name2, oinfo_f, ierr, fields = op_data%field); + visit_obj_cb = compare_h5o_info_t( oinfo_f, oinfo_c, op_data%field, .FALSE. ) + IF(visit_obj_cb.EQ.-1) RETURN + + + IF(op_data%idx.EQ.1)THEN + + ! Check H5Oget_info_f, only check field values + CALL H5Oget_info_f(group_id, oinfo_f, ierr, fields = op_data%field); + visit_obj_cb = compare_h5o_info_t( oinfo_f, oinfo_c, op_data%field, .FALSE. ) + IF(visit_obj_cb.EQ.-1) RETURN + + ! Check H5Oget_info_f; if partial field values where filled correctly + CALL H5Oget_info_f(group_id, oinfo_f, ierr); + visit_obj_cb = compare_h5o_info_t( oinfo_f, oinfo_c, op_data%field, .TRUE. ) + IF(visit_obj_cb.EQ.-1) RETURN + + ENDIF ! Advance to next location in expected output op_data%idx = op_data%idx + 1 @@ -110,7 +345,6 @@ CONTAINS END MODULE visit_cb - MODULE TH5O_F03 CONTAINS @@ -310,29 +544,110 @@ SUBROUTINE obj_visit(total_error) udata%info(9)%type_obj = H5O_TYPE_NAMED_DATATYPE_F ! Visit all the objects reachable from the root group (with file ID) - udata%idx = 1 fun_ptr = C_FUNLOC(visit_obj_cb) f_ptr = C_LOC(udata) ! Test h5ovisit_f + udata%field = H5O_INFO_ALL_F + udata%idx = 1 CALL h5ovisit_f(fid, H5_INDEX_NAME_F, H5_ITER_INC_F, fun_ptr, f_ptr, ret_val, error) CALL check("h5ovisit_f", error, total_error) IF(ret_val.LT.0)THEN CALL check("h5ovisit_f", -1, total_error) ENDIF - ! Test h5ovisit_by_name_f + ! Test fields option + udata%field = H5O_INFO_ALL_F + udata%idx = 1 + CALL h5ovisit_f(fid, H5_INDEX_NAME_F, H5_ITER_INC_F, fun_ptr, f_ptr, ret_val, error, fields=udata%field) + CALL check("h5ovisit_f", error, total_error) + IF(ret_val.LT.0)THEN + CALL check("h5ovisit_f", -1, total_error) + ENDIF + udata%field = H5O_INFO_BASIC_F + udata%idx = 1 + CALL h5ovisit_f(fid, H5_INDEX_NAME_F, H5_ITER_INC_F, fun_ptr, f_ptr, ret_val, error, fields=udata%field) + CALL check("h5ovisit_f", error, total_error) + IF(ret_val.LT.0)THEN + CALL check("h5ovisit_f", -1, total_error) + ENDIF + udata%field = H5O_INFO_TIME_F + udata%idx = 1 + CALL h5ovisit_f(fid, H5_INDEX_NAME_F, H5_ITER_INC_F, fun_ptr, f_ptr, ret_val, error, fields=udata%field) + CALL check("h5ovisit_f", error, total_error) + IF(ret_val.LT.0)THEN + CALL check("h5ovisit_f", -1, total_error) + ENDIF + udata%field = H5O_INFO_NUM_ATTRS_F + udata%idx = 1 + CALL h5ovisit_f(fid, H5_INDEX_NAME_F, H5_ITER_INC_F, fun_ptr, f_ptr, ret_val, error, fields=udata%field) + CALL check("h5ovisit_f", error, total_error) + IF(ret_val.LT.0)THEN + CALL check("h5ovisit_f", -1, total_error) + ENDIF + udata%field = H5O_INFO_HDR_F + udata%idx = 1 + CALL h5ovisit_f(fid, H5_INDEX_NAME_F, H5_ITER_INC_F, fun_ptr, f_ptr, ret_val, error, fields=udata%field) + CALL check("h5ovisit_f", error, total_error) + IF(ret_val.LT.0)THEN + CALL check("h5ovisit_f", -1, total_error) + ENDIF + udata%field = H5O_INFO_META_SIZE_F + udata%idx = 1 + CALL h5ovisit_f(fid, H5_INDEX_NAME_F, H5_ITER_INC_F, fun_ptr, f_ptr, ret_val, error, fields=udata%field) + CALL check("h5ovisit_f", error, total_error) + IF(ret_val.LT.0)THEN + CALL check("h5ovisit_f", -1, total_error) + ENDIF + ! Test h5ovisit_by_name_f object_name = "/" udata%idx = 1 - - CALL h5ovisit_by_name_f(fid, object_name, H5_INDEX_NAME_F, H5_ITER_INC_F, fun_ptr, f_ptr, ret_val, error) + udata%field = H5O_INFO_ALL_F + CALL h5ovisit_by_name_f(fid, object_name, H5_INDEX_NAME_F, H5_ITER_INC_F, fun_ptr, f_ptr, ret_val, error, fields=udata%field) CALL check("h5ovisit_by_name_f", error, total_error) IF(ret_val.LT.0)THEN CALL check("h5ovisit_by_name_f", -1, total_error) ENDIF + ! Test fields option + udata%idx = 1 + udata%field = H5O_INFO_BASIC_F + CALL h5ovisit_by_name_f(fid, object_name, H5_INDEX_NAME_F, H5_ITER_INC_F, fun_ptr, f_ptr, ret_val, error, fields=udata%field) + CALL check("h5ovisit_by_name_f", error, total_error) + IF(ret_val.LT.0)THEN + CALL check("h5ovisit_by_name_f", -1, total_error) + ENDIF + udata%idx = 1 + udata%field = H5O_INFO_TIME_F + CALL h5ovisit_by_name_f(fid, object_name, H5_INDEX_NAME_F, H5_ITER_INC_F, fun_ptr, f_ptr, ret_val, error, fields=udata%field) + CALL check("h5ovisit_by_name_f", error, total_error) + IF(ret_val.LT.0)THEN + CALL check("h5ovisit_by_name_f", -1, total_error) + ENDIF + udata%idx = 1 + udata%field = H5O_INFO_NUM_ATTRS_F + CALL h5ovisit_by_name_f(fid, object_name, H5_INDEX_NAME_F, H5_ITER_INC_F, fun_ptr, f_ptr, ret_val, error, fields=udata%field) + CALL check("h5ovisit_by_name_f", error, total_error) + IF(ret_val.LT.0)THEN + CALL check("h5ovisit_by_name_f", -1, total_error) + ENDIF + udata%idx = 1 + udata%field = H5O_INFO_HDR_F + CALL h5ovisit_by_name_f(fid, object_name, H5_INDEX_NAME_F, H5_ITER_INC_F, fun_ptr, f_ptr, ret_val, error, fields=udata%field) + CALL check("h5ovisit_by_name_f", error, total_error) + IF(ret_val.LT.0)THEN + CALL check("h5ovisit_by_name_f", -1, total_error) + ENDIF + udata%idx = 1 + udata%field = H5O_INFO_META_SIZE_F + CALL h5ovisit_by_name_f(fid, object_name, H5_INDEX_NAME_F, H5_ITER_INC_F, fun_ptr, f_ptr, ret_val, error, fields=udata%field) + CALL check("h5ovisit_by_name_f", error, total_error) + IF(ret_val.LT.0)THEN + CALL check("h5ovisit_by_name_f", -1, total_error) + ENDIF + CALL h5fclose_f(fid, error) CALL check("h5fclose_f",error, total_error) @@ -450,11 +765,32 @@ SUBROUTINE obj_info(total_error) IF(oinfo%rc.NE.1)THEN CALL check("h5oget_info_by_idx_f", -1, total_error) ENDIF + IF(oinfo%type.NE.H5O_TYPE_DATASET_F)THEN + CALL check("h5oget_info_by_idx_f", -1, total_error) + ENDIF + ! Check partial fields + CALL h5oget_info_by_idx_f(gid, ".", H5_INDEX_NAME_F, H5_ITER_INC_F, 0_hsize_t, oinfo, error, fields=H5O_INFO_BASIC_F ) + CALL check("h5oget_info_by_idx_f", error, total_error) + + IF(oinfo%rc.NE.1)THEN + CALL check("h5oget_info_by_idx_f", -1, total_error) + ENDIF IF(oinfo%type.NE.H5O_TYPE_DATASET_F)THEN CALL check("h5oget_info_by_idx_f", -1, total_error) ENDIF + CALL h5oget_info_by_idx_f(gid, ".", H5_INDEX_NAME_F, H5_ITER_INC_F, 0_hsize_t, oinfo, error, fields=H5O_INFO_TIME_F ) + CALL check("h5oget_info_by_idx_f", error, total_error) + ! These field values should not be filled + IF(oinfo%rc.EQ.1)THEN + CALL check("h5oget_info_by_idx_f", -1, total_error) + ENDIF + IF(oinfo%type.EQ.H5O_TYPE_DATASET_F)THEN + CALL check("h5oget_info_by_idx_f", -1, total_error) + ENDIF + + ! Close objects CALL h5dclose_f(did, error) CALL check("h5dclose_f", error, total_error) @@ -483,11 +819,12 @@ SUBROUTINE build_visit_file(fid) USE TH5_MISC IMPLICIT NONE - INTEGER(hid_t) :: fid ! File ID - INTEGER(hid_t) :: gid = -1, gid2 = -1 ! Group IDs + INTEGER(hid_t) :: fid ! File ID + INTEGER(hid_t) :: gid = -1, gid2 = -1 ! Group IDs INTEGER(hid_t) :: sid = -1 ! Dataspace ID INTEGER(hid_t) :: did = -1 ! Dataset ID INTEGER(hid_t) :: tid = -1 ! Datatype ID + INTEGER(hid_t) :: aid = -1, aid2 = -1, aid3 = -1 ! Attribute ID CHARACTER(LEN=20) :: filename = 'visit.h5' INTEGER :: error @@ -500,6 +837,15 @@ SUBROUTINE build_visit_file(fid) ! Create nested group CALL H5Gcreate_f(gid, "Group2", gid2, error) + CALL H5Screate_f(H5S_SCALAR_F, sid, error) + CALL H5Acreate_f(gid2, "Attr1", H5T_NATIVE_INTEGER, sid, aid, error) + CALL H5Acreate_f(gid2, "Attr2", H5T_NATIVE_INTEGER, sid, aid2, error) + CALL H5Acreate_f(gid2, "Attr3", H5T_NATIVE_INTEGER, sid, aid3, error) + CALL H5Aclose_f(aid,error) + CALL H5Aclose_f(aid2,error) + CALL H5Aclose_f(aid3,error) + CALL H5Sclose_f(sid,error) + ! Close groups CALL h5gclose_f(gid2, error) CALL h5gclose_f(gid, error) diff --git a/src/H5Oint.c b/src/H5Oint.c index 2503eb7..d3a409c 100644 --- a/src/H5Oint.c +++ b/src/H5Oint.c @@ -125,12 +125,7 @@ const H5O_msg_class_t *const H5O_msg_class_g[] = { H5O_MSG_REFCOUNT, /*0x0016 Object's ref. count */ H5O_MSG_FSINFO, /*0x0017 Free-space manager info */ H5O_MSG_MDCI, /*0x0018 Metadata cache image */ - H5O_MSG_UNKNOWN, /*0x0019 Placeholder for unknown message */ -#ifdef H5O_ENABLE_BOGUS - H5O_MSG_BOGUS_INVALID, /*0x001A "Bogus invalid" (for testing) */ -#else /* H5O_ENABLE_BOGUS */ - NULL, /*0x001A "Bogus invalid" (for testing) */ -#endif /* H5O_ENABLE_BOGUS */ + H5O_MSG_UNKNOWN /*0x0019 Placeholder for unknown message */ }; /* Format version bounds for object header */ diff --git a/src/H5Pprivate.h b/src/H5Pprivate.h index 7007635..866f088 100644 --- a/src/H5Pprivate.h +++ b/src/H5Pprivate.h @@ -44,6 +44,7 @@ typedef struct H5P_genplist_t H5P_genplist_t; #define H5_COLL_MD_READ_FLAG_NAME "collective_metadata_read" + /****************************/ /* Library Private Typedefs */ /****************************/ diff --git a/src/H5private.h b/src/H5private.h index a3056a4..f58faec 100644 --- a/src/H5private.h +++ b/src/H5private.h @@ -568,9 +568,6 @@ #define H5_PB (1024.0F * 1024.0F * 1024.0F * 1024.0F * 1024.0F) #define H5_EB (1024.0F * 1024.0F * 1024.0F * 1024.0F * 1024.0F * 1024.0F) -/* Define 2GB -- Used for 2GB limitation checks */ -#define H5_2GB (2.0F * 1024.0F * 1024.0F * 1024.0F) - #ifndef H5_HAVE_FLOCK /* flock() operations. Used in the source so we have to define them when * the call is not available (e.g.: Windows). These should NOT be used -- cgit v0.12