From dc4756fbf47d8fe84472269f24cedc16c8093c48 Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Fri, 1 Oct 2010 00:39:05 -0500 Subject: [svn-r19498] Description: Optimize the vector-vector memcpy() routine even further, for a total of ~2x speedup. :-) Make a generic vector-vector operation routine and convert other vector-vector read & write routines to use generic routine instead of multiple copies of the basic algorithm. Tested on: FreeBSD/32 6.3 (duty) in debug mode FreeBSD/64 6.3 (liberty) w/C++ & FORTRAN, in debug mode Linux/32 2.6 (jam) w/PGI compilers, w/default API=1.8.x, w/C++ & FORTRAN, w/threadsafe, in debug mode Linux/64-amd64 2.6 (amani) w/Intel compilers, w/default API=1.6.x, w/C++ & FORTRAN, in production mode Solaris/32 2.10 (linew) w/deprecated symbols disabled, w/C++ & FORTRAN, w/szip filter, w/threadsafe, in production mode Linux/PPC 2.6 (heiwa) w/C++ & FORTRAN, w/threadsafe, in debug mode Linux/64-ia64 2.6 (cobalt) w/Intel compilers, w/C++ & FORTRAN, in production mode Linux/64-amd64 2.6 (abe) w/parallel, w/FORTRAN, in debug mode Mac OS X/32 10.6.4 (amazon) in debug mode Mac OS X/32 10.6.4 (amazon) w/C++ & FORTRAN, w/threadsafe, in production mode Mac OS X/32 10.6.4 (amazon) w/parallel, in debug mode --- src/H5Dchunk.c | 137 ++++---- src/H5Dcontig.c | 973 +++++++++++++++++++++++++++++-------------------------- src/H5Defl.c | 212 ++++++------ src/H5Dpkg.h | 8 +- src/H5Shyper.c | 5 + src/H5V.c | 403 +++++++++++++++++++++-- src/H5Vprivate.h | 11 +- 7 files changed, 1087 insertions(+), 662 deletions(-) diff --git a/src/H5Dchunk.c b/src/H5Dchunk.c index 1511515..910497b 100644 --- a/src/H5Dchunk.c +++ b/src/H5Dchunk.c @@ -161,6 +161,13 @@ typedef struct H5D_chunk_it_ud4_t { unsigned ndims; /* Number of dimensions for chunk/dataset */ } H5D_chunk_it_ud4_t; +/* Callback info for nonexistent readvv operation */ +typedef struct H5D_chunk_readvv_ud_t { + unsigned char *rbuf; /* Read buffer to initialize */ + H5D_t *dset; /* Dataset to operate on */ + hid_t dxpl_id; /* DXPL for operation */ +} H5D_chunk_readvv_ud_t; + /********************/ /* Local Prototypes */ @@ -4928,6 +4935,55 @@ done: /*------------------------------------------------------------------------- + * Function: H5D_nonexistent_readvv_cb + * + * Purpose: Callback operation for performing fill value I/O operation + * on memory buffer. + * + * Note: This algorithm is pretty inefficient about initializing and + * terminating the fill buffer info structure and it would be + * faster to refactor this into a "real" initialization routine, + * and a "vectorized fill" routine. -QAK + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * 30 Sep 2010 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D_nonexistent_readvv_cb(hsize_t UNUSED dst_off, hsize_t src_off, size_t len, + void *_udata) +{ + H5D_chunk_readvv_ud_t *udata = (H5D_chunk_readvv_ud_t *)_udata; /* User data for H5V_opvv() operator */ + H5D_fill_buf_info_t fb_info; /* Dataset's fill buffer info */ + hbool_t fb_info_init = FALSE; /* Whether the fill value buffer has been initialized */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5D_nonexistent_readvv_cb) + + /* Initialize the fill value buffer */ + if(H5D_fill_init(&fb_info, (udata->rbuf + src_off), NULL, NULL, NULL, NULL, + &udata->dset->shared->dcpl_cache.fill, udata->dset->shared->type, + udata->dset->shared->type_id, (size_t)0, len, udata->dxpl_id) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize fill buffer info") + fb_info_init = TRUE; + + /* Check for VL datatype & fill the buffer with VL datatype fill values */ + if(fb_info.has_vlen_fill_type && H5D_fill_refill_vl(&fb_info, fb_info.elmts_per_buf, udata->dxpl_id) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "can't refill fill value buffer") + +done: + /* Release the fill buffer info, if it's been initialized */ + if(fb_info_init && H5D_fill_term(&fb_info) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release fill buffer info") + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5D_nonexistent_readvv_cb() */ + + +/*------------------------------------------------------------------------- * Function: H5D_nonexistent_readvv * * Purpose: When the chunk doesn't exist on disk and the chunk is bigger @@ -4949,80 +5005,35 @@ done: */ static ssize_t H5D_nonexistent_readvv(const H5D_io_info_t *io_info, - size_t chunk_max_nseq, size_t *chunk_curr_seq, size_t chunk_len_arr[], hsize_t chunk_offset_arr[], - size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]) + size_t chunk_max_nseq, size_t *chunk_curr_seq, size_t chunk_len_arr[], hsize_t chunk_off_arr[], + size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_off_arr[]) { - H5D_t *dset = io_info->dset; /* Local pointer to the dataset info */ - H5D_fill_buf_info_t fb_info; /* Dataset's fill buffer info */ - hbool_t fb_info_init = FALSE; /* Whether the fill value buffer has been initialized */ - size_t u, v; /* Local index variables */ - ssize_t ret_value = 0; /* Return value */ + H5D_chunk_readvv_ud_t udata; /* User data for H5V_opvv() operator */ + ssize_t ret_value; /* Return value */ FUNC_ENTER_NOAPI_NOINIT(H5D_nonexistent_readvv) /* Check args */ + HDassert(io_info); + HDassert(chunk_curr_seq); HDassert(chunk_len_arr); - HDassert(chunk_offset_arr); + HDassert(chunk_off_arr); + HDassert(mem_curr_seq); HDassert(mem_len_arr); - HDassert(mem_offset_arr); - - /* Work through all the sequences */ - for(u = *mem_curr_seq, v = *chunk_curr_seq; u < mem_max_nseq && v < chunk_max_nseq; ) { - unsigned char *buf; /* Temporary pointer into read buffer */ - size_t size; /* Size of sequence in bytes */ - - /* Choose smallest buffer to write */ - if(chunk_len_arr[v] < mem_len_arr[u]) - size = chunk_len_arr[v]; - else - size = mem_len_arr[u]; - - /* Compute offset in memory */ - buf = (unsigned char *)io_info->u.rbuf + mem_offset_arr[u]; + HDassert(mem_off_arr); - /* Initialize the fill value buffer */ - if(H5D_fill_init(&fb_info, buf, NULL, NULL, NULL, NULL, - &dset->shared->dcpl_cache.fill, dset->shared->type, - dset->shared->type_id, (size_t)0, size, io_info->dxpl_id) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't initialize fill buffer info") - fb_info_init = TRUE; - - /* Check for VL datatype & fill the buffer with VL datatype fill values */ - if(fb_info.has_vlen_fill_type && H5D_fill_refill_vl(&fb_info, fb_info.elmts_per_buf, io_info->dxpl_id) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "can't refill fill value buffer") + /* Set up user data for H5V_opvv() */ + udata.rbuf = (unsigned char *)io_info->u.rbuf; + udata.dset = io_info->dset; + udata.dxpl_id = io_info->dxpl_id; - /* Release the fill buffer info */ - if(H5D_fill_term(&fb_info) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release fill buffer info") - fb_info_init = FALSE; - - /* Update source information */ - chunk_len_arr[v] -= size; - if(chunk_len_arr[v] == 0) - v++; - else - chunk_offset_arr[v] += size; - - /* Update destination information */ - mem_len_arr[u] -= size; - if(mem_len_arr[u] == 0) - u++; - else - mem_offset_arr[u] += size; - - /* Increment number of bytes copied */ - ret_value += (ssize_t)size; - } /* end for */ - - /* Update current sequence vectors */ - *mem_curr_seq = u; - *chunk_curr_seq = v; + /* Call generic sequence operation routine */ + if((ret_value = H5V_opvv(chunk_max_nseq, chunk_curr_seq, chunk_len_arr, chunk_off_arr, + mem_max_nseq, mem_curr_seq, mem_len_arr, mem_off_arr, + H5D_nonexistent_readvv_cb, &udata)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTOPERATE, FAIL, "can't perform vectorized fill value init") done: - /* Release the fill buffer info, if it's been initialized */ - if(fb_info_init && H5D_fill_term(&fb_info) < 0) - HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release fill buffer info") - FUNC_LEAVE_NOAPI(ret_value) } /* H5D_nonexistent_readvv() */ diff --git a/src/H5Dcontig.c b/src/H5Dcontig.c index 78c07e6..9b4f338 100644 --- a/src/H5Dcontig.c +++ b/src/H5Dcontig.c @@ -55,6 +55,40 @@ /* Local Typedefs */ /******************/ +/* Callback info for sieve buffer readvv operation */ +typedef struct H5D_contig_readvv_sieve_ud_t { + H5F_t *file; /* File for dataset */ + H5D_rdcdc_t *dset_contig; /* Cached information about contiguous data */ + const H5D_contig_storage_t *store_contig; /* Contiguous storage info for this I/O operation */ + unsigned char *rbuf; /* Pointer to buffer to fill */ + hid_t dxpl_id; /* DXPL for operation */ +} H5D_contig_readvv_sieve_ud_t; + +/* Callback info for [plain] readvv operation */ +typedef struct H5D_contig_readvv_ud_t { + H5F_t *file; /* File for dataset */ + haddr_t dset_addr; /* Address of dataset */ + unsigned char *rbuf; /* Pointer to buffer to fill */ + hid_t dxpl_id; /* DXPL for operation */ +} H5D_contig_readvv_ud_t; + +/* Callback info for sieve buffer writevv operation */ +typedef struct H5D_contig_writevv_sieve_ud_t { + H5F_t *file; /* File for dataset */ + H5D_rdcdc_t *dset_contig; /* Cached information about contiguous data */ + const H5D_contig_storage_t *store_contig; /* Contiguous storage info for this I/O operation */ + const unsigned char *wbuf; /* Pointer to buffer to write */ + hid_t dxpl_id; /* DXPL for operation */ +} H5D_contig_writevv_sieve_ud_t; + +/* Callback info for [plain] writevv operation */ +typedef struct H5D_contig_writevv_ud_t { + H5F_t *file; /* File for dataset */ + haddr_t dset_addr; /* Address of dataset */ + const unsigned char *wbuf; /* Pointer to buffer to write */ + hid_t dxpl_id; /* DXPL for operation */ +} H5D_contig_writevv_ud_t; + /********************/ /* Local Prototypes */ @@ -65,6 +99,12 @@ static herr_t H5D_contig_construct(H5F_t *f, H5D_t *dset); static herr_t H5D_contig_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, H5D_chunk_map_t *cm); +static ssize_t H5D_contig_readvv(const H5D_io_info_t *io_info, + size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], + size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]); +static ssize_t H5D_contig_writevv(const H5D_io_info_t *io_info, + size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], + size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]); static herr_t H5D_contig_flush(H5D_t *dset, hid_t dxpl_id); /* Helper routines */ @@ -600,572 +640,591 @@ done: /*------------------------------------------------------------------------- - * Function: H5D_contig_readvv + * Function: H5D_contig_readvv_sieve_cb * - * Purpose: Reads some data vectors from a dataset into a buffer. - * The data is contiguous. The address is the start of the dataset, - * relative to the base address for the file and the offsets and - * sequence lengths are in bytes. + * Purpose: Callback operator for H5D_contig_readvv() with sieve buffer. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol - * Friday, May 3, 2001 - * - * Notes: - * Offsets in the sequences must be monotonically increasing + * Thursday, Sept 30, 2010 * *------------------------------------------------------------------------- */ -ssize_t -H5D_contig_readvv(const H5D_io_info_t *io_info, - size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], - size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]) +static herr_t +H5D_contig_readvv_sieve_cb(hsize_t dst_off, hsize_t src_off, size_t len, + void *_udata) { - H5F_t *file = io_info->dset->oloc.file; /* File for dataset */ - H5D_rdcdc_t *dset_contig = &(io_info->dset->shared->cache.contig); /* Cached information about contiguous data */ - const H5D_contig_storage_t *store_contig = &(io_info->store->contig); /* Contiguous storage info for this I/O operation */ - unsigned char *buf = (unsigned char *)io_info->u.rbuf; /* Pointer to buffer to fill */ + H5D_contig_readvv_sieve_ud_t *udata = (H5D_contig_readvv_sieve_ud_t *)_udata; /* User data for H5V_opvv() operator */ + H5F_t *file = udata->file; /* File for dataset */ + H5D_rdcdc_t *dset_contig = udata->dset_contig; /* Cached information about contiguous data */ + const H5D_contig_storage_t *store_contig = udata->store_contig; /* Contiguous storage info for this I/O operation */ + unsigned char *buf; /* Pointer to buffer to fill */ haddr_t addr; /* Actual address to read */ - size_t size; /* Size of sequence in bytes */ - size_t u, v; /* Counting variables */ - ssize_t ret_value = 0; /* Return value (Total size of sequence in bytes) */ - - FUNC_ENTER_NOAPI(H5D_contig_readvv, FAIL) -#ifdef QAK -HDfprintf(stderr, "%s: dset_max_nseq = %Zu\n", FUNC, dset_max_nseq); -HDfprintf(stderr, "%s: mem_max_nseq = %Zu\n", FUNC, mem_max_nseq); -HDfprintf(stderr, "%s: *dset_curr_seq= %Zu\n", FUNC, *dset_curr_seq); -HDfprintf(stderr, "%s: *mem_curr_seq= %Zu\n", FUNC, *mem_curr_seq); -for(u = 0; u < dset_max_nseq; u++) - HDfprintf(stderr, "%s: dset_len_arr[%Zu] = %Zu, dset_offset_arr[%Zu] = %Hu\n", FUNC, u, dset_len_arr[u], u, dset_offset_arr[u]); -for(u = 0; u < mem_max_nseq; u++) - HDfprintf(stderr, "%s: mem_len_arr[%Zu] = %Zu, mem_offset_arr[%Zu] = %Hu\n", FUNC, u, mem_len_arr[u], u, mem_offset_arr[u]); -#endif /* QAK */ + haddr_t sieve_start = HADDR_UNDEF, sieve_end = HADDR_UNDEF; /* Start & end locations of sieve buffer */ + haddr_t contig_end; /* End locations of block to write */ + size_t sieve_size = (size_t)-1; /* Size of sieve buffer */ + haddr_t rel_eoa; /* Relative end of file address */ + hsize_t max_data; /* Actual maximum size of data to cache */ + herr_t ret_value = SUCCEED; /* Return value */ - /* Check args */ - HDassert(io_info); - HDassert(io_info->dset); - HDassert(io_info->store); - HDassert(buf); + FUNC_ENTER_NOAPI_NOINIT(H5D_contig_readvv_sieve_cb) - /* Check if data sieving is enabled */ - if(H5F_HAS_FEATURE(file, H5FD_FEAT_DATA_SIEVE)) { - haddr_t sieve_start = HADDR_UNDEF, sieve_end = HADDR_UNDEF; /* Start & end locations of sieve buffer */ - haddr_t contig_end; /* End locations of block to write */ - size_t sieve_size = (size_t)-1; /* size of sieve buffer */ - haddr_t rel_eoa; /* Relative end of file address */ - hsize_t max_data; /* Actual maximum size of data to cache */ - - /* Set offsets in sequence lists */ - u = *dset_curr_seq; - v = *mem_curr_seq; - - /* Stash local copies of these value */ - if(dset_contig->sieve_buf != NULL) { - sieve_start = dset_contig->sieve_loc; - sieve_size = dset_contig->sieve_size; - sieve_end = sieve_start+sieve_size; + /* Stash local copies of these value */ + if(dset_contig->sieve_buf != NULL) { + sieve_start = dset_contig->sieve_loc; + sieve_size = dset_contig->sieve_size; + sieve_end = sieve_start + sieve_size; + } /* end if */ + + /* Compute offset on disk */ + addr = store_contig->dset_addr + dst_off; + + /* Compute offset in memory */ + buf = udata->rbuf + src_off; + + /* Check if the sieve buffer is allocated yet */ + if(NULL == dset_contig->sieve_buf) { + /* Check if we can actually hold the I/O request in the sieve buffer */ + if(len > dset_contig->sieve_buf_size) { + if(H5F_block_read(file, H5FD_MEM_DRAW, addr, len, udata->dxpl_id, buf) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed") } /* end if */ + else { + /* Allocate room for the data sieve buffer */ + if(NULL == (dset_contig->sieve_buf = H5FL_BLK_MALLOC(sieve_buf, dset_contig->sieve_buf_size))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "memory allocation failed") - /* Works through sequences as fast as possible */ - for(; u < dset_max_nseq && v < mem_max_nseq; ) { - /* Choose smallest buffer to write */ - if(mem_len_arr[v] < dset_len_arr[u]) - size = mem_len_arr[v]; - else - size = dset_len_arr[u]; + /* Determine the new sieve buffer size & location */ + dset_contig->sieve_loc = addr; - /* Compute offset on disk */ - addr = store_contig->dset_addr + dset_offset_arr[u]; + /* Make certain we don't read off the end of the file */ + if(HADDR_UNDEF == (rel_eoa = H5F_get_eoa(file, H5FD_MEM_DRAW))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to determine file size") - /* Compute offset in memory */ - buf = (unsigned char *)io_info->u.rbuf + mem_offset_arr[v]; + /* Set up the buffer parameters */ + max_data = store_contig->dset_size - dst_off; - /* Check if the sieve buffer is allocated yet */ - if(dset_contig->sieve_buf == NULL) { - /* Check if we can actually hold the I/O request in the sieve buffer */ - if(size>dset_contig->sieve_buf_size) { - if(H5F_block_read(file, H5FD_MEM_DRAW, addr, size, io_info->dxpl_id, buf) < 0) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "block read failed") - } /* end if */ - else { - /* Allocate room for the data sieve buffer */ - if(NULL == (dset_contig->sieve_buf = H5FL_BLK_MALLOC(sieve_buf, dset_contig->sieve_buf_size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") + /* Compute the size of the sieve buffer */ + H5_ASSIGN_OVERFLOW(dset_contig->sieve_size, MIN3(rel_eoa - dset_contig->sieve_loc, max_data, dset_contig->sieve_buf_size), hsize_t, size_t); - /* Determine the new sieve buffer size & location */ - dset_contig->sieve_loc = addr; + /* Read the new sieve buffer */ + if(H5F_block_read(file, H5FD_MEM_DRAW, dset_contig->sieve_loc, dset_contig->sieve_size, udata->dxpl_id, dset_contig->sieve_buf) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed") - /* Make certain we don't read off the end of the file */ - if(HADDR_UNDEF == (rel_eoa = H5F_get_eoa(file, H5FD_MEM_DRAW))) - HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "unable to determine file size") + /* Grab the data out of the buffer (must be first piece of data in buffer ) */ + HDmemcpy(buf, dset_contig->sieve_buf, len); - /* Set up the buffer parameters */ - max_data = store_contig->dset_size - dset_offset_arr[u]; + /* Reset sieve buffer dirty flag */ + dset_contig->sieve_dirty = FALSE; - /* Compute the size of the sieve buffer */ - H5_ASSIGN_OVERFLOW(dset_contig->sieve_size, MIN3(rel_eoa - dset_contig->sieve_loc, max_data, dset_contig->sieve_buf_size), hsize_t, size_t); + /* Stash local copies of these value */ + sieve_start = dset_contig->sieve_loc; + sieve_size = dset_contig->sieve_size; + sieve_end = sieve_start+sieve_size; + } /* end else */ + } /* end if */ + else { + /* Compute end of sequence to retrieve */ + contig_end = addr + len - 1; - /* Read the new sieve buffer */ - if(H5F_block_read(file, H5FD_MEM_DRAW, dset_contig->sieve_loc, dset_contig->sieve_size, io_info->dxpl_id, dset_contig->sieve_buf) < 0) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "block read failed") + /* If entire read is within the sieve buffer, read it from the buffer */ + if(addr >= sieve_start && contig_end < sieve_end) { + unsigned char *base_sieve_buf = dset_contig->sieve_buf + (addr - sieve_start); - /* Grab the data out of the buffer (must be first piece of data in buffer ) */ - HDmemcpy(buf, dset_contig->sieve_buf, size); + /* Grab the data out of the buffer */ + HDmemcpy(buf, base_sieve_buf, len); + } /* end if */ + /* Entire request is not within this data sieve buffer */ + else { + /* Check if we can actually hold the I/O request in the sieve buffer */ + if(len > dset_contig->sieve_buf_size) { + /* Check for any overlap with the current sieve buffer */ + if((sieve_start >= addr && sieve_start < (contig_end + 1)) + || ((sieve_end - 1) >= addr && (sieve_end - 1) < (contig_end + 1))) { + /* Flush the sieve buffer, if it's dirty */ + if(dset_contig->sieve_dirty) { + /* Write to file */ + if(H5F_block_write(file, H5FD_MEM_DRAW, sieve_start, sieve_size, udata->dxpl_id, dset_contig->sieve_buf) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed") - /* Reset sieve buffer dirty flag */ - dset_contig->sieve_dirty = 0; + /* Reset sieve buffer dirty flag */ + dset_contig->sieve_dirty = FALSE; + } /* end if */ + } /* end if */ - /* Stash local copies of these value */ - sieve_start = dset_contig->sieve_loc; - sieve_size = dset_contig->sieve_size; - sieve_end = sieve_start+sieve_size; - } /* end else */ + /* Read directly into the user's buffer */ + if(H5F_block_read(file, H5FD_MEM_DRAW, addr, len, udata->dxpl_id, buf) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed") } /* end if */ + /* Element size fits within the buffer size */ else { - /* Compute end of sequence to retrieve */ - contig_end = addr + size - 1; - - /* If entire read is within the sieve buffer, read it from the buffer */ - if(addr>=sieve_start && contig_endsieve_buf+(addr-sieve_start); + /* Flush the sieve buffer if it's dirty */ + if(dset_contig->sieve_dirty) { + /* Write to file */ + if(H5F_block_write(file, H5FD_MEM_DRAW, sieve_start, sieve_size, udata->dxpl_id, dset_contig->sieve_buf) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed") - /* Grab the data out of the buffer */ - HDmemcpy(buf, base_sieve_buf, size); + /* Reset sieve buffer dirty flag */ + dset_contig->sieve_dirty = FALSE; } /* end if */ - /* Entire request is not within this data sieve buffer */ - else { - /* Check if we can actually hold the I/O request in the sieve buffer */ - if(size>dset_contig->sieve_buf_size) { - /* Check for any overlap with the current sieve buffer */ - if((sieve_start >= addr && sieve_start < (contig_end + 1)) - || ((sieve_end - 1) >= addr && (sieve_end - 1) < (contig_end + 1))) { - /* Flush the sieve buffer, if it's dirty */ - if(dset_contig->sieve_dirty) { - /* Write to file */ - if(H5F_block_write(file, H5FD_MEM_DRAW, sieve_start, sieve_size, io_info->dxpl_id, dset_contig->sieve_buf) < 0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "block write failed") - - /* Reset sieve buffer dirty flag */ - dset_contig->sieve_dirty = 0; - } /* end if */ - } /* end if */ - - /* Read directly into the user's buffer */ - if(H5F_block_read(file, H5FD_MEM_DRAW, addr, size, io_info->dxpl_id, buf) < 0) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "block read failed") - } /* end if */ - /* Element size fits within the buffer size */ - else { - /* Flush the sieve buffer if it's dirty */ - if(dset_contig->sieve_dirty) { - /* Write to file */ - if(H5F_block_write(file, H5FD_MEM_DRAW, sieve_start, sieve_size, io_info->dxpl_id, dset_contig->sieve_buf) < 0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "block write failed") - /* Reset sieve buffer dirty flag */ - dset_contig->sieve_dirty = 0; - } /* end if */ + /* Determine the new sieve buffer size & location */ + dset_contig->sieve_loc = addr; - /* Determine the new sieve buffer size & location */ - dset_contig->sieve_loc = addr; - - /* Make certain we don't read off the end of the file */ - if(HADDR_UNDEF == (rel_eoa = H5F_get_eoa(file, H5FD_MEM_DRAW))) - HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "unable to determine file size") + /* Make certain we don't read off the end of the file */ + if(HADDR_UNDEF == (rel_eoa = H5F_get_eoa(file, H5FD_MEM_DRAW))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to determine file size") - /* Only need this when resizing sieve buffer */ - max_data = store_contig->dset_size - dset_offset_arr[u]; + /* Only need this when resizing sieve buffer */ + max_data = store_contig->dset_size - dst_off; - /* Compute the size of the sieve buffer */ - /* Don't read off the end of the file, don't read past the end of the data element and don't read more than the buffer size */ - H5_ASSIGN_OVERFLOW(dset_contig->sieve_size, MIN3(rel_eoa - dset_contig->sieve_loc, max_data, dset_contig->sieve_buf_size), hsize_t, size_t); + /* Compute the size of the sieve buffer */ + /* Don't read off the end of the file, don't read past the end of the data element and don't read more than the buffer size */ + H5_ASSIGN_OVERFLOW(dset_contig->sieve_size, MIN3(rel_eoa - dset_contig->sieve_loc, max_data, dset_contig->sieve_buf_size), hsize_t, size_t); - /* Update local copies of sieve information */ - sieve_start = dset_contig->sieve_loc; - sieve_size = dset_contig->sieve_size; - sieve_end = sieve_start + sieve_size; + /* Update local copies of sieve information */ + sieve_start = dset_contig->sieve_loc; + sieve_size = dset_contig->sieve_size; + sieve_end = sieve_start + sieve_size; - /* Read the new sieve buffer */ - if(H5F_block_read(file, H5FD_MEM_DRAW, dset_contig->sieve_loc, dset_contig->sieve_size, io_info->dxpl_id, dset_contig->sieve_buf) < 0) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "block read failed") + /* Read the new sieve buffer */ + if(H5F_block_read(file, H5FD_MEM_DRAW, dset_contig->sieve_loc, dset_contig->sieve_size, udata->dxpl_id, dset_contig->sieve_buf) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed") - /* Grab the data out of the buffer (must be first piece of data in buffer ) */ - HDmemcpy(buf, dset_contig->sieve_buf, size); + /* Grab the data out of the buffer (must be first piece of data in buffer ) */ + HDmemcpy(buf, dset_contig->sieve_buf, len); - /* Reset sieve buffer dirty flag */ - dset_contig->sieve_dirty = 0; - } /* end else */ - } /* end else */ + /* Reset sieve buffer dirty flag */ + dset_contig->sieve_dirty = FALSE; } /* end else */ + } /* end else */ + } /* end else */ - /* Update memory information */ - mem_len_arr[v] -= size; - if(mem_len_arr[v] == 0) - v++; - else - mem_offset_arr[v] += size; - - /* Update file information */ - dset_len_arr[u] -= size; - if(dset_len_arr[u] == 0) - u++; - else - dset_offset_arr[u] += size; - - /* Increment number of bytes copied */ - ret_value += (ssize_t)size; - } /* end for */ - } /* end if */ - else { - /* Work through all the sequences */ - for(u = *dset_curr_seq, v = *mem_curr_seq; u < dset_max_nseq && v < mem_max_nseq; ) { - /* Choose smallest buffer to write */ - if(mem_len_arr[v] < dset_len_arr[u]) - size = mem_len_arr[v]; - else - size = dset_len_arr[u]; - - /* Compute offset on disk */ - addr = store_contig->dset_addr + dset_offset_arr[u]; - - /* Compute offset in memory */ - buf = (unsigned char *)io_info->u.rbuf + mem_offset_arr[v]; - - /* Write data */ - if(H5F_block_read(file, H5FD_MEM_DRAW, addr, size, io_info->dxpl_id, buf) < 0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "block write failed") - - /* Update memory information */ - mem_len_arr[v] -= size; - if(mem_len_arr[v] == 0) - v++; - else - mem_offset_arr[v] += size; +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_contig_readvv_sieve_cb() */ - /* Update file information */ - dset_len_arr[u] -= size; - if(dset_len_arr[u] == 0) - u++; - else - dset_offset_arr[u] += size; + +/*------------------------------------------------------------------------- + * Function: H5D_contig_readvv_cb + * + * Purpose: Callback operator for H5D_contig_readvv() without sieve buffer. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Thursday, Sept 30, 2010 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D_contig_readvv_cb(hsize_t dst_off, hsize_t src_off, size_t len, void *_udata) +{ + H5D_contig_readvv_ud_t *udata = (H5D_contig_readvv_ud_t *)_udata; /* User data for H5V_opvv() operator */ + herr_t ret_value = SUCCEED; /* Return value */ - /* Increment number of bytes copied */ - ret_value += (ssize_t)size; - } /* end for */ - } /* end else */ + FUNC_ENTER_NOAPI_NOINIT(H5D_contig_readvv_cb) - /* Update current sequence vectors */ - *dset_curr_seq = u; - *mem_curr_seq = v; + /* Write data */ + if(H5F_block_read(udata->file, H5FD_MEM_DRAW, (udata->dset_addr + dst_off), + len, udata->dxpl_id, (udata->rbuf + src_off)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed") done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D_contig_readvv() */ +} /* end H5D_contig_readvv_cb() */ /*------------------------------------------------------------------------- - * Function: H5D_contig_writevv + * Function: H5D_contig_readvv * - * Purpose: Writes some data vectors into a dataset from vectors into a - * buffer. The address is the start of the dataset, + * Purpose: Reads some data vectors from a dataset into a buffer. + * The data is contiguous. The address is the start of the dataset, * relative to the base address for the file and the offsets and * sequence lengths are in bytes. * * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol - * Friday, May 2, 2003 + * Friday, May 3, 2001 * * Notes: * Offsets in the sequences must be monotonically increasing * *------------------------------------------------------------------------- */ -ssize_t -H5D_contig_writevv(const H5D_io_info_t *io_info, - size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], - size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]) +static ssize_t +H5D_contig_readvv(const H5D_io_info_t *io_info, + size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_off_arr[], + size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_off_arr[]) { - H5F_t *file = io_info->dset->oloc.file; /* File for dataset */ - H5D_rdcdc_t *dset_contig = &(io_info->dset->shared->cache.contig); /* Cached information about contiguous data */ - const H5D_contig_storage_t *store_contig = &(io_info->store->contig); /* Contiguous storage info for this I/O operation */ - const unsigned char *buf = (const unsigned char *)io_info->u.wbuf; /* Pointer to buffer to fill */ - haddr_t addr; /* Actual address to read */ - size_t size; /* Size of sequence in bytes */ - size_t u, v; /* Counting variables */ - ssize_t ret_value = 0; /* Return value (Size of sequence in bytes) */ + ssize_t ret_value; /* Return value */ - FUNC_ENTER_NOAPI(H5D_contig_writevv, FAIL) + FUNC_ENTER_NOAPI_NOINIT(H5D_contig_readvv) /* Check args */ HDassert(io_info); - HDassert(io_info->dset); - HDassert(io_info->store); - HDassert(buf); + HDassert(dset_curr_seq); + HDassert(dset_len_arr); + HDassert(dset_off_arr); + HDassert(mem_curr_seq); + HDassert(mem_len_arr); + HDassert(mem_off_arr); /* Check if data sieving is enabled */ - if(H5F_HAS_FEATURE(file, H5FD_FEAT_DATA_SIEVE)) { - haddr_t sieve_start = HADDR_UNDEF, sieve_end = HADDR_UNDEF; /* Start & end locations of sieve buffer */ - haddr_t contig_end; /* End locations of block to write */ - size_t sieve_size = (size_t)-1; /* size of sieve buffer */ - haddr_t rel_eoa; /* Relative end of file address */ - hsize_t max_data; /* Actual maximum size of data to cache */ - - /* Set offsets in sequence lists */ - u = *dset_curr_seq; - v = *mem_curr_seq; - - /* Stash local copies of these values */ - if(dset_contig->sieve_buf != NULL) { + if(H5F_HAS_FEATURE(io_info->dset->oloc.file, H5FD_FEAT_DATA_SIEVE)) { + H5D_contig_readvv_sieve_ud_t udata; /* User data for H5V_opvv() operator */ + + /* Set up user data for H5V_opvv() */ + udata.file = io_info->dset->oloc.file; + udata.dset_contig = &(io_info->dset->shared->cache.contig); + udata.store_contig = &(io_info->store->contig); + udata.rbuf = (unsigned char *)io_info->u.rbuf; + udata.dxpl_id = io_info->dxpl_id; + + /* Call generic sequence operation routine */ + if((ret_value = H5V_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr, + mem_max_nseq, mem_curr_seq, mem_len_arr, mem_off_arr, + H5D_contig_readvv_sieve_cb, &udata)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTOPERATE, FAIL, "can't perform vectorized sieve buffer read") + } /* end if */ + else { + H5D_contig_readvv_ud_t udata; /* User data for H5V_opvv() operator */ + + /* Set up user data for H5V_opvv() */ + udata.file = io_info->dset->oloc.file; + udata.dset_addr = io_info->store->contig.dset_addr; + udata.rbuf = (unsigned char *)io_info->u.rbuf; + udata.dxpl_id = io_info->dxpl_id; + + /* Call generic sequence operation routine */ + if((ret_value = H5V_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr, + mem_max_nseq, mem_curr_seq, mem_len_arr, mem_off_arr, + H5D_contig_readvv_cb, &udata)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTOPERATE, FAIL, "can't perform vectorized read") + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_contig_readvv() */ + + +/*------------------------------------------------------------------------- + * Function: H5D_contig_writevv_sieve_cb + * + * Purpose: Callback operator for H5D_contig_writevv() with sieve buffer. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Thursday, Sept 30, 2010 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D_contig_writevv_sieve_cb(hsize_t dst_off, hsize_t src_off, size_t len, + void *_udata) +{ + H5D_contig_writevv_sieve_ud_t *udata = (H5D_contig_writevv_sieve_ud_t *)_udata; /* User data for H5V_opvv() operator */ + H5F_t *file = udata->file; /* File for dataset */ + H5D_rdcdc_t *dset_contig = udata->dset_contig; /* Cached information about contiguous data */ + const H5D_contig_storage_t *store_contig = udata->store_contig; /* Contiguous storage info for this I/O operation */ + const unsigned char *buf; /* Pointer to buffer to fill */ + haddr_t addr; /* Actual address to read */ + haddr_t sieve_start = HADDR_UNDEF, sieve_end = HADDR_UNDEF; /* Start & end locations of sieve buffer */ + haddr_t contig_end; /* End locations of block to write */ + size_t sieve_size = (size_t)-1; /* size of sieve buffer */ + haddr_t rel_eoa; /* Relative end of file address */ + hsize_t max_data; /* Actual maximum size of data to cache */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5D_contig_writevv_sieve_cb) + + /* Stash local copies of these values */ + if(dset_contig->sieve_buf != NULL) { + sieve_start = dset_contig->sieve_loc; + sieve_size = dset_contig->sieve_size; + sieve_end = sieve_start + sieve_size; + } /* end if */ + + /* Compute offset on disk */ + addr = store_contig->dset_addr + dst_off; + + /* Compute offset in memory */ + buf = udata->wbuf + src_off; + + /* No data sieve buffer yet, go allocate one */ + if(NULL == dset_contig->sieve_buf) { + /* Check if we can actually hold the I/O request in the sieve buffer */ + if(len > dset_contig->sieve_buf_size) { + if(H5F_block_write(file, H5FD_MEM_DRAW, addr, len, udata->dxpl_id, buf) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed") + } /* end if */ + else { + /* Allocate room for the data sieve buffer */ + if(NULL == (dset_contig->sieve_buf = H5FL_BLK_MALLOC(sieve_buf, dset_contig->sieve_buf_size))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "memory allocation failed") +#ifdef H5_CLEAR_MEMORY +if(dset_contig->sieve_size > len) + HDmemset(dset_contig->sieve_buf + len, 0, (dset_contig->sieve_size - len)); +#endif /* H5_CLEAR_MEMORY */ + + /* Determine the new sieve buffer size & location */ + dset_contig->sieve_loc = addr; + + /* Make certain we don't read off the end of the file */ + if(HADDR_UNDEF == (rel_eoa = H5F_get_eoa(file, H5FD_MEM_DRAW))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to determine file size") + + /* Set up the buffer parameters */ + max_data = store_contig->dset_size - dst_off; + + /* Compute the size of the sieve buffer */ + H5_ASSIGN_OVERFLOW(dset_contig->sieve_size, MIN3(rel_eoa - dset_contig->sieve_loc, max_data, dset_contig->sieve_buf_size), hsize_t, size_t); + + /* Check if there is any point in reading the data from the file */ + if(dset_contig->sieve_size > len) { + /* Read the new sieve buffer */ + if(H5F_block_read(file, H5FD_MEM_DRAW, dset_contig->sieve_loc, dset_contig->sieve_size, udata->dxpl_id, dset_contig->sieve_buf) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed") + } /* end if */ + + /* Grab the data out of the buffer (must be first piece of data in buffer ) */ + HDmemcpy(dset_contig->sieve_buf, buf, len); + + /* Set sieve buffer dirty flag */ + dset_contig->sieve_dirty = TRUE; + + /* Stash local copies of these values */ sieve_start = dset_contig->sieve_loc; sieve_size = dset_contig->sieve_size; sieve_end = sieve_start + sieve_size; + } /* end else */ + } /* end if */ + else { + /* Compute end of sequence to retrieve */ + contig_end = addr + len - 1; + + /* If entire write is within the sieve buffer, write it to the buffer */ + if(addr >= sieve_start && contig_end < sieve_end) { + unsigned char *base_sieve_buf = dset_contig->sieve_buf + (addr - sieve_start); + + /* Put the data into the sieve buffer */ + HDmemcpy(base_sieve_buf, buf, len); + + /* Set sieve buffer dirty flag */ + dset_contig->sieve_dirty = TRUE; } /* end if */ + /* Entire request is not within this data sieve buffer */ + else { + /* Check if we can actually hold the I/O request in the sieve buffer */ + if(len > dset_contig->sieve_buf_size) { + /* Check for any overlap with the current sieve buffer */ + if((sieve_start >= addr && sieve_start < (contig_end + 1)) + || ((sieve_end - 1) >= addr && (sieve_end - 1) < (contig_end + 1))) { + /* Flush the sieve buffer, if it's dirty */ + if(dset_contig->sieve_dirty) { + /* Write to file */ + if(H5F_block_write(file, H5FD_MEM_DRAW, sieve_start, sieve_size, udata->dxpl_id, dset_contig->sieve_buf) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed") - /* Works through sequences as fast as possible */ - for(; u < dset_max_nseq && v < mem_max_nseq; ) { - /* Choose smallest buffer to write */ - if(mem_len_arr[v] < dset_len_arr[u]) - size = mem_len_arr[v]; - else - size = dset_len_arr[u]; + /* Reset sieve buffer dirty flag */ + dset_contig->sieve_dirty = FALSE; + } /* end if */ - /* Compute offset on disk */ - addr = store_contig->dset_addr + dset_offset_arr[u]; + /* Force the sieve buffer to be re-read the next time */ + dset_contig->sieve_loc = HADDR_UNDEF; + dset_contig->sieve_size = 0; + } /* end if */ + + /* Write directly from the user's buffer */ + if(H5F_block_write(file, H5FD_MEM_DRAW, addr, len, udata->dxpl_id, buf) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed") + } /* end if */ + /* Element size fits within the buffer size */ + else { + /* Check if it is possible to (exactly) prepend or append to existing (dirty) sieve buffer */ + if(((addr + len) == sieve_start || addr == sieve_end) && + (len + sieve_size) <= dset_contig->sieve_buf_size && + dset_contig->sieve_dirty) { + /* Prepend to existing sieve buffer */ + if((addr + len) == sieve_start) { + /* Move existing sieve information to correct location */ + HDmemmove(dset_contig->sieve_buf + len, dset_contig->sieve_buf, dset_contig->sieve_size); + + /* Copy in new information (must be first in sieve buffer) */ + HDmemcpy(dset_contig->sieve_buf, buf, len); + + /* Adjust sieve location */ + dset_contig->sieve_loc = addr; - /* Compute offset in memory */ - buf = (const unsigned char *)io_info->u.wbuf + mem_offset_arr[v]; + } /* end if */ + /* Append to existing sieve buffer */ + else { + /* Copy in new information */ + HDmemcpy(dset_contig->sieve_buf + sieve_size, buf, len); + } /* end else */ - /* No data sieve buffer yet, go allocate one */ - if(NULL == dset_contig->sieve_buf) { - /* Check if we can actually hold the I/O request in the sieve buffer */ - if(size>dset_contig->sieve_buf_size) { - if(H5F_block_write(file, H5FD_MEM_DRAW, addr, size, io_info->dxpl_id, buf) < 0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "block write failed") + /* Adjust sieve size */ + dset_contig->sieve_size += len; + + /* Update local copies of sieve information */ + sieve_start = dset_contig->sieve_loc; + sieve_size = dset_contig->sieve_size; + sieve_end = sieve_start + sieve_size; } /* end if */ + /* Can't add the new data onto the existing sieve buffer */ else { - /* Allocate room for the data sieve buffer */ - if(NULL == (dset_contig->sieve_buf = H5FL_BLK_MALLOC(sieve_buf, dset_contig->sieve_buf_size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") -#ifdef H5_CLEAR_MEMORY -if(dset_contig->sieve_size > size) - HDmemset(dset_contig->sieve_buf + size, 0, (dset_contig->sieve_size - size)); -#endif /* H5_CLEAR_MEMORY */ + /* Flush the sieve buffer if it's dirty */ + if(dset_contig->sieve_dirty) { + /* Write to file */ + if(H5F_block_write(file, H5FD_MEM_DRAW, sieve_start, sieve_size, udata->dxpl_id, dset_contig->sieve_buf) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed") + + /* Reset sieve buffer dirty flag */ + dset_contig->sieve_dirty = FALSE; + } /* end if */ /* Determine the new sieve buffer size & location */ dset_contig->sieve_loc = addr; /* Make certain we don't read off the end of the file */ if(HADDR_UNDEF == (rel_eoa = H5F_get_eoa(file, H5FD_MEM_DRAW))) - HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "unable to determine file size") + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "unable to determine file size") - /* Set up the buffer parameters */ - max_data = store_contig->dset_size - dset_offset_arr[u]; + /* Only need this when resizing sieve buffer */ + max_data = store_contig->dset_size - dst_off; /* Compute the size of the sieve buffer */ + /* Don't read off the end of the file, don't read past the end of the data element and don't read more than the buffer size */ H5_ASSIGN_OVERFLOW(dset_contig->sieve_size, MIN3(rel_eoa - dset_contig->sieve_loc, max_data, dset_contig->sieve_buf_size), hsize_t, size_t); - /* Check if there is any point in reading the data from the file */ - if(dset_contig->sieve_size>size) { - /* Read the new sieve buffer */ - if(H5F_block_read(file, H5FD_MEM_DRAW, dset_contig->sieve_loc, dset_contig->sieve_size, io_info->dxpl_id, dset_contig->sieve_buf) < 0) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "block read failed") - } /* end if */ - - /* Grab the data out of the buffer (must be first piece of data in buffer ) */ - HDmemcpy(dset_contig->sieve_buf, buf, size); - - /* Set sieve buffer dirty flag */ - dset_contig->sieve_dirty = 1; - - /* Stash local copies of these values */ + /* Update local copies of sieve information */ sieve_start = dset_contig->sieve_loc; sieve_size = dset_contig->sieve_size; sieve_end = sieve_start + sieve_size; - } /* end else */ - } /* end if */ - else { - /* Compute end of sequence to retrieve */ - contig_end = addr + size - 1; - /* If entire write is within the sieve buffer, write it to the buffer */ - if(addr >= sieve_start && contig_end < sieve_end) { - unsigned char *base_sieve_buf = dset_contig->sieve_buf + (addr - sieve_start); + /* Check if there is any point in reading the data from the file */ + if(dset_contig->sieve_size > len) { + /* Read the new sieve buffer */ + if(H5F_block_read(file, H5FD_MEM_DRAW, dset_contig->sieve_loc, dset_contig->sieve_size, udata->dxpl_id, dset_contig->sieve_buf) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "block read failed") + } /* end if */ - /* Put the data into the sieve buffer */ - HDmemcpy(base_sieve_buf, buf, size); + /* Grab the data out of the buffer (must be first piece of data in buffer ) */ + HDmemcpy(dset_contig->sieve_buf, buf, len); /* Set sieve buffer dirty flag */ - dset_contig->sieve_dirty = 1; - } /* end if */ - /* Entire request is not within this data sieve buffer */ - else { - /* Check if we can actually hold the I/O request in the sieve buffer */ - if(size>dset_contig->sieve_buf_size) { - /* Check for any overlap with the current sieve buffer */ - if((sieve_start >= addr && sieve_start < (contig_end + 1)) - || ((sieve_end - 1) >= addr && (sieve_end - 1) < (contig_end + 1))) { - /* Flush the sieve buffer, if it's dirty */ - if(dset_contig->sieve_dirty) { - /* Write to file */ - if(H5F_block_write(file, H5FD_MEM_DRAW, sieve_start, sieve_size, io_info->dxpl_id, dset_contig->sieve_buf) < 0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "block write failed") - - /* Reset sieve buffer dirty flag */ - dset_contig->sieve_dirty = 0; - } /* end if */ - - /* Force the sieve buffer to be re-read the next time */ - dset_contig->sieve_loc = HADDR_UNDEF; - dset_contig->sieve_size = 0; - } /* end if */ - - /* Write directly from the user's buffer */ - if(H5F_block_write(file, H5FD_MEM_DRAW, addr, size, io_info->dxpl_id, buf) < 0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "block write failed") - } /* end if */ - /* Element size fits within the buffer size */ - else { - /* Check if it is possible to (exactly) prepend or append to existing (dirty) sieve buffer */ - if(((addr + size) == sieve_start || addr == sieve_end) && - (size + sieve_size) <= dset_contig->sieve_buf_size && - dset_contig->sieve_dirty) { - /* Prepend to existing sieve buffer */ - if((addr + size) == sieve_start) { - /* Move existing sieve information to correct location */ - HDmemmove(dset_contig->sieve_buf + size, dset_contig->sieve_buf, dset_contig->sieve_size); - - /* Copy in new information (must be first in sieve buffer) */ - HDmemcpy(dset_contig->sieve_buf, buf, size); - - /* Adjust sieve location */ - dset_contig->sieve_loc = addr; - - } /* end if */ - /* Append to existing sieve buffer */ - else { - /* Copy in new information */ - HDmemcpy(dset_contig->sieve_buf + sieve_size, buf, size); - } /* end else */ - - /* Adjust sieve size */ - dset_contig->sieve_size += size; - - /* Update local copies of sieve information */ - sieve_start = dset_contig->sieve_loc; - sieve_size = dset_contig->sieve_size; - sieve_end = sieve_start + sieve_size; - } /* end if */ - /* Can't add the new data onto the existing sieve buffer */ - else { - /* Flush the sieve buffer if it's dirty */ - if(dset_contig->sieve_dirty) { - /* Write to file */ - if(H5F_block_write(file, H5FD_MEM_DRAW, sieve_start, sieve_size, io_info->dxpl_id, dset_contig->sieve_buf) < 0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "block write failed") - - /* Reset sieve buffer dirty flag */ - dset_contig->sieve_dirty = 0; - } /* end if */ - - /* Determine the new sieve buffer size & location */ - dset_contig->sieve_loc = addr; - - /* Make certain we don't read off the end of the file */ - if(HADDR_UNDEF == (rel_eoa = H5F_get_eoa(file, H5FD_MEM_DRAW))) - HGOTO_ERROR(H5E_FILE, H5E_CANTOPENFILE, FAIL, "unable to determine file size") - - /* Only need this when resizing sieve buffer */ - max_data = store_contig->dset_size - dset_offset_arr[u]; - - /* Compute the size of the sieve buffer */ - /* Don't read off the end of the file, don't read past the end of the data element and don't read more than the buffer size */ - H5_ASSIGN_OVERFLOW(dset_contig->sieve_size, MIN3(rel_eoa - dset_contig->sieve_loc, max_data, dset_contig->sieve_buf_size), hsize_t, size_t); - - /* Update local copies of sieve information */ - sieve_start = dset_contig->sieve_loc; - sieve_size = dset_contig->sieve_size; - sieve_end = sieve_start + sieve_size; - - /* Check if there is any point in reading the data from the file */ - if(dset_contig->sieve_size > size) { - /* Read the new sieve buffer */ - if(H5F_block_read(file, H5FD_MEM_DRAW, dset_contig->sieve_loc, dset_contig->sieve_size, io_info->dxpl_id, dset_contig->sieve_buf) < 0) - HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "block read failed") - } /* end if */ - - /* Grab the data out of the buffer (must be first piece of data in buffer ) */ - HDmemcpy(dset_contig->sieve_buf, buf, size); - - /* Set sieve buffer dirty flag */ - dset_contig->sieve_dirty = 1; - } /* end else */ - } /* end else */ + dset_contig->sieve_dirty = TRUE; } /* end else */ } /* end else */ + } /* end else */ + } /* end else */ - /* Update memory information */ - mem_len_arr[v] -= size; - if(mem_len_arr[v] == 0) - v++; - else - mem_offset_arr[v] += size; +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_contig_writevv_sieve_cb() */ - /* Update file information */ - dset_len_arr[u] -= size; - if(dset_len_arr[u] == 0) - u++; - else - dset_offset_arr[u] += size; + +/*------------------------------------------------------------------------- + * Function: H5D_contig_writevv_cb + * + * Purpose: Callback operator for H5D_contig_writevv(). + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Thursday, Sept 30, 2010 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D_contig_writevv_cb(hsize_t dst_off, hsize_t src_off, size_t len, void *_udata) +{ + H5D_contig_writevv_ud_t *udata = (H5D_contig_writevv_ud_t *)_udata; /* User data for H5V_opvv() operator */ + herr_t ret_value = SUCCEED; /* Return value */ - /* Increment number of bytes copied */ - ret_value += (ssize_t)size; - } /* end for */ - } /* end if */ - else { - /* Work through all the sequences */ - for(u = *dset_curr_seq, v = *mem_curr_seq; u < dset_max_nseq && v < mem_max_nseq; ) { - /* Choose smallest buffer to write */ - if(mem_len_arr[v] < dset_len_arr[u]) - size = mem_len_arr[v]; - else - size = dset_len_arr[u]; + FUNC_ENTER_NOAPI_NOINIT(H5D_contig_writevv_cb) - /* Compute offset on disk */ - addr = store_contig->dset_addr + dset_offset_arr[u]; + /* Write data */ + if(H5F_block_write(udata->file, H5FD_MEM_DRAW, (udata->dset_addr + dst_off), len, udata->dxpl_id, (udata->wbuf + src_off)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "block write failed") - /* Compute offset in memory */ - buf = (const unsigned char *)io_info->u.wbuf + mem_offset_arr[v]; +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_contig_writevv_cb() */ - /* Write data */ - if(H5F_block_write(file, H5FD_MEM_DRAW, addr, size, io_info->dxpl_id, buf) < 0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "block write failed") + +/*------------------------------------------------------------------------- + * Function: H5D_contig_writevv + * + * Purpose: Writes some data vectors into a dataset from vectors into a + * buffer. The address is the start of the dataset, + * relative to the base address for the file and the offsets and + * sequence lengths are in bytes. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Friday, May 2, 2003 + * + * Notes: + * Offsets in the sequences must be monotonically increasing + * + *------------------------------------------------------------------------- + */ +static ssize_t +H5D_contig_writevv(const H5D_io_info_t *io_info, + size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_off_arr[], + size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_off_arr[]) +{ + ssize_t ret_value; /* Return value (Size of sequence in bytes) */ - /* Update memory information */ - mem_len_arr[v] -= size; - if(mem_len_arr[v] == 0) - v++; - else - mem_offset_arr[v] += size; + FUNC_ENTER_NOAPI_NOINIT(H5D_contig_writevv) - /* Update file information */ - dset_len_arr[u] -= size; - if(dset_len_arr[u] == 0) - u++; - else - dset_offset_arr[u] += size; + /* Check args */ + HDassert(io_info); + HDassert(dset_curr_seq); + HDassert(dset_len_arr); + HDassert(dset_off_arr); + HDassert(mem_curr_seq); + HDassert(mem_len_arr); + HDassert(mem_off_arr); - /* Increment number of bytes copied */ - ret_value += (ssize_t)size; - } /* end for */ + /* Check if data sieving is enabled */ + if(H5F_HAS_FEATURE(io_info->dset->oloc.file, H5FD_FEAT_DATA_SIEVE)) { + H5D_contig_writevv_sieve_ud_t udata; /* User data for H5V_opvv() operator */ + + /* Set up user data for H5V_opvv() */ + udata.file = io_info->dset->oloc.file; + udata.dset_contig = &(io_info->dset->shared->cache.contig); + udata.store_contig = &(io_info->store->contig); + udata.wbuf = (const unsigned char *)io_info->u.wbuf; + udata.dxpl_id = io_info->dxpl_id; + + /* Call generic sequence operation routine */ + if((ret_value = H5V_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr, + mem_max_nseq, mem_curr_seq, mem_len_arr, mem_off_arr, + H5D_contig_writevv_sieve_cb, &udata)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTOPERATE, FAIL, "can't perform vectorized sieve buffer write") + } /* end if */ + else { + H5D_contig_writevv_ud_t udata; /* User data for H5V_opvv() operator */ + + /* Set up user data for H5V_opvv() */ + udata.file = io_info->dset->oloc.file; + udata.dset_addr = io_info->store->contig.dset_addr; + udata.wbuf = (const unsigned char *)io_info->u.wbuf; + udata.dxpl_id = io_info->dxpl_id; + + /* Call generic sequence operation routine */ + if((ret_value = H5V_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr, + mem_max_nseq, mem_curr_seq, mem_len_arr, mem_off_arr, + H5D_contig_writevv_cb, &udata)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTOPERATE, FAIL, "can't perform vectorized read") } /* end else */ - /* Update current sequence vectors */ - *dset_curr_seq = u; - *mem_curr_seq = v; - done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D_contig_writevv() */ diff --git a/src/H5Defl.c b/src/H5Defl.c index 87471f1..bcb47a2 100644 --- a/src/H5Defl.c +++ b/src/H5Defl.c @@ -33,6 +33,7 @@ #include "H5Eprivate.h" /* Error handling */ #include "H5Fprivate.h" /* Files */ #include "H5HLprivate.h" /* Local Heaps */ +#include "H5Vprivate.h" /* Vector and array functions */ /****************/ @@ -44,6 +45,18 @@ /* Local Typedefs */ /******************/ +/* Callback info for readvv operation */ +typedef struct H5D_efl_readvv_ud_t { + const H5O_efl_t *efl; /* Pointer to efl info */ + unsigned char *rbuf; /* Read buffer */ +} H5D_efl_readvv_ud_t; + +/* Callback info for writevv operation */ +typedef struct H5D_efl_writevv_ud_t { + const H5O_efl_t *efl; /* Pointer to efl info */ + const unsigned char *wbuf; /* Write buffer */ +} H5D_efl_writevv_ud_t; + /********************/ /* Local Prototypes */ @@ -398,6 +411,35 @@ done: /*------------------------------------------------------------------------- + * Function: H5D_efl_readvv_cb + * + * Purpose: Callback operator for H5D_efl_readvv(). + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Thursday, Sept 30, 2010 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D_efl_readvv_cb(hsize_t dst_off, hsize_t src_off, size_t len, void *_udata) +{ + H5D_efl_readvv_ud_t *udata = (H5D_efl_readvv_ud_t *)_udata; /* User data for H5V_opvv() operator */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5D_efl_readvv_cb) + + /* Read data */ + if(H5D_efl_read(udata->efl, dst_off, len, (udata->rbuf + src_off)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "EFL read failed") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_efl_readvv_cb() */ + + +/*------------------------------------------------------------------------- * Function: H5D_efl_readvv * * Purpose: Reads data from an external file list. It is an error to @@ -414,65 +456,67 @@ done: */ static ssize_t H5D_efl_readvv(const H5D_io_info_t *io_info, - size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], - size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]) + size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_off_arr[], + size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_off_arr[]) { - const H5O_efl_t *efl = &(io_info->store->efl); /* Pointer to efl info */ - unsigned char *buf; /* Pointer to buffer to write */ - haddr_t addr; /* Actual address to read */ - size_t size; /* Size of sequence in bytes */ - size_t u, v; /* Counting variables */ - ssize_t ret_value = 0; /* Return value (Total size of sequence in bytes) */ + H5D_efl_readvv_ud_t udata; /* User data for H5V_opvv() operator */ + ssize_t ret_value; /* Return value (Total size of sequence in bytes) */ FUNC_ENTER_NOAPI_NOINIT(H5D_efl_readvv) /* Check args */ - HDassert(efl && efl->nused > 0); + HDassert(io_info); + HDassert(io_info->store->efl.nused > 0); HDassert(io_info->u.rbuf); + HDassert(dset_curr_seq); + HDassert(dset_len_arr); + HDassert(dset_off_arr); + HDassert(mem_curr_seq); + HDassert(mem_len_arr); + HDassert(mem_off_arr); + + /* Set up user data for H5V_opvv() */ + udata.efl = &(io_info->store->efl); + udata.rbuf = (unsigned char *)io_info->u.rbuf; + + /* Call generic sequence operation routine */ + if((ret_value = H5V_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr, + mem_max_nseq, mem_curr_seq, mem_len_arr, mem_off_arr, + H5D_efl_readvv_cb, &udata)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTOPERATE, FAIL, "can't perform vectorized EFL read") - /* Work through all the sequences */ - for(u = *dset_curr_seq, v = *mem_curr_seq; u < dset_max_nseq && v < mem_max_nseq; ) { - /* Choose smallest buffer to write */ - if(mem_len_arr[v] < dset_len_arr[u]) - size = mem_len_arr[v]; - else - size = dset_len_arr[u]; - - /* Compute offset on disk */ - addr = dset_offset_arr[u]; - - /* Compute offset in memory */ - buf = (unsigned char *)io_info->u.rbuf + mem_offset_arr[v]; - - /* Read data */ - if(H5D_efl_read(efl, addr, size, buf) < 0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "block write failed") - - /* Update memory information */ - mem_len_arr[v] -= size; - if(mem_len_arr[v] == 0) - v++; - else - mem_offset_arr[v] += size; - - /* Update file information */ - dset_len_arr[u] -= size; - if(dset_len_arr[u] == 0) - u++; - else - dset_offset_arr[u] += size; - - /* Increment number of bytes copied */ - ret_value += (ssize_t)size; - } /* end for */ +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D_efl_readvv() */ + + +/*------------------------------------------------------------------------- + * Function: H5D_efl_writevv_cb + * + * Purpose: Callback operator for H5D_efl_writevv(). + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Thursday, Sept 30, 2010 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D_efl_writevv_cb(hsize_t dst_off, hsize_t src_off, size_t len, void *_udata) +{ + H5D_efl_writevv_ud_t *udata = (H5D_efl_writevv_ud_t *)_udata; /* User data for H5V_opvv() operator */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5D_efl_writevv_cb) - /* Update current sequence vectors */ - *dset_curr_seq = u; - *mem_curr_seq = v; + /* Write data */ + if(H5D_efl_write(udata->efl, dst_off, len, (udata->wbuf + src_off)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "EFL write failed") done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D_efl_readvv() */ +} /* end H5D_efl_writevv_cb() */ /*------------------------------------------------------------------------- @@ -492,62 +536,34 @@ done: */ static ssize_t H5D_efl_writevv(const H5D_io_info_t *io_info, - size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], - size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]) + size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_off_arr[], + size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_off_arr[]) { - const H5O_efl_t *efl = &(io_info->store->efl); /* Pointer to efl info */ - const unsigned char *buf; /* Pointer to buffer to write */ - haddr_t addr; /* Actual address to read */ - size_t size; /* Size of sequence in bytes */ - size_t u, v; /* Counting variables */ - ssize_t ret_value = 0; /* Return value (Total size of sequence in bytes) */ + H5D_efl_writevv_ud_t udata; /* User data for H5V_opvv() operator */ + ssize_t ret_value; /* Return value (Total size of sequence in bytes) */ FUNC_ENTER_NOAPI_NOINIT(H5D_efl_writevv) /* Check args */ - HDassert(efl && efl->nused > 0); + HDassert(io_info); + HDassert(io_info->store->efl.nused > 0); HDassert(io_info->u.wbuf); - - /* Work through all the sequences */ - for(u = *dset_curr_seq, v = *mem_curr_seq; u < dset_max_nseq && v < mem_max_nseq; ) { - /* Choose smallest buffer to write */ - if(mem_len_arr[v] < dset_len_arr[u]) - size = mem_len_arr[v]; - else - size = dset_len_arr[u]; - - /* Compute offset on disk */ - addr = dset_offset_arr[u]; - - /* Compute offset in memory */ - buf = (const unsigned char *)io_info->u.wbuf + mem_offset_arr[v]; - - /* Write data */ - if(H5D_efl_write(efl, addr, size, buf) < 0) - HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "block write failed") - - /* Update memory information */ - mem_len_arr[v] -= size; - if(mem_len_arr[v] == 0) - v++; - else - mem_offset_arr[v] += size; - - /* Update file information */ - dset_len_arr[u] -= size; - if(dset_len_arr[u] == 0) - u++; - else - dset_offset_arr[u] += size; - - /* Increment number of bytes copied */ - ret_value += (ssize_t)size; - } /* end for */ - - /* Update current sequence vectors */ - *dset_curr_seq = u; - *mem_curr_seq = v; - + HDassert(dset_curr_seq); + HDassert(dset_len_arr); + HDassert(dset_off_arr); + HDassert(mem_curr_seq); + HDassert(mem_len_arr); + HDassert(mem_off_arr); + + /* Set up user data for H5V_opvv() */ + udata.efl = &(io_info->store->efl); + udata.wbuf = (const unsigned char *)io_info->u.wbuf; + + /* Call generic sequence operation routine */ + if((ret_value = H5V_opvv(dset_max_nseq, dset_curr_seq, dset_len_arr, dset_off_arr, + mem_max_nseq, mem_curr_seq, mem_len_arr, mem_off_arr, + H5D_efl_writevv_cb, &udata)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTOPERATE, FAIL, "can't perform vectorized EFL write") done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5D_efl_writevv() */ diff --git a/src/H5Dpkg.h b/src/H5Dpkg.h index 34bf1da..96acc58 100644 --- a/src/H5Dpkg.h +++ b/src/H5Dpkg.h @@ -394,7 +394,7 @@ typedef struct H5D_rdcdc_t { haddr_t sieve_loc; /* File location (offset) of the data sieve buffer */ size_t sieve_size; /* Size of the data sieve buffer used (in bytes) */ size_t sieve_buf_size; /* Size of the data sieve buffer allocated (in bytes) */ - unsigned sieve_dirty; /* Flag to indicate that the data sieve buffer is dirty */ + hbool_t sieve_dirty; /* Flag to indicate that the data sieve buffer is dirty */ } H5D_rdcdc_t; /* @@ -583,12 +583,6 @@ H5_DLL herr_t H5D_contig_read(H5D_io_info_t *io_info, const H5D_type_info_t *typ H5_DLL herr_t H5D_contig_write(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space, H5D_chunk_map_t *fm); -H5_DLL ssize_t H5D_contig_readvv(const H5D_io_info_t *io_info, - size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], - size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]); -H5_DLL ssize_t H5D_contig_writevv(const H5D_io_info_t *io_info, - size_t dset_max_nseq, size_t *dset_curr_seq, size_t dset_len_arr[], hsize_t dset_offset_arr[], - size_t mem_max_nseq, size_t *mem_curr_seq, size_t mem_len_arr[], hsize_t mem_offset_arr[]); H5_DLL herr_t H5D_contig_copy(H5F_t *f_src, const H5O_storage_contig_t *storage_src, H5F_t *f_dst, H5O_storage_contig_t *storage_dst, H5T_t *src_dtype, H5O_copy_t *cpy_info, hid_t dxpl_id); diff --git a/src/H5Shyper.c b/src/H5Shyper.c index 45371dd..4aa887b 100644 --- a/src/H5Shyper.c +++ b/src/H5Shyper.c @@ -8652,6 +8652,10 @@ H5S_hyper_get_seq_list_single(const H5S_t *space, H5S_sel_iter_t *iter, *nelem += elmt_remainder; } /* end if */ + /* Sanity check */ + HDassert(*nseq > 0); + HDassert(*nelem > 0); + FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5S_hyper_get_seq_list_single() */ @@ -8699,6 +8703,7 @@ H5S_hyper_get_seq_list(const H5S_t *space, unsigned UNUSED flags, H5S_sel_iter_t /* Check args */ HDassert(space); HDassert(iter); + HDassert(iter->elmt_left > 0); HDassert(maxseq > 0); HDassert(maxelem > 0); HDassert(nseq); diff --git a/src/H5V.c b/src/H5V.c index 979b591..37d558f 100644 --- a/src/H5V.c +++ b/src/H5V.c @@ -24,6 +24,12 @@ #include "H5Oprivate.h" #include "H5Vprivate.h" +/* Local typedefs */ +typedef struct H5V_memcpy_ud_t { + unsigned char *dst; /* Pointer to destination buffer */ + const unsigned char *src; /* Pointer to source buffer */ +} H5V_memcpy_ud_t; + /* Local macros */ #define H5V_HYPER_NDIMS H5O_LAYOUT_NDIMS @@ -1149,9 +1155,9 @@ done: * *------------------------------------------------------------------------- */ -herr_t -H5V_array_calc_pre(hsize_t offset, unsigned n, const hsize_t *total_size, - const hsize_t *down, hsize_t *coords) +static herr_t +H5V_array_calc_pre(hsize_t offset, unsigned n, const hsize_t *down, + hsize_t *coords) { unsigned u; /* Local index variable */ @@ -1159,7 +1165,6 @@ H5V_array_calc_pre(hsize_t offset, unsigned n, const hsize_t *total_size, /* Sanity check */ HDassert(n <= H5V_HYPER_NDIMS); - HDassert(total_size); HDassert(coords); /* Compute the coordinates from the offset */ @@ -1210,7 +1215,7 @@ H5V_array_calc(hsize_t offset, unsigned n, const hsize_t *total_size, hsize_t *c HGOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, FAIL, "can't compute down sizes") /* Compute the coordinates from the offset */ - if(H5V_array_calc_pre(offset, n, total_size, idx, coords) < 0) + if(H5V_array_calc_pre(offset, n, idx, coords) < 0) HGOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, FAIL, "can't compute coordinates") done: @@ -1287,6 +1292,212 @@ H5V_chunk_index(unsigned ndims, const hsize_t *coord, const uint32_t *chunk, /*------------------------------------------------------------------------- + * Function: H5V_opvv + * + * Purpose: Perform an operation on a source & destination sequences + * of offset/length pairs. Each set of sequnces has an array + * of lengths, an array of offsets, the maximum number of + * sequences and the current sequence to start at in the sequence. + * + * There may be different numbers of bytes in the source and + * destination sequences, the operation stops when either the + * source or destination sequence runs out of information. + * + * Note: The algorithm in this routine is [basically] the same as for + * H5V_memcpyvv(). Changes should be made to both! + * + * Return: Non-negative # of bytes operated on, on success/Negative on failure + * + * Programmer: Quincey Koziol + * Thursday, September 30, 2010 + * + *------------------------------------------------------------------------- + */ +ssize_t +H5V_opvv(size_t dst_max_nseq, size_t *dst_curr_seq, size_t dst_len_arr[], + hsize_t dst_off_arr[], + size_t src_max_nseq, size_t *src_curr_seq, size_t src_len_arr[], + hsize_t src_off_arr[], + H5V_opvv_func_t op, void *op_data) +{ + hsize_t *max_dst_off_ptr, *max_src_off_ptr; /* Pointers to max. source and destination offset locations */ + hsize_t *dst_off_ptr, *src_off_ptr; /* Pointers to source and destination offset arrays */ + size_t *dst_len_ptr, *src_len_ptr; /* Pointers to source and destination length arrays */ + hsize_t tmp_dst_off, tmp_src_off; /* Temporary source and destination offset values */ + size_t tmp_dst_len, tmp_src_len; /* Temporary source and destination length values */ + size_t acc_len; /* Accumulated length of sequences */ + ssize_t ret_value = 0; /* Return value (Total size of sequence in bytes) */ + + FUNC_ENTER_NOAPI(H5V_opvv, FAIL) + + /* Sanity check */ + HDassert(dst_curr_seq); + HDassert(*dst_curr_seq < dst_max_nseq); + HDassert(dst_len_arr); + HDassert(dst_off_arr); + HDassert(src_curr_seq); + HDassert(*src_curr_seq < src_max_nseq); + HDassert(src_len_arr); + HDassert(src_off_arr); + HDassert(op); + + /* Set initial offset & length pointers */ + dst_len_ptr = dst_len_arr + *dst_curr_seq; + dst_off_ptr = dst_off_arr + *dst_curr_seq; + src_len_ptr = src_len_arr + *src_curr_seq; + src_off_ptr = src_off_arr + *src_curr_seq; + + /* Get temporary source & destination sequence offsets & lengths */ + tmp_dst_len = *dst_len_ptr; + tmp_dst_off = *dst_off_ptr; + tmp_src_len = *src_len_ptr; + tmp_src_off = *src_off_ptr; + + /* Compute maximum offset pointer values */ + max_dst_off_ptr = dst_off_arr + dst_max_nseq; + max_src_off_ptr = src_off_arr + src_max_nseq; + +/* Work through the sequences */ +/* (Choose smallest sequence available initially) */ + + /* Source sequence is less than destination sequence */ + if(tmp_src_len < tmp_dst_len) { +src_smaller: + acc_len = 0; + do { + /* Make operator callback */ + if((*op)(tmp_dst_off, tmp_src_off, tmp_src_len, op_data) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_CANTOPERATE, FAIL, "can't perform operation") + + /* Accumulate number of bytes copied */ + acc_len += tmp_src_len; + + /* Update destination length */ + tmp_dst_off += tmp_src_len; + tmp_dst_len -= tmp_src_len; + + /* Advance source offset & check for being finished */ + src_off_ptr++; + if(src_off_ptr >= max_src_off_ptr) { + /* Roll accumulated changes into appropriate counters */ + *dst_off_ptr = tmp_dst_off; + *dst_len_ptr = tmp_dst_len; + + /* Done with sequences */ + goto finished; + } /* end if */ + tmp_src_off = *src_off_ptr; + + /* Update source information */ + src_len_ptr++; + tmp_src_len = *src_len_ptr; + } while(tmp_src_len < tmp_dst_len); + + /* Roll accumulated sequence lengths into return value */ + ret_value += (ssize_t)acc_len; + + /* Transition to next state */ + if(tmp_dst_len < tmp_src_len) + goto dst_smaller; + else + goto equal; + } /* end if */ + /* Destination sequence is less than source sequence */ + else if(tmp_dst_len < tmp_src_len) { +dst_smaller: + acc_len = 0; + do { + /* Make operator callback */ + if((*op)(tmp_dst_off, tmp_src_off, tmp_dst_len, op_data) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_CANTOPERATE, FAIL, "can't perform operation") + + /* Accumulate number of bytes copied */ + acc_len += tmp_dst_len; + + /* Update source length */ + tmp_src_off += tmp_dst_len; + tmp_src_len -= tmp_dst_len; + + /* Advance destination offset & check for being finished */ + dst_off_ptr++; + if(dst_off_ptr >= max_dst_off_ptr) { + /* Roll accumulated changes into appropriate counters */ + *src_off_ptr = tmp_src_off; + *src_len_ptr = tmp_src_len; + + /* Done with sequences */ + goto finished; + } /* end if */ + tmp_dst_off = *dst_off_ptr; + + /* Update destination information */ + dst_len_ptr++; + tmp_dst_len = *dst_len_ptr; + } while(tmp_dst_len < tmp_src_len); + + /* Roll accumulated sequence lengths into return value */ + ret_value += (ssize_t)acc_len; + + /* Transition to next state */ + if(tmp_src_len < tmp_dst_len) + goto src_smaller; + else + goto equal; + } /* end else-if */ + /* Destination sequence and source sequence are same length */ + else { +equal: + acc_len = 0; + do { + /* Make operator callback */ + if((*op)(tmp_dst_off, tmp_src_off, tmp_dst_len, op_data) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_CANTOPERATE, FAIL, "can't perform operation") + + /* Accumulate number of bytes copied */ + acc_len += tmp_dst_len; + + /* Advance source & destination offset & check for being finished */ + src_off_ptr++; + dst_off_ptr++; + if(src_off_ptr >= max_src_off_ptr || dst_off_ptr >= max_dst_off_ptr) + /* Done with sequences */ + goto finished; + tmp_src_off = *src_off_ptr; + tmp_dst_off = *dst_off_ptr; + + /* Update source information */ + src_len_ptr++; + tmp_src_len = *src_len_ptr; + + /* Update destination information */ + dst_len_ptr++; + tmp_dst_len = *dst_len_ptr; + } while(tmp_dst_len == tmp_src_len); + + /* Roll accumulated sequence lengths into return value */ + ret_value += (ssize_t)acc_len; + + /* Transition to next state */ + if(tmp_dst_len < tmp_src_len) + goto dst_smaller; + else + goto src_smaller; + } /* end else */ + +finished: + /* Roll accumulated sequence lengths into return value */ + ret_value += (ssize_t)acc_len; + + /* Update current sequence vectors */ + *dst_curr_seq = (size_t)(dst_off_ptr - dst_off_arr); + *src_curr_seq = (size_t)(src_off_ptr - src_off_arr); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5V_opvv() */ + + +/*------------------------------------------------------------------------- * Function: H5V_memcpyvv * * Purpose: Given source and destination buffers in memory (SRC & DST) @@ -1299,6 +1510,9 @@ H5V_chunk_index(unsigned ndims, const hsize_t *coord, const uint32_t *chunk, * destination sequences, data copying stops when either the * source or destination buffer runs out of sequence information. * + * Note: The algorithm in this routine is [basically] the same as for + * H5V_opvv(). Changes should be made to both! + * * Return: Non-negative # of bytes copied on success/Negative on failure * * Programmer: Quincey Koziol @@ -1314,8 +1528,12 @@ H5V_memcpyvv(void *_dst, { unsigned char *dst; /* Destination buffer pointer */ const unsigned char *src; /* Source buffer pointer */ - size_t size; /* Size of sequence in bytes */ - size_t u,v; /* Local index variables */ + hsize_t *max_dst_off_ptr, *max_src_off_ptr; /* Pointers to max. source and destination offset locations */ + hsize_t *dst_off_ptr, *src_off_ptr; /* Pointers to source and destination offset arrays */ + size_t *dst_len_ptr, *src_len_ptr; /* Pointers to source and destination length arrays */ + size_t tmp_dst_len; /* Temporary dest. length value */ + size_t tmp_src_len; /* Temporary source length value */ + size_t acc_len; /* Accumulated length of sequences */ ssize_t ret_value = 0; /* Return value (Total size of sequence in bytes) */ FUNC_ENTER_NOAPI_NOFUNC(H5V_memcpyvv) @@ -1332,44 +1550,159 @@ H5V_memcpyvv(void *_dst, HDassert(src_len_arr); HDassert(src_off_arr); - /* Work through all the sequences */ - for(u = *dst_curr_seq, v = *src_curr_seq; u < dst_max_nseq && v < src_max_nseq; ) { - /* Choose smallest buffer to write */ - if(src_len_arr[v] < dst_len_arr[u]) - size = src_len_arr[v]; - else - size = dst_len_arr[u]; + /* Set initial offset & length pointers */ + dst_len_ptr = dst_len_arr + *dst_curr_seq; + dst_off_ptr = dst_off_arr + *dst_curr_seq; + src_len_ptr = src_len_arr + *src_curr_seq; + src_off_ptr = src_off_arr + *src_curr_seq; + + /* Get temporary source & destination sequence lengths */ + tmp_dst_len = *dst_len_ptr; + tmp_src_len = *src_len_ptr; + + /* Compute maximum offset pointer values */ + max_dst_off_ptr = dst_off_arr + dst_max_nseq; + max_src_off_ptr = src_off_arr + src_max_nseq; + + /* Compute buffer offsets */ + dst = (unsigned char *)_dst + *dst_off_ptr; + src = (const unsigned char *)_src + *src_off_ptr; + +/* Work through the sequences */ +/* (Choose smallest sequence available initially) */ + + /* Source sequence is less than destination sequence */ + if(tmp_src_len < tmp_dst_len) { +src_smaller: + acc_len = 0; + do { + /* Copy data */ + HDmemcpy(dst, src, tmp_src_len); + + /* Accumulate number of bytes copied */ + acc_len += tmp_src_len; + + /* Update destination length */ + tmp_dst_len -= tmp_src_len; + + /* Advance source offset & check for being finished */ + src_off_ptr++; + if(src_off_ptr >= max_src_off_ptr) { + /* Roll accumulated changes into appropriate counters */ + *dst_off_ptr += acc_len; + *dst_len_ptr = tmp_dst_len; + + /* Done with sequences */ + goto finished; + } /* end if */ - /* Compute offset on disk */ - dst = (unsigned char *)_dst + dst_off_arr[u]; + /* Update destination pointer */ + dst += tmp_src_len; - /* Compute offset in memory */ - src = (const unsigned char *)_src + src_off_arr[v]; + /* Update source information */ + src_len_ptr++; + tmp_src_len = *src_len_ptr; + src = (const unsigned char *)_src + *src_off_ptr; + } while(tmp_src_len < tmp_dst_len); - /* Copy data */ - HDmemcpy(dst, src, size); + /* Roll accumulated sequence lengths into return value */ + ret_value += (ssize_t)acc_len; - /* Update source information */ - src_len_arr[v] -= size; - if(0 == src_len_arr[v]) - v++; + /* Transition to next state */ + if(tmp_dst_len < tmp_src_len) + goto dst_smaller; else - src_off_arr[v] += size; + goto equal; + } /* end if */ + /* Destination sequence is less than source sequence */ + else if(tmp_dst_len < tmp_src_len) { +dst_smaller: + acc_len = 0; + do { + /* Copy data */ + HDmemcpy(dst, src, tmp_dst_len); + + /* Accumulate number of bytes copied */ + acc_len += tmp_dst_len; + + /* Update source length */ + tmp_src_len -= tmp_dst_len; + + /* Advance destination offset & check for being finished */ + dst_off_ptr++; + if(dst_off_ptr >= max_dst_off_ptr) { + /* Roll accumulated changes into appropriate counters */ + *src_off_ptr += acc_len; + *src_len_ptr = tmp_src_len; + + /* Done with sequences */ + goto finished; + } /* end if */ + + /* Update source pointer */ + src += tmp_dst_len; + + /* Update destination information */ + dst_len_ptr++; + tmp_dst_len = *dst_len_ptr; + dst = (unsigned char *)_dst + *dst_off_ptr; + } while(tmp_dst_len < tmp_src_len); - /* Update destination information */ - dst_len_arr[u] -= size; - if(0 == dst_len_arr[u]) - u++; + /* Roll accumulated sequence lengths into return value */ + ret_value += (ssize_t)acc_len; + + /* Transition to next state */ + if(tmp_src_len < tmp_dst_len) + goto src_smaller; + else + goto equal; + } /* end else-if */ + /* Destination sequence and source sequence are same length */ + else { +equal: + acc_len = 0; + do { + /* Copy data */ + HDmemcpy(dst, src, tmp_dst_len); + + /* Accumulate number of bytes copied */ + acc_len += tmp_dst_len; + + /* Advance source & destination offset & check for being finished */ + src_off_ptr++; + dst_off_ptr++; + if(src_off_ptr >= max_src_off_ptr || dst_off_ptr >= max_dst_off_ptr) + /* Done with sequences */ + goto finished; + + /* Update source information */ + src_len_ptr++; + tmp_src_len = *src_len_ptr; + src = (const unsigned char *)_src + *src_off_ptr; + + /* Update destination information */ + dst_len_ptr++; + tmp_dst_len = *dst_len_ptr; + dst = (unsigned char *)_dst + *dst_off_ptr; + } while(tmp_dst_len == tmp_src_len); + + /* Roll accumulated sequence lengths into return value */ + ret_value += (ssize_t)acc_len; + + /* Transition to next state */ + if(tmp_dst_len < tmp_src_len) + goto dst_smaller; else - dst_off_arr[u] += size; + goto src_smaller; + } /* end else */ - /* Increment number of bytes copied */ - ret_value += (ssize_t)size; - } /* end for */ +finished: + /* Roll accumulated sequence lengths into return value */ + ret_value += (ssize_t)acc_len; /* Update current sequence vectors */ - *dst_curr_seq = u; - *src_curr_seq = v; + *dst_curr_seq = (size_t)(dst_off_ptr - dst_off_arr); + *src_curr_seq = (size_t)(src_off_ptr - src_off_arr); FUNC_LEAVE_NOAPI(ret_value) } /* end H5V_memcpyvv() */ diff --git a/src/H5Vprivate.h b/src/H5Vprivate.h index e351f86..382263f 100644 --- a/src/H5Vprivate.h +++ b/src/H5Vprivate.h @@ -24,6 +24,10 @@ #include "H5private.h" /* Generic Functions */ #include "H5Eprivate.h" /* Error handling */ +/* Vector-Vector sequence operation callback */ +typedef herr_t (*H5V_opvv_func_t)(hsize_t dst_off, hsize_t src_off, + size_t len, void *udata); + /* Vector comparison functions like Fortran66 comparison operators */ #define H5V_vector_eq_s(N,V1,V2) (H5V_vector_cmp_s (N, V1, V2)==0) #define H5V_vector_lt_s(N,V1,V2) (H5V_vector_cmp_s (N, V1, V2)<0) @@ -83,12 +87,15 @@ H5_DLL hsize_t H5V_array_offset_pre(unsigned n, const hsize_t *acc, const hsize_t *offset); H5_DLL hsize_t H5V_array_offset(unsigned n, const hsize_t *total_size, const hsize_t *offset); -H5_DLL herr_t H5V_array_calc_pre(hsize_t offset, unsigned n, const hsize_t *total_size, - const hsize_t *down, hsize_t *coords); H5_DLL herr_t H5V_array_calc(hsize_t offset, unsigned n, const hsize_t *total_size, hsize_t *coords); H5_DLL herr_t H5V_chunk_index(unsigned ndims, const hsize_t *coord, const uint32_t *chunk, const hsize_t *down_nchunks, hsize_t *chunk_idx); +H5_DLL ssize_t H5V_opvv(size_t dst_max_nseq, size_t *dst_curr_seq, size_t dst_len_arr[], + hsize_t dst_off_arr[], + size_t src_max_nseq, size_t *src_curr_seq, size_t src_len_arr[], + hsize_t src_off_arr[], + H5V_opvv_func_t op, void *op_data); H5_DLL ssize_t H5V_memcpyvv(void *_dst, size_t dst_max_nseq, size_t *dst_curr_seq, size_t dst_len_arr[], hsize_t dst_off_arr[], const void *_src, -- cgit v0.12