diff options
author | Quincey Koziol <koziol@hdfgroup.org> | 2009-06-12 15:28:34 (GMT) |
---|---|---|
committer | Quincey Koziol <koziol@hdfgroup.org> | 2009-06-12 15:28:34 (GMT) |
commit | c9b6d5bf85c9db862bf5eb4a85d64e8b141fba08 (patch) | |
tree | c0229668f82b39fb109a45ab5173b2d8d1d42832 | |
parent | dc8650cfebf31643b45570b55e5cdfa7f60290a4 (diff) | |
download | hdf5-c9b6d5bf85c9db862bf5eb4a85d64e8b141fba08.zip hdf5-c9b6d5bf85c9db862bf5eb4a85d64e8b141fba08.tar.gz hdf5-c9b6d5bf85c9db862bf5eb4a85d64e8b141fba08.tar.bz2 |
[svn-r17045] Description:
Update the metadata accumulator code:
- Fix a bug where we were adding 2, instead of multiplying by 2 :-/
- Put an upper limit on the size of the metadata accumulator
- Allocate the accumulator in powers of 2, instead of random sizes
- Roll out the writes from the accumulator in a more I/O friendly way
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/C++ & FORTRAN, w/threadsafe,
in debug mode
Linux/64-amd64 2.6 (smirom) 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, in production mode
Linux/64-ia64 2.6 (cobalt) w/Intel compilers, w/C++ & FORTRAN,
in production mode
Linux/64-ia64 2.4 (tg-login3) w/parallel, w/FORTRAN, in debug mode
Linux/64-amd64 2.6 (abe) w/parallel, w/FORTRAN, in production mode
Mac OS X/32 10.5.7 (amazon) in debug mode
Mac OS X/32 10.5.7 (amazon) w/C++ & FORTRAN, w/threadsafe,
in production mode
-rw-r--r-- | src/H5Faccum.c | 206 |
1 files changed, 150 insertions, 56 deletions
diff --git a/src/H5Faccum.c b/src/H5Faccum.c index 05f6910..8e5ea4a 100644 --- a/src/H5Faccum.c +++ b/src/H5Faccum.c @@ -40,6 +40,7 @@ #include "H5Eprivate.h" /* Error handling */ #include "H5Fpkg.h" /* File access */ #include "H5FDprivate.h" /* File drivers */ +#include "H5Vprivate.h" /* Vectors and arrays */ /****************/ @@ -49,12 +50,19 @@ /* Metadata accumulator controls */ #define H5F_ACCUM_THROTTLE 8 #define H5F_ACCUM_THRESHOLD 2048 +#define H5F_ACCUM_MAX_SIZE (1024 *1024) /* Max. accum. buf size (max. I/Os will be 1/2 this size) */ /******************/ /* Local Typedefs */ /******************/ +/* Enumerated type to indicate how data will be added to accumulator */ +typedef enum { + H5F_ACCUM_PREPEND, /* Data will be prepended to accumulator */ + H5F_ACCUM_APPEND /* Data will be appended to accumulator */ +} H5F_accum_adjust_t; + /********************/ /* Package Typedefs */ @@ -112,7 +120,8 @@ H5F_accum_read(const H5F_t *f, hid_t dxpl_id, H5FD_mem_t type, haddr_t addr, HDassert(buf); /* Check if this information is in the metadata accumulator */ - if((f->shared->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) && type != H5FD_MEM_DRAW) { + if((f->shared->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) && type != H5FD_MEM_DRAW + && size < H5F_ACCUM_MAX_SIZE) { /* Current read overlaps with metadata accumulator */ if(H5F_addr_overlap(addr, size, f->shared->accum.loc, f->shared->accum.size)) { unsigned char *read_buf = (unsigned char *)buf; /* Pointer to the buffer being read in */ @@ -195,12 +204,17 @@ H5F_accum_read(const H5F_t *f, hid_t dxpl_id, H5FD_mem_t type, haddr_t addr, /* Cache the new piece of metadata */ /* Check if we need to resize the buffer */ if(size > f->shared->accum.alloc_size) { + size_t new_size; /* New size of accumulator */ + + /* Adjust the buffer size to be a power of 2 that is large enough to hold data */ + new_size = (size_t)1 << (1 + H5V_log2_gen(size - 1)); + /* Grow the metadata accumulator buffer */ - if(NULL == (f->shared->accum.buf = H5FL_BLK_REALLOC(meta_accum, f->shared->accum.buf, size))) + if(NULL == (f->shared->accum.buf = H5FL_BLK_REALLOC(meta_accum, f->shared->accum.buf, new_size))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer") /* Note the new buffer size */ - f->shared->accum.alloc_size = size; + f->shared->accum.alloc_size = new_size; } /* end if */ else { /* Check if we should shrink the accumulator buffer */ @@ -246,6 +260,111 @@ done: /*------------------------------------------------------------------------- + * Function: H5F_accum_adjust + * + * Purpose: Adjust accumulator size, if necessary + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * koziol@hdfgroup.org + * Jun 11 2009 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5F_accum_adjust(H5F_meta_accum_t *accum, H5FD_t *lf, hid_t dxpl_id, + H5F_accum_adjust_t adjust, size_t size) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT(H5F_accum_adjust) + + HDassert(accum); + HDassert(lf); + HDassert(size > 0); + HDassert(size <= H5F_ACCUM_MAX_SIZE); + + /* Check if we need more buffer space */ + if((size + accum->size) > accum->alloc_size) { + size_t new_size; /* New size of accumulator */ + + /* Adjust the buffer size to be a power of 2 that is large enough to hold data */ + new_size = (size_t)1 << (1 + H5V_log2_gen((size + accum->size) - 1)); + + /* Check for accumulator getting too big */ + if(new_size > H5F_ACCUM_MAX_SIZE) { + size_t shrink_size; /* Amount to shrink accumulator by */ + size_t remnant_size; /* Amount left in accumulator */ + + /* Cap the accumulator's growth, leaving some room */ + + /* Determine the amounts to work with */ + if(size > (H5F_ACCUM_MAX_SIZE / 2)) { + new_size = H5F_ACCUM_MAX_SIZE; + shrink_size = accum->size; + remnant_size = 0; + } /* end if */ + else { + new_size = (H5F_ACCUM_MAX_SIZE / 2); + shrink_size = (H5F_ACCUM_MAX_SIZE / 2); + remnant_size = accum->size - shrink_size; + } /* end else */ + + /* Check if we need to flush accumulator data to file */ + if(accum->dirty) { + /* Check whether to accumulator will be prepended or appended */ + if(H5F_ACCUM_PREPEND == adjust) { + /* Write out upper part of the existing metadata accumulator, with dispatch to driver */ + if(H5FD_write(lf, dxpl_id, H5FD_MEM_DEFAULT, (accum->loc + remnant_size), shrink_size, (accum->buf + remnant_size)) < 0) + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed") + } /* end if */ + else { + /* Sanity check */ + HDassert(H5F_ACCUM_APPEND == adjust); + + /* Write out lower part of the existing metadata accumulator, with dispatch to driver */ + if(H5FD_write(lf, dxpl_id, H5FD_MEM_DEFAULT, accum->loc, shrink_size, accum->buf) < 0) + HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file write failed") + + /* Move remnant of accumulator down */ + HDmemmove(accum->buf, (accum->buf + shrink_size), remnant_size); + + /* Adjust accumulator's location */ + accum->loc += shrink_size; + } /* end else */ + + /* Reset accumulator dirty flag (in case of error) */ + accum->dirty = FALSE; + } /* end if */ + + /* Trim the accumulator's use of its buffer */ + accum->size = remnant_size; + } /* end if */ + + /* Check for accumulator needing to be reallocated */ + if(new_size > accum->alloc_size) { + unsigned char *new_buf; /* New buffer to hold the accumulated metadata */ + + /* Reallocate the metadata accumulator buffer */ + if(NULL == (new_buf = H5FL_BLK_REALLOC(meta_accum, accum->buf, new_size))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer") + + /* Update accumulator info */ + accum->buf = new_buf; + accum->alloc_size = new_size; +#ifdef H5_CLEAR_MEMORY +HDmemset(accum->buf + accum->size, 0, (accum->alloc_size - (accum->size + size))); +#endif /* H5_CLEAR_MEMORY */ + } /* end if */ + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5F_accum_adjust() */ + + +/*------------------------------------------------------------------------- * Function: H5F_accum_write * * Purpose: Attempts to read some data from the metadata accumulator for @@ -273,23 +392,15 @@ H5F_accum_write(const H5F_t *f, hid_t dxpl_id, H5FD_mem_t type, haddr_t addr, HDassert(buf); /* Check for accumulating metadata */ - if((f->shared->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) && type != H5FD_MEM_DRAW) { + if((f->shared->feature_flags & H5FD_FEAT_ACCUMULATE_METADATA) && type != H5FD_MEM_DRAW + && size < H5F_ACCUM_MAX_SIZE) { /* Check if there is already metadata in the accumulator */ if(f->shared->accum.size > 0) { /* Check if the new metadata adjoins the beginning of the current accumulator */ if((addr + size) == f->shared->accum.loc) { - /* Check if we need more buffer space */ - if((size + f->shared->accum.size) > f->shared->accum.alloc_size) { - /* Adjust the buffer size, by doubling it */ - f->shared->accum.alloc_size = MAX(f->shared->accum.alloc_size * 2, size + f->shared->accum.size); - - /* Reallocate the metadata accumulator buffer */ - if(NULL == (f->shared->accum.buf = H5FL_BLK_REALLOC(meta_accum, f->shared->accum.buf, f->shared->accum.alloc_size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer") -#ifdef H5_CLEAR_MEMORY -HDmemset(f->shared->accum.buf + f->shared->accum.size, 0, (f->shared->accum.alloc_size - (f->shared->accum.size + size))); -#endif /* H5_CLEAR_MEMORY */ - } /* end if */ + /* Check if we need to adjust accumulator size */ + if(H5F_accum_adjust(&f->shared->accum, f->shared->lf, dxpl_id, H5F_ACCUM_PREPEND, size) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTRESIZE, FAIL, "can't adjust metadata accumulator") /* Move the existing metadata to the proper location */ HDmemmove(f->shared->accum.buf + size, f->shared->accum.buf, f->shared->accum.size); @@ -306,18 +417,9 @@ HDmemset(f->shared->accum.buf + f->shared->accum.size, 0, (f->shared->accum.allo } /* end if */ /* Check if the new metadata adjoins the end of the current accumulator */ else if(addr == (f->shared->accum.loc + f->shared->accum.size)) { - /* Check if we need more buffer space */ - if((size + f->shared->accum.size) > f->shared->accum.alloc_size) { - /* Adjust the buffer size, by doubling it */ - f->shared->accum.alloc_size = MAX(f->shared->accum.alloc_size * 2, size + f->shared->accum.size); - - /* Reallocate the metadata accumulator buffer */ - if(NULL == (f->shared->accum.buf = H5FL_BLK_REALLOC(meta_accum, f->shared->accum.buf, f->shared->accum.alloc_size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer") -#ifdef H5_CLEAR_MEMORY -HDmemset(f->shared->accum.buf + f->shared->accum.size + size, 0, (f->shared->accum.alloc_size - (f->shared->accum.size + size))); -#endif /* H5_CLEAR_MEMORY */ - } /* end if */ + /* Check if we need to adjust accumulator size */ + if(H5F_accum_adjust(&f->shared->accum, f->shared->lf, dxpl_id, H5F_ACCUM_APPEND, size) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTRESIZE, FAIL, "can't adjust metadata accumulator") /* Copy the new metadata to the end */ HDmemcpy(f->shared->accum.buf + f->shared->accum.size, buf, size); @@ -347,18 +449,9 @@ HDmemset(f->shared->accum.buf + f->shared->accum.size + size, 0, (f->shared->acc /* Calculate the new accumulator size, based on the amount of overlap */ H5_ASSIGN_OVERFLOW(new_size, (f->shared->accum.loc - addr) + f->shared->accum.size, hsize_t, size_t); - /* Check if we need more buffer space */ - if(new_size > f->shared->accum.alloc_size) { - /* Adjust the buffer size, by doubling it */ - f->shared->accum.alloc_size = MAX(f->shared->accum.alloc_size + 2, new_size); - - /* Reallocate the metadata accumulator buffer */ - if(NULL == (f->shared->accum.buf = H5FL_BLK_REALLOC(meta_accum, f->shared->accum.buf, f->shared->accum.alloc_size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer") -#ifdef H5_CLEAR_MEMORY -HDmemset(f->shared->accum.buf + f->shared->accum.size, 0, (f->shared->accum.alloc_size - f->shared->accum.size)); -#endif /* H5_CLEAR_MEMORY */ - } /* end if */ + /* Check if we need to adjust accumulator size */ + if(H5F_accum_adjust(&f->shared->accum, f->shared->lf, dxpl_id, H5F_ACCUM_PREPEND, (new_size - f->shared->accum.size)) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTRESIZE, FAIL, "can't adjust metadata accumulator") /* Calculate the proper offset of the existing metadata */ H5_ASSIGN_OVERFLOW(old_offset, (addr + size) - f->shared->accum.loc, hsize_t, size_t); @@ -381,18 +474,9 @@ HDmemset(f->shared->accum.buf + f->shared->accum.size, 0, (f->shared->accum.allo /* Calculate the new accumulator size, based on the amount of overlap */ H5_ASSIGN_OVERFLOW(new_size, (addr - f->shared->accum.loc) + size, hsize_t, size_t); - /* Check if we need more buffer space */ - if(new_size > f->shared->accum.alloc_size) { - /* Adjust the buffer size, by doubling it */ - f->shared->accum.alloc_size = MAX(f->shared->accum.alloc_size * 2, new_size); - - /* Reallocate the metadata accumulator buffer */ - if(NULL == (f->shared->accum.buf = H5FL_BLK_REALLOC(meta_accum, f->shared->accum.buf, f->shared->accum.alloc_size))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer") -#ifdef H5_CLEAR_MEMORY -HDmemset(f->shared->accum.buf + f->shared->accum.size, 0, (f->shared->accum.alloc_size - f->shared->accum.size)); -#endif /* H5_CLEAR_MEMORY */ - } /* end if */ + /* Check if we need to adjust accumulator size */ + if(H5F_accum_adjust(&f->shared->accum, f->shared->lf, dxpl_id, H5F_ACCUM_APPEND, (new_size - f->shared->accum.size)) < 0) + HGOTO_ERROR(H5E_IO, H5E_CANTRESIZE, FAIL, "can't adjust metadata accumulator") /* Copy the new metadata to the end */ HDmemcpy(f->shared->accum.buf + (addr - f->shared->accum.loc), buf, size); @@ -421,12 +505,17 @@ HDmemset(f->shared->accum.buf + f->shared->accum.size, 0, (f->shared->accum.allo /* Cache the new piece of metadata */ /* Check if we need to resize the buffer */ if(size > f->shared->accum.alloc_size) { + size_t new_size; /* New size of accumulator */ + + /* Adjust the buffer size to be a power of 2 that is large enough to hold data */ + new_size = (size_t)1 << (1 + H5V_log2_gen(size - 1)); + /* Grow the metadata accumulator buffer */ - if(NULL == (f->shared->accum.buf = H5FL_BLK_REALLOC(meta_accum, f->shared->accum.buf, size))) + if(NULL == (f->shared->accum.buf = H5FL_BLK_REALLOC(meta_accum, f->shared->accum.buf, new_size))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer") /* Note the new buffer size */ - f->shared->accum.alloc_size = size; + f->shared->accum.alloc_size = new_size; #ifdef H5_CLEAR_MEMORY { size_t clear_size = MAX(f->shared->accum.size, size); @@ -462,12 +551,17 @@ HDmemset(f->shared->accum.buf + clear_size, 0, (f->shared->accum.alloc_size - cl else { /* Check if we need to reallocate the buffer */ if(size > f->shared->accum.alloc_size) { + size_t new_size; /* New size of accumulator */ + + /* Adjust the buffer size to be a power of 2 that is large enough to hold data */ + new_size = (size_t)1 << (1 + H5V_log2_gen(size - 1)); + /* Reallocate the metadata accumulator buffer */ - if(NULL == (f->shared->accum.buf = H5FL_BLK_REALLOC(meta_accum, f->shared->accum.buf, size))) + if(NULL == (f->shared->accum.buf = H5FL_BLK_REALLOC(meta_accum, f->shared->accum.buf, new_size))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate metadata accumulator buffer") /* Note the new buffer size */ - f->shared->accum.alloc_size = size; + f->shared->accum.alloc_size = new_size; } /* end if */ /* Update the metadata accumulator information */ |