From 7ae00db7a4a4e8330245b15aa1e2fa1659cb9b1b Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Wed, 3 Apr 2002 12:07:14 -0500 Subject: [svn-r5138] Purpose: Bug Fix & Code Cleanup Description: The MPI-IO optimized transfer routines (H5S_mpio_spaces_read/H5S_mpio_space_write) are not being invoked in all the cases where they could be used. Additionally, the code for determining if an optimized transfer is wrapped into the actual I/O transfer routine in a very confusing way. Solution: Re-enabled MPI-IO optimized transfer routines in all the cases where they should work. Extracted all the pre-conditions for optimized transfers into separate routines from the transfer routines. Platforms tested: FreeBSD 4.5 (sleipnir) & IRIX64 6.5 (modi4) --- release_docs/RELEASE.txt | 2 + src/H5D.c | 61 +++++++++++++---- src/H5S.c | 89 ++++++++++++++---------- src/H5Sall.c | 101 ++++++++++++++++------------ src/H5Shyper.c | 43 +++++++++++- src/H5Smpio.c | 107 ++++++++++++++++++++--------- src/H5Spkg.h | 15 +++-- src/H5Spoint.c | 42 ++++++++++++ src/H5Sprivate.h | 36 +++++----- src/H5Sselect.c | 171 +++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 517 insertions(+), 150 deletions(-) diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt index 90e2386..f477b99 100644 --- a/release_docs/RELEASE.txt +++ b/release_docs/RELEASE.txt @@ -156,6 +156,8 @@ Documentation New Features ============ + * Improved performance of "regular" hyperslab I/O when using MPI-IO and the + datatype conversion is unneccessary. QAK - 2002/04/02 * Improved performance of single hyperslab I/O when datatype conversion is unneccessary. QAK - 2002/04/02 * Added new "H5Sget_select_type" API function to determine which type of diff --git a/src/H5D.c b/src/H5D.c index acfd055..2b0b717 100644 --- a/src/H5D.c +++ b/src/H5D.c @@ -1969,6 +1969,10 @@ H5D_close(H5D_t *dataset) * Raymond Lu, 2001-10-2 * Changed the way to retrieve property for generic property list. * + * QAK - 2002/04/02 + * Removed the must_convert parameter and move preconditions to + * H5S__opt_possible() routine + * *------------------------------------------------------------------------- */ herr_t @@ -1994,7 +1998,6 @@ H5D_read(H5D_t *dataset, const H5T_t *mem_type, const H5S_t *mem_space, hsize_t request_nelmts; /*requested strip mine */ H5T_bkg_t need_bkg; /*type of background buf*/ H5S_t *free_this_space=NULL; /*data space to free */ - hbool_t must_convert; /*have to xfer the slow way*/ #ifdef H5_HAVE_PARALLEL H5FD_mpio_dxpl_t *dx = NULL; H5FD_mpio_xfer_t xfer_mode; /*xfer_mode for this request */ @@ -2089,6 +2092,24 @@ printf("%s: check 1.0, nelmts=%d, H5S_get_select_npoints(file_space)=%d\n",FUNC, HGOTO_ERROR(H5E_DATASET, H5E_CANTREGISTER, FAIL, "unable to register types for conversion"); } /* end if */ + /* Set the storage flags for the space conversion check */ + switch(dataset->layout.type) { + case H5D_COMPACT: + sconv_flags |= H5S_CONV_STORAGE_COMPACT; + break; + + case H5D_CONTIGUOUS: + sconv_flags |= H5S_CONV_STORAGE_CONTIGUOUS; + break; + + case H5D_CHUNKED: + sconv_flags |= H5S_CONV_STORAGE_CHUNKED; + break; + + default: + assert(0 && "Unhandled layout type!"); + } /* end switch */ + /* Get dataspace functions */ if (NULL==(sconv=H5S_find(mem_space, file_space, sconv_flags))) HGOTO_ERROR (H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to convert from file to memory data space"); @@ -2112,15 +2133,11 @@ printf("%s: check 1.1, \n",FUNC); HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get external file list"); status = (sconv->read)(dataset->ent.file, &(dataset->layout), &pline, &fill, &efl, H5T_get_size(dataset->type), file_space, - mem_space, dxpl_id, buf/*out*/, &must_convert); + mem_space, dxpl_id, buf/*out*/); /* Supports only no conversion, type or space, for now. */ - if (status<0) + if (status<0) { HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "optimized read failed"); - - if (must_convert) { - /* sconv->read cannot do a direct transfer; - * fall through and xfer the data in the more roundabout way */ } else { /* direct xfer accomplished successfully */ #ifdef H5S_DEBUG @@ -2424,6 +2441,10 @@ done: * Raymond Lu, 2001-10-2 * Changed the way to retrieve property for generic property list. * + * QAK - 2002/04/02 + * Removed the must_convert parameter and move preconditions to + * H5S__opt_possible() routine + * *------------------------------------------------------------------------- */ herr_t @@ -2449,7 +2470,6 @@ H5D_write(H5D_t *dataset, const H5T_t *mem_type, const H5S_t *mem_space, hsize_t request_nelmts; /*requested strip mine */ H5T_bkg_t need_bkg; /*type of background buf*/ H5S_t *free_this_space=NULL; /*data space to free */ - hbool_t must_convert; /*have to xfer the slow way*/ #ifdef H5_HAVE_PARALLEL H5FD_mpio_dxpl_t *dx = NULL; H5FD_mpio_xfer_t xfer_mode; /*xfer_mode for this request */ @@ -2571,6 +2591,24 @@ H5D_write(H5D_t *dataset, const H5T_t *mem_type, const H5S_t *mem_space, printf("%s: check 0.6, after H5T_find, tpath=%p, tpath->name=%s\n",FUNC,tpath,tpath->name); #endif /* QAK */ + /* Set the storage flags for the space conversion check */ + switch(dataset->layout.type) { + case H5D_COMPACT: + sconv_flags |= H5S_CONV_STORAGE_COMPACT; + break; + + case H5D_CONTIGUOUS: + sconv_flags |= H5S_CONV_STORAGE_CONTIGUOUS; + break; + + case H5D_CHUNKED: + sconv_flags |= H5S_CONV_STORAGE_CHUNKED; + break; + + default: + assert(0 && "Unhandled layout type!"); + } /* end switch */ + /* Get dataspace functions */ if (NULL==(sconv=H5S_find(mem_space, file_space, sconv_flags))) HGOTO_ERROR (H5E_DATASET, H5E_UNSUPPORTED, FAIL, "unable to convert from memory to file data space"); @@ -2594,14 +2632,11 @@ H5D_write(H5D_t *dataset, const H5T_t *mem_type, const H5S_t *mem_space, HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get external file list"); status = (sconv->write)(dataset->ent.file, &(dataset->layout), &pline, &fill, &efl, H5T_get_size(dataset->type), file_space, - mem_space, dxpl_id, buf/*out*/, &must_convert); + mem_space, dxpl_id, buf/*out*/); /* Supports only no conversion, type or space, for now. */ - if (status<0) + if (status<0) { HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "optimized write failed"); - if (must_convert) { - /* sconv->write cannot do a direct transfer; - * fall through and xfer the data in the more roundabout way */ } else { /* direct xfer accomplished successfully */ #ifdef H5S_DEBUG diff --git a/src/H5S.c b/src/H5S.c index 20241a8..383c851 100644 --- a/src/H5S.c +++ b/src/H5S.c @@ -1497,7 +1497,7 @@ H5S_conv_t * H5S_find (const H5S_t *mem_space, const H5S_t *file_space, unsigned flags) { H5S_conv_t *path; /* Space conversion path */ - htri_t c1,c2; /* Flags whether a selection is contiguous */ + htri_t opt; /* Flag whether a selection is optimizable */ size_t i; /* Index variable */ FUNC_ENTER (H5S_find, NULL); @@ -1522,33 +1522,41 @@ H5S_find (const H5S_t *mem_space, const H5S_t *file_space, unsigned flags) for (i=0; if->type==file_space->select.type && H5S_conv_g[i]->m->type==mem_space->select.type) { + +#ifdef H5_HAVE_PARALLEL /* - * Initialize direct read/write functions + * Check if we can set direct MPI-IO read/write functions */ - c1=H5S_select_single(file_space); - c2=H5S_select_single(mem_space); - if(c1==FAIL || c2==FAIL) + opt=H5S_mpio_opt_possible(mem_space,file_space,flags); + if(opt==FAIL) HRETURN_ERROR(H5E_DATASPACE, H5E_BADRANGE, NULL, "invalid check for contiguous dataspace "); - if (c1==TRUE && c2==TRUE) { -#ifdef H5_HAVE_PARALLEL - if(flags&H5S_CONV_PAR_IO_POSSIBLE) { - H5S_conv_g[i]->read = H5S_mpio_spaces_read; - H5S_conv_g[i]->write = H5S_mpio_spaces_write; - } /* end if */ - else { + /* Check if we can use the optimized parallel I/O routines */ + if(opt==TRUE) { + H5S_conv_g[i]->read = H5S_mpio_spaces_read; + H5S_conv_g[i]->write = H5S_mpio_spaces_write; + } /* end if */ + else { +#endif /* H5_HAVE_PARALLEL */ + /* + * Check if we can set direct "all" read/write functions + */ + opt=H5S_all_opt_possible(mem_space,file_space,flags); + if(opt==FAIL) + HRETURN_ERROR(H5E_DATASPACE, H5E_BADRANGE, NULL, "invalid check for contiguous dataspace "); + + /* Check if we can use the optimized "all" I/O routines */ + if(opt==TRUE) { H5S_conv_g[i]->read = H5S_all_read; H5S_conv_g[i]->write = H5S_all_write; + } /* end if */ + else { + H5S_conv_g[i]->read = NULL; + H5S_conv_g[i]->write = NULL; } /* end else */ -#else /* H5_HAVE_PARALLEL */ - H5S_conv_g[i]->read = H5S_all_read; - H5S_conv_g[i]->write = H5S_all_write; +#ifdef H5_HAVE_PARALLEL + } /* end else */ #endif /* H5_HAVE_PARALLEL */ - } - else { - H5S_conv_g[i]->read = NULL; - H5S_conv_g[i]->write = NULL; - } HRETURN(H5S_conv_g[i]); } @@ -1571,29 +1579,40 @@ H5S_find (const H5S_t *mem_space, const H5S_t *file_space, unsigned flags) path->f = H5S_fconv_g[file_space->select.type]; path->m = H5S_mconv_g[mem_space->select.type]; +#ifdef H5_HAVE_PARALLEL /* - * Initialize direct read/write functions + * Check if we can set direct MPI-IO read/write functions */ - c1=H5S_select_single(file_space); - c2=H5S_select_single(mem_space); - if(c1==FAIL || c2==FAIL) + opt=H5S_mpio_opt_possible(mem_space,file_space,flags); + if(opt==FAIL) HRETURN_ERROR(H5E_DATASPACE, H5E_BADRANGE, NULL, "invalid check for contiguous dataspace "); - if (c1==TRUE && c2==TRUE) { -#ifdef H5_HAVE_PARALLEL - if(flags&H5S_CONV_PAR_IO_POSSIBLE) { - path->read = H5S_mpio_spaces_read; - path->write = H5S_mpio_spaces_write; - } /* end if */ - else { + /* Check if we can use the optimized parallel I/O routines */ + if(opt==TRUE) { + path->read = H5S_mpio_spaces_read; + path->write = H5S_mpio_spaces_write; + } /* end if */ + else { +#endif /* H5_HAVE_PARALLEL */ + /* + * Check if we can set direct "all" read/write functions + */ + opt=H5S_all_opt_possible(mem_space,file_space,flags); + if(opt==FAIL) + HRETURN_ERROR(H5E_DATASPACE, H5E_BADRANGE, NULL, "invalid check for contiguous dataspace "); + + /* Check if we can use the optimized "all" I/O routines */ + if(opt==TRUE) { path->read = H5S_all_read; path->write = H5S_all_write; + } /* end if */ + else { + path->read = NULL; + path->write = NULL; } /* end else */ -#else /* H5_HAVE_PARALLEL */ - path->read = H5S_all_read; - path->write = H5S_all_write; +#ifdef H5_HAVE_PARALLEL + } /* end else */ #endif /* H5_HAVE_PARALLEL */ - } /* end if */ /* * Add the new path to the table. diff --git a/src/H5Sall.c b/src/H5Sall.c index 1692ff7..e38607b 100644 --- a/src/H5Sall.c +++ b/src/H5Sall.c @@ -368,6 +368,58 @@ H5S_all_mscat (const void *tconv_buf, size_t elmt_size, /*------------------------------------------------------------------------- + * Function: H5S_all_opt_possible + * + * Purpose: Checks if an direct I/O transfer is possible between memory and + * the file. + * + * Return: Success: Non-negative: TRUE or FALSE + * Failure: Negative + * + * Programmer: Quincey Koziol + * Wednesday, April 3, 2002 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +htri_t +H5S_all_opt_possible( const H5S_t *mem_space, const H5S_t *file_space, const unsigned UNUSED flags) +{ + htri_t c1,c2; /* Flags whether a selection is optimizable */ + htri_t ret_value=TRUE; + + FUNC_ENTER(H5S_all_opt_possible, FAIL); + + /* Check args */ + assert(mem_space); + assert(file_space); + + /* Check whether these are both simple dataspaces */ + if (H5S_SIMPLE!=mem_space->extent.type || H5S_SIMPLE!=file_space->extent.type) + HGOTO_DONE(FALSE); + + /* Check whether both selections are single blocks */ + c1=H5S_select_single(file_space); + c2=H5S_select_single(mem_space); + if(c1==FAIL || c2==FAIL) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "invalid check for single selection blocks"); + if(c1==FALSE || c2==FALSE) + HGOTO_DONE(FALSE); + + /* Check whether the shape of each block is the same */ + c1=H5S_select_shape_same(mem_space,file_space); + if(c1==FAIL) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "invalid check for selection blocks same"); + if(c1==FALSE) + HGOTO_DONE(FALSE); + +done: + FUNC_LEAVE(ret_value); +} /* H5S_all_opt_possible() */ + + +/*------------------------------------------------------------------------- * Function: H5S_all_read * * Purpose: Reads directly from file into application memory if possible. @@ -395,12 +447,11 @@ herr_t H5S_all_read(H5F_t *f, const H5O_layout_t *layout, const H5O_pline_t *pline, const struct H5O_fill_t *fill, const H5O_efl_t *efl, size_t elmt_size, const H5S_t *file_space, - const H5S_t *mem_space, hid_t dxpl_id, void *_buf/*out*/, - hbool_t *must_convert/*out*/) + const H5S_t *mem_space, hid_t dxpl_id, void *_buf/*out*/) { H5S_hyper_span_t *file_span=NULL,*mem_span=NULL; /* Hyperslab span node */ char *buf=(char*)_buf; /* Get pointer to buffer */ - hsize_t mem_elmts,file_elmts; /* Number of elements in each dimension of selection */ + hsize_t file_elmts; /* Number of elements in each dimension of selection */ hssize_t file_off,mem_off; /* Offset (in elements) of selection */ hsize_t mem_size[H5O_LAYOUT_NDIMS]; /* Size of memory buffer */ hsize_t size[H5O_LAYOUT_NDIMS]; /* Size of selection */ @@ -410,30 +461,19 @@ H5S_all_read(H5F_t *f, const H5O_layout_t *layout, const H5O_pline_t *pline, herr_t ret_value=SUCCEED; FUNC_ENTER(H5S_all_read, FAIL); - *must_convert = TRUE; #ifdef QAK printf("%s: check 1.0\n",FUNC); #endif /* QAK */ - /* Check whether we can handle this */ - if (H5S_SIMPLE!=mem_space->extent.type) - HGOTO_DONE(SUCCEED); - if (H5S_SIMPLE!=file_space->extent.type) - HGOTO_DONE(SUCCEED); - if (mem_space->extent.u.simple.rank!=file_space->extent.u.simple.rank) - HGOTO_DONE(SUCCEED); - /* Get information about memory and file */ for (u=0; uextent.u.simple.rank; u++) { switch(mem_space->select.type) { case H5S_SEL_HYPERSLABS: /* Check for a "regular" hyperslab selection */ if(mem_space->select.sel_info.hslab.diminfo != NULL) { - mem_elmts=mem_space->select.sel_info.hslab.diminfo[u].block; mem_off=mem_space->select.sel_info.hslab.diminfo[u].start; } /* end if */ else { - mem_elmts=(mem_span->high-mem_span->low)+1; mem_off=mem_span->low; mem_span=mem_span->down->head; } /* end else */ @@ -441,12 +481,10 @@ printf("%s: check 1.0\n",FUNC); break; case H5S_SEL_ALL: - mem_elmts=mem_space->extent.u.simple.size[u]; mem_off=0; break; case H5S_SEL_POINTS: - mem_elmts=1; mem_off=mem_space->select.sel_info.pnt_lst->head->pnt[u] +mem_space->select.offset[u]; break; @@ -485,9 +523,6 @@ printf("%s: check 1.0\n",FUNC); assert(0 && "Invalid selection type!"); } /* end switch */ - if (mem_elmts!=file_elmts) - HGOTO_DONE(SUCCEED); - mem_size[u]=mem_space->extent.u.simple.size[u]; size[u] = file_elmts; file_offset[u] = file_off; @@ -511,11 +546,8 @@ for (u=0; u<=mem_space->extent.u.simple.rank; u++) #endif /* QAK */ /* Read data from the file */ if (H5F_arr_read(f, dxpl_id, layout, pline, fill, efl, size, - mem_size, mem_offset, file_offset, buf/*out*/)<0) { - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, - "unable to read data from the file"); - } - *must_convert = FALSE; + mem_size, mem_offset, file_offset, buf/*out*/)<0) + HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "unable to read data from the file"); done: FUNC_LEAVE(ret_value); @@ -552,8 +584,7 @@ H5S_all_write(H5F_t *f, const struct H5O_layout_t *layout, const struct H5O_fill_t *fill, const H5O_efl_t *efl, size_t elmt_size, const H5S_t *file_space, - const H5S_t *mem_space, hid_t dxpl_id, const void *_buf, - hbool_t *must_convert/*out*/) + const H5S_t *mem_space, hid_t dxpl_id, const void *_buf) { H5S_hyper_span_t *file_span=NULL,*mem_span=NULL; /* Hyperslab span node */ const char *buf=(const char*)_buf; /* Get pointer to buffer */ @@ -567,18 +598,10 @@ H5S_all_write(H5F_t *f, const struct H5O_layout_t *layout, herr_t ret_value=SUCCEED; FUNC_ENTER(H5S_all_write, FAIL); - *must_convert = TRUE; #ifdef QAK printf("%s: check 1.0\n",FUNC); #endif /* QAK */ - /* Check whether we can handle this */ - if (H5S_SIMPLE!=mem_space->extent.type) - HGOTO_DONE(SUCCEED); - if (H5S_SIMPLE!=file_space->extent.type) - HGOTO_DONE(SUCCEED); - if (mem_space->extent.u.simple.rank!=file_space->extent.u.simple.rank) - HGOTO_DONE(SUCCEED); /* Get information about memory and file */ for (u=0; uextent.u.simple.rank; u++) { @@ -642,9 +665,6 @@ printf("%s: check 1.0\n",FUNC); assert(0 && "Invalid selection type!"); } /* end switch */ - if (mem_elmts!=file_elmts) - HGOTO_DONE(SUCCEED); - mem_size[u]=mem_space->extent.u.simple.size[u]; size[u] = file_elmts; file_offset[u] = file_off; @@ -668,11 +688,8 @@ for (u=0; u<=mem_space->extent.u.simple.rank; u++) #endif /* QAK */ /* Write data to the file */ if (H5F_arr_write(f, dxpl_id, layout, pline, fill, efl, size, - mem_size, mem_offset, file_offset, buf)<0) { - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, - "unable to write data to the file"); - } - *must_convert = FALSE; + mem_size, mem_offset, file_offset, buf)<0) + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "unable to write data to the file"); done: FUNC_LEAVE(ret_value); diff --git a/src/H5Shyper.c b/src/H5Shyper.c index 487de1b..4c1f3f5 100644 --- a/src/H5Shyper.c +++ b/src/H5Shyper.c @@ -5963,7 +5963,7 @@ H5S_hyper_select_single(const H5S_t *space) assert(space); - /* Check for a "regular" hyperslab selection */ + /* Check for a "single" hyperslab selection */ if(space->select.sel_info.hslab.diminfo != NULL) { /* * For a regular hyperslab to be single, it must have only one @@ -6013,6 +6013,47 @@ H5S_hyper_select_single(const H5S_t *space) /*-------------------------------------------------------------------------- NAME + H5S_hyper_select_regular + PURPOSE + Check if a hyperslab selection is "regular" + USAGE + htri_t H5S_hyper_select_regular(space) + const H5S_t *space; IN: Dataspace pointer to check + RETURNS + TRUE/FALSE/FAIL + DESCRIPTION + Checks to see if the current selection in a dataspace is the a regular + pattern. + This is primarily used for reading the entire selection in one swoop. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + Doesn't check for "regular" hyperslab selections composed of spans + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +htri_t +H5S_hyper_select_regular(const H5S_t *space) +{ + htri_t ret_value=FAIL; /* return value */ + + FUNC_ENTER (H5S_hyper_select_regular, FAIL); + + /* Check args */ + assert(space); + + /* Only simple check for regular hyperslabs for now... */ + if(space->select.sel_info.hslab.diminfo != NULL) + ret_value=TRUE; + else + ret_value=FALSE; + +done: + FUNC_LEAVE (ret_value); +} /* H5S_hyper_select_regular() */ + + +/*-------------------------------------------------------------------------- + NAME H5S_hyper_select_iterate_helper PURPOSE Internal routine to iterate over the elements of a span tree hyperslab selection diff --git a/src/H5Smpio.c b/src/H5Smpio.c index b5e7028..13293c3 100644 --- a/src/H5Smpio.c +++ b/src/H5Smpio.c @@ -63,8 +63,7 @@ H5S_mpio_spaces_xfer(H5F_t *f, const struct H5O_layout_t *layout, const struct H5O_fill_t UNUSED *fill, const struct H5O_efl_t UNUSED *efl, size_t elmt_size, const H5S_t *file_space, const H5S_t *mem_space, - hid_t dxpl_id, void *buf/*out*/, - hbool_t *must_convert/*out*/, const hbool_t do_write); + hid_t dxpl_id, void *buf/*out*/, const hbool_t do_write); /*------------------------------------------------------------------------- * Function: H5S_mpio_all_type @@ -533,9 +532,6 @@ H5S_mpio_space_type( const H5S_t *space, const size_t elmt_size, * directly between app buffer and file. * * Return: non-negative on success, negative on failure. - * If MPI-IO is indeed used, must_convert is set to 0; - * otherwise it is set to 1 with return code succeed (so that the - * calling routine may try other means.) * * Programmer: rky 980813 * @@ -547,6 +543,10 @@ H5S_mpio_space_type( const H5S_t *space, const size_t elmt_size, * Albert Cheng, 001123 * Include the MPI_type freeing as part of cleanup code. * + * QAK - 2002/04/02 + * Removed the must_convert parameter and move preconditions to + * H5S_mpio_opt_possible() routine + * *------------------------------------------------------------------------- */ herr_t @@ -556,7 +556,6 @@ H5S_mpio_spaces_xfer(H5F_t *f, const struct H5O_layout_t *layout, const struct H5O_efl_t UNUSED *efl, size_t elmt_size, const H5S_t *file_space, const H5S_t *mem_space, hid_t dxpl_id, void *buf /*out*/, - hbool_t *must_convert /*out*/, const hbool_t do_write ) { herr_t ret_value = SUCCEED; @@ -571,8 +570,6 @@ H5S_mpio_spaces_xfer(H5F_t *f, const struct H5O_layout_t *layout, FUNC_ENTER (H5S_mpio_spaces_xfer, FAIL); - *must_convert = 0; /* means we at least tried to do optimized xfer */ - /* Check args */ assert (f); assert (layout); @@ -584,18 +581,6 @@ H5S_mpio_spaces_xfer(H5F_t *f, const struct H5O_layout_t *layout, assert(H5I_GENPROP_LST==H5I_get_type(dxpl_id)); assert(TRUE==H5P_isa_class(dxpl_id,H5P_DATASET_XFER)); - /* INCOMPLETE!!! rky 980816 */ - /* Currently can only handle H5D_CONTIGUOUS layout */ - if (layout->type != H5D_CONTIGUOUS) { -#ifdef H5S_DEBUG - if (H5DEBUG(S)) { - HDfprintf (H5DEBUG(S), "H5S: can only create MPI datatype for hyperslab when layout is contiguous.\n" ); - } -#endif - *must_convert = 1; /* can't do optimized xfer; do the old way */ - HGOTO_DONE(SUCCEED); - } - /* * For collective data transfer only since this would eventually * call H5FD_mpio_setup to do setup to eveually call MPI_File_set_view @@ -624,12 +609,6 @@ H5S_mpio_spaces_xfer(H5F_t *f, const struct H5O_layout_t *layout, /* Get the driver information */ if(H5P_get(plist, H5D_XFER_VFL_INFO_NAME, &dx)<0) HGOTO_ERROR (H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve VFL driver info"); - - /* Check if we are using the MPIO driver */ - if(H5FD_MPIO!=driver_id || H5FD_MPIO_COLLECTIVE!=dx->xfer_mode) { - *must_convert = 1; /* can't do optimized xfer; do the old way */ - HGOTO_DONE(SUCCEED); - } /* end if */ } #endif @@ -717,6 +696,10 @@ done: * rky 980918 * Added must_convert parameter to let caller know we can't optimize the xfer. * + * QAK - 2002/04/02 + * Removed the must_convert parameter and move preconditions to + * H5S_mpio_opt_possible() routine + * *------------------------------------------------------------------------- */ herr_t @@ -725,8 +708,7 @@ H5S_mpio_spaces_read(H5F_t *f, const struct H5O_layout_t *layout, const struct H5O_fill_t *fill, const struct H5O_efl_t *efl, size_t elmt_size, const H5S_t *file_space, const H5S_t *mem_space, - hid_t dxpl_id, void *buf/*out*/, - hbool_t *must_convert/*out*/) + hid_t dxpl_id, void *buf/*out*/) { herr_t ret_value = FAIL; @@ -734,7 +716,7 @@ H5S_mpio_spaces_read(H5F_t *f, const struct H5O_layout_t *layout, ret_value = H5S_mpio_spaces_xfer(f, layout, pline, fill, efl, elmt_size, file_space, mem_space, dxpl_id, - buf, must_convert/*out*/, 0/*read*/); + buf, 0/*read*/); FUNC_LEAVE (ret_value); } @@ -754,6 +736,10 @@ H5S_mpio_spaces_read(H5F_t *f, const struct H5O_layout_t *layout, * rky 980918 * Added must_convert parameter to let caller know we can't optimize the xfer. * + * QAK - 2002/04/02 + * Removed the must_convert parameter and move preconditions to + * H5S_mpio_opt_possible() routine + * *------------------------------------------------------------------------- */ herr_t @@ -762,8 +748,7 @@ H5S_mpio_spaces_write(H5F_t *f, const struct H5O_layout_t *layout, const struct H5O_fill_t *fill, const struct H5O_efl_t *efl, size_t elmt_size, const H5S_t *file_space, const H5S_t *mem_space, - hid_t dxpl_id, const void *buf, - hbool_t *must_convert/*out*/) + hid_t dxpl_id, const void *buf) { herr_t ret_value = FAIL; @@ -771,10 +756,66 @@ H5S_mpio_spaces_write(H5F_t *f, const struct H5O_layout_t *layout, ret_value = H5S_mpio_spaces_xfer(f, layout, pline, fill, efl, elmt_size, file_space, mem_space, dxpl_id, - (void*)buf, must_convert/*out*/, - 1/*write*/); + (void*)buf, 1/*write*/); FUNC_LEAVE (ret_value); } + +/*------------------------------------------------------------------------- + * Function: H5S_mpio_opt_possible + * + * Purpose: Checks if an direct I/O transfer is possible between memory and + * the file. + * + * Return: Success: Non-negative: TRUE or FALSE + * Failure: Negative + * + * Programmer: Quincey Koziol + * Wednesday, April 3, 2002 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +htri_t +H5S_mpio_opt_possible( const H5S_t *mem_space, const H5S_t *file_space, const unsigned flags) +{ + htri_t c1,c2; /* Flags whether a selection is optimizable */ + htri_t ret_value=TRUE; + + FUNC_ENTER(H5S_all_opt_possible, FAIL); + + /* Check args */ + assert(mem_space); + assert(file_space); + + /* Check whether these are both simple dataspaces */ + if (H5S_SIMPLE!=mem_space->extent.type || H5S_SIMPLE!=file_space->extent.type) + HGOTO_DONE(FALSE); + + /* Check whether both selections are "regular" */ + c1=H5S_select_regular(file_space); + c2=H5S_select_regular(mem_space); + if(c1==FAIL || c2==FAIL) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "invalid check for single selection blocks"); + if(c1==FALSE || c2==FALSE) + HGOTO_DONE(FALSE); + + /* Can't currently handle point selections */ + if (H5S_SEL_POINTS==mem_space->select.type || H5S_SEL_POINTS==file_space->select.type) + HGOTO_DONE(FALSE); + + /* Dataset storage must be contiguous currently */ + if ((sconv_flags&H5S_CONV_STORAGE_MASK)!=H5S_CONV_STORAGE_CONTIGUOUS) + HGOTO_DONE(FALSE); + + /* Parallel I/O conversion flag must be set */ + if(!(flags&H5S_CONV_PAR_IO_POSSIBLE)) + HGOTO_DONE(FALSE); + +done: + FUNC_LEAVE(ret_value); +} /* H5S_mpio_opt_possible() */ + #endif /* H5_HAVE_PARALLEL */ diff --git a/src/H5Spkg.h b/src/H5Spkg.h index 0e6a0c5..0fc4513 100644 --- a/src/H5Spkg.h +++ b/src/H5Spkg.h @@ -133,11 +133,11 @@ __DLL__ herr_t H5S_point_select_deserialize(H5S_t *space, const uint8_t *buf); __DLL__ herr_t H5S_point_bounds(H5S_t *space, hsize_t *start, hsize_t *end); __DLL__ htri_t H5S_point_select_contiguous(const H5S_t *space); __DLL__ htri_t H5S_point_select_single(const H5S_t *space); +__DLL__ htri_t H5S_point_select_regular(const H5S_t *space); __DLL__ herr_t H5S_select_elements (H5S_t *space, H5S_seloper_t op, size_t num_elem, const hssize_t **coord); __DLL__ herr_t H5S_point_select_iterate(void *buf, hid_t type_id, H5S_t *space, - H5D_operator_t op, - void *operator_data); + H5D_operator_t op, void *operator_data); /* "All" select functions */ __DLL__ herr_t H5S_all_release(H5S_t *space); @@ -150,17 +150,17 @@ __DLL__ herr_t H5S_all_read(H5F_t *f, const struct H5O_layout_t *layout, const struct H5O_fill_t *fill, const struct H5O_efl_t *efl, size_t elmt_size, const H5S_t *file_space, const H5S_t *mem_space, - hid_t dxpl_id, void *buf/*out*/, - hbool_t *must_convert/*out*/); + hid_t dxpl_id, void *buf/*out*/); __DLL__ herr_t H5S_all_write(H5F_t *f, const struct H5O_layout_t *layout, const struct H5O_pline_t *pline, const struct H5O_fill_t *fill, const struct H5O_efl_t *efl, size_t elmt_size, const H5S_t *file_space, const H5S_t *mem_space, - hid_t dxpl_id, const void *buf, - hbool_t *must_convert/*out*/); + hid_t dxpl_id, const void *buf); __DLL__ herr_t H5S_all_select_iterate(void *buf, hid_t type_id, H5S_t *space, - H5D_operator_t op, void *operator_data); + H5D_operator_t op, void *operator_data); +__DLL__ htri_t H5S_all_opt_possible(const H5S_t *mem_space, + const H5S_t *file_space, const unsigned flags); /* Hyperslab selection functions */ __DLL__ herr_t H5S_hyper_release(H5S_t *space); @@ -176,6 +176,7 @@ __DLL__ herr_t H5S_hyper_span_blocklist(H5S_hyper_span_info_t *spans, hssize_t s __DLL__ herr_t H5S_hyper_bounds(H5S_t *space, hsize_t *start, hsize_t *end); __DLL__ htri_t H5S_hyper_select_contiguous(const H5S_t *space); __DLL__ htri_t H5S_hyper_select_single(const H5S_t *space); +__DLL__ htri_t H5S_hyper_select_regular(const H5S_t *space); __DLL__ herr_t H5S_hyper_select_iterate(void *buf, hid_t type_id, H5S_t *space, H5D_operator_t op, void *operator_data); diff --git a/src/H5Spoint.c b/src/H5Spoint.c index 5cb9079..7ca1bed 100644 --- a/src/H5Spoint.c +++ b/src/H5Spoint.c @@ -1167,6 +1167,48 @@ H5S_point_select_single(const H5S_t *space) /*-------------------------------------------------------------------------- NAME + H5S_point_select_regular + PURPOSE + Check if a point selection is "regular" + USAGE + htri_t H5S_point_select_regular(space) + const H5S_t *space; IN: Dataspace pointer to check + RETURNS + TRUE/FALSE/FAIL + DESCRIPTION + Checks to see if the current selection in a dataspace is the a regular + pattern. + This is primarily used for reading the entire selection in one swoop. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + Doesn't check for points selected to be next to one another in a regular + pattern yet. + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +htri_t +H5S_point_select_regular(const H5S_t *space) +{ + htri_t ret_value=FAIL; /* return value */ + + FUNC_ENTER (H5S_point_select_regular, FAIL); + + /* Check args */ + assert(space); + + /* Only simple check for regular points for now... */ + if(space->select.num_elem==1) + ret_value=TRUE; + else + ret_value=FALSE; + +done: + FUNC_LEAVE (ret_value); +} /* H5S_point_select_regular() */ + + +/*-------------------------------------------------------------------------- + NAME H5S_select_elements PURPOSE Specify a series of elements in the dataspace to select diff --git a/src/H5Sprivate.h b/src/H5Sprivate.h index 713d52f..5af635d 100644 --- a/src/H5Sprivate.h +++ b/src/H5Sprivate.h @@ -32,6 +32,12 @@ /* Flags for H5S_find */ #define H5S_CONV_PAR_IO_POSSIBLE 0x0001 +/* The storage options are mutually exclusive */ +/* (2-bits reserved for storage type currently) */ +#define H5S_CONV_STORAGE_COMPACT 0x0000 /* i.e. '0' */ +#define H5S_CONV_STORAGE_CONTIGUOUS 0x0002 /* i.e. '1' */ +#define H5S_CONV_STORAGE_CHUNKED 0x0004 /* i.e. '2' */ +#define H5S_CONV_STORAGE_MASK 0x0006 /* Forward references of common typedefs */ typedef struct H5S_t H5S_t; @@ -129,17 +135,6 @@ typedef struct H5S_conv_t { * If there is no data type conversion then it might be possible to * transfer data points between application memory and the file in one * step without going through the data type conversion buffer. - * - * rky 980918 - * If the direct read or write function determines that the transfer - * must be done indirectly, i.e., through the conversion buffer or - * (in the case of parallel MPI-IO) in block-by-block transfers - * then the function returns with the value of must_convert!=0, - * the function's return value is SUCCEED, - * and no transfer of data is attempted. - * Otherwise the direct read or write function returns must_convert 0, - * with the function's return value being SUCCEED or FAIL - * depending on whether or not the transfer of data was successful. */ /* Read from file to application w/o intermediate scratch buffer */ @@ -148,8 +143,7 @@ typedef struct H5S_conv_t { const struct H5O_fill_t *fill, const struct H5O_efl_t *efl, size_t elmt_size, const H5S_t *file_space, const H5S_t *mem_space, - hid_t dxpl_id, void *buf/*out*/, - hbool_t *must_convert/*out*/); + hid_t dxpl_id, void *buf/*out*/); /* Write directly from app buffer to file */ @@ -158,8 +152,7 @@ typedef struct H5S_conv_t { const struct H5O_fill_t *fill, const struct H5O_efl_t *efl, size_t elmt_size, const H5S_t *file_space, const H5S_t *mem_space, - hid_t dxpl_id, const void *buf, - hbool_t *must_convert/*out*/); + hid_t dxpl_id, const void *buf); #ifdef H5S_DEBUG struct { @@ -224,12 +217,19 @@ __DLL__ herr_t H5S_select_serialize(const H5S_t *space, uint8_t *buf); __DLL__ herr_t H5S_select_deserialize(H5S_t *space, const uint8_t *buf); __DLL__ htri_t H5S_select_contiguous(const H5S_t *space); __DLL__ htri_t H5S_select_single(const H5S_t *space); +__DLL__ htri_t H5S_select_regular(const H5S_t *space); +__DLL__ htri_t H5S_select_shape_same(const H5S_t *space1, const H5S_t *space2); __DLL__ herr_t H5S_select_iterate(void *buf, hid_t type_id, H5S_t *space, H5D_operator_t op, void *operator_data); __DLL__ herr_t H5S_sel_iter_release(const H5S_t *space, H5S_sel_iter_t *sel_iter); #ifdef H5_HAVE_PARALLEL + +/* MPI-IO function to check whether its possible to transfer directly from app buffer to file */ +__DLL__ htri_t H5S_all_opt_possible(const H5S_t *mem_space, + const H5S_t *file_space, const unsigned flags); + /* MPI-IO function to read directly from app buffer to file rky980813 */ __DLL__ herr_t H5S_mpio_spaces_read(H5F_t *f, const struct H5O_layout_t *layout, @@ -238,8 +238,7 @@ __DLL__ herr_t H5S_mpio_spaces_read(H5F_t *f, const struct H5O_efl_t *efl, size_t elmt_size, const H5S_t *file_space, const H5S_t *mem_space, hid_t dxpl_id, - void *buf/*out*/, - hbool_t *must_convert /*out*/ ); + void *buf/*out*/); /* MPI-IO function to write directly from app buffer to file rky980813 */ __DLL__ herr_t H5S_mpio_spaces_write(H5F_t *f, @@ -249,8 +248,7 @@ __DLL__ herr_t H5S_mpio_spaces_write(H5F_t *f, const struct H5O_efl_t *efl, size_t elmt_size, const H5S_t *file_space, const H5S_t *mem_space, hid_t dxpl_id, - const void *buf, - hbool_t *must_convert /*out*/ ); + const void *buf); #ifndef _H5S_IN_H5S_C /* Global var whose value comes from environment variable */ __DLLVAR__ hbool_t H5_mpi_opt_types_g; diff --git a/src/H5Sselect.c b/src/H5Sselect.c index b592e9f..92f9832 100644 --- a/src/H5Sselect.c +++ b/src/H5Sselect.c @@ -1342,6 +1342,7 @@ H5S_select_single(const H5S_t *space) FUNC_ENTER (H5S_select_single, FAIL); + /* Check args */ assert(space); switch(space->select.type) { @@ -1369,3 +1370,173 @@ H5S_select_single(const H5S_t *space) FUNC_LEAVE (ret_value); } /* H5S_select_single() */ + +/*-------------------------------------------------------------------------- + NAME + H5S_select_shape_same + PURPOSE + Check if two selections are the same shape + USAGE + htri_t H5S_select_shape_same(space1, space2) + const H5S_t *space1; IN: 1st Dataspace pointer to compare + const H5S_t *space2; IN: 2nd Dataspace pointer to compare + RETURNS + TRUE/FALSE/FAIL + DESCRIPTION + Checks to see if the current selection in the dataspaces are the same + dimensionality and shape. + This is primarily used for reading the entire selection in one swoop. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + Assumes that there is only a single "block" for hyperslab selections. + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +htri_t +H5S_select_shape_same(const H5S_t *space1, const H5S_t *space2) +{ + H5S_hyper_span_t *span1=NULL,*span2=NULL; /* Hyperslab span node */ + hsize_t elmts1,elmts2; /* Number of elements in each dimension of selection */ + unsigned u; /* Index variable */ + htri_t ret_value=TRUE; /* return value */ + + FUNC_ENTER (H5S_select_shape_same, FAIL); + + /* Check args */ + assert(space1); + assert(space2); + + if (space1->extent.u.simple.rank!=space2->extent.u.simple.rank) + HGOTO_DONE(FALSE); + + /* Get information about memory and file */ + for (u=0; uextent.u.simple.rank; u++) { + switch(space1->select.type) { + case H5S_SEL_HYPERSLABS: + /* Check size hyperslab selection in this dimension */ + if(space1->select.sel_info.hslab.diminfo != NULL) { + elmts1=space1->select.sel_info.hslab.diminfo[u].block; + } /* end if */ + else { + /* Check for the first dimension */ + if(span1==NULL) + span1=space1->select.sel_info.hslab.span_lst->head; + + /* Get the number of elements in the span */ + elmts1=(span1->high-span1->low)+1; + + /* Advance to the next dimension */ + span1=span1->down->head; + } /* end else */ + break; + + case H5S_SEL_ALL: + elmts1=space1->extent.u.simple.size[u]; + break; + + case H5S_SEL_POINTS: + elmts1=1; + break; + + default: + assert(0 && "Invalid selection type!"); + } /* end switch */ + + switch(space2->select.type) { + case H5S_SEL_HYPERSLABS: + /* Check size hyperslab selection in this dimension */ + if(space2->select.sel_info.hslab.diminfo != NULL) { + elmts2=space2->select.sel_info.hslab.diminfo[u].block; + } /* end if */ + else { + /* Check for the first dimension */ + if(span2==NULL) + span2=space2->select.sel_info.hslab.span_lst->head; + + /* Get the number of elements in the span */ + elmts2=(span2->high-span2->low)+1; + + /* Advance to the next dimension */ + span2=span2->down->head; + } /* end else */ + break; + + case H5S_SEL_ALL: + elmts2=space2->extent.u.simple.size[u]; + break; + + case H5S_SEL_POINTS: + elmts2=1; + break; + + default: + assert(0 && "Invalid selection type!"); + } /* end switch */ + + /* Make certaint the selections have the same number of elements in this dimension */ + if (elmts1!=elmts2) + HGOTO_DONE(FALSE); + } /* end for */ + +done: + FUNC_LEAVE (ret_value); +} /* H5S_select_shape_same() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_select_regular + PURPOSE + Check if a selection is "regular" + USAGE + htri_t H5S_select_regular(space) + const H5S_t *space; IN: Dataspace pointer to check + RETURNS + TRUE/FALSE/FAIL + DESCRIPTION + Checks to see if the current selection in a dataspace is the a regular + pattern. + This is primarily used for reading the entire selection in one swoop. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +htri_t +H5S_select_regular(const H5S_t *space) +{ + htri_t ret_value=FAIL; /* return value */ + + FUNC_ENTER (H5S_select_regular, FAIL); + + /* Check args */ + assert(space); + + /* Check for a "regular" selection */ + /* [Defer (mostly) to the selection routines] */ + switch(space->select.type) { + case H5S_SEL_POINTS: /* Sequence of points selected */ + ret_value=H5S_point_select_regular(space); + break; + + case H5S_SEL_HYPERSLABS: /* Hyperslab selection defined */ + ret_value=H5S_hyper_select_regular(space); + break; + + case H5S_SEL_ALL: /* Entire extent selected */ + ret_value=TRUE; + break; + + case H5S_SEL_NONE: /* Nothing selected */ + ret_value=FALSE; + break; + + case H5S_SEL_ERROR: + case H5S_SEL_N: + break; + } /* end switch */ + +done: + FUNC_LEAVE (ret_value); +} /* H5S_select_regular() */ + -- cgit v0.12