summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRaymond Lu <songyulu@hdfgroup.org>2007-06-19 20:05:24 (GMT)
committerRaymond Lu <songyulu@hdfgroup.org>2007-06-19 20:05:24 (GMT)
commit6017d0c70fda2a36cf963193e979f0548cb0c954 (patch)
treebc54a1f86fb94fe5dcecd2ba8b2b2623c5c38a77 /src
parent32d09759bdf082d1a5d87903a58b0ed6c03dbe8c (diff)
downloadhdf5-6017d0c70fda2a36cf963193e979f0548cb0c954.zip
hdf5-6017d0c70fda2a36cf963193e979f0548cb0c954.tar.gz
hdf5-6017d0c70fda2a36cf963193e979f0548cb0c954.tar.bz2
[svn-r13884] The second step of optimization for compound data for the Chicago
company. The I/O is optimized when the source and destination members are a subset of each other one way or another, and the order is the same, and no conversion is needed. For example: struct source { struct destination { TYPE1 A; --> TYPE1 A; TYPE2 B; --> TYPE2 B; TYPE3 C; --> TYPE3 C; }; TYPE4 D; TYPE5 E; }; or struct destination { struct source { TYPE1 A; --> TYPE1 A; TYPE2 B; --> TYPE2 B; TYPE3 C; --> TYPE3 C; }; TYPE4 D; TYPE5 E; }; The optimization is simply moving data from the source to the appropriate places in the buffer and bypass the reading of the background data and data conversion. Tested on smirom, liberty, sol, and copper.
Diffstat (limited to 'src')
-rw-r--r--src/H5Dio.c363
-rw-r--r--src/H5T.c45
-rw-r--r--src/H5Tconv.c158
-rw-r--r--src/H5Tpkg.h3
-rw-r--r--src/H5Tprivate.h12
5 files changed, 508 insertions, 73 deletions
diff --git a/src/H5Dio.c b/src/H5Dio.c
index b494596..9b0102f 100644
--- a/src/H5Dio.c
+++ b/src/H5Dio.c
@@ -77,6 +77,12 @@ static herr_t H5D_chunk_write(H5D_io_info_t *io_info, hsize_t nelmts,
const H5T_t *mem_type, const H5S_t *mem_space,
const H5S_t *file_space, H5T_path_t *tpath,
hid_t src_id, hid_t dst_id, const void *buf);
+static herr_t H5D_compound_opt_read(hsize_t nelmts, const H5S_t *mem_space,
+ H5S_sel_iter_t *iter, const H5D_dxpl_cache_t *dxpl_cache,
+ hid_t src_id, hid_t dst_id, H5T_subset_t subset, void *data_buf,
+ void *user_buf/*out*/);
+static herr_t H5D_compound_opt_write(hsize_t nelmts, hid_t src_id, hid_t dst_id,
+ void *data_buf);
#ifdef H5_HAVE_PARALLEL
static herr_t H5D_ioinfo_term(H5D_io_info_t *io_info);
@@ -116,6 +122,13 @@ H5FL_BLK_DEFINE(type_conv);
/* Declare a free list to manage the H5D_chunk_info_t struct */
H5FL_DEFINE_STATIC(H5D_chunk_info_t);
+/* Declare a free list to manage sequences of size_t */
+H5FL_SEQ_DEFINE_STATIC(size_t);
+
+/* Declare a free list to manage sequences of hsize_t */
+H5FL_SEQ_DEFINE_STATIC(hsize_t);
+
+
/*--------------------------------------------------------------------------
NAME
@@ -1167,6 +1180,23 @@ H5D_contig_read(H5D_io_info_t *io_info, hsize_t nelmts,
if (n!=smine_nelmts)
HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file gather failed")
+ /* If the source and destination are compound types and subset of each other
+ * and no conversion is needed, copy the data directly into user's buffer and
+ * bypass the rest of steps. This optimization is for Chicago company */
+ if(H5T_SUBSET_SRC==H5T_path_compound_subset(tpath)) {
+ if(H5D_compound_opt_read(smine_nelmts, mem_space, &mem_iter, dxpl_cache,
+ src_id, dst_id, H5T_SUBSET_SRC, tconv_buf, buf /*out*/)<0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed")
+
+ continue;
+ } else if(H5T_SUBSET_DST==H5T_path_compound_subset(tpath)) {
+ if(H5D_compound_opt_read(smine_nelmts, mem_space, &mem_iter, dxpl_cache,
+ src_id, dst_id, H5T_SUBSET_DST, tconv_buf, buf /*out*/)<0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed")
+
+ continue;
+ }
+
if (H5T_BKG_YES==need_bkg) {
#ifdef H5S_DEBUG
H5_timer_begin(&timer);
@@ -1421,33 +1451,44 @@ H5D_contig_write(H5D_io_info_t *io_info, hsize_t nelmts,
if (n!=smine_nelmts)
HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "mem gather failed")
- if (H5T_BKG_YES==need_bkg) {
+ /* If the source and destination are compound types and the destination is
+ * is a subset of the source and no conversion is needed, copy the data
+ * directly into user's buffer and bypass the rest of steps. If the source
+ * is a subset of the destination, the optimization is done in conversion
+ * function H5T_conv_struct_opt to protect the background data. This
+ * optimization is for Chicago company */
+ if(H5T_SUBSET_DST==H5T_path_compound_subset(tpath)) {
+ if(H5D_compound_opt_write(smine_nelmts, src_id, dst_id, tconv_buf)<0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed")
+ } else {
+ if (H5T_BKG_YES==need_bkg) {
#ifdef H5S_DEBUG
- H5_timer_begin(&timer);
+ H5_timer_begin(&timer);
#endif
- n = H5D_select_fgath(io_info,
- file_space, &bkg_iter, smine_nelmts,
- bkg_buf/*out*/);
+ n = H5D_select_fgath(io_info,
+ file_space, &bkg_iter, smine_nelmts,
+ bkg_buf/*out*/);
#ifdef H5S_DEBUG
- H5_timer_end(&(io_info->stats->stats[0].bkg_timer), &timer);
- io_info->stats->stats[0].bkg_nbytes += n * dst_type_size;
- io_info->stats->stats[0].bkg_ncalls++;
+ H5_timer_end(&(io_info->stats->stats[0].bkg_timer), &timer);
+ io_info->stats->stats[0].bkg_nbytes += n * dst_type_size;
+ io_info->stats->stats[0].bkg_ncalls++;
#endif
- if (n!=smine_nelmts)
- HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file gather failed")
- } /* end if */
+ if (n!=smine_nelmts)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file gather failed")
+ } /* end if */
- /*
- * Perform datatype conversion.
- */
- if(H5T_convert(tpath, src_id, dst_id, smine_nelmts, (size_t)0, (size_t)0, tconv_buf, bkg_buf, io_info->dxpl_id) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed")
+ /*
+ * Perform datatype conversion.
+ */
+ if(H5T_convert(tpath, src_id, dst_id, smine_nelmts, (size_t)0, (size_t)0, tconv_buf, bkg_buf, io_info->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed")
- /* Do the data transform after the type conversion (since we're using dataset->shared->type). */
- if(!H5Z_xform_noop(dxpl_cache->data_xform_prop))
- if( H5Z_xform_eval(dxpl_cache->data_xform_prop, tconv_buf, smine_nelmts, dataset->shared->type) < 0)
+ /* Do the data transform after the type conversion (since we're using dataset->shared->type). */
+ if(!H5Z_xform_noop(dxpl_cache->data_xform_prop))
+ if( H5Z_xform_eval(dxpl_cache->data_xform_prop, tconv_buf, smine_nelmts, dataset->shared->type) < 0)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Error performing data transform")
+ }
/*
* Scatter the data out to the file.
@@ -1455,9 +1496,8 @@ H5D_contig_write(H5D_io_info_t *io_info, hsize_t nelmts,
#ifdef H5S_DEBUG
H5_timer_begin(&timer);
#endif
- status = H5D_select_fscat(io_info,
- file_space, &file_iter, smine_nelmts,
- tconv_buf);
+ status = H5D_select_fscat(io_info, file_space, &file_iter, smine_nelmts,
+ tconv_buf);
#ifdef H5S_DEBUG
H5_timer_end(&(io_info->stats->stats[0].scat_timer), &timer);
io_info->stats->stats[0].scat_nbytes += smine_nelmts * dst_type_size;
@@ -1723,6 +1763,23 @@ H5D_chunk_read(H5D_io_info_t *io_info, hsize_t nelmts,
if(n != smine_nelmts)
HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file gather failed")
+ /* If the source and destination are compound types and subset of each other
+ * and no conversion is needed, copy the data directly into user's buffer and
+ * bypass the rest of steps. This optimization is for Chicago company */
+ if(H5T_SUBSET_SRC==H5T_path_compound_subset(tpath)) {
+ if(H5D_compound_opt_read(smine_nelmts, chunk_info->mspace, &mem_iter, dxpl_cache,
+ src_id, dst_id, H5T_SUBSET_SRC, tconv_buf, buf /*out*/)<0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed")
+
+ continue;
+ } else if(H5T_SUBSET_DST==H5T_path_compound_subset(tpath)) {
+ if(H5D_compound_opt_read(smine_nelmts, chunk_info->mspace, &mem_iter, dxpl_cache,
+ src_id, dst_id, H5T_SUBSET_DST, tconv_buf, buf /*out*/)<0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed")
+
+ continue;
+ }
+
if(H5T_BKG_YES == need_bkg) {
#ifdef H5S_DEBUG
H5_timer_begin(&timer);
@@ -2041,33 +2098,43 @@ H5D_chunk_write(H5D_io_info_t *io_info, hsize_t nelmts,
if (n!=smine_nelmts)
HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file gather failed")
- if (H5T_BKG_YES==need_bkg) {
+ /* If the source and destination are compound types and the destination is
+ * is a subset of the source and no conversion is needed, copy the data
+ * directly into user's buffer and bypass the rest of steps. If the source
+ * is a subset of the destination, the optimization is done in conversion
+ * function H5T_conv_struct_opt to protect the background data. This
+ * optimization is for Chicago company */
+ if(H5T_SUBSET_DST==H5T_path_compound_subset(tpath)) {
+ if(H5D_compound_opt_write(smine_nelmts, src_id, dst_id, tconv_buf)<0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed")
+ } else {
+ if (H5T_BKG_YES==need_bkg) {
#ifdef H5S_DEBUG
- H5_timer_begin(&timer);
+ H5_timer_begin(&timer);
#endif
- n = H5D_select_fgath(io_info,
- chunk_info->fspace, &bkg_iter, smine_nelmts,
- bkg_buf/*out*/);
+ n = H5D_select_fgath(io_info, chunk_info->fspace, &bkg_iter, smine_nelmts,
+ bkg_buf/*out*/);
#ifdef H5S_DEBUG
- H5_timer_end(&(io_info->stats->stats[0].bkg_timer), &timer);
- io_info->stats->stats[0].bkg_nbytes += n * dst_type_size;
- io_info->stats->stats[0].bkg_ncalls++;
+ H5_timer_end(&(io_info->stats->stats[0].bkg_timer), &timer);
+ io_info->stats->stats[0].bkg_nbytes += n * dst_type_size;
+ io_info->stats->stats[0].bkg_ncalls++;
#endif
- if (n!=smine_nelmts)
- HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file gather failed")
- } /* end if */
+ if (n!=smine_nelmts)
+ HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "file gather failed")
+ } /* end if */
- /*
- * Perform datatype conversion.
- */
- if(H5T_convert(tpath, src_id, dst_id, smine_nelmts, (size_t)0, (size_t)0, tconv_buf, bkg_buf, io_info->dxpl_id) < 0)
- HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed")
+ /*
+ * Perform datatype conversion.
+ */
+ if(H5T_convert(tpath, src_id, dst_id, smine_nelmts, (size_t)0, (size_t)0, tconv_buf, bkg_buf, io_info->dxpl_id) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed")
- /* Do the data transform after the type conversion (since we're using dataset->shared->type) */
- if(!H5Z_xform_noop(dxpl_cache->data_xform_prop))
- if( H5Z_xform_eval(dxpl_cache->data_xform_prop, tconv_buf, smine_nelmts, dataset->shared->type) < 0)
- HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Error performing data transform")
+ /* Do the data transform after the type conversion (since we're using dataset->shared->type) */
+ if(!H5Z_xform_noop(dxpl_cache->data_xform_prop))
+ if( H5Z_xform_eval(dxpl_cache->data_xform_prop, tconv_buf, smine_nelmts, dataset->shared->type) < 0)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Error performing data transform")
+ }
/*
* Scatter the data out to the file.
@@ -2138,6 +2205,218 @@ done:
/*-------------------------------------------------------------------------
+ * Function: H5D_compound_opt_read
+ *
+ * Purpose: A shortcut optimization for the Chicago company for
+ * a special optimization case when the source and
+ * destination members are a subset of each other, and
+ * the order is the same, and no conversion is needed.
+ * For example:
+ * struct source { struct destination {
+ * TYPE1 A; --> TYPE1 A;
+ * TYPE2 B; --> TYPE2 B;
+ * TYPE3 C; --> TYPE3 C;
+ * }; TYPE4 D;
+ * TYPE5 E;
+ * };
+ * or
+ * struct destination { struct source {
+ * TYPE1 A; --> TYPE1 A;
+ * TYPE2 B; --> TYPE2 B;
+ * TYPE3 C; --> TYPE3 C;
+ * }; TYPE4 D;
+ * TYPE5 E;
+ * };
+ * The optimization is simply moving data to the appropriate
+ * places in the buffer.
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * 11 June 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D_compound_opt_read(hsize_t nelmts, const H5S_t *space,
+ H5S_sel_iter_t *iter, const H5D_dxpl_cache_t *dxpl_cache,
+ hid_t src_id, hid_t dst_id, H5T_subset_t subset,
+ void *data_buf, void *user_buf/*out*/)
+{
+ uint8_t *dbuf = (uint8_t *)data_buf; /*cast for pointer arithmetic */
+ uint8_t *ubuf = (uint8_t *)user_buf; /*cast for pointer arithmetic */
+ uint8_t *xdbuf;
+ uint8_t *xubuf;
+
+ hsize_t _off[H5D_IO_VECTOR_SIZE]; /* Array to store sequence offsets */
+ hsize_t *off=NULL; /* Pointer to sequence offsets */
+ size_t _len[H5D_IO_VECTOR_SIZE]; /* Array to store sequence lengths */
+ size_t *len=NULL; /* Pointer to sequence lengths */
+ size_t nseq; /* Number of sequences generated */
+ size_t curr_off; /* offset of bytes left to process in sequence */
+ size_t curr_seq; /* Current sequence being processed */
+ size_t curr_len; /* Length of bytes left to process in sequence */
+ size_t curr_nelmts; /* number of elements to process in sequence */
+ size_t i;
+
+ H5T_t *src, *dst;
+ size_t src_stride, dst_stride, type_size;
+ size_t elmtno; /*element counter */
+
+ herr_t ret_value = SUCCEED; /*return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5D_compound_opt_read)
+
+ /* Check args */
+ assert (data_buf);
+ assert (user_buf);
+ assert (space);
+ assert (iter);
+ assert (nelmts>0);
+
+ /* Allocate the vector I/O arrays */
+ if(dxpl_cache->vec_size != H5D_IO_VECTOR_SIZE) {
+ if((len = H5FL_SEQ_MALLOC(size_t,dxpl_cache->vec_size))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O length vector array");
+ if((off = H5FL_SEQ_MALLOC(hsize_t,dxpl_cache->vec_size))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate I/O offset vector array");
+ } /* end if */
+ else {
+ len=_len;
+ off=_off;
+ } /* end else */
+
+ if (NULL == (src = H5I_object(src_id)) || NULL == (dst = H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type");
+
+ src_stride = H5T_get_size(src);
+ dst_stride = H5T_get_size(dst);
+
+ if(H5T_SUBSET_SRC == subset)
+ type_size = src_stride;
+ else if(H5T_SUBSET_DST == subset)
+ type_size = dst_stride;
+
+ xdbuf = dbuf;
+
+ /* Loop until all elements are written */
+ while(nelmts>0) {
+ /* Get list of sequences for selection to write */
+ if(H5S_SELECT_GET_SEQ_LIST(space,0,iter,dxpl_cache->vec_size,nelmts,&nseq,&elmtno,off,len)<0)
+ HGOTO_ERROR (H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed");
+
+ /* Loop, while sequences left to process */
+ for(curr_seq=0; curr_seq<nseq; curr_seq++) {
+ /* Get the number of bytes and offset in sequence */
+ curr_len=len[curr_seq];
+ curr_off=off[curr_seq];
+
+ /* Decide the number of elements and position in the buffer. */
+ curr_nelmts = curr_len/dst_stride;
+ xubuf = ubuf + curr_off;
+
+ /* Copy the data into the right place. */
+ for(i=0; i<curr_nelmts; i++) {
+ HDmemmove(xubuf, xdbuf, type_size);
+
+ /* Update pointers */
+ xdbuf += src_stride;
+ xubuf += dst_stride;
+ }
+
+ } /* end for */
+
+ /* Decrement number of elements left to process */
+ nelmts -= elmtno;
+ } /* end while */
+
+done:
+ if(dxpl_cache->vec_size != H5D_IO_VECTOR_SIZE) {
+ if(len!=NULL)
+ H5FL_SEQ_FREE(size_t,len);
+ if(off!=NULL)
+ H5FL_SEQ_FREE(hsize_t,off);
+ } /* end if */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_compound_opt_read() */
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5D_compound_opt_write
+ *
+ * Purpose: A shortcut optimization for the Chicago company for
+ * a special optimization case when the source and
+ * destination members are a subset of each other, and
+ * the order is the same, and no conversion is needed.
+ * For example:
+ * struct source { struct destination {
+ * TYPE1 A; --> TYPE1 A;
+ * TYPE2 B; --> TYPE2 B;
+ * TYPE3 C; --> TYPE3 C;
+ * }; TYPE4 D;
+ * TYPE5 E;
+ * };
+ * or
+ * struct destination { struct source {
+ * TYPE1 A; --> TYPE1 A;
+ * TYPE2 B; --> TYPE2 B;
+ * TYPE3 C; --> TYPE3 C;
+ * }; TYPE4 D;
+ * TYPE5 E;
+ * };
+ * The optimization is simply moving data to the appropriate
+ * places in the buffer.
+ *
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Raymond Lu
+ * 11 June 2007
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5D_compound_opt_write(hsize_t nelmts, hid_t src_id, hid_t dst_id, void *data_buf)
+{
+ uint8_t *dbuf = (uint8_t *)data_buf; /*cast for pointer arithmetic */
+ uint8_t *xsbuf, *xdbuf;
+ size_t i;
+ H5T_t *src, *dst;
+ size_t src_stride, dst_stride;
+ herr_t ret_value = SUCCEED; /*return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5D_compound_opt_write)
+
+ /* Check args */
+ assert (data_buf);
+ assert (nelmts>0);
+
+ if (NULL == (src = H5I_object(src_id)) || NULL == (dst = H5I_object(dst_id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data type");
+
+ src_stride = H5T_get_size(src);
+ dst_stride = H5T_get_size(dst);
+
+ xsbuf = dbuf;
+ xdbuf = dbuf;
+
+ /* Loop until all elements are written */
+ for(i=0; i<nelmts; i++) {
+ HDmemmove(xdbuf, xsbuf, dst_stride);
+
+ /* Update pointers */
+ xsbuf += src_stride;
+ xdbuf += dst_stride;
+ }
+
+done:
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5D_compound_opt_write() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5D_create_chunk_map
*
* Purpose: Creates the mapping between elements selected in each chunk
diff --git a/src/H5T.c b/src/H5T.c
index b4bfe2d..a08f010 100644
--- a/src/H5T.c
+++ b/src/H5T.c
@@ -4451,6 +4451,11 @@ H5T_path_find(const H5T_t *src, const H5T_t *dst, const char *name,
table = path;
}
+ /* Set the flag to indicate both source and destination types are compound types
+ * for the optimization of data reading (in H5Dio.c). */
+ if(H5T_COMPOUND==H5T_get_class(src, TRUE) && H5T_COMPOUND==H5T_get_class(dst, TRUE))
+ path->are_compounds = TRUE;
+
/* Set return value */
ret_value = path;
@@ -4496,6 +4501,46 @@ H5T_path_noop(const H5T_path_t *p)
/*-------------------------------------------------------------------------
+ * Function: H5T_path_compound_subset
+ *
+ * Purpose: Checks if the source and destination types are both compound.
+ * Tells whether whether the source members are a subset of
+ * destination, and the order is the same, and no conversion
+ * is needed. For example:
+ * struct source { struct destination {
+ * TYPE1 A; --> TYPE1 A;
+ * TYPE2 B; --> TYPE2 B;
+ * TYPE3 C; --> TYPE3 C;
+ * }; TYPE4 D;
+ * TYPE5 E;
+ * };
+ *
+ * Return: One of the values of H5T_subset_t (can't fail).
+ *
+ * Programmer: Raymond Lu
+ * 8 June 2007
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+H5T_subset_t
+H5T_path_compound_subset(const H5T_path_t *p)
+{
+ H5T_subset_t ret_value = FALSE;
+
+ FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5T_path_compound_subset);
+
+ assert(p);
+
+ if(p->are_compounds)
+ ret_value = H5T_conv_struct_subset(&(p->cdata));
+
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* end H5T_path_compound_subset */
+
+
+/*-------------------------------------------------------------------------
* Function: H5T_path_bkg
*
* Purpose: Get the "background" flag for the conversion path.
diff --git a/src/H5Tconv.c b/src/H5Tconv.c
index a0ca3da..9dd7b30 100644
--- a/src/H5Tconv.c
+++ b/src/H5Tconv.c
@@ -35,7 +35,7 @@ typedef struct H5T_conv_struct_t {
hid_t *src_memb_id; /*source member type ID's */
hid_t *dst_memb_id; /*destination member type ID's */
H5T_path_t **memb_path; /*conversion path for each member */
- hbool_t smembs_subset; /*are source members a subset and in the top of dest? */
+ H5T_subset_t smembs_subset; /*are source and dest members a subset of each other? */
} H5T_conv_struct_t;
/* Conversion data for H5T_conv_enum() */
@@ -1704,8 +1704,8 @@ done:
* Modifications:
* Raymond Lu, 3 May 2007
* Added the detection for a special optimization case when the
- * source members are a subset of destination, and the order is
- * the same, and no conversion is needed. For example:
+ * source and destination members are a subset of each other, and
+ * the order is the same, and no conversion is needed. For example:
* struct source { struct destination {
* TYPE1 A; --> TYPE1 A;
* TYPE2 B; --> TYPE2 B;
@@ -1713,6 +1713,14 @@ done:
* }; TYPE4 D;
* TYPE5 E;
* };
+ * or
+ * struct destination { struct source {
+ * TYPE1 A; --> TYPE1 A;
+ * TYPE2 B; --> TYPE2 B;
+ * TYPE3 C; --> TYPE3 C;
+ * }; TYPE4 D;
+ * TYPE5 E;
+ * };
* The optimization is simply moving data to the appropriate
* places in the buffer.
*
@@ -1722,7 +1730,8 @@ static herr_t
H5T_conv_struct_init (H5T_t *src, H5T_t *dst, H5T_cdata_t *cdata, hid_t dxpl_id)
{
H5T_conv_struct_t *priv = (H5T_conv_struct_t*)(cdata->priv);
- int *src2dst = NULL;
+ int *src2dst = NULL;
+ unsigned src_nmembs, dst_nmembs;
unsigned i, j;
H5T_t *type = NULL;
hid_t tid;
@@ -1730,23 +1739,23 @@ H5T_conv_struct_init (H5T_t *src, H5T_t *dst, H5T_cdata_t *cdata, hid_t dxpl_id)
FUNC_ENTER_NOAPI_NOINIT(H5T_conv_struct_init);
+ src_nmembs = src->shared->u.compnd.nmembs;
+ dst_nmembs = dst->shared->u.compnd.nmembs;
+
if (!priv) {
/*
* Allocate private data structure and arrays.
*/
if (NULL==(priv=cdata->priv=H5MM_calloc(sizeof(H5T_conv_struct_t))) ||
- NULL==(priv->src2dst=H5MM_malloc(src->shared->u.compnd.nmembs *
- sizeof(int))) ||
- NULL==(priv->src_memb_id=H5MM_malloc(src->shared->u.compnd.nmembs *
- sizeof(hid_t))) ||
- NULL==(priv->dst_memb_id=H5MM_malloc(dst->shared->u.compnd.nmembs *
- sizeof(hid_t))))
+ NULL==(priv->src2dst=H5MM_malloc(src_nmembs * sizeof(int))) ||
+ NULL==(priv->src_memb_id=H5MM_malloc(src_nmembs * sizeof(hid_t))) ||
+ NULL==(priv->dst_memb_id=H5MM_malloc(dst_nmembs * sizeof(hid_t))))
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
src2dst = priv->src2dst;
- /* The flag of special optimization to indicate if source members are a subset
- * and in the top of the destination. Initialize it to TRUE */
- priv->smembs_subset = TRUE;
+ /* The flag of special optimization to indicate if source members and destination
+ * members are a subset of each other. Initialize it to FALSE */
+ priv->smembs_subset = H5T_SUBSET_FALSE;
/*
* Insure that members are sorted.
@@ -1761,9 +1770,9 @@ H5T_conv_struct_init (H5T_t *src, H5T_t *dst, H5T_cdata_t *cdata, hid_t dxpl_id)
* source and destination member data type so we can look up the
* member data type conversion functions later.
*/
- for (i=0; i<src->shared->u.compnd.nmembs; i++) {
+ for (i=0; i<src_nmembs; i++) {
src2dst[i] = -1;
- for (j=0; j<dst->shared->u.compnd.nmembs; j++) {
+ for (j=0; j<dst_nmembs; j++) {
if (!HDstrcmp (src->shared->u.compnd.memb[i].name,
dst->shared->u.compnd.memb[j].name)) {
src2dst[i] = j;
@@ -1782,11 +1791,6 @@ H5T_conv_struct_init (H5T_t *src, H5T_t *dst, H5T_cdata_t *cdata, hid_t dxpl_id)
assert (tid>=0);
priv->dst_memb_id[src2dst[i]] = tid;
}
-
- /* If any of source member doesn't have counterpart in the same order,
- * don't do the special optimization. */
- if(src2dst[i] != i || (src->shared->u.compnd.memb[i].offset != dst->shared->u.compnd.memb[i].offset))
- priv->smembs_subset = FALSE;
}
}
else {
@@ -1806,7 +1810,7 @@ H5T_conv_struct_init (H5T_t *src, H5T_t *dst, H5T_cdata_t *cdata, hid_t dxpl_id)
sizeof(H5T_path_t*))))
HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed");
- for (i=0; i<src->shared->u.compnd.nmembs; i++) {
+ for (i=0; i<src_nmembs; i++) {
if (src2dst[i]>=0) {
H5T_path_t *tpath = H5T_path_find(src->shared->u.compnd.memb[i].type,
dst->shared->u.compnd.memb[src2dst[i]].type, NULL, NULL, dxpl_id, FALSE);
@@ -1819,18 +1823,39 @@ H5T_conv_struct_init (H5T_t *src, H5T_t *dst, H5T_cdata_t *cdata, hid_t dxpl_id)
cdata->priv = priv = H5MM_xfree (priv);
HGOTO_ERROR (H5E_DATATYPE, H5E_UNSUPPORTED, FAIL, "unable to convert member data type");
}
-
- /* If any of source member needs conversion, don't do the special optimization. */
- if(priv->smembs_subset && ((priv->memb_path[i])->is_noop == FALSE))
- priv->smembs_subset = FALSE;
-
}
}
/* Check if we need a background buffer */
- if (H5T_detect_class(src,H5T_COMPOUND)==TRUE || H5T_detect_class(dst,H5T_COMPOUND)==TRUE)
+ if (H5T_detect_class(src,H5T_COMPOUND)==TRUE || H5T_detect_class(dst,H5T_COMPOUND)==TRUE) {
cdata->need_bkg = H5T_BKG_YES;
+ if(src_nmembs < dst_nmembs) {
+ priv->smembs_subset = H5T_SUBSET_SRC;
+ for (i=0; i<src_nmembs; i++) {
+ /* If any of source members doesn't have counterpart in the same order or
+ * there's conversion between members, don't do the optimization. */
+ if(src2dst[i] != i || (src->shared->u.compnd.memb[i].offset !=
+ dst->shared->u.compnd.memb[i].offset) || (priv->memb_path[i])->is_noop ==
+ FALSE)
+ priv->smembs_subset = H5T_SUBSET_FALSE;
+ }
+ } else if(dst_nmembs < src_nmembs) {
+ priv->smembs_subset = H5T_SUBSET_DST;
+ for (i=0; i<dst_nmembs; i++) {
+ /* If any of source members doesn't have counterpart in the same order or
+ * there's conversion between members, don't do the optimization. */
+ if(src2dst[i] != i || (src->shared->u.compnd.memb[i].offset !=
+ dst->shared->u.compnd.memb[i].offset) || (priv->memb_path[i])->is_noop ==
+ FALSE)
+ priv->smembs_subset = H5T_SUBSET_FALSE;
+ }
+ } else /* If the numbers of source and dest members are equal and no conversion is needed,
+ * the case should have been handled as noop earlier in H5Dio.c. */
+ ;
+
+ }
+
cdata->recalc = FALSE;
done:
@@ -1839,6 +1864,49 @@ done:
/*-------------------------------------------------------------------------
+ * Function: H5T_conv_struct_subset
+ *
+ * Purpose: A quick way to return a field in a struct private in this
+ * file. The flag SMEMBS_SUBSET indicates whether the source
+ * members are a subset of destination or the destination
+ * members are a subset of the source, and the order is the
+ * same, and no conversion is needed. For example:
+ * struct source { struct destination {
+ * TYPE1 A; --> TYPE1 A;
+ * TYPE2 B; --> TYPE2 B;
+ * TYPE3 C; --> TYPE3 C;
+ * }; TYPE4 D;
+ * TYPE5 E;
+ * };
+ *
+ * Return: One of the value from H5T_subset_t.
+ *
+ * Programmer: Raymond Lu
+ * 8 June 2007
+ *
+ * Modifications:
+ *-------------------------------------------------------------------------
+ */
+H5T_subset_t
+H5T_conv_struct_subset(const H5T_cdata_t *cdata)
+{
+ H5T_conv_struct_t *priv;
+ H5T_subset_t ret_value=FALSE; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOINIT(H5T_conv_struct_subset);
+
+ assert(cdata);
+ assert(cdata->priv);
+
+ priv = (H5T_conv_struct_t*)(cdata->priv);
+ ret_value = priv->smembs_subset;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+}
+
+
+/*-------------------------------------------------------------------------
* Function: H5T_conv_struct
*
* Purpose: Converts between compound data types. This is a soft
@@ -2109,9 +2177,9 @@ done:
* datatype.
*
* Raymond Lu, 3 May 2007
- * Optimize a special case when the source members are a subset of
- * destination, and the order is the same, and no conversion is needed.
- * For example:
+ * Optimize a special case when the source and destination members
+ * are a subset of each other, and the order is the same, and no
+ * conversion is needed. For example:
* struct source { struct destination {
* TYPE1 A; --> TYPE1 A;
* TYPE2 B; --> TYPE2 B;
@@ -2257,7 +2325,7 @@ H5T_conv_struct_opt(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
buf_stride = src->shared->size;
}
- if(priv->smembs_subset == TRUE) {
+ if(priv->smembs_subset == H5T_SUBSET_SRC) {
/* If the optimization flag is set to indicate source members are a subset and
* in the top of the destination, simply copy the source members to background buffer. */
xbuf = buf;
@@ -2286,6 +2354,34 @@ H5T_conv_struct_opt(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata,
xbkg += bkg_stride;
}
}
+ } else if(priv->smembs_subset == H5T_SUBSET_DST) {
+ /* If the optimization flag is set to indicate destination members are a subset
+ * and in the top of the source, simply copy the source members to background
+ * buffer. */
+ xbuf = buf;
+ xbkg = bkg;
+
+ if(src->shared->size <= dst->shared->size) {
+ /* This is to deal with a very special situation when the fields and their
+ * offset for both source and destination are identical but the datatype
+ * sizes of source and destination are different.
+ */
+ for (elmtno=0; elmtno<nelmts; elmtno++) {
+ HDmemmove(xbkg, xbuf, src->shared->size);
+
+ /* Update pointers */
+ xbuf += buf_stride;
+ xbkg += bkg_stride;
+ }
+ } else {
+ for (elmtno=0; elmtno<nelmts; elmtno++) {
+ HDmemmove(xbkg, xbuf, dst->shared->size);
+
+ /* Update pointers */
+ xbuf += buf_stride;
+ xbkg += bkg_stride;
+ }
+ }
} else {
/*
* For each member where the destination is not larger than the
diff --git a/src/H5Tpkg.h b/src/H5Tpkg.h
index c9fba39..fd3bc39 100644
--- a/src/H5Tpkg.h
+++ b/src/H5Tpkg.h
@@ -192,6 +192,7 @@ struct H5T_path_t {
H5T_conv_t func; /*data conversion function */
hbool_t is_hard; /*is it a hard function? */
hbool_t is_noop; /*is it the noop conversion? */
+ hbool_t are_compounds; /*are source and dest both compounds?*/
H5T_stats_t stats; /*statistics for the conversion */
H5T_cdata_t cdata; /*data for this function */
};
@@ -1338,6 +1339,8 @@ H5_DLL H5T_t *H5T_get_member_type(const H5T_t *dt, unsigned membno);
H5_DLL size_t H5T_get_member_offset(const H5T_t *dt, unsigned membno);
H5_DLL size_t H5T_get_member_size(const H5T_t *dt, unsigned membno);
H5_DLL htri_t H5T_is_packed(const H5T_t *dt);
+H5_DLL H5T_subset_t H5T_conv_struct_subset(const H5T_cdata_t *cdata);
+H5_DLL H5T_subset_t H5T_path_compound_subset(const H5T_path_t *p);
#endif /* _H5Tpkg_H */
diff --git a/src/H5Tprivate.h b/src/H5Tprivate.h
index a566a0a..0ac6047 100644
--- a/src/H5Tprivate.h
+++ b/src/H5Tprivate.h
@@ -64,6 +64,18 @@ typedef struct H5T_conv_cb_t {
void* user_data;
} H5T_conv_cb_t;
+/* Values for the optimization of compound data reading and writing. They indicate
+ * whether the fields of the source and destination are subset of each other and
+ * there is no conversion needed. It's for the Chicago company.
+ */
+typedef enum {
+ H5T_SUBSET_BADVALUE = -1, /* Invalid value */
+ H5T_SUBSET_FALSE = 0, /* Source and destination aren't subset of each other */
+ H5T_SUBSET_SRC, /* Source is the subset of dest and no conversion is needed */
+ H5T_SUBSET_DST, /* Dest is the subset of source and no conversion is needed */
+ H5T_SUBSET_CAP /* Must be the last value */
+} H5T_subset_t;
+
/* Forward declarations for prototype arguments */
struct H5O_t;