hdf5/testpar/API/H5_api_file_test_parallel.c

368 lines
10 KiB
C
Raw Normal View History

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Copyright by The HDF Group. *
* All rights reserved. *
* *
* This file is part of HDF5. The full HDF5 copyright notice, including *
* terms governing use, modification, and redistribution, is contained in *
* the COPYING file, which can be found at the root of the source code *
* distribution tree, or in https://www.hdfgroup.org/licenses. *
* If you do not have access to either file, you may request a copy from *
* help@hdfgroup.org. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "H5_api_file_test_parallel.h"
static int test_create_file(void);
static int test_open_file(void);
static int test_split_comm_file_access(void);
/*
* The array of parallel file tests to be performed.
*/
static int (*par_file_tests[])(void) = {
test_create_file,
test_open_file,
test_split_comm_file_access,
};
/*
* A test to ensure that a file can be created in parallel.
*/
#define FILE_CREATE_TEST_FILENAME "test_file_parallel.h5"
static int
test_create_file(void)
{
hid_t file_id = H5I_INVALID_HID;
hid_t fapl_id = H5I_INVALID_HID;
TESTING("H5Fcreate");
/* Make sure the connector supports the API functions being tested */
if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC)) {
SKIPPED();
printf(" API functions for basic file aren't supported with this connector\n");
return 0;
}
if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, true)) < 0)
TEST_ERROR;
if ((file_id = H5Fcreate(FILE_CREATE_TEST_FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0) {
H5_FAILED();
printf(" couldn't create file '%s'\n", FILE_CREATE_TEST_FILENAME);
goto error;
}
if (H5Pclose(fapl_id) < 0)
TEST_ERROR;
if (H5Fclose(file_id) < 0)
TEST_ERROR;
PASSED();
return 0;
error:
H5E_BEGIN_TRY
{
H5Pclose(fapl_id);
H5Fclose(file_id);
}
H5E_END_TRY
return 1;
}
/*
* A test to ensure that a file can be opened in parallel.
*/
static int
test_open_file(void)
{
hid_t file_id = H5I_INVALID_HID;
hid_t fapl_id = H5I_INVALID_HID;
TESTING_MULTIPART("H5Fopen");
/* Make sure the connector supports the API functions being tested */
if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC)) {
SKIPPED();
printf(" API functions for basic file aren't supported with this connector\n");
return 0;
}
TESTING_2("test setup");
if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, true)) < 0)
TEST_ERROR;
PASSED();
BEGIN_MULTIPART
{
PART_BEGIN(H5Fopen_rdonly)
{
TESTING_2("H5Fopen in read-only mode");
if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDONLY, fapl_id)) < 0) {
H5_FAILED();
printf(" unable to open file '%s' in read-only mode\n", H5_api_test_parallel_filename);
PART_ERROR(H5Fopen_rdonly);
}
PASSED();
}
PART_END(H5Fopen_rdonly);
if (file_id >= 0) {
H5E_BEGIN_TRY
{
H5Fclose(file_id);
}
H5E_END_TRY
file_id = H5I_INVALID_HID;
}
PART_BEGIN(H5Fopen_rdwrite)
{
TESTING_2("H5Fopen in read-write mode");
if ((file_id = H5Fopen(H5_api_test_parallel_filename, H5F_ACC_RDWR, fapl_id)) < 0) {
H5_FAILED();
printf(" unable to open file '%s' in read-write mode\n", H5_api_test_parallel_filename);
PART_ERROR(H5Fopen_rdwrite);
}
PASSED();
}
PART_END(H5Fopen_rdwrite);
if (file_id >= 0) {
H5E_BEGIN_TRY
{
H5Fclose(file_id);
}
H5E_END_TRY
file_id = H5I_INVALID_HID;
}
/*
* XXX: SWMR open flags
*/
}
END_MULTIPART;
TESTING_2("test cleanup");
if (H5Pclose(fapl_id) < 0)
TEST_ERROR;
PASSED();
return 0;
error:
H5E_BEGIN_TRY
{
H5Pclose(fapl_id);
H5Fclose(file_id);
}
H5E_END_TRY
return 1;
}
/*
* Tests file access by a communicator other than MPI_COMM_WORLD.
*
* Splits MPI_COMM_WORLD into two groups, where one (even_comm) contains
* the original processes of even ranks. The other (odd_comm) contains
* the original processes of odd ranks. Processes in even_comm create a
* file, then close it, using even_comm. Processes in old_comm just do
* a barrier using odd_comm. Then they all do a barrier using MPI_COMM_WORLD.
* If the file creation and close does not do correct collective action
* according to the communicator argument, the processes will freeze up
* sooner or later due to MPI_Barrier calls being mixed up.
*/
#define SPLIT_FILE_COMM_TEST_FILE_NAME "split_comm_file.h5"
static int
test_split_comm_file_access(void)
{
MPI_Comm comm;
MPI_Info info = MPI_INFO_NULL;
hid_t file_id = H5I_INVALID_HID;
hid_t fapl_id = H5I_INVALID_HID;
int is_old;
int newrank;
int err_occurred = 0;
TESTING("file access with a split communicator");
/* Make sure the connector supports the API functions being tested */
if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC)) {
SKIPPED();
printf(" API functions for basic file aren't supported with this connector\n");
return 0;
}
/* set up MPI parameters */
MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
is_old = mpi_rank % 2;
if (MPI_SUCCESS != MPI_Comm_split(MPI_COMM_WORLD, is_old, mpi_rank, &comm)) {
H5_FAILED();
printf(" failed to split communicator!\n");
goto error;
}
MPI_Comm_rank(comm, &newrank);
if (is_old) {
/* odd-rank processes */
if (MPI_SUCCESS != MPI_Barrier(comm)) {
err_occurred = 1;
goto access_end;
}
}
else {
/* even-rank processes */
int sub_mpi_rank; /* rank in the sub-comm */
MPI_Comm_rank(comm, &sub_mpi_rank);
/* setup file access template */
if ((fapl_id = create_mpi_fapl(comm, info, true)) < 0) {
err_occurred = 1;
goto access_end;
}
/* create the file collectively */
if ((file_id = H5Fcreate(SPLIT_FILE_COMM_TEST_FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id)) < 0) {
H5_FAILED();
printf(" couldn't create file '%s'\n", SPLIT_FILE_COMM_TEST_FILE_NAME);
err_occurred = 1;
goto access_end;
}
/* close the file */
if (H5Fclose(file_id) < 0) {
H5_FAILED();
printf(" failed to close file '%s'\n", SPLIT_FILE_COMM_TEST_FILE_NAME);
err_occurred = 1;
goto access_end;
}
/* delete the test file */
if (H5Fdelete(SPLIT_FILE_COMM_TEST_FILE_NAME, fapl_id) < 0) {
H5_FAILED();
printf(" failed to delete file '%s'\n", SPLIT_FILE_COMM_TEST_FILE_NAME);
err_occurred = 1;
goto access_end;
}
/* Release file-access template */
if (H5Pclose(fapl_id) < 0) {
err_occurred = 1;
goto access_end;
}
}
access_end:
/* Get the collective results about whether an error occurred */
if (MPI_SUCCESS != MPI_Allreduce(MPI_IN_PLACE, &err_occurred, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD)) {
H5_FAILED();
printf(" MPI_Allreduce failed\n");
goto error;
}
if (err_occurred) {
H5_FAILED();
printf(" an error occurred on only some ranks during split-communicator file access! - "
"collectively failing\n");
goto error;
}
if (MPI_SUCCESS != MPI_Comm_free(&comm)) {
H5_FAILED();
printf(" MPI_Comm_free failed\n");
goto error;
}
if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) {
H5_FAILED();
printf(" MPI_Barrier on MPI_COMM_WORLD failed\n");
goto error;
}
PASSED();
return 0;
error:
H5E_BEGIN_TRY
{
H5Pclose(fapl_id);
H5Fclose(file_id);
}
H5E_END_TRY
return 1;
}
/*
* Cleanup temporary test files
*/
static void
cleanup_files(void)
{
hid_t fapl_id = H5I_INVALID_HID;
if ((fapl_id = create_mpi_fapl(MPI_COMM_WORLD, MPI_INFO_NULL, true)) < 0) {
if (MAINPROCESS)
printf(" failed to create FAPL for deleting test files\n");
return;
}
H5Fdelete(FILE_CREATE_TEST_FILENAME, fapl_id);
/* The below file is deleted as part of the test */
/* H5Fdelete(SPLIT_FILE_COMM_TEST_FILE_NAME, H5P_DEFAULT); */
if (H5Pclose(fapl_id) < 0) {
if (MAINPROCESS)
printf(" failed to close FAPL used for deleting test files\n");
return;
}
}
int
H5_api_file_test_parallel(void)
{
size_t i;
int nerrors;
if (MAINPROCESS) {
printf("**********************************************\n");
printf("* *\n");
printf("* API Parallel File Tests *\n");
printf("* *\n");
printf("**********************************************\n\n");
}
for (i = 0, nerrors = 0; i < ARRAY_LENGTH(par_file_tests); i++) {
nerrors += (*par_file_tests[i])() ? 1 : 0;
if (MPI_SUCCESS != MPI_Barrier(MPI_COMM_WORLD)) {
if (MAINPROCESS)
printf(" MPI_Barrier() failed!\n");
}
}
if (MAINPROCESS) {
printf("\n");
printf("Cleaning up testing files\n");
}
cleanup_files();
return nerrors;
}