Implement optimized support for vector I/O in Subfiling VFD (#3896)

Vector I/O requests are now processed within a single
set of I/O call batches, rather than each I/O vector
entry (tuple constructed from the types, addrs, sizes
and bufs arrays) being processed individually. This allows I/O to be
more efficiently parallelized among the I/O concentrator processes
during large I/O requests.

* Fixed some calculations and add test cases for issues spotted from review

* Removed a variable that was compensating for previous miscalculations
This commit is contained in:
jhendersonHDF 2023-12-27 16:28:41 -06:00 committed by GitHub
parent 695efa94df
commit 6ffc55c6d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 2219 additions and 1089 deletions

View File

@ -278,6 +278,16 @@ New Features
Library:
--------
- Implemented optimized support for vector I/O in the Subfiling VFD
Previously, the Subfiling VFD would handle vector I/O requests by
breaking them down into individual I/O requests, one for each entry
in the I/O vectors provided. This could result in poor I/O performance
for features in HDF5 that utilize vector I/O, such as parallel I/O
to filtered datasets. The Subfiling VFD now properly handles vector
I/O requests in their entirety, resulting in fewer I/O calls, improved
vector I/O performance and improved vector I/O memory efficiency.
- Added a simple cache to the read-only S3 (ros3) VFD
The read-only S3 VFD now caches the first N bytes of a file stored

View File

@ -1610,12 +1610,14 @@ H5FD__ioc_write_vector_internal(H5FD_t *_file, uint32_t count, H5FD_mem_t H5_ATT
H5FD_ioc_t *file_ptr = (H5FD_ioc_t *)_file;
io_req_t **sf_io_reqs = NULL;
int64_t sf_context_id = -1;
size_t io_size = 0;
bool extend_sizes = false;
herr_t ret_value = SUCCEED;
assert(_file);
assert(addrs);
assert(sizes);
assert(bufs);
assert((addrs) || (count == 0));
assert((sizes) || (count == 0));
assert((bufs) || (count == 0));
if (count == 0)
H5_SUBFILING_GOTO_DONE(SUCCEED);
@ -1648,12 +1650,22 @@ H5FD__ioc_write_vector_internal(H5FD_t *_file, uint32_t count, H5FD_mem_t H5_ATT
for (size_t i = 0; i < (size_t)count; i++) {
herr_t write_status;
if (sizes[i] == 0)
if (!extend_sizes) {
if ((i > 0) && (sizes[i] == 0)) {
extend_sizes = true;
io_size = sizes[i - 1];
}
else {
io_size = sizes[i];
}
}
if (io_size == 0)
H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "invalid size argument of 0");
H5_CHECK_OVERFLOW(addrs[i], haddr_t, int64_t);
H5_CHECK_OVERFLOW(sizes[i], size_t, int64_t);
write_status = ioc__write_independent_async(sf_context_id, (int64_t)addrs[i], (int64_t)sizes[i],
H5_CHECK_OVERFLOW(io_size, size_t, int64_t);
write_status = ioc__write_independent_async(sf_context_id, (int64_t)addrs[i], (int64_t)io_size,
bufs[i], &sf_io_reqs[i]);
if (write_status < 0)
@ -1691,12 +1703,14 @@ H5FD__ioc_read_vector_internal(H5FD_t *_file, uint32_t count, haddr_t addrs[], s
H5FD_ioc_t *file_ptr = (H5FD_ioc_t *)_file;
io_req_t **sf_io_reqs = NULL;
int64_t sf_context_id = -1;
size_t io_size = 0;
bool extend_sizes = false;
herr_t ret_value = SUCCEED;
assert(_file);
assert(addrs);
assert(sizes);
assert(bufs);
assert((addrs) || (count == 0));
assert((sizes) || (count == 0));
assert((bufs) || (count == 0));
if (count == 0)
H5_SUBFILING_GOTO_DONE(SUCCEED);
@ -1720,12 +1734,22 @@ H5FD__ioc_read_vector_internal(H5FD_t *_file, uint32_t count, haddr_t addrs[], s
H5_SUBFILING_GOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate MPI request array");
for (size_t i = 0; i < (size_t)count; i++) {
int read_status;
herr_t read_status;
if (!extend_sizes) {
if ((i > 0) && (sizes[i] == 0)) {
extend_sizes = true;
io_size = sizes[i - 1];
}
else {
io_size = sizes[i];
}
}
H5_CHECK_OVERFLOW(addrs[i], haddr_t, int64_t);
H5_CHECK_OVERFLOW(sizes[i], size_t, int64_t);
read_status = ioc__read_independent_async(sf_context_id, (int64_t)addrs[i], (int64_t)sizes[i],
bufs[i], &sf_io_reqs[i]);
H5_CHECK_OVERFLOW(io_size, size_t, int64_t);
read_status = ioc__read_independent_async(sf_context_id, (int64_t)addrs[i], (int64_t)io_size, bufs[i],
&sf_io_reqs[i]);
if (read_status < 0)
H5_SUBFILING_GOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "couldn't queue read operation");

View File

@ -297,9 +297,13 @@ ioc__read_independent_async(int64_t context_id, int64_t offset, int64_t elements
* unpredictable order. However, if some IOCs own more than
* 1 subfile, we need to associate each read with a unique
* message tag to make sure the data is received in the
* correct order.
* correct order. We also need a unique message tag in the
* case where only 1 subfile is used in total. In this case,
* vector I/O calls are passed directly down to this VFD without
* being split up into multiple I/O requests, so we need the
* tag to distinguish each I/O request.
*/
need_data_tag = num_subfiles != num_io_concentrators;
need_data_tag = (num_subfiles == 1) || (num_subfiles != num_io_concentrators);
if (!need_data_tag)
data_tag = READ_INDEP_DATA;

View File

@ -456,8 +456,9 @@ translate_opcode(io_op_t op)
case LOGGING_OP:
return "LOGGING_OP";
break;
default:
return "unknown";
}
return "unknown";
}
#endif
@ -873,9 +874,14 @@ ioc_file_queue_read_indep(sf_work_request_t *msg, int ioc_idx, int source, MPI_C
* unpredictable order. However, if some IOCs own more than
* 1 subfile, we need to associate each read with a unique
* message tag to make sure the data is received in the
* correct order.
* correct order. We also need a unique message tag in the
* case where only 1 subfile is used in total. In this case,
* vector I/O calls are passed directly down to this VFD without
* being split up into multiple I/O requests, so we need the
* tag to distinguish each I/O request.
*/
need_data_tag = sf_context->sf_num_subfiles != sf_context->topology->n_io_concentrators;
need_data_tag = (sf_context->sf_num_subfiles == 1) ||
(sf_context->sf_num_subfiles != sf_context->topology->n_io_concentrators);
if (!need_data_tag)
send_tag = READ_INDEP_DATA;

File diff suppressed because it is too large Load Diff

View File

@ -3151,6 +3151,39 @@ H5_subfiling_log(int64_t sf_context_id, const char *fmt, ...)
H5FD_ioc_end_thread_exclusive();
done:
va_end(log_args);
return;
}
void
H5_subfiling_log_nonewline(int64_t sf_context_id, const char *fmt, ...)
{
subfiling_context_t *sf_context = NULL;
va_list log_args;
va_start(log_args, fmt);
/* Retrieve the subfiling object for the newly-created context ID */
if (NULL == (sf_context = H5_get_subfiling_object(sf_context_id))) {
printf("%s: couldn't get subfiling object from context ID\n", __func__);
goto done;
}
H5FD_ioc_begin_thread_exclusive();
if (sf_context->sf_logfile) {
vfprintf(sf_context->sf_logfile, fmt, log_args);
fflush(sf_context->sf_logfile);
}
else {
vprintf(fmt, log_args);
fflush(stdout);
}
H5FD_ioc_end_thread_exclusive();
done:
va_end(log_args);

View File

@ -284,7 +284,10 @@ H5_DLL herr_t H5_subfiling_validate_config(const H5FD_subfiling_params_t *subf_c
H5_DLL herr_t H5_subfiling_terminate(void);
#ifdef H5_SUBFILING_DEBUG
H5_DLL void H5_subfiling_log(int64_t sf_context_id, const char *fmt, ...);
H5_DLL void H5_subfiling_log_nonewline(int64_t sf_context_id, const char *fmt, ...);
#endif
#ifdef __cplusplus
}

View File

@ -40,7 +40,7 @@
#define PATH_MAX 4096
#endif
#define DEFAULT_DEFLATE_LEVEL 9
#define DEFAULT_DEFLATE_LEVEL 4
#define ARRAY_SIZE(a) sizeof(a) / sizeof(a[0])
@ -99,6 +99,7 @@ static void test_create_and_close(void);
static void test_ioc_only_fail(void);
static void test_config_file(void);
static void test_stripe_sizes(void);
static void test_iovec_translation(void);
static void test_selection_strategies(void);
static void test_read_different_stripe_size(void);
static void test_subfiling_precreate_rank_0(void);
@ -111,6 +112,7 @@ static test_func tests[] = {
test_ioc_only_fail,
test_config_file,
test_stripe_sizes,
test_iovec_translation,
test_selection_strategies,
test_read_different_stripe_size,
test_subfiling_precreate_rank_0,
@ -887,6 +889,697 @@ test_stripe_sizes(void)
#undef SUBF_FILENAME
#undef SUBF_NITER
/*
* Test the I/O vector translation code by writing with some
* different specific I/O patterns
*/
#define SUBF_FILENAME "test_subfiling_iovec_translation.h5"
static void
test_iovec_translation(void)
{
H5FD_subfiling_params_t cfg;
const void *c_write_buf;
h5_stat_t file_info;
int64_t stripe_size;
haddr_t write_addr;
size_t nbytes;
size_t buf_size;
herr_t status;
hid_t file_id;
H5FD_t *file_ptr = NULL;
FILE *subfile_ptr = NULL;
void *write_buf = NULL;
void *read_buf = NULL;
char *tmp_filename = NULL;
hid_t dxpl_id = H5I_INVALID_HID;
hid_t fapl_id = H5I_INVALID_HID;
bool skip = false;
int num_subfiles;
int num_digits;
curr_nerrors = nerrors;
if (MAINPROCESS)
TESTING_2("I/O vector translation");
/*
* Don't run this test if subfiling configuration
* environment variables have been set since we
* want to use fixed configurations for testing.
*/
if (getenv(H5FD_SUBFILING_STRIPE_SIZE) || getenv(H5FD_SUBFILING_IOC_PER_NODE))
skip = true;
/* I/O only needs to be done from a single rank */
if (MAINPROCESS && !skip) {
/* Use a fixed configuration for these tests */
stripe_size = 1048576;
num_subfiles = 4;
num_digits = (int)(log10(num_subfiles) + 1);
/* Allocate enough buffer space for up to 2 "subfile blocks" of I/O */
buf_size = (size_t)(2 * stripe_size * num_subfiles);
write_buf = malloc(buf_size);
VRFY(write_buf, "malloc succeeded");
read_buf = malloc(buf_size);
VRFY(read_buf, "malloc succeeded");
c_write_buf = write_buf;
tmp_filename = malloc(PATH_MAX);
VRFY(tmp_filename, "malloc succeeded");
dxpl_id = H5Pcreate(H5P_DATASET_XFER);
VRFY((dxpl_id >= 0), "DXPL creation succeeded");
/* Set selection I/O mode on DXPL */
VRFY((H5Pset_selection_io(dxpl_id, H5D_SELECTION_IO_MODE_ON) >= 0), "H5Pset_selection_io succeeded");
cfg.ioc_selection = SELECT_IOC_ONE_PER_NODE;
cfg.stripe_size = stripe_size;
cfg.stripe_count = 4;
fapl_id = create_subfiling_ioc_fapl(MPI_COMM_SELF, MPI_INFO_NULL, true, &cfg,
H5FD_IOC_DEFAULT_THREAD_POOL_SIZE);
VRFY((fapl_id >= 0), "FAPL creation succeeded");
/* Set independent I/O on DXPL */
VRFY((H5Pset_dxpl_mpio(dxpl_id, H5FD_MPIO_INDEPENDENT) >= 0), "H5Pset_dxpl_mpio succeeded");
/*
* Test the case where the index value of the last subfile
* touched by I/O is greater than or equal to the index
* value of the first subfile touched by I/O, and this results
* in "thin" I/O segments directed to the subfiles with index
* values greater than the index values of the first and
* last subfiles. This might appear as the following I/O
* pattern:
*
* SUBFILE 0 SUBFILE 1 SUBFILE 2 SUBFILE 3
* _______________________________________________
* | XXXXX | XXXXX | XXXXX | XXXXX | ROW 0
* | XXXXX | XXXXX | | | ROW 1
* | | | | | ROW 2
* | | | | | ROW ...
* | | | | |
* | | | | |
* | | | | |
* |___________|___________|___________|___________|
*/
/* Create/truncate the file */
file_id = H5Fcreate(SUBF_FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
VRFY((file_id >= 0), "H5Fcreate succeeded");
VRFY((H5Fclose(file_id) >= 0), "H5Fclose succeeded");
/* Retrieve file info to get the file inode for later use */
VRFY((HDstat(SUBF_FILENAME, &file_info) >= 0), "HDstat succeeded");
/* Re-open file through H5FDopen for direct writes */
file_ptr = H5FDopen(SUBF_FILENAME, H5F_ACC_RDWR, fapl_id, HADDR_UNDEF);
VRFY(file_ptr, "H5FDopen succeeded");
nbytes = (size_t)(6 * stripe_size);
memset(write_buf, 255, nbytes);
memset(read_buf, 0, buf_size);
write_addr = 0;
/* Set EOA for following write call */
VRFY((H5FDset_eoa(file_ptr, H5FD_MEM_DEFAULT, write_addr + nbytes) >= 0), "H5FDset_eoa succeeded");
/* Write according to the above pattern */
status = H5FDwrite(file_ptr, H5FD_MEM_DRAW, dxpl_id, write_addr, nbytes, c_write_buf);
VRFY((status >= 0), "H5FDwrite succeeded");
/* Close and re-open the file */
VRFY((H5FDclose(file_ptr) >= 0), "H5FDclose succeeded");
file_ptr = H5FDopen(SUBF_FILENAME, H5F_ACC_RDWR, fapl_id, HADDR_UNDEF);
VRFY(file_ptr, "H5FDopen succeeded");
/*
* Set EOA for following read call (since we wrote over any
* superblock information in the file)
*/
VRFY((H5FDset_eoa(file_ptr, H5FD_MEM_DEFAULT, write_addr + nbytes) >= 0), "H5FDset_eoa succeeded");
/* Read the written bytes and verify */
status = H5FDread(file_ptr, H5FD_MEM_DRAW, dxpl_id, write_addr, nbytes, read_buf);
VRFY((status >= 0), "H5FDwrite succeeded");
VRFY((0 == memcmp(write_buf, read_buf, nbytes)), "memcmp succeeded");
/* Verify the size of each subfile */
for (int i = 0; i < num_subfiles; i++) {
h5_stat_size_t subfile_size;
h5_stat_t subfile_info;
snprintf(tmp_filename, PATH_MAX, H5FD_SUBFILING_FILENAME_TEMPLATE, SUBF_FILENAME,
(uint64_t)file_info.st_ino, num_digits, i + 1, num_subfiles);
/* Ensure file exists */
subfile_ptr = fopen(tmp_filename, "r");
VRFY(subfile_ptr, "fopen on subfile succeeded");
VRFY((fclose(subfile_ptr) >= 0), "fclose on subfile succeeded");
/* Check file size */
VRFY((HDstat(tmp_filename, &subfile_info) >= 0), "HDstat succeeded");
subfile_size = (h5_stat_size_t)subfile_info.st_size;
if (i <= 1) {
/*
* Subfiles with index values <= 1 should have full
* I/O segments (2 * stripe size) written to them.
*/
VRFY((subfile_size == 2 * cfg.stripe_size), "File size verification succeeded");
}
else {
/*
* Subfiles with index values > 1 should have "thin"
* I/O segments (1 * stripe size) written to them.
*/
VRFY((subfile_size == cfg.stripe_size), "File size verification succeeded");
}
}
/* Verify that there aren't too many subfiles */
snprintf(tmp_filename, PATH_MAX, H5FD_SUBFILING_FILENAME_TEMPLATE, SUBF_FILENAME,
(uint64_t)file_info.st_ino, num_digits, num_subfiles + 1, num_subfiles);
/* Ensure file doesn't exist */
subfile_ptr = fopen(tmp_filename, "r");
VRFY(subfile_ptr == NULL, "fopen on subfile correctly failed");
VRFY((H5FDclose(file_ptr) >= 0), "H5FDclose succeeded");
/*
* Test the case where the index value of the last subfile
* touched by I/O is greater than or equal to the index
* value of the first subfile touched by I/O, and this results
* in "thin" I/O segments directed to the subfiles with index
* values less than the index values of the first and
* last subfiles. This might appear as the following I/O
* pattern:
*
* SUBFILE 0 SUBFILE 1 SUBFILE 2 SUBFILE 3
* _______________________________________________
* | | XXXXX | XXXXX | XXXXX | ROW 0
* | XXXXX | XXXXX | XXXXX | XXXXX | ROW 1
* | | | | | ROW 2
* | | | | | ROW ...
* | | | | |
* | | | | |
* | | | | |
* |___________|___________|___________|___________|
*/
/* Create/truncate the file */
file_id = H5Fcreate(SUBF_FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
VRFY((file_id >= 0), "H5Fcreate succeeded");
VRFY((H5Fclose(file_id) >= 0), "H5Fclose succeeded");
/* Retrieve file info to get the file inode for later use */
VRFY((HDstat(SUBF_FILENAME, &file_info) >= 0), "HDstat succeeded");
/* Re-open file through H5FDopen for direct writes */
file_ptr = H5FDopen(SUBF_FILENAME, H5F_ACC_RDWR, fapl_id, HADDR_UNDEF);
VRFY(file_ptr, "H5FDopen succeeded");
nbytes = (size_t)(7 * stripe_size);
memset(write_buf, 255, nbytes);
memset(read_buf, 0, buf_size);
write_addr = (haddr_t)stripe_size;
/* Set EOA for following write call */
VRFY((H5FDset_eoa(file_ptr, H5FD_MEM_DEFAULT, write_addr + nbytes) >= 0), "H5FDset_eoa succeeded");
/* Write according to the above pattern */
status = H5FDwrite(file_ptr, H5FD_MEM_DRAW, dxpl_id, write_addr, nbytes, c_write_buf);
VRFY((status >= 0), "H5FDwrite succeeded");
/* Close and re-open the file */
VRFY((H5FDclose(file_ptr) >= 0), "H5FDclose succeeded");
file_ptr = H5FDopen(SUBF_FILENAME, H5F_ACC_RDWR, fapl_id, HADDR_UNDEF);
VRFY(file_ptr, "H5FDopen succeeded");
/*
* Set EOA for following read call (since we wrote over any
* superblock information in the file)
*/
VRFY((H5FDset_eoa(file_ptr, H5FD_MEM_DEFAULT, write_addr + nbytes) >= 0), "H5FDset_eoa succeeded");
/* Read the written bytes and verify */
status = H5FDread(file_ptr, H5FD_MEM_DRAW, dxpl_id, write_addr, nbytes, read_buf);
VRFY((status >= 0), "H5FDwrite succeeded");
VRFY((0 == memcmp(write_buf, read_buf, nbytes)), "memcmp succeeded");
/* Verify the size of each subfile */
for (int i = 0; i < num_subfiles; i++) {
h5_stat_size_t subfile_size;
h5_stat_t subfile_info;
snprintf(tmp_filename, PATH_MAX, H5FD_SUBFILING_FILENAME_TEMPLATE, SUBF_FILENAME,
(uint64_t)file_info.st_ino, num_digits, i + 1, num_subfiles);
/* Ensure file exists */
subfile_ptr = fopen(tmp_filename, "r");
VRFY(subfile_ptr, "fopen on subfile succeeded");
VRFY((fclose(subfile_ptr) >= 0), "fclose on subfile succeeded");
/* Check file size */
VRFY((HDstat(tmp_filename, &subfile_info) >= 0), "HDstat succeeded");
subfile_size = (h5_stat_size_t)subfile_info.st_size;
/*
* Every subfile should be (2 * stripe size) bytes due to
* space allocated in the file for subfile index 0
*/
VRFY((subfile_size == 2 * cfg.stripe_size), "File size verification succeeded");
}
/* Verify that there aren't too many subfiles */
snprintf(tmp_filename, PATH_MAX, H5FD_SUBFILING_FILENAME_TEMPLATE, SUBF_FILENAME,
(uint64_t)file_info.st_ino, num_digits, num_subfiles + 1, num_subfiles);
/* Ensure file doesn't exist */
subfile_ptr = fopen(tmp_filename, "r");
VRFY(subfile_ptr == NULL, "fopen on subfile correctly failed");
VRFY((H5FDclose(file_ptr) >= 0), "H5FDclose succeeded");
/*
* Test the case where the index value of the last subfile
* touched by I/O is less than the index value of the first
* subfile touched by I/O, and this results in "thin" I/O
* segments directed to the subfiles with index values that
* fall between the values of the first and last subfiles.
* This might appear as the following I/O pattern:
*
* SUBFILE 0 SUBFILE 1 SUBFILE 2 SUBFILE 3
* _______________________________________________
* | | | XXXXX | XXXXX | ROW 0
* | XXXXX | XXXXX | XXXXX | XXXXX | ROW 1
* | XXXXX | | | | ROW 2
* | | | | | ROW ...
* | | | | |
* | | | | |
* | | | | |
* |___________|___________|___________|___________|
*/
/* Create/truncate the file */
file_id = H5Fcreate(SUBF_FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
VRFY((file_id >= 0), "H5Fcreate succeeded");
VRFY((H5Fclose(file_id) >= 0), "H5Fclose succeeded");
/* Retrieve file info to get the file inode for later use */
VRFY((HDstat(SUBF_FILENAME, &file_info) >= 0), "HDstat succeeded");
/* Re-open file through H5FDopen for direct writes */
file_ptr = H5FDopen(SUBF_FILENAME, H5F_ACC_RDWR, fapl_id, HADDR_UNDEF);
VRFY(file_ptr, "H5FDopen succeeded");
nbytes = (size_t)(7 * stripe_size);
memset(write_buf, 255, nbytes);
memset(read_buf, 0, buf_size);
write_addr = (haddr_t)(2 * stripe_size);
/* Set EOA for following write call */
VRFY((H5FDset_eoa(file_ptr, H5FD_MEM_DEFAULT, write_addr + nbytes) >= 0), "H5FDset_eoa succeeded");
/* Write according to the above pattern */
status = H5FDwrite(file_ptr, H5FD_MEM_DRAW, dxpl_id, write_addr, nbytes, c_write_buf);
VRFY((status >= 0), "H5FDwrite succeeded");
/* Close and re-open the file */
VRFY((H5FDclose(file_ptr) >= 0), "H5FDclose succeeded");
file_ptr = H5FDopen(SUBF_FILENAME, H5F_ACC_RDWR, fapl_id, HADDR_UNDEF);
VRFY(file_ptr, "H5FDopen succeeded");
/*
* Set EOA for following read call (since we wrote over any
* superblock information in the file)
*/
VRFY((H5FDset_eoa(file_ptr, H5FD_MEM_DEFAULT, write_addr + nbytes) >= 0), "H5FDset_eoa succeeded");
/* Read the written bytes and verify */
status = H5FDread(file_ptr, H5FD_MEM_DRAW, dxpl_id, write_addr, nbytes, read_buf);
VRFY((status >= 0), "H5FDwrite succeeded");
VRFY((0 == memcmp(write_buf, read_buf, nbytes)), "memcmp succeeded");
/* Verify the size of each subfile */
for (int i = 0; i < num_subfiles; i++) {
h5_stat_size_t subfile_size;
h5_stat_t subfile_info;
snprintf(tmp_filename, PATH_MAX, H5FD_SUBFILING_FILENAME_TEMPLATE, SUBF_FILENAME,
(uint64_t)file_info.st_ino, num_digits, i + 1, num_subfiles);
/* Ensure file exists */
subfile_ptr = fopen(tmp_filename, "r");
VRFY(subfile_ptr, "fopen on subfile succeeded");
VRFY((fclose(subfile_ptr) >= 0), "fclose on subfile succeeded");
/* Check file size */
VRFY((HDstat(tmp_filename, &subfile_info) >= 0), "HDstat succeeded");
subfile_size = (h5_stat_size_t)subfile_info.st_size;
/*
* Subfile index 0 should be (3 * stripe size) bytes due to
* space allocated in the file, while others should be
* (2 * stripe size) bytes.
*/
if (i == 0) {
VRFY((subfile_size == 3 * cfg.stripe_size), "File size verification succeeded");
}
else {
VRFY((subfile_size == 2 * cfg.stripe_size), "File size verification succeeded");
}
}
/* Verify that there aren't too many subfiles */
snprintf(tmp_filename, PATH_MAX, H5FD_SUBFILING_FILENAME_TEMPLATE, SUBF_FILENAME,
(uint64_t)file_info.st_ino, num_digits, num_subfiles + 1, num_subfiles);
/* Ensure file doesn't exist */
subfile_ptr = fopen(tmp_filename, "r");
VRFY(subfile_ptr == NULL, "fopen on subfile correctly failed");
VRFY((H5FDclose(file_ptr) >= 0), "H5FDclose succeeded");
/*
* Test the case where I/O is 2 stripe sizes in total, but
* is offset from a stripe boundary by a single byte, causing
* the I/O to cross 3 subfiles.
*/
/* Create/truncate the file */
file_id = H5Fcreate(SUBF_FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
VRFY((file_id >= 0), "H5Fcreate succeeded");
VRFY((H5Fclose(file_id) >= 0), "H5Fclose succeeded");
/* Retrieve file info to get the file inode for later use */
VRFY((HDstat(SUBF_FILENAME, &file_info) >= 0), "HDstat succeeded");
/* Re-open file through H5FDopen for direct writes */
file_ptr = H5FDopen(SUBF_FILENAME, H5F_ACC_RDWR, fapl_id, HADDR_UNDEF);
VRFY(file_ptr, "H5FDopen succeeded");
nbytes = (size_t)(2 * stripe_size);
memset(write_buf, 255, nbytes);
memset(read_buf, 0, buf_size);
write_addr = (haddr_t)1;
/* Set EOA for following write call */
VRFY((H5FDset_eoa(file_ptr, H5FD_MEM_DEFAULT, write_addr + nbytes) >= 0), "H5FDset_eoa succeeded");
/* Write according to the above pattern */
status = H5FDwrite(file_ptr, H5FD_MEM_DRAW, dxpl_id, write_addr, nbytes, c_write_buf);
VRFY((status >= 0), "H5FDwrite succeeded");
/* Close and re-open the file */
VRFY((H5FDclose(file_ptr) >= 0), "H5FDclose succeeded");
file_ptr = H5FDopen(SUBF_FILENAME, H5F_ACC_RDWR, fapl_id, HADDR_UNDEF);
VRFY(file_ptr, "H5FDopen succeeded");
/*
* Set EOA for following read call (since we wrote over any
* superblock information in the file)
*/
VRFY((H5FDset_eoa(file_ptr, H5FD_MEM_DEFAULT, write_addr + nbytes) >= 0), "H5FDset_eoa succeeded");
/* Read the written bytes and verify */
status = H5FDread(file_ptr, H5FD_MEM_DRAW, dxpl_id, write_addr, nbytes, read_buf);
VRFY((status >= 0), "H5FDwrite succeeded");
VRFY((0 == memcmp(write_buf, read_buf, nbytes)), "memcmp succeeded");
/* Verify the size of each subfile */
for (int i = 0; i < num_subfiles; i++) {
h5_stat_size_t subfile_size;
h5_stat_t subfile_info;
snprintf(tmp_filename, PATH_MAX, H5FD_SUBFILING_FILENAME_TEMPLATE, SUBF_FILENAME,
(uint64_t)file_info.st_ino, num_digits, i + 1, num_subfiles);
/* Ensure file exists */
subfile_ptr = fopen(tmp_filename, "r");
VRFY(subfile_ptr, "fopen on subfile succeeded");
VRFY((fclose(subfile_ptr) >= 0), "fclose on subfile succeeded");
/* Check file size */
VRFY((HDstat(tmp_filename, &subfile_info) >= 0), "HDstat succeeded");
subfile_size = (h5_stat_size_t)subfile_info.st_size;
/*
* Subfiles indexed 0 and 1 should both be (1 * stripe size)
* bytes (Subfile index 0 was written to with an offset of 1
* byte, but that space will still be allocated in the file).
* Subfile index 2 should have a single byte written to it and
* Subfile index 3 should have nothing written to it.
*/
if (i == 2) {
VRFY((subfile_size == 1), "File size verification succeeded");
}
else if (i == 3) {
VRFY((subfile_size == 0), "File size verification succeeded");
}
else {
VRFY((subfile_size == cfg.stripe_size), "File size verification succeeded");
}
}
/* Verify that there aren't too many subfiles */
snprintf(tmp_filename, PATH_MAX, H5FD_SUBFILING_FILENAME_TEMPLATE, SUBF_FILENAME,
(uint64_t)file_info.st_ino, num_digits, num_subfiles + 1, num_subfiles);
/* Ensure file doesn't exist */
subfile_ptr = fopen(tmp_filename, "r");
VRFY(subfile_ptr == NULL, "fopen on subfile correctly failed");
VRFY((H5FDclose(file_ptr) >= 0), "H5FDclose succeeded");
/*
* Test the case where I/O is 2 stripe sizes in total, but
* is offset from a stripe boundary by (stripe size - 1) bytes,
* causing the I/O to start at the last byte of a subfile and
* cross 3 subfiles.
*/
/* Create/truncate the file */
file_id = H5Fcreate(SUBF_FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
VRFY((file_id >= 0), "H5Fcreate succeeded");
VRFY((H5Fclose(file_id) >= 0), "H5Fclose succeeded");
/* Retrieve file info to get the file inode for later use */
VRFY((HDstat(SUBF_FILENAME, &file_info) >= 0), "HDstat succeeded");
/* Re-open file through H5FDopen for direct writes */
file_ptr = H5FDopen(SUBF_FILENAME, H5F_ACC_RDWR, fapl_id, HADDR_UNDEF);
VRFY(file_ptr, "H5FDopen succeeded");
nbytes = (size_t)(2 * stripe_size);
memset(write_buf, 255, nbytes);
memset(read_buf, 0, buf_size);
write_addr = (haddr_t)(stripe_size - 1);
/* Set EOA for following write call */
VRFY((H5FDset_eoa(file_ptr, H5FD_MEM_DEFAULT, write_addr + nbytes) >= 0), "H5FDset_eoa succeeded");
/* Write according to the above pattern */
status = H5FDwrite(file_ptr, H5FD_MEM_DRAW, dxpl_id, write_addr, nbytes, c_write_buf);
VRFY((status >= 0), "H5FDwrite succeeded");
/* Close and re-open the file */
VRFY((H5FDclose(file_ptr) >= 0), "H5FDclose succeeded");
file_ptr = H5FDopen(SUBF_FILENAME, H5F_ACC_RDWR, fapl_id, HADDR_UNDEF);
VRFY(file_ptr, "H5FDopen succeeded");
/*
* Set EOA for following read call (since we wrote over any
* superblock information in the file)
*/
VRFY((H5FDset_eoa(file_ptr, H5FD_MEM_DEFAULT, write_addr + nbytes) >= 0), "H5FDset_eoa succeeded");
/* Read the written bytes and verify */
status = H5FDread(file_ptr, H5FD_MEM_DRAW, dxpl_id, write_addr, nbytes, read_buf);
VRFY((status >= 0), "H5FDwrite succeeded");
VRFY((0 == memcmp(write_buf, read_buf, nbytes)), "memcmp succeeded");
/* Verify the size of each subfile */
for (int i = 0; i < num_subfiles; i++) {
h5_stat_size_t subfile_size;
h5_stat_t subfile_info;
snprintf(tmp_filename, PATH_MAX, H5FD_SUBFILING_FILENAME_TEMPLATE, SUBF_FILENAME,
(uint64_t)file_info.st_ino, num_digits, i + 1, num_subfiles);
/* Ensure file exists */
subfile_ptr = fopen(tmp_filename, "r");
VRFY(subfile_ptr, "fopen on subfile succeeded");
VRFY((fclose(subfile_ptr) >= 0), "fclose on subfile succeeded");
/* Check file size */
VRFY((HDstat(tmp_filename, &subfile_info) >= 0), "HDstat succeeded");
subfile_size = (h5_stat_size_t)subfile_info.st_size;
/*
* Subfiles indexed 0 and 1 should both be (1 * stripe size)
* bytes (Subfile index 0 was written to with an offset of
* stripe size - 1 bytes, but that space will still be allocated
* in the file). Subfile index 2 should be (1 * stripe size) - 1
* bytes. Subfile index 3 should have nothing written to it.
*/
if (i == 2) {
VRFY((subfile_size == cfg.stripe_size - 1), "File size verification succeeded");
}
else if (i == 3) {
VRFY((subfile_size == 0), "File size verification succeeded");
}
else {
VRFY((subfile_size == cfg.stripe_size), "File size verification succeeded");
}
}
/* Verify that there aren't too many subfiles */
snprintf(tmp_filename, PATH_MAX, H5FD_SUBFILING_FILENAME_TEMPLATE, SUBF_FILENAME,
(uint64_t)file_info.st_ino, num_digits, num_subfiles + 1, num_subfiles);
/* Ensure file doesn't exist */
subfile_ptr = fopen(tmp_filename, "r");
VRFY(subfile_ptr == NULL, "fopen on subfile correctly failed");
VRFY((H5FDclose(file_ptr) >= 0), "H5FDclose succeeded");
/*
* Test the case where I/O is 2 stripe sizes + 1 byte in total
* and starts aligned to a stripe boundary, causing the I/O
* to cross 3 subfiles.
*/
/* Create/truncate the file */
file_id = H5Fcreate(SUBF_FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
VRFY((file_id >= 0), "H5Fcreate succeeded");
VRFY((H5Fclose(file_id) >= 0), "H5Fclose succeeded");
/* Retrieve file info to get the file inode for later use */
VRFY((HDstat(SUBF_FILENAME, &file_info) >= 0), "HDstat succeeded");
/* Re-open file through H5FDopen for direct writes */
file_ptr = H5FDopen(SUBF_FILENAME, H5F_ACC_RDWR, fapl_id, HADDR_UNDEF);
VRFY(file_ptr, "H5FDopen succeeded");
nbytes = (size_t)((2 * stripe_size) + 1);
memset(write_buf, 255, nbytes);
memset(read_buf, 0, buf_size);
write_addr = (haddr_t)0;
/* Set EOA for following write call */
VRFY((H5FDset_eoa(file_ptr, H5FD_MEM_DEFAULT, write_addr + nbytes) >= 0), "H5FDset_eoa succeeded");
/* Write according to the above pattern */
status = H5FDwrite(file_ptr, H5FD_MEM_DRAW, dxpl_id, write_addr, nbytes, c_write_buf);
VRFY((status >= 0), "H5FDwrite succeeded");
/* Close and re-open the file */
VRFY((H5FDclose(file_ptr) >= 0), "H5FDclose succeeded");
file_ptr = H5FDopen(SUBF_FILENAME, H5F_ACC_RDWR, fapl_id, HADDR_UNDEF);
VRFY(file_ptr, "H5FDopen succeeded");
/*
* Set EOA for following read call (since we wrote over any
* superblock information in the file)
*/
VRFY((H5FDset_eoa(file_ptr, H5FD_MEM_DEFAULT, write_addr + nbytes) >= 0), "H5FDset_eoa succeeded");
/* Read the written bytes and verify */
status = H5FDread(file_ptr, H5FD_MEM_DRAW, dxpl_id, write_addr, nbytes, read_buf);
VRFY((status >= 0), "H5FDwrite succeeded");
VRFY((0 == memcmp(write_buf, read_buf, nbytes)), "memcmp succeeded");
/* Verify the size of each subfile */
for (int i = 0; i < num_subfiles; i++) {
h5_stat_size_t subfile_size;
h5_stat_t subfile_info;
snprintf(tmp_filename, PATH_MAX, H5FD_SUBFILING_FILENAME_TEMPLATE, SUBF_FILENAME,
(uint64_t)file_info.st_ino, num_digits, i + 1, num_subfiles);
/* Ensure file exists */
subfile_ptr = fopen(tmp_filename, "r");
VRFY(subfile_ptr, "fopen on subfile succeeded");
VRFY((fclose(subfile_ptr) >= 0), "fclose on subfile succeeded");
/* Check file size */
VRFY((HDstat(tmp_filename, &subfile_info) >= 0), "HDstat succeeded");
subfile_size = (h5_stat_size_t)subfile_info.st_size;
/*
* Subfiles indexed 0 and 1 should both be (1 * stripe size)
* bytes. Subfile index 2 should have a single byte written to
* it and Subfile index 3 should have nothing written to it.
*/
if (i == 2) {
VRFY((subfile_size == 1), "File size verification succeeded");
}
else if (i == 3) {
VRFY((subfile_size == 0), "File size verification succeeded");
}
else {
VRFY((subfile_size == cfg.stripe_size), "File size verification succeeded");
}
}
/* Verify that there aren't too many subfiles */
snprintf(tmp_filename, PATH_MAX, H5FD_SUBFILING_FILENAME_TEMPLATE, SUBF_FILENAME,
(uint64_t)file_info.st_ino, num_digits, num_subfiles + 1, num_subfiles);
/* Ensure file doesn't exist */
subfile_ptr = fopen(tmp_filename, "r");
VRFY(subfile_ptr == NULL, "fopen on subfile correctly failed");
VRFY((H5FDclose(file_ptr) >= 0), "H5FDclose succeeded");
free(write_buf);
write_buf = NULL;
free(read_buf);
write_buf = NULL;
free(tmp_filename);
VRFY((H5Pclose(dxpl_id) >= 0), "DXPL close succeeded");
H5E_BEGIN_TRY
{
H5Fdelete(SUBF_FILENAME, fapl_id);
}
H5E_END_TRY
VRFY((H5Pclose(fapl_id) >= 0), "FAPL close succeeded");
}
mpi_code_g = MPI_Barrier(comm_g);
VRFY((mpi_code_g == MPI_SUCCESS), "MPI_Barrier succeeded");
if (skip) {
if (MAINPROCESS)
SKIPPED();
}
else
CHECK_PASSED();
}
#undef SUBF_FILENAME
/*
* Test the different I/O Concentator selection strategies
* for the Subfiling VFD
@ -2360,11 +3053,33 @@ main(int argc, char **argv)
if (MAINPROCESS)
puts("");
if (MAINPROCESS)
printf(" Re-running tests with compression enabled\n");
#ifdef H5_HAVE_FILTER_DEFLATE
enable_compression = true;
for (size_t i = 0; i < ARRAY_SIZE(tests); i++) {
if (MPI_SUCCESS == (mpi_code_g = MPI_Barrier(comm_g))) {
(*tests[i])();
}
else {
if (MAINPROCESS)
MESG("MPI_Barrier failed");
nerrors++;
}
}
enable_compression = false;
#else
if (MAINPROCESS)
SKIPPED();
#endif
/*
* Set any unset Subfiling environment variables and re-run
* the tests as a quick smoke check of whether those are
* working correctly
*/
if (stripe_size_g < 0) {
int64_t stripe_size;
char tmp[64];
@ -2487,26 +3202,6 @@ main(int argc, char **argv)
if (num_iocs_g > mpi_size)
num_iocs_g = mpi_size;
if (MAINPROCESS)
printf(" Re-running tests with compression enabled\n");
#ifdef H5_HAVE_FILTER_DEFLATE
enable_compression = true;
for (size_t i = 0; i < ARRAY_SIZE(tests); i++) {
if (MPI_SUCCESS == (mpi_code_g = MPI_Barrier(comm_g))) {
(*tests[i])();
}
else {
if (MAINPROCESS)
MESG("MPI_Barrier failed");
nerrors++;
}
}
enable_compression = false;
#else
if (MAINPROCESS)
SKIPPED();
#endif
if (MAINPROCESS)
printf("\nRe-running tests with environment variables set\n");
@ -2523,6 +3218,7 @@ main(int argc, char **argv)
if (MAINPROCESS)
printf("\n Re-running tests with compression enabled\n");
#ifdef H5_HAVE_FILTER_DEFLATE
enable_compression = true;
for (size_t i = 0; i < ARRAY_SIZE(tests); i++) {
@ -2540,6 +3236,7 @@ main(int argc, char **argv)
if (MAINPROCESS)
SKIPPED();
#endif
if (nerrors)
goto exit;