Skip to content

Commit

Permalink
Restore rand_r in a few parallel tests (HDFGroup#4749)
Browse files Browse the repository at this point in the history
The t_pmulti_dset and t_select_io_dset tests rely on the behavior
of the previous private rand_r-like implementation to get the
correct sequence of random numbers to pass. This has been restored
using a fully private rand_r-like implementation that doesn't
rely on rand_r and will work on Windows and other platforms
where rand_r doesn't exist.
  • Loading branch information
derobins authored Aug 23, 2024
1 parent 9adacb5 commit 5c5b727
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 31 deletions.
21 changes: 21 additions & 0 deletions test/h5test.c
Original file line number Diff line number Diff line change
Expand Up @@ -2563,3 +2563,24 @@ h5_driver_uses_multiple_files(const char *drv_name, unsigned flags)

return ret_val;
}

/* Deterministic random number functions that don't modify the underlying
* C/POSIX library rand/random state, as this can cause spurious test failures.
*
* Adapted from the example code in the POSIX.1-2001 standard.
*/

static unsigned int next_g = 1;

int
h5_local_rand(void)
{
next_g = next_g * 1103515245 + 12345;
return next_g & RAND_MAX;
}

void
h5_local_srand(unsigned int seed)
{
next_g = seed;
}
8 changes: 8 additions & 0 deletions test/h5test.h
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,14 @@ H5TEST_DLL herr_t h5_using_parallel_driver(hid_t fapl_id, bool *driver_i
H5TEST_DLL herr_t h5_driver_is_default_vfd_compatible(hid_t fapl_id, bool *default_vfd_compatible);
H5TEST_DLL bool h5_driver_uses_multiple_files(const char *drv_name, unsigned flags);

/* Random number functions that don't modify the underlying rand/random state.
* These use rand_r with a state pointer under the hood. The state is always
* initialized to the same value so that each process in the parallel tests
* always gets the same sequence.
*/
H5TEST_DLL int h5_local_rand(void);
H5TEST_DLL void h5_local_srand(unsigned int seed);

/* Functions that will replace components of a FAPL */
H5TEST_DLL herr_t h5_get_vfd_fapl(hid_t fapl_id);
H5TEST_DLL herr_t h5_get_libver_fapl(hid_t fapl_id);
Expand Down
51 changes: 27 additions & 24 deletions testpar/t_pmulti_dset.c
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ test_pmdset(size_t niter, unsigned flags)
for (i = 0; i < niter; i++) {
/* Determine number of datasets */
ndsets = (flags & MDSET_FLAG_MLAYOUT) ? 3
: (flags & MDSET_FLAG_MDSET) ? (size_t)((size_t)rand() % max_dsets) + 1
: (flags & MDSET_FLAG_MDSET) ? (size_t)((size_t)h5_local_rand() % max_dsets) + 1
: 1;

/* Create file */
Expand All @@ -280,27 +280,27 @@ test_pmdset(size_t niter, unsigned flags)
(flags & MDSET_FLAG_CHUNK) || ((flags & MDSET_FLAG_MLAYOUT) && (j == 1 || j == 2));

/* Generate file dataspace */
dset_dims[j][0] = (hsize_t)((rand() % MAX_DSET_X) + 1);
dset_dims[j][1] = (hsize_t)((rand() % MAX_DSET_Y) + 1);
dset_dims[j][0] = (hsize_t)((h5_local_rand() % MAX_DSET_X) + 1);
dset_dims[j][1] = (hsize_t)((h5_local_rand() % MAX_DSET_Y) + 1);
if ((file_space_ids[j] = H5Screate_simple(2, dset_dims[j], use_chunk ? max_dims : NULL)) < 0)
T_PMD_ERROR;

/* Generate chunk if called for by configuration (multi layout uses chunked for datasets
* 1 and 2) */
if (use_chunk) {
chunk_dims[0] = (hsize_t)((rand() % MAX_CHUNK_X) + 1);
chunk_dims[1] = (hsize_t)((rand() % MAX_CHUNK_Y) + 1);
chunk_dims[0] = (hsize_t)((h5_local_rand() % MAX_CHUNK_X) + 1);
chunk_dims[1] = (hsize_t)((h5_local_rand() % MAX_CHUNK_Y) + 1);
if (H5Pset_chunk(dcpl_id[j], 2, chunk_dims) < 0)
T_PMD_ERROR;
} /* end if */

/* Create dataset */
/* If MDSET_FLAG_TCONV is set, use a different datatype with 50% probability, so
* some datasets require type conversion and others do not */
if ((dset_ids[j] =
H5Dcreate2(file_id, dset_name[j],
(flags & MDSET_FLAG_TCONV && rand() % 2) ? H5T_NATIVE_LONG : H5T_NATIVE_UINT,
file_space_ids[j], H5P_DEFAULT, dcpl_id[j], H5P_DEFAULT)) < 0)
if ((dset_ids[j] = H5Dcreate2(file_id, dset_name[j],
(flags & MDSET_FLAG_TCONV && h5_local_rand() % 2) ? H5T_NATIVE_LONG
: H5T_NATIVE_UINT,
file_space_ids[j], H5P_DEFAULT, dcpl_id[j], H5P_DEFAULT)) < 0)
T_PMD_ERROR;
} /* end for */

Expand All @@ -325,7 +325,7 @@ test_pmdset(size_t niter, unsigned flags)
/* Perform read/write operations */
for (j = 0; j < OPS_PER_FILE; j++) {
/* Decide whether to read or write */
do_read = (bool)(rand() % 2);
do_read = (bool)(h5_local_rand() % 2);

/* Barrier to ensure processes have finished the previous operation
*/
Expand Down Expand Up @@ -387,9 +387,9 @@ test_pmdset(size_t niter, unsigned flags)
(int)((unsigned)max_dsets * MAX_DSET_X * MAX_DSET_Y) * ((int)l - (int)mpi_rank);

/* Decide whether to do a hyperslab or point selection */
if (rand() % 2) {
if (h5_local_rand() % 2) {
/* Hyperslab */
size_t nhs = (size_t)((rand() % MAX_HS) + 1); /* Number of hyperslabs */
size_t nhs = (size_t)((h5_local_rand() % MAX_HS) + 1); /* Number of hyperslabs */
size_t max_hs_x = (MAX_HS_X <= dset_dims[k][0])
? MAX_HS_X
: dset_dims[k][0]; /* Determine maximum hyperslab size in X */
Expand All @@ -401,14 +401,16 @@ test_pmdset(size_t niter, unsigned flags)
overlap = true;
for (n = 0; overlap && (n < MAX_SEL_RETRIES); n++) {
/* Generate hyperslab */
count[m][0] = (hsize_t)(((hsize_t)rand() % max_hs_x) + 1);
count[m][1] = (hsize_t)(((hsize_t)rand() % max_hs_y) + 1);
start[m][0] = (count[m][0] == dset_dims[k][0])
? 0
: (hsize_t)rand() % (dset_dims[k][0] - count[m][0] + 1);
start[m][1] = (count[m][1] == dset_dims[k][1])
? 0
: (hsize_t)rand() % (dset_dims[k][1] - count[m][1] + 1);
count[m][0] = (hsize_t)(((hsize_t)h5_local_rand() % max_hs_x) + 1);
count[m][1] = (hsize_t)(((hsize_t)h5_local_rand() % max_hs_y) + 1);
start[m][0] =
(count[m][0] == dset_dims[k][0])
? 0
: (hsize_t)h5_local_rand() % (dset_dims[k][0] - count[m][0] + 1);
start[m][1] =
(count[m][1] == dset_dims[k][1])
? 0
: (hsize_t)h5_local_rand() % (dset_dims[k][1] - count[m][1] + 1);

/* If writing, check for overlap with other processes */
overlap = false;
Expand Down Expand Up @@ -460,7 +462,8 @@ test_pmdset(size_t niter, unsigned flags)
} /* end if */
else {
/* Point selection */
size_t npoints = (size_t)(((size_t)rand() % MAX_POINTS) + 1); /* Number of points */
size_t npoints =
(size_t)(((size_t)h5_local_rand() % MAX_POINTS) + 1); /* Number of points */

/* Reset dataset usage array if reading, since in this case we don't care
* about overlapping selections between processes */
Expand All @@ -472,8 +475,8 @@ test_pmdset(size_t niter, unsigned flags)
overlap = true;
for (n = 0; overlap && (n < MAX_SEL_RETRIES); n++) {
/* Generate point */
points[2 * m] = (unsigned)((hsize_t)rand() % dset_dims[k][0]);
points[(2 * m) + 1] = (unsigned)((hsize_t)rand() % dset_dims[k][1]);
points[2 * m] = (unsigned)((hsize_t)h5_local_rand() % dset_dims[k][0]);
points[(2 * m) + 1] = (unsigned)((hsize_t)h5_local_rand() % dset_dims[k][1]);

/* Check for overlap with other processes (write) or this process
* (always) */
Expand Down Expand Up @@ -664,7 +667,7 @@ main(int argc, char *argv[])

/* Seed random number generator with shared seed (so all ranks generate the
* same sequence) */
srand(seed);
h5_local_srand(seed);

/* Fill dset_name array */
for (i = 0; i < MAX_DSETS; i++) {
Expand Down
14 changes: 7 additions & 7 deletions testpar/t_select_io_dset.c
Original file line number Diff line number Diff line change
Expand Up @@ -1588,7 +1588,7 @@ test_multi_dsets_no_bkg(hid_t fid, unsigned chunked, unsigned dtrans, unsigned s
mwbuf ? "mwbuf" : "nomwbuf");

/* Flip a coin to see if we're doing type conversion */
tconv = rand() % 2;
tconv = h5_local_rand() % 2;
if (tconv)
any_tconv = true;

Expand Down Expand Up @@ -2079,7 +2079,7 @@ test_multi_dsets_cmpd_with_bkg(hid_t fid, unsigned chunked, unsigned select, uns
}

/* Case c */
mm = rand() % (int)ndsets;
mm = h5_local_rand() % (int)ndsets;
if (!mm)
mm++;

Expand Down Expand Up @@ -2719,9 +2719,9 @@ test_multi_dsets_conv_sel_empty(hid_t fid, unsigned chunked, unsigned dtrans, un
P_TEST_ERROR;
}
else {
if ((dset_dids[i] =
H5Dcreate2(fid, dset_names[i], ((rand() % 2) ? H5T_NATIVE_LLONG : H5T_NATIVE_SHORT),
file_sids[i], H5P_DEFAULT, dcpl, H5P_DEFAULT)) < 0)
if ((dset_dids[i] = H5Dcreate2(fid, dset_names[i],
((h5_local_rand() % 2) ? H5T_NATIVE_LLONG : H5T_NATIVE_SHORT),
file_sids[i], H5P_DEFAULT, dcpl, H5P_DEFAULT)) < 0)
P_TEST_ERROR;
}
}
Expand Down Expand Up @@ -2790,7 +2790,7 @@ test_multi_dsets_conv_sel_empty(hid_t fid, unsigned chunked, unsigned dtrans, un
* process 0: get 0 row; other processes: hyperslab
*/

mm = rand() % (int)ndsets;
mm = h5_local_rand() % (int)ndsets;
if (mm == 0)
mm++;

Expand Down Expand Up @@ -3169,7 +3169,7 @@ test_multi_dsets_all(int niter, hid_t fid, unsigned chunked, unsigned select, un
if ((mem_sids[i] = H5Screate_simple(1, block, NULL)) < 0)
P_TEST_ERROR;

mm = rand() % (int)ndsets;
mm = h5_local_rand() % (int)ndsets;
if (mm == 0) {
dset_types[i] = DSET_WITH_NO_CONV;
snprintf(dset_names[i], sizeof(dset_names[i]), "multi_all_nconv_dset%d_%s_%s_%s", i,
Expand Down

0 comments on commit 5c5b727

Please sign in to comment.