1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * Copyright by The HDF Group.                                               *
3  * Copyright by the Board of Trustees of the University of Illinois.         *
4  * All rights reserved.                                                      *
5  *                                                                           *
6  * This file is part of HDF5.  The full HDF5 copyright notice, including     *
7  * terms governing use, modification, and redistribution, is contained in    *
8  * the COPYING file, which can be found at the root of the source code       *
9  * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases.  *
10  * If you do not have access to either file, you may request a copy from     *
11  * help@hdfgroup.org.                                                        *
12  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13 
14 #include "H5private.h"
15 #include "h5tools.h"
16 #include "h5tools_utils.h"
17 #include "h5diff.h"
18 #include "ph5diff.h"
19 
20 
21 /*-------------------------------------------------------------------------
22  * Function: diff_dataset
23  *
24  * Purpose: check for comparable datasets and read into a compatible
25  *  memory type
26  *
27  * Return: Number of differences found
28  *-------------------------------------------------------------------------
29  */
diff_dataset(hid_t file1_id,hid_t file2_id,const char * obj1_name,const char * obj2_name,diff_opt_t * opts)30 hsize_t diff_dataset(hid_t file1_id,
31                      hid_t file2_id,
32                      const char *obj1_name,
33                      const char *obj2_name,
34                      diff_opt_t *opts)
35 {
36     int     ret_value = opts->err_stat;
37     int     status = -1;
38     hid_t   did1 = -1;
39     hid_t   did2 = -1;
40     hid_t   dcpl1 = -1;
41     hid_t   dcpl2 = -1;
42     hsize_t nfound = 0;
43 
44     h5difftrace("diff_dataset start\n");
45     /*-------------------------------------------------------------------------
46      * open the handles
47      *-------------------------------------------------------------------------
48      */
49     /* Open the datasets */
50     if((did1 = H5Dopen2(file1_id, obj1_name, H5P_DEFAULT)) < 0) {
51         parallel_print("Cannot open dataset <%s>\n", obj1_name);
52         HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Dopen2 first dataset failed");
53     }
54     if((did2 = H5Dopen2(file2_id, obj2_name, H5P_DEFAULT)) < 0) {
55         parallel_print("Cannot open dataset <%s>\n", obj2_name);
56         HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Dopen2 second dataset failed");
57     }
58 
59     if((dcpl1 = H5Dget_create_plist(did1)) < 0)
60         HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Dget_create_plist first dataset failed");
61     if((dcpl2 = H5Dget_create_plist(did2)) < 0)
62         HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Dget_create_plist second dataset failed");
63 
64     /*-------------------------------------------------------------------------
65      * check if the dataset creation property list has filters that
66      * are not registered in the current configuration
67      * 1) the external filters GZIP and SZIP might not be available
68      * 2) the internal filters might be turned off
69      *-------------------------------------------------------------------------
70      */
71     if ((status = h5tools_canreadf((opts->m_verbose ? obj1_name : NULL), dcpl1) == 1) &&
72             (status = h5tools_canreadf((opts->m_verbose ? obj2_name : NULL), dcpl2) == 1))
73         nfound = diff_datasetid(did1, did2, obj1_name, obj2_name, opts);
74     else if (status < 0) {
75         HGOTO_ERROR(1, H5E_tools_min_id_g, "h5tools_canreadf failed");
76     }
77     else {
78         ret_value = 1;
79         opts->not_cmp = 1;
80     }
81 
82 done:
83     opts->err_stat = opts->err_stat | ret_value;
84 
85     /* disable error reporting */
86     H5E_BEGIN_TRY {
87         H5Pclose(dcpl1);
88         H5Pclose(dcpl2);
89         H5Dclose(did1);
90         H5Dclose(did2);
91         /* enable error reporting */
92     } H5E_END_TRY;
93 
94     h5diffdebug3("diff_dataset finish:%d - errstat:%d\n", nfound, opts->err_stat);
95     return nfound;
96 }
97 
98 /*-------------------------------------------------------------------------
99  * Function: diff_datasetid
100  *
101  * Purpose: check for comparable datasets and read into a compatible
102  *  memory type
103  *
104  * Return: Number of differences found
105  *
106  * October 2006:  Read by hyperslabs for big datasets.
107  *
108  *  A threshold of H5TOOLS_MALLOCSIZE (128 MB) is the limit upon which I/O hyperslab is done
109  *  i.e., if the memory needed to read a dataset is greater than this limit,
110  *  then hyperslab I/O is done instead of one operation I/O
111  *  For each dataset, the memory needed is calculated according to
112  *
113  *  memory needed = number of elements * size of each element
114  *
115  *  if the memory needed is lower than H5TOOLS_MALLOCSIZE, then the following operations
116  *  are done
117  *
118  *  H5Dread( input_dataset1 )
119  *  H5Dread( input_dataset2 )
120  *
121  *  with all elements in the datasets selected. If the memory needed is greater than
122  *  H5TOOLS_MALLOCSIZE, then the following operations are done instead:
123  *
124  *  a strip mine is defined for each dimension k (a strip mine is defined as a
125  *  hyperslab whose size is memory manageable) according to the formula
126  *
127  *  (1) strip_mine_size[k ] = MIN(dimension[k ], H5TOOLS_BUFSIZE / size of memory type)
128  *
129  *  where H5TOOLS_BUFSIZE is a constant currently defined as 1MB. This formula assures
130  *  that for small datasets (small relative to the H5TOOLS_BUFSIZE constant), the strip
131  *  mine size k is simply defined as its dimension k, but for larger datasets the
132  *  hyperslab size is still memory manageable.
133  *  a cycle is done until the number of elements in the dataset is reached. In each
134  *  iteration, two parameters are defined for the function H5Sselect_hyperslab,
135  *  the start and size of each hyperslab, according to
136  *
137  *  (2) hyperslab_size [k] = MIN(dimension[k] - hyperslab_offset[k], strip_mine_size [k])
138  *
139  *  where hyperslab_offset [k] is initially set to zero, and later incremented in
140  *  hyperslab_size[k] offsets. The reason for the operation
141  *
142  *  dimension[k] - hyperslab_offset[k]
143  *
144  *  in (2) is that, when using the strip mine size, it assures that the "remaining" part
145  *  of the dataset that does not fill an entire strip mine is processed.
146  *
147  *-------------------------------------------------------------------------
148  */
diff_datasetid(hid_t did1,hid_t did2,const char * obj1_name,const char * obj2_name,diff_opt_t * opts)149 hsize_t diff_datasetid(hid_t did1,
150                        hid_t did2,
151                        const char *obj1_name,
152                        const char *obj2_name,
153                        diff_opt_t *opts)
154 {
155     int        ret_value = opts->err_stat;
156     hid_t      sid1 = -1;
157     hid_t      sid2 = -1;
158     hid_t      f_tid1 = -1;
159     hid_t      f_tid2 = -1;
160     hid_t      dam_tid = -1;             /* m_tid for diff_array function */
161     hid_t      m_tid1 = -1;
162     hid_t      m_tid2 = -1;
163     hid_t      dcpl1 = -1;
164     hid_t      dcpl2 = -1;
165     H5D_layout_t     stl1 = -1;
166     H5D_layout_t     stl2 = -1;
167     size_t     dam_size;                /* m_size for diff_array function */
168     size_t     m_size1;
169     size_t     m_size2;
170     H5T_sign_t sign1;
171     H5T_sign_t sign2;
172     int        rank1;
173     int        rank2;
174     hsize_t    danelmts;                /* nelmts for diff_array function */
175     hsize_t    nelmts1;
176     hsize_t    nelmts2;
177     hsize_t    *dadims;                 /* dims for diff_array function */
178     hsize_t    dims1[H5S_MAX_RANK];
179     hsize_t    dims2[H5S_MAX_RANK];
180     hsize_t    maxdim1[H5S_MAX_RANK];
181     hsize_t    maxdim2[H5S_MAX_RANK];
182     const char *name1 = NULL;           /* relative names */
183     const char *name2 = NULL;
184     hsize_t    storage_size1;
185     hsize_t    storage_size2;
186     hsize_t    nfound = 0;              /* number of differences found */
187     int        can_compare = 1;         /* do diff or not */
188     void       *buf1 = NULL;
189     void       *buf2 = NULL;
190     void       *sm_buf1 = NULL;
191     void       *sm_buf2 = NULL;
192     hid_t      sm_space = -1;           /*stripmine data space */
193     size_t     need;                    /* bytes needed for malloc */
194     int        i;
195     unsigned int  vl_data1 = 0;          /*contains VL datatypes */
196     unsigned int  vl_data2 = 0;          /*contains VL datatypes */
197 
198     h5difftrace("diff_datasetid start\n");
199     /* Get the dataspace handle */
200     if((sid1 = H5Dget_space(did1)) < 0)
201         HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Dget_space failed");
202 
203     /* Get rank */
204     if((rank1 = H5Sget_simple_extent_ndims(sid1)) < 0)
205         HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Sget_simple_extent_ndims failed");
206 
207     /* Get the dataspace handle */
208     if((sid2 = H5Dget_space(did2)) < 0 )
209         HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Dget_space failed");
210 
211     /* Get rank */
212     if((rank2 = H5Sget_simple_extent_ndims(sid2)) < 0)
213         HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Sget_simple_extent_ndims failed");
214 
215     /* Get dimensions */
216     if(H5Sget_simple_extent_dims(sid1, dims1, maxdim1) < 0)
217         HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Sget_simple_extent_dims failed");
218 
219     /* Get dimensions */
220     if(H5Sget_simple_extent_dims(sid2, dims2, maxdim2) < 0)
221         HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Sget_simple_extent_dims failed");
222     h5diffdebug3("rank: %ld - %ld\n", rank1, rank2);
223 
224     /*-------------------------------------------------------------------------
225      * get the file data type
226      *-------------------------------------------------------------------------
227      */
228 
229     /* Get the data type */
230     if((f_tid1 = H5Dget_type(did1)) < 0)
231         HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Dget_type failed");
232 
233     /* Get the data type */
234     if((f_tid2 = H5Dget_type(did2)) < 0)
235         HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Dget_type failed");
236 
237     /*-------------------------------------------------------------------------
238      * get the storage layout type
239      *-------------------------------------------------------------------------
240      */
241     if((dcpl1 = H5Dget_create_plist(did1)) < 0)
242         HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Dget_create_plist failed");
243     if((dcpl2 = H5Dget_create_plist(did2)) < 0)
244         HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Dget_create_plist failed");
245 
246     if((stl1 = H5Pget_layout(dcpl1)) < 0)
247         HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Pget_layout failed");
248     if((stl2 = H5Pget_layout(dcpl2)) < 0)
249         HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Pget_layout failed");
250 
251     /*-------------------------------------------------------------------------
252      * check for empty datasets
253      *-------------------------------------------------------------------------
254      */
255     h5difftrace("check for empty datasets\n");
256 
257     storage_size1 = H5Dget_storage_size(did1);
258     storage_size2 = H5Dget_storage_size(did2);
259     h5diffdebug3("storage size: %ld - %ld\n", storage_size1, storage_size2);
260 
261     if(storage_size1 == 0 || storage_size2 == 0) {
262         if(stl1 == H5D_VIRTUAL || stl2 == H5D_VIRTUAL) {
263             if((opts->m_verbose||opts->m_list_not_cmp) && obj1_name && obj2_name)
264                 parallel_print("Warning: <%s> or <%s> is a virtual dataset\n", obj1_name, obj2_name);
265         }
266         else {
267             if((opts->m_verbose || opts->m_list_not_cmp) && obj1_name && obj2_name)
268                 parallel_print("Not comparable: <%s> or <%s> is an empty dataset\n", obj1_name, obj2_name);
269             can_compare = 0;
270             opts->not_cmp = 1;
271         }
272     }
273 
274     /*-------------------------------------------------------------------------
275      * check for comparable TYPE and SPACE
276      *-------------------------------------------------------------------------
277      */
278     if (diff_can_type(f_tid1, f_tid2, rank1, rank2,
279             dims1, dims2, maxdim1, maxdim2,
280             obj1_name, obj2_name,
281             opts, 0) != 1)
282         can_compare = 0;
283     h5diffdebug2("diff_can_type - errstat:%d\n", opts->err_stat);
284 
285     /*-------------------------------------------------------------------------
286      * memory type and sizes
287      *-------------------------------------------------------------------------
288      */
289     h5difftrace("check for memory type and sizes\n");
290     if((m_tid1 = H5Tget_native_type(f_tid1, H5T_DIR_DEFAULT)) < 0)
291         HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Tget_native_type failed");
292 
293     if((m_tid2 = H5Tget_native_type(f_tid2, H5T_DIR_DEFAULT)) < 0)
294         HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Tget_native_type failed");
295 
296     m_size1 = H5Tget_size(m_tid1);
297     m_size2 = H5Tget_size(m_tid2);
298     h5diffdebug3("type size: %ld - %ld\n", m_size1, m_size2);
299 
300     /*-------------------------------------------------------------------------
301      * check for different signed/unsigned types
302      *-------------------------------------------------------------------------
303      */
304     if(can_compare) {
305         h5difftrace("can_compare for sign\n");
306         sign1 = H5Tget_sign(m_tid1);
307         sign2 = H5Tget_sign(m_tid2);
308         if(sign1 != sign2) {
309             h5difftrace("sign1 != sign2\n");
310             if((opts->m_verbose || opts->m_list_not_cmp) && obj1_name && obj2_name) {
311                 parallel_print("Not comparable: <%s> has sign %s ", obj1_name, get_sign(sign1));
312                 parallel_print("and <%s> has sign %s\n", obj2_name, get_sign(sign2));
313             }
314 
315             can_compare = 0;
316             opts->not_cmp = 1;
317         }
318     }
319 
320     /* Check if type is either VLEN-data or VLEN-string to reclaim any
321      * VLEN memory buffer later
322      */
323     if(TRUE == h5tools_detect_vlen(m_tid1))
324         vl_data1 = TRUE;
325     if(TRUE == h5tools_detect_vlen(m_tid2))
326         vl_data2 = TRUE;
327     h5diffdebug2("h5tools_detect_vlen - errstat:%d\n", opts->err_stat);
328 
329     /*------------------------------------------------------------------------
330      * only attempt to compare if possible
331      *-------------------------------------------------------------------------
332      */
333     if(can_compare) { /* it is possible to compare */
334         H5T_class_t  tclass = H5Tget_class(f_tid1);
335         h5difftrace("can_compare attempt\n");
336 
337         /*-----------------------------------------------------------------
338         * get number of elements
339         *------------------------------------------------------------------
340         */
341         nelmts1 = 1;
342         for(i = 0; i < rank1; i++)
343             nelmts1 *= dims1[i];
344 
345         nelmts2 = 1;
346         for(i = 0; i < rank2; i++)
347             nelmts2 *= dims2[i];
348 
349         h5diffdebug3("nelmts: %ld - %ld\n", nelmts1, nelmts2);
350 
351         if(tclass != H5T_ARRAY) {
352             /*-----------------------------------------------------------------
353              * "upgrade" the smaller memory size
354              *------------------------------------------------------------------
355              */
356             h5difftrace("upgrade the smaller memory size?\n");
357             if (FAIL == match_up_memsize (f_tid1, f_tid2,
358                                         &m_tid1, &m_tid2,
359                                         &m_size1, &m_size2))
360                 HGOTO_ERROR(1, H5E_tools_min_id_g, "match_up_memsize failed");
361             h5diffdebug3("m_size: %ld - %ld\n", m_size1, m_size2);
362             dadims = dims1;
363             dam_size = m_size1;
364             dam_tid = m_tid1;
365             danelmts = nelmts1;
366             need = (size_t)(nelmts1 * m_size1);  /* bytes needed */
367         }
368         else {
369             h5diffdebug3("Array dims: %d - %d\n", dims1[0], dims2[0]);
370             /* Compare the smallest array, but create the largest buffer */
371             if(m_size1 <= m_size2) {
372                 dadims = dims1;
373                 dam_size = m_size1;
374                 dam_tid = m_tid1;
375                 danelmts = nelmts1;
376                 need = (size_t)(nelmts2 * m_size2);  /* bytes needed */
377             }
378             else {
379                 dadims = dims2;
380                 dam_size = m_size2;
381                 dam_tid = m_tid2;
382                 danelmts = nelmts2;
383                 need = (size_t)(nelmts1 * m_size1);  /* bytes needed */
384             }
385         }
386         /* print names */
387         if(obj1_name)
388             name1 = diff_basename(obj1_name);
389         if(obj2_name)
390             name2 = diff_basename(obj2_name);
391         h5diffdebug3("obj_names: %s - %s\n", name1, name2);
392 
393 
394         /*----------------------------------------------------------------
395          * read/compare
396          *-----------------------------------------------------------------
397          */
398         if(need < H5TOOLS_MALLOCSIZE) {
399             buf1 = HDmalloc(need);
400             buf2 = HDmalloc(need);
401         } /* end if */
402 
403         if(buf1 != NULL && buf2 != NULL) {
404             h5difftrace("buf1 != NULL && buf2 != NULL\n");
405             if(H5Dread(did1, m_tid1, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf1) < 0)
406                 HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Dread failed");
407             h5difftrace("H5Dread did2\n");
408             if(H5Dread(did2, m_tid2, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf2) < 0)
409                 HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Dread failed");
410 
411             /* array diff */
412             nfound = diff_array(buf1, buf2, danelmts, (hsize_t)0, rank1, dadims,
413                 opts, name1, name2, dam_tid, did1, did2);
414             h5diffdebug2("diff_array nfound:%d\n", nfound);
415 
416             /* reclaim any VL memory, if necessary */
417             h5diffdebug2("check vl_data1:%d\n", vl_data1);
418             if(vl_data1)
419                 H5Dvlen_reclaim(m_tid1, sid1, H5P_DEFAULT, buf1);
420             h5diffdebug2("check vl_data2:%d\n", vl_data2);
421             if(vl_data2)
422                 H5Dvlen_reclaim(m_tid2, sid2, H5P_DEFAULT, buf2);
423             if(buf1 != NULL) {
424                 HDfree(buf1);
425                 buf1 = NULL;
426             }
427             if(buf2 != NULL) {
428                 HDfree(buf2);
429                 buf2 = NULL;
430             }
431         } /* end if */
432         else { /* possibly not enough memory, read/compare by hyperslabs */
433             size_t        p_type_nbytes = dam_size; /*size of memory type */
434             hsize_t       p_nelmts = danelmts;      /*total selected elmts */
435             hsize_t       elmtno;                  /*counter  */
436             int           carry;                   /*counter carry value */
437 
438             /* stripmine info */
439             hsize_t       sm_size[H5S_MAX_RANK];   /*stripmine size */
440             hsize_t       sm_nbytes;               /*bytes per stripmine */
441             hsize_t       sm_nelmts;               /*elements per stripmine*/
442 
443             /* hyperslab info */
444             hsize_t       hs_offset[H5S_MAX_RANK]; /*starting offset */
445             hsize_t       hs_size[H5S_MAX_RANK];   /*size this pass */
446             hsize_t       hs_nelmts;               /*elements in request */
447             hsize_t       zero[8];                 /*vector of zeros */
448 
449             /*
450              * determine the strip mine size and allocate a buffer. The strip mine is
451              * a hyperslab whose size is manageable.
452              */
453             sm_nbytes = p_type_nbytes;
454 
455             for(i = rank1; i > 0; --i) {
456                 hsize_t size = H5TOOLS_BUFSIZE / sm_nbytes;
457 
458                 if(size == 0) /* datum size > H5TOOLS_BUFSIZE */
459                     size = 1;
460                 sm_size[i - 1] = MIN(dadims[i - 1], size);
461                 sm_nbytes *= sm_size[i - 1];
462                 h5diffdebug2("sm_nbytes: %ld\n", sm_nbytes);
463             } /* end for */
464 
465             /* malloc return code should be verified.
466              * If fail, need to handle the error.
467              * This else branch should be recoded as a separate function.
468              * Note that there are many "goto error" within this branch
469              * that fails to address freeing other objects created here.
470              * E.g., sm_space.
471              */
472             if((sm_buf1 = HDmalloc((size_t)sm_nbytes)) == NULL)
473                 HGOTO_ERROR(1, H5E_tools_min_id_g, "HDmalloc failed");
474             if((sm_buf2 = HDmalloc((size_t)sm_nbytes)) == NULL)
475                 HGOTO_ERROR(1, H5E_tools_min_id_g, "HDmalloc failed");
476 
477             sm_nelmts = sm_nbytes / p_type_nbytes;
478             sm_space = H5Screate_simple(1, &sm_nelmts, NULL);
479 
480             /* the stripmine loop */
481             HDmemset(hs_offset, 0, sizeof hs_offset);
482             HDmemset(zero, 0, sizeof zero);
483 
484             for(elmtno = 0; elmtno < p_nelmts; elmtno += hs_nelmts) {
485                 /* calculate the hyperslab size */
486                 if(rank1 > 0) {
487                     for(i = 0, hs_nelmts = 1; i < rank1; i++) {
488                         hs_size[i] = MIN(dadims[i] - hs_offset[i], sm_size[i]);
489                         hs_nelmts *= hs_size[i];
490                     } /* end for */
491                     if(H5Sselect_hyperslab(sid1, H5S_SELECT_SET, hs_offset, NULL, hs_size, NULL) < 0)
492                         HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Sselect_hyperslab failed");
493                     if(H5Sselect_hyperslab(sid2, H5S_SELECT_SET, hs_offset, NULL, hs_size, NULL) < 0)
494                         HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Sselect_hyperslab failed");
495                     if(H5Sselect_hyperslab(sm_space, H5S_SELECT_SET, zero, NULL, &hs_nelmts, NULL) < 0)
496                         HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Sselect_hyperslab failed");
497                 } /* end if */
498                 else
499                     hs_nelmts = 1;
500 
501                 if(H5Dread(did1, m_tid1, sm_space, sid1, H5P_DEFAULT, sm_buf1) < 0)
502                     HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Dread failed");
503                 if(H5Dread(did2, m_tid2, sm_space, sid2, H5P_DEFAULT, sm_buf2) < 0)
504                     HGOTO_ERROR(1, H5E_tools_min_id_g, "H5Dread failed");
505 
506                 /* get array differences. in the case of hyperslab read, increment the number of differences
507                 found in each hyperslab and pass the position at the beginning for printing */
508                 nfound += diff_array(sm_buf1, sm_buf2, hs_nelmts, elmtno, rank1,
509                         dadims, opts, name1, name2, dam_tid, did1, did2);
510 
511                 /* reclaim any VL memory, if necessary */
512                 if(vl_data1)
513                     H5Dvlen_reclaim(m_tid1, sm_space, H5P_DEFAULT, sm_buf1);
514                 if(vl_data2)
515                     H5Dvlen_reclaim(m_tid2, sm_space, H5P_DEFAULT, sm_buf2);
516 
517                 /* calculate the next hyperslab offset */
518                 for(i = rank1, carry = 1; i > 0 && carry; --i) {
519                     hs_offset[i - 1] += hs_size[i - 1];
520                     if(hs_offset[i - 1] == dadims[i - 1])
521                         hs_offset[i - 1] = 0;
522                     else
523                         carry = 0;
524                 } /* i */
525             } /* elmtno */
526             if(sm_buf1 != NULL) {
527                 HDfree(sm_buf1);
528                 sm_buf1 = NULL;
529             }
530             if(sm_buf2 != NULL) {
531                 HDfree(sm_buf2);
532                 sm_buf2 = NULL;
533             }
534 
535             H5Sclose(sm_space);
536         } /* hyperslab read */
537     } /*can_compare*/
538 
539 
540     /*-------------------------------------------------------------------------
541      * close
542      *-------------------------------------------------------------------------
543      */
544     h5diffdebug2("reclaim any VL memory - errstat:%d\n", opts->err_stat);
545 
546 done:
547     opts->err_stat = opts->err_stat | ret_value;
548 
549     /* free */
550     if(buf1 != NULL) {
551         /* reclaim any VL memory, if necessary */
552         if(vl_data1)
553             H5Dvlen_reclaim(m_tid1, sid1, H5P_DEFAULT, buf1);
554         HDfree(buf1);
555         buf1 = NULL;
556     }
557     if(buf2 != NULL) {
558         /* reclaim any VL memory, if necessary */
559         if(vl_data2)
560             H5Dvlen_reclaim(m_tid2, sid2, H5P_DEFAULT, buf2);
561         HDfree(buf2);
562         buf2 = NULL;
563     }
564     if(sm_buf1 != NULL) {
565         /* reclaim any VL memory, if necessary */
566         if(vl_data1)
567             H5Dvlen_reclaim(m_tid1, sm_space, H5P_DEFAULT, sm_buf1);
568         HDfree(sm_buf1);
569         sm_buf1 = NULL;
570     }
571     if(sm_buf2 != NULL) {
572         /* reclaim any VL memory, if necessary */
573         if(vl_data2)
574             H5Dvlen_reclaim(m_tid2, sm_space, H5P_DEFAULT, sm_buf2);
575         HDfree(sm_buf2);
576         sm_buf2 = NULL;
577     }
578 
579     /* disable error reporting */
580     H5E_BEGIN_TRY {
581         H5Sclose(sid1);
582         H5Sclose(sid2);
583         H5Sclose(sm_space);
584         H5Tclose(f_tid1);
585         H5Tclose(f_tid2);
586         H5Tclose(m_tid1);
587         H5Tclose(m_tid2);
588         /* enable error reporting */
589     } H5E_END_TRY;
590 
591     h5diffdebug3("diff_datasetid return:%d with nfound:%d\n", ret_value, nfound);
592     return nfound;
593 }
594 
595 /*-------------------------------------------------------------------------
596  * Function: diff_can_type
597  *
598  * Purpose:  check for comparable TYPE and SPACE
599  *
600  * Return:
601  *           1, can compare
602  *           0, cannot compare
603  *          -1, error
604  *-------------------------------------------------------------------------
605  */
606 
diff_can_type(hid_t f_tid1,hid_t f_tid2,int rank1,int rank2,hsize_t * dims1,hsize_t * dims2,hsize_t * maxdim1,hsize_t * maxdim2,const char * obj1_name,const char * obj2_name,diff_opt_t * opts,int is_compound)607 int diff_can_type(hid_t       f_tid1, /* file data type */
608                   hid_t       f_tid2, /* file data type */
609                   int         rank1,
610                   int         rank2,
611                   hsize_t     *dims1,
612                   hsize_t     *dims2,
613                   hsize_t     *maxdim1,
614                   hsize_t     *maxdim2,
615                   const char  *obj1_name,
616                   const char  *obj2_name,
617                   diff_opt_t  *opts,
618                   int         is_compound)
619 {
620     int          ret_value = 1;            /* can_compare value */
621     H5T_class_t  tclass1;
622     H5T_class_t  tclass2;
623     int          maxdim_diff = 0;          /* maximum dimensions are different */
624     int          dim_diff = 0;             /* current dimensions are different */
625     int          i;
626 
627     h5difftrace("diff_can_type start\n");
628     /*-------------------------------------------------------------------------
629      * check for the same class
630      *-------------------------------------------------------------------------
631      */
632     if((tclass1 = H5Tget_class(f_tid1)) < 0)
633         HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Tget_class first object failed");
634     if((tclass2 = H5Tget_class(f_tid2)) < 0)
635         HGOTO_ERROR(FAIL, H5E_tools_min_id_g, "H5Tget_class second object failed");
636 
637     if(tclass1 != tclass2) {
638         if((opts->m_verbose || opts->m_list_not_cmp) && obj1_name && obj2_name) {
639             if(is_compound) {
640                 parallel_print("Not comparable: <%s> has a class %s and <%s> has a class %s\n",
641                         obj1_name, get_class(tclass1),
642                         obj2_name, get_class(tclass2));
643             }
644             else {
645                 parallel_print("Not comparable: <%s> is of class %s and <%s> is of class %s\n",
646                         obj1_name, get_class(tclass1),
647                         obj2_name, get_class(tclass2));
648             }
649         }
650         opts->not_cmp = 1;
651         HGOTO_DONE(0);
652     }
653 
654     /*-------------------------------------------------------------------------
655      * check for non supported classes
656      *-------------------------------------------------------------------------
657      */
658     switch (tclass1) {
659         case H5T_TIME:
660             if((opts->m_verbose || opts->m_list_not_cmp) && obj1_name && obj2_name) {
661                 parallel_print("Not comparable: <%s> and <%s> are of class %s\n",
662                         obj1_name, obj2_name, get_class(tclass2));
663             } /* end if */
664             opts->not_cmp = 1;
665             HGOTO_DONE(0);
666 
667         case H5T_INTEGER:
668         case H5T_FLOAT:
669         case H5T_COMPOUND:
670         case H5T_STRING:
671         case H5T_ARRAY:
672         case H5T_BITFIELD:
673         case H5T_OPAQUE:
674         case H5T_ENUM:
675         case H5T_VLEN:
676         case H5T_REFERENCE:
677         case H5T_NO_CLASS:
678         case H5T_NCLASSES:
679         default:
680             h5diffdebug2("diff_can_type class - %s\n", get_class(tclass1));
681             break;
682     } /* end switch */
683 
684     /*-------------------------------------------------------------------------
685      * check for equal file datatype; warning only
686      *-------------------------------------------------------------------------
687      */
688     if((H5Tequal(f_tid1, f_tid2) == 0) && (opts->m_verbose) && obj1_name && obj2_name) {
689         H5T_class_t cl = H5Tget_class(f_tid1);
690 
691         parallel_print("Warning: different storage datatype\n");
692         if(cl == H5T_INTEGER || cl == H5T_FLOAT) {
693             parallel_print("<%s> has file datatype ", obj1_name);
694             print_type(f_tid1);
695             parallel_print("\n");
696             parallel_print("<%s> has file datatype ", obj2_name);
697             print_type(f_tid2);
698             parallel_print("\n");
699         }
700     }
701 
702     /*-------------------------------------------------------------------------
703      * check for the same rank
704      *-------------------------------------------------------------------------
705      */
706     if(rank1 != rank2) {
707         if((opts->m_verbose || opts->m_list_not_cmp) && obj1_name && obj2_name) {
708             parallel_print("Not comparable: <%s> has rank %d, dimensions ", obj1_name, rank1);
709             print_dimensions(rank1, dims1);
710             parallel_print(", max dimensions ");
711             print_dimensions(rank1, maxdim1);
712             parallel_print("\n" );
713             parallel_print("and <%s> has rank %d, dimensions ", obj2_name, rank2);
714             print_dimensions(rank2, dims2);
715             parallel_print(", max dimensions ");
716             print_dimensions(rank2, maxdim2);
717             parallel_print("\n");
718         }
719         opts->not_cmp = 1;
720         HGOTO_DONE(0);
721     }
722 
723     /*-------------------------------------------------------------------------
724      * check for different dimensions
725      *-------------------------------------------------------------------------
726      */
727     for(i = 0; i<rank1; i++) {
728         if(maxdim1 && maxdim2) {
729             if(maxdim1[i] != maxdim2[i])
730                 maxdim_diff = 1;
731         }
732         if(dims1[i] != dims2[i])
733             dim_diff = 1;
734     }
735 
736     /*-------------------------------------------------------------------------
737      * current dimensions
738      *-------------------------------------------------------------------------
739      */
740     if(dim_diff == 1) {
741         if((opts->m_verbose || opts->m_list_not_cmp) && obj1_name && obj2_name) {
742             parallel_print("Not comparable: <%s> has rank %d, dimensions ", obj1_name, rank1);
743             print_dimensions(rank1, dims1);
744             if(maxdim1 && maxdim2) {
745                 parallel_print(", max dimensions ");
746                 print_dimensions(rank1, maxdim1);
747                 parallel_print("\n" );
748                 parallel_print("and <%s> has rank %d, dimensions ", obj2_name, rank2);
749                 print_dimensions(rank2, dims2);
750                 parallel_print(", max dimensions ");
751                 print_dimensions(rank2, maxdim2);
752                 parallel_print("\n");
753             }
754         }
755         opts->not_cmp = 1;
756         HGOTO_DONE(0);
757     }
758 
759     /*-------------------------------------------------------------------------
760      * maximum dimensions; just give a warning
761      *-------------------------------------------------------------------------
762      */
763     if(maxdim1 && maxdim2 && maxdim_diff == 1 && obj1_name) {
764         if(opts->m_verbose) {
765             parallel_print( "Warning: different maximum dimensions\n");
766             parallel_print("<%s> has max dimensions ", obj1_name);
767             print_dimensions(rank1, maxdim1);
768             parallel_print("\n");
769             parallel_print("<%s> has max dimensions ", obj2_name);
770             print_dimensions(rank2, maxdim2);
771             parallel_print("\n");
772         }
773     }
774 
775     if(tclass1 == H5T_STRING) {
776         htri_t vstrtype1 = -1;
777         htri_t vstrtype2 = -1;
778         h5difftrace("diff_can_type end - H5T_STRING\n");
779 
780         vstrtype1 = H5Tis_variable_str(f_tid1);
781         vstrtype2 = H5Tis_variable_str(f_tid2);
782 
783         /* no compare if either one but not both are variable string type */
784         if (vstrtype1 != vstrtype2) {
785             if((opts->m_verbose || opts->m_list_not_cmp) && obj1_name && obj2_name)
786                 parallel_print("Not comparable: <%s> or <%s> is of mixed string type\n",
787                         obj1_name, obj2_name);
788             opts->not_cmp = 1;
789             HGOTO_DONE(0);
790         }
791     }
792 
793     if(tclass1 == H5T_COMPOUND) {
794         int   nmembs1;
795         int   nmembs2;
796         int   j;
797         hid_t memb_type1 = -1;
798         hid_t memb_type2 = -1;
799         h5difftrace("diff_can_type end - H5T_COMPOUND\n");
800 
801         nmembs1 = H5Tget_nmembers(f_tid1);
802         nmembs2 = H5Tget_nmembers(f_tid2);
803 
804         if(nmembs1 != nmembs2) {
805             if((opts->m_verbose || opts->m_list_not_cmp) && obj1_name && obj2_name) {
806                 parallel_print("Not comparable: <%s> has %d members ", obj1_name, nmembs1);
807                 parallel_print("<%s> has %d members ", obj2_name, nmembs2);
808                 parallel_print("\n");
809             }
810             opts->not_cmp = 1;
811             HGOTO_DONE(0);
812         }
813 
814         for (j = 0; j < nmembs1; j++) {
815             memb_type1 = H5Tget_member_type(f_tid1, (unsigned)j);
816             memb_type2 = H5Tget_member_type(f_tid2, (unsigned)j);
817 
818             if (diff_can_type(memb_type1, memb_type2, rank1, rank2,
819                     dims1, dims2, maxdim1, maxdim2, obj1_name, obj2_name,
820                     opts, 1) != 1) {
821                 opts->not_cmp = 1;
822                 H5Tclose(memb_type1);
823                 H5Tclose(memb_type2);
824                 HGOTO_DONE(0);
825             }
826             H5Tclose(memb_type1);
827             H5Tclose(memb_type2);
828         }
829     }
830 done:
831     if (ret_value < 0)
832         opts->err_stat = 1;
833 
834     h5diffdebug2("diff_can_type end - %d\n", ret_value);
835     return ret_value;
836 }
837 
838 
839 /*-------------------------------------------------------------------------
840  * Function: print_sizes
841  *
842  * Purpose: Print datatype sizes
843  *-------------------------------------------------------------------------
844  */
845 #if defined (H5DIFF_DEBUG)
print_sizes(const char * obj1,const char * obj2,hid_t f_tid1,hid_t f_tid2,hid_t m_tid1,hid_t m_tid2)846 void print_sizes( const char *obj1,
847                   const char *obj2,
848                   hid_t f_tid1,
849                   hid_t f_tid2,
850                   hid_t m_tid1,
851                   hid_t m_tid2 )
852 {
853     size_t  f_size1, f_size2;       /* size of type in file */
854     size_t  m_size1, m_size2;       /* size of type in memory */
855 
856     f_size1 = H5Tget_size( f_tid1 );
857     f_size2 = H5Tget_size( f_tid2 );
858     m_size1 = H5Tget_size( m_tid1 );
859     m_size2 = H5Tget_size( m_tid2 );
860 
861     parallel_print("\n");
862     parallel_print("------------------\n");
863     parallel_print("sizeof(char)   %u\n", sizeof(char) );
864     parallel_print("sizeof(short)  %u\n", sizeof(short) );
865     parallel_print("sizeof(int)    %u\n", sizeof(int) );
866     parallel_print("sizeof(long)   %u\n", sizeof(long) );
867     parallel_print("<%s> ------------------\n", obj1);
868     parallel_print("type on file   ");
869     print_type(f_tid1);
870     parallel_print("\n");
871     parallel_print("size on file   %u\n", f_size1 );
872 
873     parallel_print("type on memory ");
874     print_type(m_tid1);
875     parallel_print("\n");
876     parallel_print("size on memory %u\n", m_size1 );
877 
878     parallel_print("<%s> ------------------\n", obj2);
879     parallel_print("type on file   ");
880     print_type(f_tid2);
881     parallel_print("\n");
882     parallel_print("size on file   %u\n", f_size2 );
883 
884     parallel_print("type on memory ");
885     print_type(m_tid2);
886     parallel_print("\n");
887     parallel_print("size on memory %u\n", m_size2 );
888     parallel_print("\n");
889 }
890 #endif /* H5DIFF_DEBUG */
891