diff options
author | Quincey Koziol <koziol@hdfgroup.org> | 2000-09-13 21:58:18 (GMT) |
---|---|---|
committer | Quincey Koziol <koziol@hdfgroup.org> | 2000-09-13 21:58:18 (GMT) |
commit | 1f109221dffd39ca93470923b32eb2a13ccb5715 (patch) | |
tree | 296f00b85e2aab5c5100a585af8074525b4fd1d6 /src | |
parent | 683a11a633bb78695714f981d40a0265fdd81154 (diff) | |
download | hdf5-1f109221dffd39ca93470923b32eb2a13ccb5715.zip hdf5-1f109221dffd39ca93470923b32eb2a13ccb5715.tar.gz hdf5-1f109221dffd39ca93470923b32eb2a13ccb5715.tar.bz2 |
[svn-r2544] Optimized regular hyperslab I/O routines and data structures. On my benchmarks,
they are about 4-5 times faster than before. We no longer generate "general"
hyperslab data structures for regular hyperslabs, the general data structures
are only generated when needed for irregular hyperslabs.
Still fixing a couple of nook-and-cranny functions to understand the new
information for the regular hyperslabs, so the tests aren't completely passing,
but I wanted to get this checked in for Elena's benchmarks. I should have
more/all tests passing later today.
Diffstat (limited to 'src')
-rw-r--r-- | src/H5Shyper.c | 2060 | ||||
-rw-r--r-- | src/H5Sselect.c | 138 |
2 files changed, 1886 insertions, 312 deletions
diff --git a/src/H5Shyper.c b/src/H5Shyper.c index c140e70..4348c82 100644 --- a/src/H5Shyper.c +++ b/src/H5Shyper.c @@ -60,8 +60,18 @@ static H5S_hyper_region_t * H5S_hyper_get_regions (size_t *num_regions, uintn rank, uintn dim, size_t bound_count, H5S_hyper_bound_t **lo_bounds, hssize_t *pos, hssize_t *offset); static size_t H5S_hyper_fread (intn dim, H5S_hyper_io_info_t *io_info); +static size_t H5S_hyper_fread_opt (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, H5S_sel_iter_t *file_iter, + size_t nelmts, hid_t dxpl_id, void *_buf/*out*/); static size_t H5S_hyper_fwrite (intn dim, H5S_hyper_io_info_t *io_info); +static size_t H5S_hyper_fwrite_opt (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, H5S_sel_iter_t *file_iter, + size_t nelmts, hid_t dxpl_id, const void *_buf); static herr_t H5S_hyper_init (const struct H5O_layout_t *layout, const H5S_t *space, H5S_sel_iter_t *iter, size_t *min_elem_out); static size_t H5S_hyper_favail (const H5S_t *space, const H5S_sel_iter_t *iter, @@ -80,10 +90,18 @@ static herr_t H5S_hyper_fscat (H5F_t *f, const struct H5O_layout_t *layout, const H5S_t *file_space, H5S_sel_iter_t *file_iter, size_t nelmts, hid_t dxpl_id, const void *buf); +static size_t H5S_hyper_mread (intn dim, H5S_hyper_io_info_t *io_info); +static herr_t H5S_hyper_mread_opt (const void *_buf, size_t elmt_size, + const H5S_t *mem_space, H5S_sel_iter_t *mem_iter, + size_t nelmts, void *_tconv_buf/*out*/); static size_t H5S_hyper_mgath (const void *_buf, size_t elmt_size, const H5S_t *mem_space, H5S_sel_iter_t *mem_iter, size_t nelmts, void *_tconv_buf/*out*/); +static size_t H5S_hyper_mwrite (intn dim, H5S_hyper_io_info_t *io_info); +static herr_t H5S_hyper_mwrite_opt (const void *_tconv_buf, size_t elmt_size, + const H5S_t *mem_space, H5S_sel_iter_t *mem_iter, + size_t nelmts, void *_buf/*out*/); static herr_t H5S_hyper_mscat (const void *_tconv_buf, size_t elmt_size, const H5S_t *mem_space, H5S_sel_iter_t *mem_iter, size_t nelmts, @@ -808,6 +826,338 @@ H5S_hyper_fread (intn dim, H5S_hyper_io_info_t *io_info) /*------------------------------------------------------------------------- + * Function: H5S_hyper_iter_next + * + * Purpose: Moves a hyperslab iterator to the beginning of the next sequence + * of elements to read. Handles walking off the end in all dimensions. + * + * Return: Success: non-negative + * Failure: negative + * + * Programmer: Quincey Koziol + * Friday, September 8, 2000 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static int +H5S_hyper_iter_next (const H5S_t *file_space, H5S_sel_iter_t *file_iter) +{ + hssize_t iter_offset[H5O_LAYOUT_NDIMS]; + hssize_t iter_count[H5O_LAYOUT_NDIMS]; + intn fast_dim; /* Rank of the fastest changing dimension for the dataspace */ + intn temp_dim; /* Temporary rank holder */ + intn i; /* Counters */ + uintn ndims; /* Number of dimensions of dataset */ + size_t num_read=0; /* Number of elements read */ + + FUNC_ENTER (H5S_hyper_iter_next, FAIL); + + /* Set some useful rank information */ + fast_dim=file_space->extent.u.simple.rank-1; + ndims=file_space->extent.u.simple.rank; + + /* Calculate the offset and block count for each dimension */ + for(i=0; i<ndims; i++) { + iter_offset[i]=(file_iter->hyp.pos[i]-file_space->select.sel_info.hslab.diminfo[i].start)%file_space->select.sel_info.hslab.diminfo[i].stride; + iter_count[i]=(file_iter->hyp.pos[i]-file_space->select.sel_info.hslab.diminfo[i].start)/file_space->select.sel_info.hslab.diminfo[i].stride; + } /* end for */ + + /* Start with the fastest changing dimension */ + temp_dim=fast_dim; + while(temp_dim>=0) { + if(temp_dim==fast_dim) { + /* Move to the next block in the current dimension */ + iter_offset[temp_dim]=0; /* reset the offset in the fastest dimension */ + iter_count[temp_dim]++; + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(iter_count[temp_dim]<file_space->select.sel_info.hslab.diminfo[temp_dim].count) + break; + else + iter_count[temp_dim]=0; /* reset back to the beginning of the line */ + } /* end if */ + else { + /* Move to the next row in the curent dimension */ + iter_offset[temp_dim]++; + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(iter_offset[temp_dim]<file_space->select.sel_info.hslab.diminfo[temp_dim].block) + break; + else { + /* Move to the next block in the current dimension */ + iter_offset[temp_dim]=0; + iter_count[temp_dim]++; + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(iter_count[temp_dim]<file_space->select.sel_info.hslab.diminfo[temp_dim].count) + break; + else + iter_count[temp_dim]=0; /* reset back to the beginning of the line */ + } /* end else */ + } /* end else */ + + /* Decrement dimension count */ + temp_dim--; + } /* end while */ + + /* Translate current iter_offset and iter_count into iterator position */ + for(i=0; i<ndims; i++) + file_iter->hyp.pos[i]=file_space->select.sel_info.hslab.diminfo[i].start+(file_space->select.sel_info.hslab.diminfo[i].stride*iter_count[i])+iter_offset[i]; + + FUNC_LEAVE (SUCCEED); +} /* H5S_hyper_iter_next() */ + + +/*------------------------------------------------------------------------- + * Function: H5S_hyper_fread_opt + * + * Purpose: Performs an optimized gather from the file, based on a regular + * hyperslab (i.e. one which was generated from just one call to + * H5Sselect_hyperslab). + * + * Return: Success: Number of elements copied. + * Failure: 0 + * + * Programmer: Quincey Koziol + * Friday, September 8, 2000 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static size_t +H5S_hyper_fread_opt (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, H5S_sel_iter_t *file_iter, + size_t nelmts, hid_t dxpl_id, void *_buf/*out*/) +{ + hsize_t hsize[H5O_LAYOUT_NDIMS]; /* Hyperslab size */ + hssize_t zero[H5O_LAYOUT_NDIMS]; /*zero */ + hssize_t offset[H5O_LAYOUT_NDIMS]; /* Offset on disk */ + hsize_t tmp_count[H5O_LAYOUT_NDIMS]; /* Temporary block count */ + hsize_t tmp_block[H5O_LAYOUT_NDIMS]; /* Temporary block offset */ + uint8_t *buf=(uint8_t *)_buf; /* Alias for pointer arithmetic */ + intn fast_dim; /* Rank of the fastest changing dimension for the dataspace */ + intn temp_dim; /* Temporary rank holder */ + intn i; /* Counters */ + uintn ndims; /* Number of dimensions of dataset */ + intn actual_read; /* The actual number of elements to read in */ + size_t num_read=0; /* Number of elements read */ + + FUNC_ENTER (H5S_hyper_fread_opt, 0); + +#ifdef QAK +printf("%s: Called!\n",FUNC); +#endif /* QAK */ + /* Check if this is the first element read in from the hyperslab */ + if(file_iter->hyp.pos[0]==(-1)) { + for(i=0; i<file_space->extent.u.simple.rank; i++) + file_iter->hyp.pos[i]=file_space->select.sel_info.hslab.diminfo[i].start; + } /* end if */ + +#ifdef QAK +for(i=0; i<file_space->extent.u.simple.rank; i++) + printf("%s: file_file->hyp.pos[%d]=%d\n",FUNC,(int)i,(int)file_iter->hyp.pos[i]); +#endif /* QAK */ + + /* Set the rank of the fastest changing dimension */ + fast_dim=file_space->extent.u.simple.rank-1; + + /* Set up the hyperslab and 'zero' arrays */ + ndims=file_space->extent.u.simple.rank; + /* initialize hyperslab size and offset in memory buffer */ + for(i=0; i<(int)(ndims+1); i++) { + hsize[i]=1; /* hyperslab size is 1, except for last element */ + zero[i]=0; /* memory offset is 0 */ + } /* end for */ + hsize[ndims] = elmt_size; + + /* Check if we stopped in the middle of a sequence of elements */ + if((file_iter->hyp.pos[fast_dim]-file_space->select.sel_info.hslab.diminfo[fast_dim].start)%file_space->select.sel_info.hslab.diminfo[fast_dim].stride!=0) { + intn leftover; /* The number of elements left over from the last sequence */ + +#ifdef QAK +printf("%s: Check 1.0\n",FUNC); +#endif /* QAK */ + /* Calculate the number of elements left in the sequence */ + leftover=file_space->select.sel_info.hslab.diminfo[fast_dim].block-((file_iter->hyp.pos[fast_dim]-file_space->select.sel_info.hslab.diminfo[fast_dim].start)%file_space->select.sel_info.hslab.diminfo[fast_dim].stride); + + /* Make certain that we don't read too many */ + actual_read=MIN(leftover,nelmts); + + /* Set the hyperslab size in the fastest changing dimension to read in */ + hsize[fast_dim]=actual_read; + + /* Copy the location of the point to get */ + HDmemcpy(offset, file_iter->hyp.pos,ndims*sizeof(hssize_t)); + offset[ndims] = 0; + + /* Add in the selection offset */ + for(i=0; i<ndims; i++) + offset[i] += file_space->select.offset[i]; + + /* Read in the rest of the sequence, if possible */ + if (H5F_arr_read(f, dxpl_id, layout, pline, fill, efl, hsize, + hsize, zero, offset, buf/*out*/)<0) { + HRETURN_ERROR(H5E_DATASPACE, H5E_READERROR, 0, "read error"); + } + + /* Increment the offset of the buffer */ + buf+=elmt_size*actual_read; + + /* Increment the count read */ + num_read+=actual_read; + + /* Decrement the number of elements left in selection */ + file_iter->hyp.elmt_left-=actual_read; + + /* Advance the point iterator */ + /* If we had enough buffer space to read in the rest of the sequence + * in the fastest changing dimension, move the iterator offset to + * the beginning of the next block to read. Otherwise, just advance + * the iterator in the fastest changing dimension. + */ + if(actual_read==leftover) { + /* Move iterator offset to beginning of next sequence in the fastest changing dimension */ + H5S_hyper_iter_next(file_space,file_iter); + } /* end if */ + else { + file_iter->hyp.pos[fast_dim]+=actual_read; /* whole sequence not read in, just advance fastest dimension offset */ + } /* end if */ + } /* end if */ + + /* Now that we've cleared the "remainder" of the previous fastest dimension + * sequence, we must be at the beginning of a sequence, so use the fancy + * algorithm to compute the offsets and run through as many as possible, + * until the buffer fills up. + */ + if(num_read<nelmts) { /* Just in case the "remainder" aboce filled the buffer */ +#ifdef QAK +printf("%s: Check 2.0\n",FUNC); +#endif /* QAK */ + /* Compute the arrays to perform I/O on */ + /* Copy the location of the point to get */ + HDmemcpy(offset, file_iter->hyp.pos,ndims*sizeof(hssize_t)); + offset[ndims] = 0; + + /* Add in the selection offset */ + for(i=0; i<ndims; i++) + offset[i] += file_space->select.offset[i]; + + /* Compute the current "counts" for this location */ + for(i=0; i<ndims; i++) { + tmp_count[i] = (file_iter->hyp.pos[i]-file_space->select.sel_info.hslab.diminfo[i].start)%file_space->select.sel_info.hslab.diminfo[i].stride; + tmp_block[i] = (file_iter->hyp.pos[i]-file_space->select.sel_info.hslab.diminfo[i].start)/file_space->select.sel_info.hslab.diminfo[i].stride; + } /* end for */ + + /* Set the number of elements to read each time */ + actual_read=file_space->select.sel_info.hslab.diminfo[fast_dim].block; + hsize[fast_dim]=actual_read; +#ifdef QAK +printf("%s: actual_read=%d\n",FUNC,(int)actual_read); +for(i=0; i<file_space->extent.u.simple.rank; i++) + printf("%s: diminfo: start[%d]=%d, stride[%d]=%d, block[%d]=%d, count[%d]=%d\n",FUNC, + (int)i,(int)file_space->select.sel_info.hslab.diminfo[i].start, + (int)i,(int)file_space->select.sel_info.hslab.diminfo[i].stride, + (int)i,(int)file_space->select.sel_info.hslab.diminfo[i].block, + (int)i,(int)file_space->select.sel_info.hslab.diminfo[i].count); +#endif /* QAK */ + + /* Read in data until an entire sequence can't be read in any longer */ + while(num_read<nelmts) { + /* Check if we are running out of room in the buffer */ + if((actual_read+num_read)>nelmts) { + actual_read=nelmts-num_read; + hsize[fast_dim]=actual_read; + } /* end if */ + +#ifdef QAK +printf("%s: num_read=%d\n",FUNC,(int)num_read); +for(i=0; i<file_space->extent.u.simple.rank; i++) + printf("%s: tmp_count[%d]=%d, offset[%d]=%d\n",FUNC,(int)i,(int)tmp_count[i],(int)i,(int)offset[i]); +#endif /* QAK */ + + /* Read in the sequence, if possible */ + if (H5F_arr_read(f, dxpl_id, layout, pline, fill, efl, hsize, + hsize, zero, offset, buf/*out*/)<0) { + HRETURN_ERROR(H5E_DATASPACE, H5E_READERROR, 0, "read error"); + } + + /* Increment the offset of the buffer */ + buf+=elmt_size*actual_read; + + /* Increment the count read */ + num_read+=actual_read; + + /* Decrement the number of elements left in selection */ + file_iter->hyp.elmt_left-=actual_read; + + /* Increment the offset and count */ + temp_dim=fast_dim; + while(temp_dim>=0) { + if(temp_dim==fast_dim) { + /* Move to the next block in the current dimension */ + /* Check for partial block read! */ + if(actual_read<file_space->select.sel_info.hslab.diminfo[fast_dim].block) { + offset[temp_dim]+=actual_read; + break; + } /* end if */ + else { + offset[temp_dim]+=file_space->select.sel_info.hslab.diminfo[temp_dim].stride; /* reset the offset in the fastest dimension */ + tmp_count[temp_dim]++; + } /* end else */ + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(tmp_count[temp_dim]<file_space->select.sel_info.hslab.diminfo[temp_dim].count) + break; + else { + tmp_count[temp_dim]=0; /* reset back to the beginning of the line */ + offset[temp_dim]=file_space->select.sel_info.hslab.diminfo[temp_dim].start+file_space->select.offset[temp_dim]; + } /* end else */ + } /* end if */ + else { + /* Move to the next row in the curent dimension */ + offset[temp_dim]++; + tmp_block[temp_dim]++; + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(tmp_block[temp_dim]<file_space->select.sel_info.hslab.diminfo[temp_dim].block) + break; + else { + /* Move to the next block in the current dimension */ + offset[temp_dim]+=(file_space->select.sel_info.hslab.diminfo[temp_dim].stride-file_space->select.sel_info.hslab.diminfo[temp_dim].block); + tmp_block[temp_dim]=0; + tmp_count[temp_dim]++; + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(tmp_count[temp_dim]<file_space->select.sel_info.hslab.diminfo[temp_dim].count) + break; + else { + tmp_count[temp_dim]=0; /* reset back to the beginning of the line */ + tmp_block[temp_dim]=0; + offset[temp_dim]=file_space->select.sel_info.hslab.diminfo[temp_dim].start+file_space->select.offset[temp_dim]; + } + } /* end else */ + } /* end else */ + + /* Decrement dimension count */ + temp_dim--; + } /* end while */ + } /* end while */ + + /* Update the iterator with the location we stopped */ + HDmemcpy(file_iter->hyp.pos, offset, ndims*sizeof(hssize_t)); + } /* end if */ + + FUNC_LEAVE (num_read); +} /* H5S_hyper_fread_opt() */ + + +/*------------------------------------------------------------------------- * Function: H5S_hyper_fgath * * Purpose: Gathers data points from file F and accumulates them in the @@ -859,31 +1209,39 @@ H5S_hyper_fgath (H5F_t *f, const struct H5O_layout_t *layout, printf("%s: check 1.0\n", FUNC); #endif /* QAK */ - /* Initialize parameter block for recursive calls */ - io_info.f=f; - io_info.layout=layout; - io_info.pline=pline; - io_info.fill=fill; - io_info.efl=efl; - io_info.elmt_size=elmt_size; - io_info.space=file_space; - io_info.iter=file_iter; - io_info.nelmts=nelmts; - io_info.dxpl_id = dxpl_id; - io_info.src=NULL; - io_info.dst=_buf; - - /* Set the hyperslab size to copy */ - io_info.hsize[0]=1; - H5V_array_fill(io_info.hsize,io_info.hsize,sizeof(io_info.hsize[0]),file_space->extent.u.simple.rank); - io_info.hsize[file_space->extent.u.simple.rank]=elmt_size; - - /* Recursively input the hyperslabs currently defined */ - /* starting with the slowest changing dimension */ - num_read=H5S_hyper_fread(-1,&io_info); + /* Check for the special case of just one H5Sselect_hyperslab call made */ + if(file_space->select.sel_info.hslab.diminfo!=NULL) { + /* Use optimized call to read in regular hyperslab */ + num_read=H5S_hyper_fread_opt(f,layout,pline,fill,efl,elmt_size,file_space,file_iter,nelmts,dxpl_id,_buf); + } /* end if */ + /* Perform generic hyperslab operation */ + else { + /* Initialize parameter block for recursive calls */ + io_info.f=f; + io_info.layout=layout; + io_info.pline=pline; + io_info.fill=fill; + io_info.efl=efl; + io_info.elmt_size=elmt_size; + io_info.space=file_space; + io_info.iter=file_iter; + io_info.nelmts=nelmts; + io_info.dxpl_id = dxpl_id; + io_info.src=NULL; + io_info.dst=_buf; + + /* Set the hyperslab size to copy */ + io_info.hsize[0]=1; + H5V_array_fill(io_info.hsize,io_info.hsize,sizeof(io_info.hsize[0]),file_space->extent.u.simple.rank); + io_info.hsize[file_space->extent.u.simple.rank]=elmt_size; + + /* Recursively input the hyperslabs currently defined */ + /* starting with the slowest changing dimension */ + num_read=H5S_hyper_fread(-1,&io_info); #ifdef QAK - printf("%s: check 5.0, num_read=%d\n",FUNC,(int)num_read); + printf("%s: check 5.0, num_read=%d\n",FUNC,(int)num_read); #endif /* QAK */ + } /* end else */ FUNC_LEAVE (ret_value==SUCCEED ? num_read : 0); } /* H5S_hyper_fgath() */ @@ -1053,6 +1411,253 @@ H5S_hyper_fwrite (intn dim, H5S_hyper_io_info_t *io_info) /*------------------------------------------------------------------------- + * Function: H5S_hyper_fwrite_opt + * + * Purpose: Performs an optimized scatter to the file, based on a regular + * hyperslab (i.e. one which was generated from just one call to + * H5Sselect_hyperslab). + * + * Return: Success: Number of elements copied. + * Failure: 0 + * + * Programmer: Quincey Koziol + * Tuesday, September 12, 2000 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static size_t +H5S_hyper_fwrite_opt (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, H5S_sel_iter_t *file_iter, + size_t nelmts, hid_t dxpl_id, const void *_buf) +{ + hsize_t hsize[H5O_LAYOUT_NDIMS]; /* Hyperslab size */ + hssize_t zero[H5O_LAYOUT_NDIMS]; /*zero */ + hssize_t offset[H5O_LAYOUT_NDIMS]; /* Offset on disk */ + hsize_t tmp_count[H5O_LAYOUT_NDIMS]; /* Temporary block count */ + hsize_t tmp_block[H5O_LAYOUT_NDIMS]; /* Temporary block offset */ + const uint8_t *buf=(const uint8_t *)_buf; /* Alias for pointer arithmetic */ + intn fast_dim; /* Rank of the fastest changing dimension for the dataspace */ + intn temp_dim; /* Temporary rank holder */ + intn i; /* Counters */ + uintn ndims; /* Number of dimensions of dataset */ + intn actual_write; /* The actual number of elements to read in */ + size_t num_write=0; /* Number of elements read */ + + FUNC_ENTER (H5S_hyper_fwrite_opt, 0); + +#ifdef QAK +printf("%s: Called!\n",FUNC); +#endif /* QAK */ + /* Check if this is the first element read in from the hyperslab */ + if(file_iter->hyp.pos[0]==(-1)) { + for(i=0; i<file_space->extent.u.simple.rank; i++) + file_iter->hyp.pos[i]=file_space->select.sel_info.hslab.diminfo[i].start; + } /* end if */ + +#ifdef QAK +for(i=0; i<file_space->extent.u.simple.rank; i++) + printf("%s: file_file->hyp.pos[%d]=%d\n",FUNC,(int)i,(int)file_iter->hyp.pos[i]); +#endif /* QAK */ + + /* Set the rank of the fastest changing dimension */ + fast_dim=file_space->extent.u.simple.rank-1; + + /* Set up the hyperslab and 'zero' arrays */ + ndims=file_space->extent.u.simple.rank; + /* initialize hyperslab size and offset in memory buffer */ + for(i=0; i<(int)(ndims+1); i++) { + hsize[i]=1; /* hyperslab size is 1, except for last element */ + zero[i]=0; /* memory offset is 0 */ + } /* end for */ + hsize[ndims] = elmt_size; + + /* Check if we stopped in the middle of a sequence of elements */ + if((file_iter->hyp.pos[fast_dim]-file_space->select.sel_info.hslab.diminfo[fast_dim].start)%file_space->select.sel_info.hslab.diminfo[fast_dim].stride!=0) { + intn leftover; /* The number of elements left over from the last sequence */ + +#ifdef QAK +printf("%s: Check 1.0\n",FUNC); +#endif /* QAK */ + /* Calculate the number of elements left in the sequence */ + leftover=file_space->select.sel_info.hslab.diminfo[fast_dim].block-((file_iter->hyp.pos[fast_dim]-file_space->select.sel_info.hslab.diminfo[fast_dim].start)%file_space->select.sel_info.hslab.diminfo[fast_dim].stride); + + /* Make certain that we don't write too many */ + actual_write=MIN(leftover,nelmts); + + /* Set the hyperslab size in the fastest changing dimension to write in */ + hsize[fast_dim]=actual_write; + + /* Copy the location of the point to get */ + HDmemcpy(offset, file_iter->hyp.pos,ndims*sizeof(hssize_t)); + offset[ndims] = 0; + + /* Add in the selection offset */ + for(i=0; i<ndims; i++) + offset[i] += file_space->select.offset[i]; + + /* Read in the rest of the sequence, if possible */ + if (H5F_arr_write(f, dxpl_id, layout, pline, fill, efl, hsize, + hsize, zero, offset, buf)<0) { + HRETURN_ERROR(H5E_DATASPACE, H5E_READERROR, 0, "write error"); + } + + /* Increment the offset of the buffer */ + buf+=elmt_size*actual_write; + + /* Increment the count write */ + num_write+=actual_write; + + /* Decrement the number of elements left in selection */ + file_iter->hyp.elmt_left-=actual_write; + + /* Advance the point iterator */ + /* If we had enough buffer space to write out the rest of the sequence + * in the fastest changing dimension, move the iterator offset to + * the beginning of the next block to write. Otherwise, just advance + * the iterator in the fastest changing dimension. + */ + if(actual_write==leftover) { + /* Move iterator offset to beginning of next sequence in the fastest changing dimension */ + H5S_hyper_iter_next(file_space,file_iter); + } /* end if */ + else { + file_iter->hyp.pos[fast_dim]+=actual_write; /* whole sequence not written out, just advance fastest dimension offset */ + } /* end if */ + } /* end if */ + + /* Now that we've cleared the "remainder" of the previous fastest dimension + * sequence, we must be at the beginning of a sequence, so use the fancy + * algorithm to compute the offsets and run through as many as possible, + * until the buffer fills up. + */ + if(num_write<nelmts) { /* Just in case the "remainder" aboce filled the buffer */ +#ifdef QAK +printf("%s: Check 2.0\n",FUNC); +#endif /* QAK */ + /* Compute the arrays to perform I/O on */ + /* Copy the location of the point to get */ + HDmemcpy(offset, file_iter->hyp.pos,ndims*sizeof(hssize_t)); + offset[ndims] = 0; + + /* Add in the selection offset */ + for(i=0; i<ndims; i++) + offset[i] += file_space->select.offset[i]; + + /* Compute the current "counts" for this location */ + for(i=0; i<ndims; i++) { + tmp_count[i] = (file_iter->hyp.pos[i]-file_space->select.sel_info.hslab.diminfo[i].start)%file_space->select.sel_info.hslab.diminfo[i].stride; + tmp_block[i] = (file_iter->hyp.pos[i]-file_space->select.sel_info.hslab.diminfo[i].start)/file_space->select.sel_info.hslab.diminfo[i].stride; + } /* end for */ + + /* Set the number of elements to write each time */ + actual_write=file_space->select.sel_info.hslab.diminfo[fast_dim].block; + hsize[fast_dim]=actual_write; +#ifdef QAK +printf("%s: actual_write=%d\n",FUNC,(int)actual_write); +for(i=0; i<file_space->extent.u.simple.rank; i++) + printf("%s: diminfo: start[%d]=%d, stride[%d]=%d, block[%d]=%d, count[%d]=%d\n",FUNC, + (int)i,(int)file_space->select.sel_info.hslab.diminfo[i].start, + (int)i,(int)file_space->select.sel_info.hslab.diminfo[i].stride, + (int)i,(int)file_space->select.sel_info.hslab.diminfo[i].block, + (int)i,(int)file_space->select.sel_info.hslab.diminfo[i].count); +#endif /* QAK */ + + /* Read in data until an entire sequence can't be written out any longer */ + while(num_write<nelmts) { + /* Check if we are running out of room in the buffer */ + if((actual_write+num_write)>nelmts) { + actual_write=nelmts-num_write; + hsize[fast_dim]=actual_write; + } /* end if */ + +#ifdef QAK +printf("%s: num_write=%d\n",FUNC,(int)num_write); +for(i=0; i<file_space->extent.u.simple.rank; i++) + printf("%s: tmp_count[%d]=%d, offset[%d]=%d\n",FUNC,(int)i,(int)tmp_count[i],(int)i,(int)offset[i]); +#endif /* QAK */ + + /* Read in the sequence, if possible */ + if (H5F_arr_write(f, dxpl_id, layout, pline, fill, efl, hsize, + hsize, zero, offset, buf)<0) { + HRETURN_ERROR(H5E_DATASPACE, H5E_READERROR, 0, "write error"); + } + + /* Increment the offset of the buffer */ + buf+=elmt_size*actual_write; + + /* Increment the count write */ + num_write+=actual_write; + + /* Decrement the number of elements left in selection */ + file_iter->hyp.elmt_left-=actual_write; + + /* Increment the offset and count */ + temp_dim=fast_dim; + while(temp_dim>=0) { + if(temp_dim==fast_dim) { + /* Move to the next block in the current dimension */ + /* Check for partial block write! */ + if(actual_write<file_space->select.sel_info.hslab.diminfo[fast_dim].block) { + offset[temp_dim]+=actual_write; + break; + } /* end if */ + else { + offset[temp_dim]+=file_space->select.sel_info.hslab.diminfo[temp_dim].stride; /* reset the offset in the fastest dimension */ + tmp_count[temp_dim]++; + } /* end else */ + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(tmp_count[temp_dim]<file_space->select.sel_info.hslab.diminfo[temp_dim].count) + break; + else { + tmp_count[temp_dim]=0; /* reset back to the beginning of the line */ + offset[temp_dim]=file_space->select.sel_info.hslab.diminfo[temp_dim].start+file_space->select.offset[temp_dim]; + } /* end else */ + } /* end if */ + else { + /* Move to the next row in the curent dimension */ + offset[temp_dim]++; + tmp_block[temp_dim]++; + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(tmp_block[temp_dim]<file_space->select.sel_info.hslab.diminfo[temp_dim].block) + break; + else { + /* Move to the next block in the current dimension */ + offset[temp_dim]+=(file_space->select.sel_info.hslab.diminfo[temp_dim].stride-file_space->select.sel_info.hslab.diminfo[temp_dim].block); + tmp_block[temp_dim]=0; + tmp_count[temp_dim]++; + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(tmp_count[temp_dim]<file_space->select.sel_info.hslab.diminfo[temp_dim].count) + break; + else { + tmp_count[temp_dim]=0; /* reset back to the beginning of the line */ + tmp_block[temp_dim]=0; + offset[temp_dim]=file_space->select.sel_info.hslab.diminfo[temp_dim].start+file_space->select.offset[temp_dim]; + } + } /* end else */ + } /* end else */ + + /* Decrement dimension count */ + temp_dim--; + } /* end while */ + } /* end while */ + + /* Update the iterator with the location we stopped */ + HDmemcpy(file_iter->hyp.pos, offset, ndims*sizeof(hssize_t)); + } /* end if */ + + FUNC_LEAVE (num_write); +} /* H5S_hyper_fwrite_opt() */ + + +/*------------------------------------------------------------------------- * Function: H5S_hyper_fscat * * Purpose: Scatters dataset elements from the type conversion buffer BUF @@ -1099,31 +1704,38 @@ H5S_hyper_fscat (H5F_t *f, const struct H5O_layout_t *layout, printf("%s: check 1.0\n", FUNC); #endif /* QAK */ - /* Initialize parameter block for recursive calls */ - io_info.f=f; - io_info.layout=layout; - io_info.pline=pline; - io_info.fill=fill; - io_info.efl=efl; - io_info.elmt_size=elmt_size; - io_info.space=file_space; - io_info.iter=file_iter; - io_info.nelmts=nelmts; - io_info.dxpl_id = dxpl_id; - io_info.src=_buf; - io_info.dst=NULL; - - /* Set the hyperslab size to copy */ - io_info.hsize[0]=1; - H5V_array_fill(io_info.hsize,io_info.hsize,sizeof(io_info.hsize[0]),file_space->extent.u.simple.rank); - io_info.hsize[file_space->extent.u.simple.rank]=elmt_size; - - /* Recursively input the hyperslabs currently defined */ - /* starting with the slowest changing dimension */ - num_written=H5S_hyper_fwrite(-1,&io_info); + /* Check for the special case of just one H5Sselect_hyperslab call made */ + if(file_space->select.sel_info.hslab.diminfo!=NULL) { + /* Use optimized call to write out regular hyperslab */ + num_written=H5S_hyper_fwrite_opt(f,layout,pline,fill,efl,elmt_size,file_space,file_iter,nelmts,dxpl_id,_buf); + } + else { + /* Initialize parameter block for recursive calls */ + io_info.f=f; + io_info.layout=layout; + io_info.pline=pline; + io_info.fill=fill; + io_info.efl=efl; + io_info.elmt_size=elmt_size; + io_info.space=file_space; + io_info.iter=file_iter; + io_info.nelmts=nelmts; + io_info.dxpl_id = dxpl_id; + io_info.src=_buf; + io_info.dst=NULL; + + /* Set the hyperslab size to copy */ + io_info.hsize[0]=1; + H5V_array_fill(io_info.hsize,io_info.hsize,sizeof(io_info.hsize[0]),file_space->extent.u.simple.rank); + io_info.hsize[file_space->extent.u.simple.rank]=elmt_size; + + /* Recursively input the hyperslabs currently defined */ + /* starting with the slowest changing dimension */ + num_written=H5S_hyper_fwrite(-1,&io_info); #ifdef QAK - printf("%s: check 2.0\n", FUNC); + printf("%s: check 2.0\n", FUNC); #endif /* QAK */ + } /* end else */ FUNC_LEAVE (ret_value==FAIL ? ret_value : (num_written >0) ? SUCCEED : FAIL); } /* H5S_hyper_fscat() */ @@ -1273,6 +1885,258 @@ H5S_hyper_mread (intn dim, H5S_hyper_io_info_t *io_info) /*------------------------------------------------------------------------- + * Function: H5S_hyper_mread_opt + * + * Purpose: Performs an optimized gather from a memory buffer, based on a + * regular hyperslab (i.e. one which was generated from just one call to + * H5Sselect_hyperslab). + * + * Return: Success: Number of elements copied. + * Failure: 0 + * + * Programmer: Quincey Koziol + * Tuesday, September 12, 2000 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5S_hyper_mread_opt (const void *_buf, size_t elmt_size, + const H5S_t *mem_space, H5S_sel_iter_t *mem_iter, + size_t nelmts, void *_tconv_buf/*out*/) +{ + hsize_t mem_size[H5O_LAYOUT_NDIMS]; /* Size of the source buffer */ + hsize_t hsize[H5O_LAYOUT_NDIMS]; /* Hyperslab size */ + hssize_t zero[H5O_LAYOUT_NDIMS]; /*zero */ + hssize_t offset[H5O_LAYOUT_NDIMS]; /* Offset on disk */ + hsize_t tmp_count[H5O_LAYOUT_NDIMS]; /* Temporary block count */ + hsize_t tmp_block[H5O_LAYOUT_NDIMS]; /* Temporary block offset */ + const uint8_t *src=(const uint8_t *)_buf; /* Alias for pointer arithmetic */ + uint8_t *dst=(uint8_t *)_tconv_buf; /* Alias for pointer arithmetic */ + intn fast_dim; /* Rank of the fastest changing dimension for the dataspace */ + intn temp_dim; /* Temporary rank holder */ + intn i; /* Counters */ + uintn ndims; /* Number of dimensions of dataset */ + intn actual_read; /* The actual number of elements to read in */ + size_t num_read=0; /* Number of elements read */ + + FUNC_ENTER (H5S_hyper_fread_opt, 0); + +#ifdef QAK +printf("%s: Called!\n",FUNC); +#endif /* QAK */ + /* Check if this is the first element read in from the hyperslab */ + if(mem_iter->hyp.pos[0]==(-1)) { + for(i=0; i<mem_space->extent.u.simple.rank; i++) + mem_iter->hyp.pos[i]=mem_space->select.sel_info.hslab.diminfo[i].start; + } /* end if */ + +#ifdef QAK +for(i=0; i<mem_space->extent.u.simple.rank; i++) + printf("%s: mem_file->hyp.pos[%d]=%d\n",FUNC,(int)i,(int)mem_iter->hyp.pos[i]); +#endif /* QAK */ + + /* Set the rank of the fastest changing dimension */ + fast_dim=mem_space->extent.u.simple.rank-1; + + /* Set up the hyperslab and 'zero' arrays */ + ndims=mem_space->extent.u.simple.rank; + /* initialize hyperslab size and offset in memory buffer */ + for(i=0; i<(int)(ndims+1); i++) { + hsize[i]=1; /* hyperslab size is 1, except for last element */ + zero[i]=0; /* memory offset is 0 */ + } /* end for */ + hsize[ndims] = elmt_size; + + /* Set up the size of the memory space */ + HDmemcpy(mem_size, mem_space->extent.u.simple.size,mem_space->extent.u.simple.rank*sizeof(hsize_t)); + mem_size[mem_space->extent.u.simple.rank]=elmt_size; + + /* Check if we stopped in the middle of a sequence of elements */ + if((mem_iter->hyp.pos[fast_dim]-mem_space->select.sel_info.hslab.diminfo[fast_dim].start)%mem_space->select.sel_info.hslab.diminfo[fast_dim].stride!=0) { + intn leftover; /* The number of elements left over from the last sequence */ + +#ifdef QAK +printf("%s: Check 1.0\n",FUNC); +#endif /* QAK */ + /* Calculate the number of elements left in the sequence */ + leftover=mem_space->select.sel_info.hslab.diminfo[fast_dim].block-((mem_iter->hyp.pos[fast_dim]-mem_space->select.sel_info.hslab.diminfo[fast_dim].start)%mem_space->select.sel_info.hslab.diminfo[fast_dim].stride); + + /* Make certain that we don't read too many */ + actual_read=MIN(leftover,nelmts); + + /* Set the hyperslab size in the fastest changing dimension to read in */ + hsize[fast_dim]=actual_read; + + /* Copy the location of the point to get */ + HDmemcpy(offset, mem_iter->hyp.pos,ndims*sizeof(hssize_t)); + offset[ndims] = 0; + + /* Add in the selection offset */ + for(i=0; i<ndims; i++) + offset[i] += mem_space->select.offset[i]; + + /* Scatter out the rest of the sequence, if possible */ + if (H5V_hyper_copy (ndims+1, hsize, + hsize, zero, dst, + mem_size, offset, src)<0) { + HRETURN_ERROR (H5E_DATASPACE, H5E_READERROR, 0, "unable to gather data from memory"); + } + + /* Increment the offset of the buffer */ + dst+=elmt_size*actual_read; + + /* Increment the count read */ + num_read+=actual_read; + + /* Decrement the number of elements left in selection */ + mem_iter->hyp.elmt_left-=actual_read; + + /* Advance the point iterator */ + /* If we had enough buffer space to read in the rest of the sequence + * in the fastest changing dimension, move the iterator offset to + * the beginning of the next block to read. Otherwise, just advance + * the iterator in the fastest changing dimension. + */ + if(actual_read==leftover) { + /* Move iterator offset to beginning of next sequence in the fastest changing dimension */ + H5S_hyper_iter_next(mem_space,mem_iter); + } /* end if */ + else { + mem_iter->hyp.pos[fast_dim]+=actual_read; /* whole sequence not read in, just advance fastest dimension offset */ + } /* end if */ + } /* end if */ + + /* Now that we've cleared the "remainder" of the previous fastest dimension + * sequence, we must be at the beginning of a sequence, so use the fancy + * algorithm to compute the offsets and run through as many as possible, + * until the buffer fills up. + */ + if(num_read<nelmts) { /* Just in case the "remainder" aboce filled the buffer */ +#ifdef QAK +printf("%s: Check 2.0\n",FUNC); +#endif /* QAK */ + /* Compute the arrays to perform I/O on */ + /* Copy the location of the point to get */ + HDmemcpy(offset, mem_iter->hyp.pos,ndims*sizeof(hssize_t)); + offset[ndims] = 0; + + /* Add in the selection offset */ + for(i=0; i<ndims; i++) + offset[i] += mem_space->select.offset[i]; + + /* Compute the current "counts" for this location */ + for(i=0; i<ndims; i++) { + tmp_count[i] = (mem_iter->hyp.pos[i]-mem_space->select.sel_info.hslab.diminfo[i].start)%mem_space->select.sel_info.hslab.diminfo[i].stride; + tmp_block[i] = (mem_iter->hyp.pos[i]-mem_space->select.sel_info.hslab.diminfo[i].start)/mem_space->select.sel_info.hslab.diminfo[i].stride; + } /* end for */ + + /* Set the number of elements to read each time */ + actual_read=mem_space->select.sel_info.hslab.diminfo[fast_dim].block; + hsize[fast_dim]=actual_read; +#ifdef QAK +printf("%s: actual_read=%d\n",FUNC,(int)actual_read); +for(i=0; i<file_space->extent.u.simple.rank; i++) + printf("%s: diminfo: start[%d]=%d, stride[%d]=%d, block[%d]=%d, count[%d]=%d\n",FUNC, + (int)i,(int)mem_space->select.sel_info.hslab.diminfo[i].start, + (int)i,(int)mem_space->select.sel_info.hslab.diminfo[i].stride, + (int)i,(int)mem_space->select.sel_info.hslab.diminfo[i].block, + (int)i,(int)mem_space->select.sel_info.hslab.diminfo[i].count); +#endif /* QAK */ + + /* Read in data until an entire sequence can't be written out any longer */ + while(num_read<nelmts) { + /* Check if we are running out of room in the buffer */ + if((actual_read+num_read)>nelmts) { + actual_read=nelmts-num_read; + hsize[fast_dim]=actual_read; + } /* end if */ + +#ifdef QAK +printf("%s: num_read=%d\n",FUNC,(int)num_read); +for(i=0; i<mem_space->extent.u.simple.rank; i++) + printf("%s: tmp_count[%d]=%d, offset[%d]=%d\n",FUNC,(int)i,(int)tmp_count[i],(int)i,(int)offset[i]); +#endif /* QAK */ + + /* Scatter out the rest of the sequence, if possible */ + if (H5V_hyper_copy (ndims+1, hsize, + hsize, zero, dst, + mem_size, offset, src)<0) { + HRETURN_ERROR (H5E_DATASPACE, H5E_READERROR, 0, "unable to gather data from memory"); + } + + /* Increment the offset of the buffer */ + dst+=elmt_size*actual_read; + + /* Increment the count read */ + num_read+=actual_read; + + /* Decrement the number of elements left in selection */ + mem_iter->hyp.elmt_left-=actual_read; + + /* Increment the offset and count */ + temp_dim=fast_dim; + while(temp_dim>=0) { + if(temp_dim==fast_dim) { + /* Move to the next block in the current dimension */ + /* Check for partial block read! */ + if(actual_read<mem_space->select.sel_info.hslab.diminfo[fast_dim].block) { + offset[temp_dim]+=actual_read; + break; + } /* end if */ + else { + offset[temp_dim]+=mem_space->select.sel_info.hslab.diminfo[temp_dim].stride; /* reset the offset in the fastest dimension */ + tmp_count[temp_dim]++; + } /* end else */ + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(tmp_count[temp_dim]<mem_space->select.sel_info.hslab.diminfo[temp_dim].count) + break; + else { + tmp_count[temp_dim]=0; /* reset back to the beginning of the line */ + offset[temp_dim]=mem_space->select.sel_info.hslab.diminfo[temp_dim].start+mem_space->select.offset[temp_dim]; + } /* end else */ + } /* end if */ + else { + /* Move to the next row in the curent dimension */ + offset[temp_dim]++; + tmp_block[temp_dim]++; + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(tmp_block[temp_dim]<mem_space->select.sel_info.hslab.diminfo[temp_dim].block) + break; + else { + /* Move to the next block in the current dimension */ + offset[temp_dim]+=(mem_space->select.sel_info.hslab.diminfo[temp_dim].stride-mem_space->select.sel_info.hslab.diminfo[temp_dim].block); + tmp_block[temp_dim]=0; + tmp_count[temp_dim]++; + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(tmp_count[temp_dim]<mem_space->select.sel_info.hslab.diminfo[temp_dim].count) + break; + else { + tmp_count[temp_dim]=0; /* reset back to the beginning of the line */ + tmp_block[temp_dim]=0; + offset[temp_dim]=mem_space->select.sel_info.hslab.diminfo[temp_dim].start+mem_space->select.offset[temp_dim]; + } + } /* end else */ + } /* end else */ + + /* Decrement dimension count */ + temp_dim--; + } /* end while */ + } /* end while */ + + /* Update the iterator with the location we stopped */ + HDmemcpy(mem_iter->hyp.pos, offset, ndims*sizeof(hssize_t)); + } /* end if */ + + FUNC_LEAVE (num_read); +} /* end H5S_hyper_mread_opt() */ + + +/*------------------------------------------------------------------------- * Function: H5S_hyper_mgath * * Purpose: Gathers dataset elements from application memory BUF and @@ -1317,29 +2181,36 @@ H5S_hyper_mgath (const void *_buf, size_t elmt_size, assert (_buf); assert (_tconv_buf); - /* Initialize parameter block for recursive calls */ - io_info.elmt_size=elmt_size; - io_info.space=mem_space; - io_info.iter=mem_iter; - io_info.nelmts=nelmts; - io_info.src=_buf; - io_info.dst=_tconv_buf; - - /* Set up the size of the memory space */ - HDmemcpy(io_info.mem_size, mem_space->extent.u.simple.size,mem_space->extent.u.simple.rank*sizeof(hsize_t)); - io_info.mem_size[mem_space->extent.u.simple.rank]=elmt_size; - - /* Set the hyperslab size to copy */ - io_info.hsize[0]=1; - H5V_array_fill(io_info.hsize, io_info.hsize, sizeof(io_info.hsize[0]),mem_space->extent.u.simple.rank); - io_info.hsize[mem_space->extent.u.simple.rank]=elmt_size; - - /* Recursively input the hyperslabs currently defined */ - /* starting with the slowest changing dimension */ - num_read=H5S_hyper_mread(-1,&io_info); + /* Check for the special case of just one H5Sselect_hyperslab call made */ + if(mem_space->select.sel_info.hslab.diminfo!=NULL) { + /* Use optimized call to read in regular hyperslab */ + num_read=H5S_hyper_mread_opt(_buf,elmt_size,mem_space,mem_iter,nelmts,_tconv_buf); + } + else { + /* Initialize parameter block for recursive calls */ + io_info.elmt_size=elmt_size; + io_info.space=mem_space; + io_info.iter=mem_iter; + io_info.nelmts=nelmts; + io_info.src=_buf; + io_info.dst=_tconv_buf; + + /* Set up the size of the memory space */ + HDmemcpy(io_info.mem_size, mem_space->extent.u.simple.size,mem_space->extent.u.simple.rank*sizeof(hsize_t)); + io_info.mem_size[mem_space->extent.u.simple.rank]=elmt_size; + + /* Set the hyperslab size to copy */ + io_info.hsize[0]=1; + H5V_array_fill(io_info.hsize, io_info.hsize, sizeof(io_info.hsize[0]),mem_space->extent.u.simple.rank); + io_info.hsize[mem_space->extent.u.simple.rank]=elmt_size; + + /* Recursively input the hyperslabs currently defined */ + /* starting with the slowest changing dimension */ + num_read=H5S_hyper_mread(-1,&io_info); #ifdef QAK - printf("%s: check 5.0, num_read=%d\n",FUNC,(int)num_read); + printf("%s: check 5.0, num_read=%d\n",FUNC,(int)num_read); #endif /* QAK */ + } /* end else */ FUNC_LEAVE (num_read); } /* H5S_hyper_mgath() */ @@ -1488,6 +2359,258 @@ H5S_hyper_mwrite (intn dim, H5S_hyper_io_info_t *io_info) /*------------------------------------------------------------------------- + * Function: H5S_hyper_mwrite_opt + * + * Purpose: Performs an optimized scatter to a memory buffer, based on a + * regular hyperslab (i.e. one which was generated from just one call to + * H5Sselect_hyperslab). + * + * Return: Success: Number of elements copied. + * Failure: 0 + * + * Programmer: Quincey Koziol + * Tuesday, September 12, 2000 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5S_hyper_mwrite_opt (const void *_tconv_buf, size_t elmt_size, + const H5S_t *mem_space, H5S_sel_iter_t *mem_iter, + size_t nelmts, void *_buf/*out*/) +{ + hsize_t mem_size[H5O_LAYOUT_NDIMS]; /* Size of the source buffer */ + hsize_t hsize[H5O_LAYOUT_NDIMS]; /* Hyperslab size */ + hssize_t zero[H5O_LAYOUT_NDIMS]; /*zero */ + hssize_t offset[H5O_LAYOUT_NDIMS]; /* Offset on disk */ + hsize_t tmp_count[H5O_LAYOUT_NDIMS]; /* Temporary block count */ + hsize_t tmp_block[H5O_LAYOUT_NDIMS]; /* Temporary block offset */ + const uint8_t *src=(const uint8_t *)_tconv_buf; /* Alias for pointer arithmetic */ + uint8_t *dst=(uint8_t *)_buf; /* Alias for pointer arithmetic */ + intn fast_dim; /* Rank of the fastest changing dimension for the dataspace */ + intn temp_dim; /* Temporary rank holder */ + intn i; /* Counters */ + uintn ndims; /* Number of dimensions of dataset */ + intn actual_write; /* The actual number of elements to read in */ + size_t num_write=0; /* Number of elements read */ + + FUNC_ENTER (H5S_hyper_fwrite_opt, 0); + +#ifdef QAK +printf("%s: Called!\n",FUNC); +#endif /* QAK */ + /* Check if this is the first element read in from the hyperslab */ + if(mem_iter->hyp.pos[0]==(-1)) { + for(i=0; i<mem_space->extent.u.simple.rank; i++) + mem_iter->hyp.pos[i]=mem_space->select.sel_info.hslab.diminfo[i].start; + } /* end if */ + +#ifdef QAK +for(i=0; i<mem_space->extent.u.simple.rank; i++) + printf("%s: mem_file->hyp.pos[%d]=%d\n",FUNC,(int)i,(int)mem_iter->hyp.pos[i]); +#endif /* QAK */ + + /* Set the rank of the fastest changing dimension */ + fast_dim=mem_space->extent.u.simple.rank-1; + + /* Set up the hyperslab and 'zero' arrays */ + ndims=mem_space->extent.u.simple.rank; + /* initialize hyperslab size and offset in memory buffer */ + for(i=0; i<(int)(ndims+1); i++) { + hsize[i]=1; /* hyperslab size is 1, except for last element */ + zero[i]=0; /* memory offset is 0 */ + } /* end for */ + hsize[ndims] = elmt_size; + + /* Set up the size of the memory space */ + HDmemcpy(mem_size, mem_space->extent.u.simple.size,mem_space->extent.u.simple.rank*sizeof(hsize_t)); + mem_size[mem_space->extent.u.simple.rank]=elmt_size; + + /* Check if we stopped in the middle of a sequence of elements */ + if((mem_iter->hyp.pos[fast_dim]-mem_space->select.sel_info.hslab.diminfo[fast_dim].start)%mem_space->select.sel_info.hslab.diminfo[fast_dim].stride!=0) { + intn leftover; /* The number of elements left over from the last sequence */ + +#ifdef QAK +printf("%s: Check 1.0\n",FUNC); +#endif /* QAK */ + /* Calculate the number of elements left in the sequence */ + leftover=mem_space->select.sel_info.hslab.diminfo[fast_dim].block-((mem_iter->hyp.pos[fast_dim]-mem_space->select.sel_info.hslab.diminfo[fast_dim].start)%mem_space->select.sel_info.hslab.diminfo[fast_dim].stride); + + /* Make certain that we don't write too many */ + actual_write=MIN(leftover,nelmts); + + /* Set the hyperslab size in the fastest changing dimension to write in */ + hsize[fast_dim]=actual_write; + + /* Copy the location of the point to get */ + HDmemcpy(offset, mem_iter->hyp.pos,ndims*sizeof(hssize_t)); + offset[ndims] = 0; + + /* Add in the selection offset */ + for(i=0; i<ndims; i++) + offset[i] += mem_space->select.offset[i]; + + /* Scatter out the rest of the sequence, if possible */ + if (H5V_hyper_copy (ndims+1, hsize, + mem_size, offset, dst, + hsize, zero, src)<0) { + HRETURN_ERROR (H5E_DATASPACE, H5E_READERROR, 0, "unable to gather data from memory"); + } + + /* Increment the offset of the buffer */ + src+=elmt_size*actual_write; + + /* Increment the count write */ + num_write+=actual_write; + + /* Decrement the number of elements left in selection */ + mem_iter->hyp.elmt_left-=actual_write; + + /* Advance the point iterator */ + /* If we had enough buffer space to write out the rest of the sequence + * in the fastest changing dimension, move the iterator offset to + * the beginning of the next block to write. Otherwise, just advance + * the iterator in the fastest changing dimension. + */ + if(actual_write==leftover) { + /* Move iterator offset to beginning of next sequence in the fastest changing dimension */ + H5S_hyper_iter_next(mem_space,mem_iter); + } /* end if */ + else { + mem_iter->hyp.pos[fast_dim]+=actual_write; /* whole sequence not written out, just advance fastest dimension offset */ + } /* end if */ + } /* end if */ + + /* Now that we've cleared the "remainder" of the previous fastest dimension + * sequence, we must be at the beginning of a sequence, so use the fancy + * algorithm to compute the offsets and run through as many as possible, + * until the buffer fills up. + */ + if(num_write<nelmts) { /* Just in case the "remainder" aboce filled the buffer */ +#ifdef QAK +printf("%s: Check 2.0\n",FUNC); +#endif /* QAK */ + /* Compute the arrays to perform I/O on */ + /* Copy the location of the point to get */ + HDmemcpy(offset, mem_iter->hyp.pos,ndims*sizeof(hssize_t)); + offset[ndims] = 0; + + /* Add in the selection offset */ + for(i=0; i<ndims; i++) + offset[i] += mem_space->select.offset[i]; + + /* Compute the current "counts" for this location */ + for(i=0; i<ndims; i++) { + tmp_count[i] = (mem_iter->hyp.pos[i]-mem_space->select.sel_info.hslab.diminfo[i].start)%mem_space->select.sel_info.hslab.diminfo[i].stride; + tmp_block[i] = (mem_iter->hyp.pos[i]-mem_space->select.sel_info.hslab.diminfo[i].start)/mem_space->select.sel_info.hslab.diminfo[i].stride; + } /* end for */ + + /* Set the number of elements to write each time */ + actual_write=mem_space->select.sel_info.hslab.diminfo[fast_dim].block; + hsize[fast_dim]=actual_write; +#ifdef QAK +printf("%s: actual_write=%d\n",FUNC,(int)actual_write); +for(i=0; i<file_space->extent.u.simple.rank; i++) + printf("%s: diminfo: start[%d]=%d, stride[%d]=%d, block[%d]=%d, count[%d]=%d\n",FUNC, + (int)i,(int)mem_space->select.sel_info.hslab.diminfo[i].start, + (int)i,(int)mem_space->select.sel_info.hslab.diminfo[i].stride, + (int)i,(int)mem_space->select.sel_info.hslab.diminfo[i].block, + (int)i,(int)mem_space->select.sel_info.hslab.diminfo[i].count); +#endif /* QAK */ + + /* Read in data until an entire sequence can't be written out any longer */ + while(num_write<nelmts) { + /* Check if we are running out of room in the buffer */ + if((actual_write+num_write)>nelmts) { + actual_write=nelmts-num_write; + hsize[fast_dim]=actual_write; + } /* end if */ + +#ifdef QAK +printf("%s: num_write=%d\n",FUNC,(int)num_write); +for(i=0; i<mem_space->extent.u.simple.rank; i++) + printf("%s: tmp_count[%d]=%d, offset[%d]=%d\n",FUNC,(int)i,(int)tmp_count[i],(int)i,(int)offset[i]); +#endif /* QAK */ + + /* Scatter out the rest of the sequence, if possible */ + if (H5V_hyper_copy (ndims+1, hsize, + mem_size, offset, dst, + hsize, zero, src)<0) { + HRETURN_ERROR (H5E_DATASPACE, H5E_READERROR, 0, "unable to gather data from memory"); + } + + /* Increment the offset of the buffer */ + src+=elmt_size*actual_write; + + /* Increment the count write */ + num_write+=actual_write; + + /* Decrement the number of elements left in selection */ + mem_iter->hyp.elmt_left-=actual_write; + + /* Increment the offset and count */ + temp_dim=fast_dim; + while(temp_dim>=0) { + if(temp_dim==fast_dim) { + /* Move to the next block in the current dimension */ + /* Check for partial block write! */ + if(actual_write<mem_space->select.sel_info.hslab.diminfo[fast_dim].block) { + offset[temp_dim]+=actual_write; + break; + } /* end if */ + else { + offset[temp_dim]+=mem_space->select.sel_info.hslab.diminfo[temp_dim].stride; /* reset the offset in the fastest dimension */ + tmp_count[temp_dim]++; + } /* end else */ + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(tmp_count[temp_dim]<mem_space->select.sel_info.hslab.diminfo[temp_dim].count) + break; + else { + tmp_count[temp_dim]=0; /* reset back to the beginning of the line */ + offset[temp_dim]=mem_space->select.sel_info.hslab.diminfo[temp_dim].start+mem_space->select.offset[temp_dim]; + } /* end else */ + } /* end if */ + else { + /* Move to the next row in the curent dimension */ + offset[temp_dim]++; + tmp_block[temp_dim]++; + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(tmp_block[temp_dim]<mem_space->select.sel_info.hslab.diminfo[temp_dim].block) + break; + else { + /* Move to the next block in the current dimension */ + offset[temp_dim]+=(mem_space->select.sel_info.hslab.diminfo[temp_dim].stride-mem_space->select.sel_info.hslab.diminfo[temp_dim].block); + tmp_block[temp_dim]=0; + tmp_count[temp_dim]++; + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(tmp_count[temp_dim]<mem_space->select.sel_info.hslab.diminfo[temp_dim].count) + break; + else { + tmp_count[temp_dim]=0; /* reset back to the beginning of the line */ + tmp_block[temp_dim]=0; + offset[temp_dim]=mem_space->select.sel_info.hslab.diminfo[temp_dim].start+mem_space->select.offset[temp_dim]; + } + } /* end else */ + } /* end else */ + + /* Decrement dimension count */ + temp_dim--; + } /* end while */ + } /* end while */ + + /* Update the iterator with the location we stopped */ + HDmemcpy(mem_iter->hyp.pos, offset, ndims*sizeof(hssize_t)); + } /* end if */ + + FUNC_LEAVE (num_write); +} /* end H5S_hyper_mwrite_opt() */ + + +/*------------------------------------------------------------------------- * Function: H5S_hyper_mscat * * Purpose: Scatters NELMTS data points from the type conversion buffer @@ -1509,8 +2632,8 @@ H5S_hyper_mscat (const void *_tconv_buf, size_t elmt_size, const H5S_t *mem_space, H5S_sel_iter_t *mem_iter, size_t nelmts, void *_buf/*out*/) { - H5S_hyper_io_info_t io_info; /* Block of parameters to pass into recursive calls */ - size_t num_read; /* number of elements read into buffer */ + H5S_hyper_io_info_t io_info; /* Block of parameters to pass into recursive calls */ + size_t num_written; /* number of elements written into buffer */ FUNC_ENTER (H5S_hyper_mscat, 0); @@ -1522,34 +2645,41 @@ H5S_hyper_mscat (const void *_tconv_buf, size_t elmt_size, assert (_buf); assert (_tconv_buf); - /* Initialize parameter block for recursive calls */ - io_info.elmt_size=elmt_size; - io_info.space=mem_space; - io_info.iter=mem_iter; - io_info.nelmts=nelmts; - io_info.src=_tconv_buf; - io_info.dst=_buf; - - /* Set up the size of the memory space */ - HDmemcpy(io_info.mem_size, mem_space->extent.u.simple.size,mem_space->extent.u.simple.rank*sizeof(hsize_t)); - io_info.mem_size[mem_space->extent.u.simple.rank]=elmt_size; - - /* Set the hyperslab size to copy */ - io_info.hsize[0]=1; - H5V_array_fill(io_info.hsize, io_info.hsize, sizeof(io_info.hsize[0]), mem_space->extent.u.simple.rank); - io_info.hsize[mem_space->extent.u.simple.rank]=elmt_size; - - /* Recursively input the hyperslabs currently defined */ - /* starting with the slowest changing dimension */ + /* Check for the special case of just one H5Sselect_hyperslab call made */ + if(mem_space->select.sel_info.hslab.diminfo!=NULL) { + /* Use optimized call to write out regular hyperslab */ + num_written=H5S_hyper_mwrite_opt(_tconv_buf,elmt_size,mem_space,mem_iter,nelmts,_buf); + } + else { + /* Initialize parameter block for recursive calls */ + io_info.elmt_size=elmt_size; + io_info.space=mem_space; + io_info.iter=mem_iter; + io_info.nelmts=nelmts; + io_info.src=_tconv_buf; + io_info.dst=_buf; + + /* Set up the size of the memory space */ + HDmemcpy(io_info.mem_size, mem_space->extent.u.simple.size,mem_space->extent.u.simple.rank*sizeof(hsize_t)); + io_info.mem_size[mem_space->extent.u.simple.rank]=elmt_size; + + /* Set the hyperslab size to copy */ + io_info.hsize[0]=1; + H5V_array_fill(io_info.hsize, io_info.hsize, sizeof(io_info.hsize[0]), mem_space->extent.u.simple.rank); + io_info.hsize[mem_space->extent.u.simple.rank]=elmt_size; + + /* Recursively input the hyperslabs currently defined */ + /* starting with the slowest changing dimension */ #ifdef QAK - printf("%s: check 1.0\n",FUNC); + printf("%s: check 1.0\n",FUNC); #endif /* QAK */ - num_read=H5S_hyper_mwrite(-1,&io_info); + num_written=H5S_hyper_mwrite(-1,&io_info); #ifdef QAK - printf("%s: check 2.0\n",FUNC); + printf("%s: check 2.0\n",FUNC); #endif /* QAK */ + } /* end else */ - FUNC_LEAVE (num_read>0 ? SUCCEED : FAIL); + FUNC_LEAVE (num_written>0 ? SUCCEED : FAIL); } /* H5S_hyper_mscat() */ @@ -2380,30 +3510,36 @@ H5S_hyper_release (H5S_t *space) /* Reset the number of points selected */ space->select.num_elem=0; - /* Release the per-dimension selection info */ - if(space->select.sel_info.hslab.diminfo!=NULL) + /* Release the regular selection info */ + if(space->select.sel_info.hslab.diminfo!=NULL) { H5FL_ARR_FREE(H5S_hyper_dim_t,space->select.sel_info.hslab.diminfo); - space->select.sel_info.hslab.diminfo = NULL; + space->select.sel_info.hslab.diminfo = NULL; + } /* end if */ - /* Release hi and lo boundary information */ - for(i=0; i<space->extent.u.simple.rank; i++) { - H5FL_ARR_FREE(H5S_hyper_bound_t,space->select.sel_info.hslab.hyper_lst->lo_bounds[i]); - space->select.sel_info.hslab.hyper_lst->lo_bounds[i] = NULL; - } /* end for */ - H5FL_ARR_FREE(H5S_hyper_bound_ptr_t,space->select.sel_info.hslab.hyper_lst->lo_bounds); - space->select.sel_info.hslab.hyper_lst->lo_bounds = NULL; + /* Release irregular hyperslab information */ + if(space->select.sel_info.hslab.hyper_lst!=NULL) { + /* Release hi and lo boundary information */ + if(space->select.sel_info.hslab.hyper_lst->lo_bounds!=NULL) { + for(i=0; i<space->extent.u.simple.rank; i++) { + H5FL_ARR_FREE(H5S_hyper_bound_t,space->select.sel_info.hslab.hyper_lst->lo_bounds[i]); + space->select.sel_info.hslab.hyper_lst->lo_bounds[i] = NULL; + } /* end for */ + H5FL_ARR_FREE(H5S_hyper_bound_ptr_t,space->select.sel_info.hslab.hyper_lst->lo_bounds); + space->select.sel_info.hslab.hyper_lst->lo_bounds = NULL; + } /* end if */ - /* Release list of selected regions */ - curr=space->select.sel_info.hslab.hyper_lst->head; - while(curr!=NULL) { - next=curr->next; - H5S_hyper_node_release(curr); - curr=next; - } /* end while */ + /* Release list of selected regions */ + curr=space->select.sel_info.hslab.hyper_lst->head; + while(curr!=NULL) { + next=curr->next; + H5S_hyper_node_release(curr); + curr=next; + } /* end while */ - /* Release hyperslab selection node itself */ - H5FL_FREE(H5S_hyper_list_t,space->select.sel_info.hslab.hyper_lst); - space->select.sel_info.hslab.hyper_lst=NULL; + /* Release hyperslab selection node itself */ + H5FL_FREE(H5S_hyper_list_t,space->select.sel_info.hslab.hyper_lst); + space->select.sel_info.hslab.hyper_lst=NULL; + } /* end if */ #ifdef QAK printf("%s: check 2.0\n",FUNC); @@ -2522,7 +3658,7 @@ H5S_hyper_compare_bounds (const void *r1, const void *r2) herr_t H5S_hyper_copy (H5S_t *dst, const H5S_t *src) { - H5S_hyper_list_t *new_hyper; /* New hyperslab selection */ + H5S_hyper_list_t *new_hyper=NULL; /* New hyperslab selection */ H5S_hyper_node_t *curr, *new, *new_head; /* Hyperslab information nodes */ H5S_hyper_dim_t *new_diminfo=NULL; /* New per-dimension info array[rank] */ intn i; /* Counters */ @@ -2537,6 +3673,7 @@ H5S_hyper_copy (H5S_t *dst, const H5S_t *src) #ifdef QAK printf("%s: check 3.0\n", FUNC); #endif /* QAK */ + /* Check if there is regular hyperslab information to copy */ if(src->select.sel_info.hslab.diminfo!=NULL) { /* Create the per-dimension selection info */ if((new_diminfo = H5FL_ARR_ALLOC(H5S_hyper_dim_t,src->extent.u.simple.rank,0))==NULL) @@ -2552,87 +3689,91 @@ H5S_hyper_copy (H5S_t *dst, const H5S_t *src) } /* end if */ dst->select.sel_info.hslab.diminfo = new_diminfo; - /* Create the new hyperslab information node */ - if((new_hyper = H5FL_ALLOC(H5S_hyper_list_t,0))==NULL) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, - "can't allocate point node"); + /* Check if there is irregular hyperslab information to copy */ + if(src->select.sel_info.hslab.hyper_lst!=NULL) { + /* Create the new hyperslab information node */ + if((new_hyper = H5FL_ALLOC(H5S_hyper_list_t,0))==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, + "can't allocate point node"); - /* Copy the basic hyperslab selection information */ - *new_hyper=*(src->select.sel_info.hslab.hyper_lst); + /* Copy the basic hyperslab selection information */ + *new_hyper=*(src->select.sel_info.hslab.hyper_lst); - /* Attach the hyperslab information to the destination dataspace */ - dst->select.sel_info.hslab.hyper_lst=new_hyper; - #ifdef QAK - printf("%s: check 4.0\n", FUNC); + printf("%s: check 4.0\n", FUNC); #endif /* QAK */ - /* Allocate space for the low & high bound arrays */ - if((new_hyper->lo_bounds = H5FL_ARR_ALLOC(H5S_hyper_bound_ptr_t,src->extent.u.simple.rank,0))==NULL) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, - "can't allocate boundary node"); - for(i=0; i<src->extent.u.simple.rank; i++) { - if((new_hyper->lo_bounds[i] = H5FL_ARR_ALLOC(H5S_hyper_bound_t,src->select.sel_info.hslab.hyper_lst->count,0))==NULL) + /* Allocate space for the low & high bound arrays */ + if((new_hyper->lo_bounds = H5FL_ARR_ALLOC(H5S_hyper_bound_ptr_t,src->extent.u.simple.rank,0))==NULL) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, - "can't allocate boundary list"); - } /* end for */ + "can't allocate boundary node"); + for(i=0; i<src->extent.u.simple.rank; i++) { + if((new_hyper->lo_bounds[i] = H5FL_ARR_ALLOC(H5S_hyper_bound_t,src->select.sel_info.hslab.hyper_lst->count,0))==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, + "can't allocate boundary list"); + } /* end for */ #ifdef QAK - printf("%s: check 5.0\n", FUNC); + printf("%s: check 5.0\n", FUNC); #endif /* QAK */ - /* Copy the hyperslab selection nodes, adding them to the lo & hi bound arrays also */ - curr=src->select.sel_info.hslab.hyper_lst->head; - new_head=NULL; - u=0; - while(curr!=NULL) { + /* Copy the hyperslab selection nodes, adding them to the lo & hi bound arrays also */ + curr=src->select.sel_info.hslab.hyper_lst->head; + new_head=NULL; + u=0; + while(curr!=NULL) { #ifdef QAK - printf("%s: check 5.1\n", FUNC); + printf("%s: check 5.1\n", FUNC); #endif /* QAK */ - /* Create each point */ - if((new = H5FL_ALLOC(H5S_hyper_node_t,0))==NULL) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, - "can't allocate point node"); - HDmemcpy(new,curr,sizeof(H5S_hyper_node_t)); /* copy caching information */ - if((new->start = H5FL_ARR_ALLOC(hsize_t,src->extent.u.simple.rank,0))==NULL) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, - "can't allocate coordinate information"); - if((new->end = H5FL_ARR_ALLOC(hsize_t,src->extent.u.simple.rank,0))==NULL) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, - "can't allocate coordinate information"); - HDmemcpy(new->start,curr->start,(src->extent.u.simple.rank*sizeof(hssize_t))); - HDmemcpy(new->end,curr->end,(src->extent.u.simple.rank*sizeof(hssize_t))); - new->next=NULL; - - /* Insert into low & high bound arrays */ - for(i=0; i<src->extent.u.simple.rank; i++) { - new_hyper->lo_bounds[i][u].bound=new->start[i]; - new_hyper->lo_bounds[i][u].node=new; - } /* end for */ - u++; /* Increment the location of the next node in the boundary arrays */ + /* Create each point */ + if((new = H5FL_ALLOC(H5S_hyper_node_t,0))==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, + "can't allocate point node"); + HDmemcpy(new,curr,sizeof(H5S_hyper_node_t)); /* copy caching information */ + if((new->start = H5FL_ARR_ALLOC(hsize_t,src->extent.u.simple.rank,0))==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, + "can't allocate coordinate information"); + if((new->end = H5FL_ARR_ALLOC(hsize_t,src->extent.u.simple.rank,0))==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, + "can't allocate coordinate information"); + HDmemcpy(new->start,curr->start,(src->extent.u.simple.rank*sizeof(hssize_t))); + HDmemcpy(new->end,curr->end,(src->extent.u.simple.rank*sizeof(hssize_t))); + new->next=NULL; + + /* Insert into low & high bound arrays */ + for(i=0; i<src->extent.u.simple.rank; i++) { + new_hyper->lo_bounds[i][u].bound=new->start[i]; + new_hyper->lo_bounds[i][u].node=new; + } /* end for */ + u++; /* Increment the location of the next node in the boundary arrays */ - /* Keep the order the same when copying */ - if(new_head==NULL) - new_head=new_hyper->head=new; - else { - new_head->next=new; - new_head=new; - } /* end else */ + /* Keep the order the same when copying */ + if(new_head==NULL) + new_head=new_hyper->head=new; + else { + new_head->next=new; + new_head=new; + } /* end else */ - curr=curr->next; - } /* end while */ + curr=curr->next; + } /* end while */ #ifdef QAK - printf("%s: check 6.0\n", FUNC); + printf("%s: check 6.0\n", FUNC); #endif /* QAK */ - /* Sort the boundary array */ - for(i=0; i<src->extent.u.simple.rank; i++) - HDqsort(new_hyper->lo_bounds[i], new_hyper->count, sizeof(H5S_hyper_bound_t), H5S_hyper_compare_bounds); + /* Sort the boundary array */ + for(i=0; i<src->extent.u.simple.rank; i++) + HDqsort(new_hyper->lo_bounds[i], new_hyper->count, sizeof(H5S_hyper_bound_t), H5S_hyper_compare_bounds); #ifdef QAK - printf("%s: check 7.0\n", FUNC); + printf("%s: check 7.0\n", FUNC); #endif /* QAK */ + } /* end if */ + + /* Attach the hyperslab information to the destination dataspace */ + dst->select.sel_info.hslab.hyper_lst=new_hyper; done: FUNC_LEAVE (ret_value); } /* end H5S_hyper_copy() */ + /*-------------------------------------------------------------------------- NAME @@ -2665,23 +3806,49 @@ H5S_hyper_select_valid (const H5S_t *space) assert(space); - /* Check each point to determine whether selection+offset is within extent */ - curr=space->select.sel_info.hslab.hyper_lst->head; - while(curr!=NULL && ret_value==TRUE) { + /* Check for a "regular" hyperslab selection */ + if(space->select.sel_info.hslab.diminfo != NULL) { + const H5S_hyper_dim_t *diminfo=space->select.sel_info.hslab.diminfo; /* local alias for diminfo */ + hssize_t end; /* The high bound of a region in a dimension */ + /* Check each dimension */ for(i=0; i<space->extent.u.simple.rank; i++) { - /* Check if an offset has been defined */ - /* Bounds check the selected point + offset against the extent */ - if(((curr->start[i]+space->select.offset[i])>(hssize_t)space->extent.u.simple.size[i]) - || ((curr->start[i]+space->select.offset[i])<0) - || ((curr->end[i]+space->select.offset[i])>(hssize_t)space->extent.u.simple.size[i]) - || ((curr->end[i]+space->select.offset[i])<0)) { + /* Bounds check the start point in this dimension */ + if((diminfo[i].start+space->select.offset[i])<0 || + (diminfo[i].start+space->select.offset[i])>=(hssize_t)space->extent.u.simple.size[i]) { + ret_value=FALSE; + break; + } /* end if */ + + /* Compute the largest location in this dimension */ + end=diminfo[i].start+diminfo[i].stride*(diminfo[i].count-1)+(diminfo[i].block-1)+space->select.offset[i]; + + /* Bounds check the end point in this dimension */ + if(end<0 || end>=(hssize_t)space->extent.u.simple.size[i]) { ret_value=FALSE; break; } /* end if */ } /* end for */ + } /* end if */ + else { + /* Check each point to determine whether selection+offset is within extent */ + curr=space->select.sel_info.hslab.hyper_lst->head; + while(curr!=NULL && ret_value==TRUE) { + /* Check each dimension */ + for(i=0; i<space->extent.u.simple.rank; i++) { + /* Check if an offset has been defined */ + /* Bounds check the selected point + offset against the extent */ + if(((curr->start[i]+space->select.offset[i])>(hssize_t)space->extent.u.simple.size[i]) + || ((curr->start[i]+space->select.offset[i])<0) + || ((curr->end[i]+space->select.offset[i])>(hssize_t)space->extent.u.simple.size[i]) + || ((curr->end[i]+space->select.offset[i])<0)) { + ret_value=FALSE; + break; + } /* end if */ + } /* end for */ - curr=curr->next; + curr=curr->next; + } /* end while */ } /* end while */ FUNC_LEAVE (ret_value); @@ -2973,55 +4140,71 @@ H5S_hyper_select_contiguous(const H5S_t *space) assert(space); - /* If there is more than one hyperslab in the selection, they are not contiguous */ - if(space->select.sel_info.hslab.hyper_lst->count>1) - ret_value=FALSE; - else { /* If there is one hyperslab, then it might be contiguous */ - /* Get the dataspace extent rank */ - rank=space->extent.u.simple.rank; - - /* Get the hyperslab node */ - node=space->select.sel_info.hslab.hyper_lst->head; - - /* - * For a hyperslab to be contiguous, it's size must be the same as the - * dataspace extent's in all but the slowest changing dimension - */ - ret_value=TRUE; /* assume true and reset if the dimensions don't match */ - for(i=1; i<rank; i++) { - if(((node->end[i]-node->start[i])+1)!=(hssize_t)space->extent.u.simple.size[i]) { - ret_value=FALSE; - break; - } /* end if */ - } + /* Check for a "regular" hyperslab selection */ + if(space->select.sel_info.hslab.diminfo != NULL) { + /* + * For a regular hyperslab to be contiguous, it must have only one + * block (i.e. count==1 in all dimensions) and the block size must be + * the same as the dataspace extent's in all but the slowest changing + * dimension. + */ + ret_value=TRUE; /* assume true and reset if the dimensions don't match */ + for(i=1; i<space->extent.u.simple.rank; i++) { + if(space->select.sel_info.hslab.diminfo[i].block>1 || space->select.sel_info.hslab.diminfo[i].block!=(hssize_t)space->extent.u.simple.size[i]) { + ret_value=FALSE; + break; + } /* end if */ + } /* end for */ + } /* end if */ + else { + /* If there is more than one hyperslab in the selection, they are not contiguous */ + if(space->select.sel_info.hslab.hyper_lst->count>1) + ret_value=FALSE; + else { /* If there is one hyperslab, then it might be contiguous */ + /* Get the dataspace extent rank */ + rank=space->extent.u.simple.rank; + + /* Get the hyperslab node */ + node=space->select.sel_info.hslab.hyper_lst->head; + + /* + * For a hyperslab to be contiguous, it's size must be the same as the + * dataspace extent's in all but the slowest changing dimension + */ + ret_value=TRUE; /* assume true and reset if the dimensions don't match */ + for(i=1; i<rank; i++) { + if(((node->end[i]-node->start[i])+1)!=(hssize_t)space->extent.u.simple.size[i]) { + ret_value=FALSE; + break; + } /* end if */ + } /* end for */ + } /* end else */ } /* end else */ FUNC_LEAVE (ret_value); } /* H5S_hyper_select_contiguous() */ /*------------------------------------------------------------------------- - * Function: H5S_select_hyperslab + * Function: H5S_generate_hyperlab * - * Purpose: Internal version of H5Sselect_hyperslab(). + * Purpose: Generate hyperslab information from H5S_select_hyperslab() * * Return: Non-negative on success/Negative on failure * - * Programmer: Robb Matzke (split from HSselect_hyperslab()). - * Tuesday, August 25, 1998 + * Programmer: Quincey Koziol (split from HS_select_hyperslab()). + * Tuesday, September 12, 2000 * * Modifications: * *------------------------------------------------------------------------- */ -herr_t -H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op, +static herr_t +H5S_generate_hyperslab (H5S_t *space, H5S_seloper_t op, const hssize_t start[/*space_id*/], const hsize_t stride[/*space_id*/], const hsize_t count[/*space_id*/], const hsize_t block[/*space_id*/]) { - hsize_t *_stride=NULL; /* Stride array */ - hsize_t *_block=NULL; /* Block size array */ hssize_t slab[H5O_LAYOUT_NDIMS]; /* Location of the block to add for strided selections */ size_t slice[H5O_LAYOUT_NDIMS]; /* Size of preceding dimension's slice */ H5S_hyper_node_t *add=NULL, /* List of hyperslab nodes to add */ @@ -3030,54 +4213,18 @@ H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op, uintn acc; /* Accumulator for building slices */ uintn contig; /* whether selection is contiguous or not */ int i,j; /* Counters */ - H5S_hyper_dim_t *diminfo; /* per-dimension info for the selection */ herr_t ret_value=FAIL; /* return value */ - FUNC_ENTER (H5S_select_hyperslab, FAIL); + FUNC_ENTER (H5S_generate_hyperslab, FAIL); /* Check args */ + assert(block); + assert(stride); assert(space); assert(start); assert(count); assert(op>H5S_SELECT_NOOP && op<H5S_SELECT_INVALID); - /* Fill in the correct stride values */ - if(stride==NULL) { - hssize_t fill=1; - - /* Allocate temporary buffer */ - if ((_stride=H5FL_ARR_ALLOC(hsize_t,space->extent.u.simple.rank,0))==NULL) - HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, - "memory allocation failed for stride buffer"); - H5V_array_fill(_stride,&fill,sizeof(hssize_t),space->extent.u.simple.rank); - stride = _stride; - } - - /* Fill in the correct block values */ - if(block==NULL) { - hssize_t fill=1; - - /* Allocate temporary buffer */ - if ((_block=H5FL_ARR_ALLOC(hsize_t,space->extent.u.simple.rank,0))==NULL) - HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, - "memory allocation failed for stride buffer"); - H5V_array_fill(_block,&fill,sizeof(hssize_t),space->extent.u.simple.rank); - block = _block; - } - - /* - * Check for overlapping hyperslab blocks in new selection (remove when - * real block-merging algorithm is in place? -QAK). - */ - if(op==H5S_SELECT_SET && block!=NULL) { - for(i=0; i<space->extent.u.simple.rank; i++) { - if(stride[i]<block[i]) { - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, - "hyperslab blocks overlap"); - } /* end if */ - } /* end for */ - } /* end if */ - /* Determine if selection is contiguous */ /* assume hyperslab is contiguous, until proven otherwise */ contig=1; @@ -3092,13 +4239,6 @@ H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op, #ifdef QAK printf("%s: check 1.0, contig=%d, op=%s\n",FUNC,(int)contig,(op==H5S_SELECT_SET? "H5S_SELECT_SET" : (op==H5S_SELECT_OR ? "H5S_SELECT_OR" : "Unknown"))); #endif /* QAK */ - /* If we are setting a new selection, remove current selection first */ - if(op==H5S_SELECT_SET) { - if(H5S_select_release(space)<0) { - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, - "can't release hyperslab"); - } /* end if */ - } /* end if */ #ifdef QAK printf("%s: check 2.0, rank=%d\n",FUNC,(int)space->extent.u.simple.rank); @@ -3176,22 +4316,6 @@ H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op, H5S_hyper_clip(space,add,&uniq,NULL); add=uniq; } /* end if */ - else { -#ifdef QAK - printf("%s: check 4.5.2\n",FUNC); -#endif /* QAK */ - /* Copy all the per-dimension selection info into the space descriptor */ - if((diminfo = H5FL_ARR_ALLOC(H5S_hyper_dim_t,space->extent.u.simple.rank,0))==NULL) { - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate per-dimension vector"); - } /* end if */ - for(i=0; i<space->extent.u.simple.rank; i++) { - diminfo[i].start = start[i]; - diminfo[i].stride = stride[i]; - diminfo[i].count = count[i]; - diminfo[i].block = block[i]; - } /* end for */ - space->select.sel_info.hslab.diminfo = diminfo; - } /* end else */ #ifdef QAK printf("%s: check 4.5.5\n",FUNC); #endif /* QAK */ @@ -3215,8 +4339,186 @@ H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op, printf("%s: check 6.0\n",FUNC); #endif /* QAK */ + /* Set return value */ + ret_value=SUCCEED; + +done: + FUNC_LEAVE (ret_value); +} /* end H5S_generate_hyperslab() */ + + +/*------------------------------------------------------------------------- + * Function: H5S_select_hyperslab + * + * Purpose: Internal version of H5Sselect_hyperslab(). + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Robb Matzke (split from HSselect_hyperslab()). + * Tuesday, August 25, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op, + const hssize_t start[/*space_id*/], + const hsize_t stride[/*space_id*/], + const hsize_t count[/*space_id*/], + const hsize_t block[/*space_id*/]) +{ + hsize_t *_stride=NULL; /* Stride array */ + hsize_t *_block=NULL; /* Block size array */ + hssize_t slab[H5O_LAYOUT_NDIMS]; /* Location of the block to add for strided selections */ + size_t slice[H5O_LAYOUT_NDIMS]; /* Size of preceding dimension's slice */ + H5S_hyper_node_t *add=NULL, /* List of hyperslab nodes to add */ + *uniq=NULL, /* List of unique hyperslab nodes */ + *tmp; /* Temporary hyperslab node */ + uintn acc; /* Accumulator for building slices */ + uintn contig; /* whether selection is contiguous or not */ + int i,j; /* Counters */ + H5S_hyper_dim_t *diminfo; /* per-dimension info for the selection */ + herr_t ret_value=FAIL; /* return value */ + + FUNC_ENTER (H5S_select_hyperslab, FAIL); + + /* Check args */ + assert(space); + assert(start); + assert(count); + assert(op>H5S_SELECT_NOOP && op<H5S_SELECT_INVALID); + + /* Fill in the correct stride values */ + if(stride==NULL) { + hssize_t fill=1; + + /* Allocate temporary buffer */ + if ((_stride=H5FL_ARR_ALLOC(hsize_t,space->extent.u.simple.rank,0))==NULL) + HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, + "memory allocation failed for stride buffer"); + H5V_array_fill(_stride,&fill,sizeof(hssize_t),space->extent.u.simple.rank); + stride = _stride; + } + + /* Fill in the correct block values */ + if(block==NULL) { + hssize_t fill=1; + + /* Allocate temporary buffer */ + if ((_block=H5FL_ARR_ALLOC(hsize_t,space->extent.u.simple.rank,0))==NULL) + HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, + "memory allocation failed for stride buffer"); + H5V_array_fill(_block,&fill,sizeof(hssize_t),space->extent.u.simple.rank); + block = _block; + } + + /* Determine if selection is contiguous */ + /* assume hyperslab is contiguous, until proven otherwise */ + contig=1; + for(i=0; i<space->extent.u.simple.rank; i++) { + /* contiguous hyperslabs have the block size equal to the stride */ + if(stride[i]!=block[i]) { + contig=0; /* hyperslab isn't contiguous */ + break; /* no use looking further */ + } /* end if */ + } /* end for */ + +#ifdef QAK + printf("%s: check 1.0, contig=%d, op=%s\n",FUNC,(int)contig,(op==H5S_SELECT_SET? "H5S_SELECT_SET" : (op==H5S_SELECT_OR ? "H5S_SELECT_OR" : "Unknown"))); +#endif /* QAK */ + if(op==H5S_SELECT_SET) { + /* + * Check for overlapping hyperslab blocks in new selection + * (remove when real block-merging algorithm is in place? -QAK). + */ + for(i=0; i<space->extent.u.simple.rank; i++) { + if(count[i]>1 && stride[i]<block[i]) { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, + "hyperslab blocks overlap"); + } /* end if */ + } /* end for */ + + /* If we are setting a new selection, remove current selection first */ + if(H5S_select_release(space)<0) { + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, + "can't release hyperslab"); + } /* end if */ + + /* Copy all the per-dimension selection info into the space descriptor */ + if((diminfo = H5FL_ARR_ALLOC(H5S_hyper_dim_t,space->extent.u.simple.rank,0))==NULL) { + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate per-dimension vector"); + } /* end if */ + for(i=0; i<space->extent.u.simple.rank; i++) { + diminfo[i].start = start[i]; + diminfo[i].stride = stride[i]; + diminfo[i].count = count[i]; + diminfo[i].block = block[i]; + } /* end for */ + space->select.sel_info.hslab.diminfo = diminfo; + + /* Set the number of elements in the hyperslab selection */ + for(space->select.num_elem=1,i=0; i<space->extent.u.simple.rank; i++) + space->select.num_elem*=block[i]*count[i]; + } /* end if */ + else if(op==H5S_SELECT_OR) { + switch(space->select.type) { + case H5S_SEL_ALL: + /* break out now, 'or'ing with an all selection leaves the all selection */ + HGOTO_DONE(SUCCEED); + break; + + case H5S_SEL_HYPERSLABS: + /* Is this the first 'or' operation? */ + if(space->select.sel_info.hslab.diminfo != NULL) { + /* yes, a "regular" hyperslab is selected currently */ + + hssize_t tmp_start[H5O_LAYOUT_NDIMS]; + hsize_t tmp_stride[H5O_LAYOUT_NDIMS]; + hsize_t tmp_count[H5O_LAYOUT_NDIMS]; + hsize_t tmp_block[H5O_LAYOUT_NDIMS]; + + /* Generate the hyperslab information for the regular hyperslab */ + + /* Copy over the 'diminfo' information */ + for(i=0; i<space->extent.u.simple.rank; i++) { + tmp_start[i]=space->select.sel_info.hslab.diminfo[i].start; + tmp_stride[i]=space->select.sel_info.hslab.diminfo[i].stride; + tmp_count[i]=space->select.sel_info.hslab.diminfo[i].count; + tmp_block[i]=space->select.sel_info.hslab.diminfo[i].block; + } /* end for */ + + /* Reset the number of selection elements */ + space->select.num_elem=0; + + /* Build the hyperslab information */ + H5S_generate_hyperslab (space, H5S_SELECT_SET, tmp_start, tmp_stride, tmp_count, tmp_block); + + /* Remove the 'diminfo' information, since we're adding to it */ + H5FL_ARR_FREE(H5S_hyper_dim_t,space->select.sel_info.hslab.diminfo); + space->select.sel_info.hslab.diminfo = NULL; + + /* Add in the new hyperslab information */ + H5S_generate_hyperslab (space, op, start, stride, count, block); + } /* end if */ + else { + /* nope, an "irregular" hyperslab is selected currently */ + /* Add in the new hyperslab information */ + H5S_generate_hyperslab (space, op, start, stride, count, block); + } /* end else */ + break; + + default: + HRETURN_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation"); + } /* end switch() */ + } /* end if */ + else { + HRETURN_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation"); + } /* end else */ + /* Set selection type */ space->select.type=H5S_SEL_HYPERSLABS; + ret_value=SUCCEED; done: @@ -3225,7 +4527,7 @@ done: if(_block!=NULL) H5FL_ARR_FREE(hsize_t,_block); FUNC_LEAVE (ret_value); -} +} /* end H5S_select_hyperslab() */ /*-------------------------------------------------------------------------- @@ -3403,6 +4705,174 @@ H5S_hyper_select_iterate_mem (intn dim, H5S_hyper_iter_info_t *iter_info) /*-------------------------------------------------------------------------- NAME + H5S_hyper_select_iterate_mem_opt + PURPOSE + Iterate over the data points in a regular hyperslab selection, calling a + user's function for each element. + USAGE + herr_t H5S_hyper_select_iterate_mem_opt(buf, type_id, space, op, operator_data) + H5S_sel_iter_t *iter; IN/OUT: Selection iterator + void *buf; IN/OUT: Buffer containing elements to iterate over + hid_t type_id; IN: Datatype ID of BUF array. + H5S_t *space; IN: Dataspace object containing selection to iterate over + H5D_operator_t op; IN: Function pointer to the routine to be + called for each element in BUF iterated over. + void *op_data; IN/OUT: Pointer to any user-defined data associated + with the operation. + RETURNS + Returns the return value of the last operator if it was non-zero, or zero + if all elements were processed. Otherwise returns a negative value. + DESCRIPTION + Iterates over the selected elements in a memory buffer, calling the user's + callback function for each element. The selection in the dataspace is + modified so that any elements already iterated over are removed from the + selection if the iteration is interrupted (by the H5D_operator_t function + returning non-zero) in the "middle" of the iteration and may be re-started + by the user where it left off. + + NOTE: Until "subtracting" elements from a selection is implemented, + the selection is not modified. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S_hyper_select_iterate_mem_opt(H5S_sel_iter_t *iter, void *buf, hid_t type_id, H5S_t *space, H5D_operator_t op, + void *op_data) +{ + H5S_hyper_dim_t *diminfo; /* Alias for dataspace's diminfo information */ + hsize_t tmp_count[H5O_LAYOUT_NDIMS]; /* Temporary hyperslab counts */ + hsize_t tmp_block[H5O_LAYOUT_NDIMS]; /* Temporary hyperslab blocks */ + hssize_t offset[H5O_LAYOUT_NDIMS]; /* Offset of element in dataspace */ + hsize_t slab[H5O_LAYOUT_NDIMS]; /* Size of objects in buffer */ + size_t elem_size; /* Size of data element in buffer */ + size_t temp_off; /* Offset in a given dimension */ + uint8_t *loc; /* Current element location */ + intn i; /* Counter */ + intn fast_dim; /* Rank of the fastest changing dimension for the dataspace */ + intn temp_dim; /* Temporary rank holder */ + intn ndims; /* Rank of the dataspace */ + herr_t user_ret=0; /* User's return value */ + + FUNC_ENTER (H5S_hyper_select_iterate_mem_opt, FAIL); + + /* Set some convienence values */ + ndims=space->extent.u.simple.rank; + fast_dim=ndims-1; + diminfo=space->select.sel_info.hslab.diminfo; + + /* Get the data element size */ + elem_size=H5Tget_size(type_id); + + /* Elements in the fastest dimension are 'elem_size' */ + slab[ndims-1]=elem_size; + + /* If we have two or more dimensions, build the other dimension's element sizes */ + if(ndims>=2) { + /* Build the table of next-dimension down 'element' sizes */ + for(i=ndims-2; i>=0; i--) + slab[i]=slab[i+1]*space->extent.u.simple.size[i+1]; + } /* end if */ + + /* Build the tables of count & block sizes as well as the initial offset */ + for(i=0; i<ndims; i++) { + tmp_count[i]=diminfo[i].count; + tmp_block[i]=diminfo[i].block; + offset[i]=diminfo[i].start; + } /* end for */ + + /* Initialize the starting location */ + for(loc=buf,i=0; i<ndims; i++) + loc+=diminfo[i].start*slab[i]; + + /* Go iterate over the hyperslabs */ + while(user_ret==0) { + /* Iterate over the blocks in the fastest dimension */ + while(tmp_count[fast_dim]>0 && user_ret==0) { + + /* Iterate over the elements in the fastest dimension */ + while(tmp_block[fast_dim]>0 && user_ret==0) { + user_ret=(*op)(loc,type_id,ndims,offset,op_data); + + /* Increment the buffer location */ + loc+=slab[fast_dim]; + + /* Increment the offset in the dataspace */ + offset[fast_dim]++; + + /* Decrement the sequence count */ + tmp_block[fast_dim]--; + } /* end while */ + + /* Reset the sequence count */ + tmp_block[fast_dim]=diminfo[fast_dim].block; + + /* Move the location to the next sequence to start */ + loc+=(diminfo[fast_dim].stride-diminfo[fast_dim].block)*slab[fast_dim]; + + /* Move the offset to the next sequence to start */ + offset[fast_dim]+=(diminfo[fast_dim].stride-diminfo[fast_dim].block); + + /* Decrement the block count */ + tmp_count[fast_dim]--; + } /* end while */ + + /* Work on other dimensions if necessary */ + if(fast_dim>0 && user_ret==0) { + /* Reset the sequence and block counts */ + tmp_block[fast_dim]=diminfo[fast_dim].block; + tmp_count[fast_dim]=diminfo[fast_dim].count; + + /* Bubble up the decrement to the slower changing dimensions */ + temp_dim=fast_dim-1; + while(temp_dim>=0) { + /* Decrement the sequence count in this dimension */ + tmp_block[temp_dim]--; + + /* Check if we are still in the sequence */ + if(tmp_block[temp_dim]>0) + break; + + /* Reset the sequence count in this dimension */ + tmp_block[temp_dim]=diminfo[temp_dim].block; + + /* Decrement the block count */ + tmp_count[temp_dim]--; + + /* Check if we have more blocks left */ + if(tmp_count[temp_dim]>0) + break; + + /* Check for getting out of iterator */ + if(temp_dim==0) + goto done; /* Yes, an evil goto.. :-) -QAK */ + + /* Reset the block count in this dimension */ + tmp_count[temp_dim]=diminfo[temp_dim].count; + + /* Wrapped a dimension, go up to next dimension */ + temp_dim--; + } /* end while */ + } /* end if */ + + /* Re-compute buffer location & offset array */ + for(loc=buf,i=0; i<ndims; i++) { + temp_off=diminfo[i].start + +diminfo[i].stride*(diminfo[i].count-tmp_count[i]) + +(diminfo[i].block-tmp_block[i]); + loc+=temp_off*slab[i]; + offset[i]=temp_off; + } /* end for */ + } /* end while */ + +done: + FUNC_LEAVE (user_ret); +} /* end H5S_hyper_select_iterate_mem_opt() */ + + +/*-------------------------------------------------------------------------- + NAME H5S_hyper_select_iterate PURPOSE Iterate over a hyperslab selection, calling a user's function for each @@ -3450,33 +4920,37 @@ H5S_hyper_select_iterate(void *buf, hid_t type_id, H5S_t *space, H5D_operator_t assert(op); assert(H5I_DATATYPE == H5I_get_type(type_id)); - /* Initialize these before any errors can occur */ - HDmemset(&iter,0,sizeof(H5S_sel_iter_t)); - /* Initialize the selection iterator */ if (H5S_hyper_init(NULL, space, &iter, &min_elem_out)<0) { HGOTO_ERROR (H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection information"); } - /* Initialize parameter block for recursive calls */ - iter_info.dt=type_id; - iter_info.elem_size=H5Tget_size(type_id); - iter_info.space=space; - iter_info.iter=&iter; - iter_info.src=buf; + /* Check for the special case of just one H5Sselect_hyperslab call made */ + if(space->select.sel_info.hslab.diminfo!=NULL) { + /* Use optimized call to iterate over regular hyperslab */ + ret_value=H5S_hyper_select_iterate_mem_opt(&iter,buf,type_id,space,op,operator_data); + } + else { + /* Initialize parameter block for recursive calls */ + iter_info.dt=type_id; + iter_info.elem_size=H5Tget_size(type_id); + iter_info.space=space; + iter_info.iter=&iter; + iter_info.src=buf; - /* Set up the size of the memory space */ - HDmemcpy(iter_info.mem_size, space->extent.u.simple.size, space->extent.u.simple.rank*sizeof(hsize_t)); - iter_info.mem_size[space->extent.u.simple.rank]=iter_info.elem_size; + /* Set up the size of the memory space */ + HDmemcpy(iter_info.mem_size, space->extent.u.simple.size, space->extent.u.simple.rank*sizeof(hsize_t)); + iter_info.mem_size[space->extent.u.simple.rank]=iter_info.elem_size; - /* Copy the location of the region in the file */ - iter_info.op=op; - iter_info.op_data=operator_data; + /* Copy the location of the region in the file */ + iter_info.op=op; + iter_info.op_data=operator_data; - /* Recursively input the hyperslabs currently defined */ - /* starting with the slowest changing dimension */ - ret_value=H5S_hyper_select_iterate_mem(-1,&iter_info); + /* Recursively input the hyperslabs currently defined */ + /* starting with the slowest changing dimension */ + ret_value=H5S_hyper_select_iterate_mem(-1,&iter_info); + } /* end else */ /* Release selection iterator */ H5S_sel_iter_release(space,&iter); diff --git a/src/H5Sselect.c b/src/H5Sselect.c index 4c80cb3..08f3752 100644 --- a/src/H5Sselect.c +++ b/src/H5Sselect.c @@ -590,12 +590,20 @@ static hssize_t H5S_get_select_hyper_nblocks(H5S_t *space) { hssize_t ret_value=FAIL; /* return value */ + intn i; /* Counter */ FUNC_ENTER (H5S_get_select_hyper_nblocks, FAIL); assert(space); - ret_value = (hssize_t)space->select.sel_info.hslab.hyper_lst->count; + /* Check for a "regular" hyperslab selection */ + if(space->select.sel_info.hslab.diminfo != NULL) { + /* Check each dimension */ + for(ret_value=1,i=0; i<space->extent.u.simple.rank; i++) + ret_value*=space->select.sel_info.hslab.diminfo[i].count; + } /* end if */ + else + ret_value = (hssize_t)space->select.sel_info.hslab.hyper_lst->count; FUNC_LEAVE (ret_value); } /* H5Sget_select_hyper_nblocks() */ @@ -742,8 +750,17 @@ H5Sget_select_elem_npoints(hid_t spaceid) static herr_t H5S_get_select_hyper_blocklist(H5S_t *space, hsize_t startblock, hsize_t numblocks, hsize_t *buf) { + H5S_hyper_dim_t *diminfo; /* Alias for dataspace's diminfo information */ + hsize_t tmp_count[H5O_LAYOUT_NDIMS]; /* Temporary hyperslab counts */ + hssize_t offset[H5O_LAYOUT_NDIMS]; /* Offset of element in dataspace */ + size_t temp_off; /* Offset in a given dimension */ H5S_hyper_node_t *node; /* Hyperslab node */ intn rank; /* Dataspace rank */ + intn i; /* Counter */ + intn fast_dim; /* Rank of the fastest changing dimension for the dataspace */ + intn temp_dim; /* Temporary rank holder */ + intn ndims; /* Rank of the dataspace */ + intn done; /* Whether we are done with the iteration */ herr_t ret_value=SUCCEED; /* return value */ FUNC_ENTER (H5S_get_select_hyper_blocklist, FAIL); @@ -754,24 +771,107 @@ H5S_get_select_hyper_blocklist(H5S_t *space, hsize_t startblock, hsize_t numbloc /* Get the dataspace extent rank */ rank=space->extent.u.simple.rank; - /* Get the head of the hyperslab list */ - node=space->select.sel_info.hslab.hyper_lst->head; - - /* Get to the correct first node to give back to the user */ - while(node!=NULL && startblock>0) { - startblock--; - node=node->next; - } /* end while */ - - /* Iterate through the node, copying each hyperslab's information */ - while(node!=NULL && numblocks>0) { - HDmemcpy(buf,node->start,sizeof(hsize_t)*rank); - buf+=rank; - HDmemcpy(buf,node->end,sizeof(hsize_t)*rank); - buf+=rank; - numblocks--; - node=node->next; - } /* end while */ + /* Check for a "regular" hyperslab selection */ + if(space->select.sel_info.hslab.diminfo != NULL) { + /* Set some convienence values */ + ndims=space->extent.u.simple.rank; + fast_dim=ndims-1; + diminfo=space->select.sel_info.hslab.diminfo; + + /* Build the tables of count sizes as well as the initial offset */ + for(i=0; i<ndims; i++) { + tmp_count[i]=diminfo[i].count; + offset[i]=diminfo[i].start; + } /* end for */ + + /* We're not done with the iteration */ + done=0; + + /* Go iterate over the hyperslabs */ + while(done==0 && numblocks>0) { + /* Iterate over the blocks in the fastest dimension */ + while(tmp_count[fast_dim]>0 && numblocks>0) { + + /* Check if we should copy this block information */ + if(startblock==0) { + /* Copy the starting location */ + HDmemcpy(buf,offset,sizeof(hsize_t)*ndims); + buf+=ndims; + + /* Compute the ending location */ + HDmemcpy(buf,offset,sizeof(hsize_t)*ndims); + for(i=0; i<ndims; i++) + buf[i]+=(diminfo[i].block-1); + buf+=ndims; + + /* Decrement the number of blocks to retrieve */ + numblocks--; + } /* end if */ + else + startblock--; + + /* Move the offset to the next sequence to start */ + offset[fast_dim]+=diminfo[fast_dim].stride; + + /* Decrement the block count */ + tmp_count[fast_dim]--; + } /* end while */ + + /* Work on other dimensions if necessary */ + if(fast_dim>0 && numblocks>0) { + /* Reset the block counts */ + tmp_count[fast_dim]=diminfo[fast_dim].count; + + /* Bubble up the decrement to the slower changing dimensions */ + temp_dim=fast_dim-1; + while(temp_dim>=0 && done==0) { + /* Decrement the block count */ + tmp_count[temp_dim]--; + + /* Check if we have more blocks left */ + if(tmp_count[temp_dim]>0) + break; + + /* Check for getting out of iterator */ + if(temp_dim==0) + done=1; + + /* Reset the block count in this dimension */ + tmp_count[temp_dim]=diminfo[temp_dim].count; + + /* Wrapped a dimension, go up to next dimension */ + temp_dim--; + } /* end while */ + } /* end if */ + + /* Re-compute offset array */ + for(i=0; i<ndims; i++) { + temp_off=diminfo[i].start + +diminfo[i].stride*(diminfo[i].count-tmp_count[i]); + offset[i]=temp_off; + } /* end for */ + } /* end while */ + } /* end if */ + else { + /* Get the head of the hyperslab list */ + node=space->select.sel_info.hslab.hyper_lst->head; + + /* Get to the correct first node to give back to the user */ + while(node!=NULL && startblock>0) { + startblock--; + node=node->next; + } /* end while */ + + /* Iterate through the node, copying each hyperslab's information */ + while(node!=NULL && numblocks>0) { + HDmemcpy(buf,node->start,sizeof(hsize_t)*rank); + buf+=rank; + HDmemcpy(buf,node->end,sizeof(hsize_t)*rank); + buf+=rank; + numblocks--; + node=node->next; + } /* end while */ + } /* end else */ FUNC_LEAVE (ret_value); } /* H5Sget_select_hyper_blocklist() */ |