diff options
Diffstat (limited to 'testpar/API/t_chunk_alloc.c')
-rw-r--r-- | testpar/API/t_chunk_alloc.c | 512 |
1 files changed, 512 insertions, 0 deletions
diff --git a/testpar/API/t_chunk_alloc.c b/testpar/API/t_chunk_alloc.c new file mode 100644 index 0000000..dd78225 --- /dev/null +++ b/testpar/API/t_chunk_alloc.c @@ -0,0 +1,512 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * This verifies if the storage space allocation methods are compatible between + * serial and parallel modes. + * + * Created by: Christian Chilan and Albert Cheng + * Date: 2006/05/25 + */ + +#include "hdf5.h" +#include "testphdf5.h" +static int mpi_size, mpi_rank; + +#define DSET_NAME "ExtendibleArray" +#define CHUNK_SIZE 1000 /* #elements per chunk */ +#define CHUNK_FACTOR 200 /* default dataset size in terms of chunks */ +#define CLOSE 1 +#define NO_CLOSE 0 + +#if 0 +static MPI_Offset +get_filesize(const char *filename) +{ + int mpierr; + MPI_File fd; + MPI_Offset filesize; + + mpierr = MPI_File_open(MPI_COMM_SELF, filename, MPI_MODE_RDONLY, MPI_INFO_NULL, &fd); + VRFY((mpierr == MPI_SUCCESS), ""); + + mpierr = MPI_File_get_size(fd, &filesize); + VRFY((mpierr == MPI_SUCCESS), ""); + + mpierr = MPI_File_close(&fd); + VRFY((mpierr == MPI_SUCCESS), ""); + + return (filesize); +} +#endif + +typedef enum write_pattern { none, sec_last, all } write_type; + +typedef enum access_ { write_all, open_only, extend_only } access_type; + +/* + * This creates a dataset serially with chunks, each of CHUNK_SIZE + * elements. The allocation time is set to H5D_ALLOC_TIME_EARLY. Another + * routine will open this in parallel for extension test. + */ +static void +create_chunked_dataset(const char *filename, int chunk_factor, write_type write_pattern) +{ + hid_t file_id, dataset; /* handles */ + hid_t dataspace, memspace; + hid_t cparms; + hsize_t dims[1]; + hsize_t maxdims[1] = {H5S_UNLIMITED}; + + hsize_t chunk_dims[1] = {CHUNK_SIZE}; + hsize_t count[1]; + hsize_t stride[1]; + hsize_t block[1]; + hsize_t offset[1]; /* Selection offset within dataspace */ + /* Variables used in reading data back */ + char buffer[CHUNK_SIZE]; + long nchunks; + herr_t hrc; +#if 0 + MPI_Offset filesize, /* actual file size */ + est_filesize; /* estimated file size */ +#endif + /* set up MPI parameters */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Only MAINPROCESS should create the file. Others just wait. */ + if (MAINPROCESS) { + nchunks = chunk_factor * mpi_size; + dims[0] = (hsize_t)(nchunks * CHUNK_SIZE); + /* Create the data space with unlimited dimensions. */ + dataspace = H5Screate_simple(1, dims, maxdims); + VRFY((dataspace >= 0), ""); + + memspace = H5Screate_simple(1, chunk_dims, NULL); + VRFY((memspace >= 0), ""); + + /* Create a new file. If file exists its contents will be overwritten. */ + file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + VRFY((file_id >= 0), "H5Fcreate"); + + /* Modify dataset creation properties, i.e. enable chunking */ + cparms = H5Pcreate(H5P_DATASET_CREATE); + VRFY((cparms >= 0), ""); + + hrc = H5Pset_alloc_time(cparms, H5D_ALLOC_TIME_EARLY); + VRFY((hrc >= 0), ""); + + hrc = H5Pset_chunk(cparms, 1, chunk_dims); + VRFY((hrc >= 0), ""); + + /* Create a new dataset within the file using cparms creation properties. */ + dataset = + H5Dcreate2(file_id, DSET_NAME, H5T_NATIVE_UCHAR, dataspace, H5P_DEFAULT, cparms, H5P_DEFAULT); + VRFY((dataset >= 0), ""); + + if (write_pattern == sec_last) { + HDmemset(buffer, 100, CHUNK_SIZE); + + count[0] = 1; + stride[0] = 1; + block[0] = chunk_dims[0]; + offset[0] = (hsize_t)(nchunks - 2) * chunk_dims[0]; + + hrc = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, offset, stride, count, block); + VRFY((hrc >= 0), ""); + + /* Write sec_last chunk */ + hrc = H5Dwrite(dataset, H5T_NATIVE_UCHAR, memspace, dataspace, H5P_DEFAULT, buffer); + VRFY((hrc >= 0), "H5Dwrite"); + } /* end if */ + + /* Close resources */ + hrc = H5Dclose(dataset); + VRFY((hrc >= 0), ""); + dataset = -1; + + hrc = H5Sclose(dataspace); + VRFY((hrc >= 0), ""); + + hrc = H5Sclose(memspace); + VRFY((hrc >= 0), ""); + + hrc = H5Pclose(cparms); + VRFY((hrc >= 0), ""); + + hrc = H5Fclose(file_id); + VRFY((hrc >= 0), ""); + file_id = -1; + +#if 0 + /* verify file size */ + filesize = get_filesize(filename); + est_filesize = (MPI_Offset)nchunks * (MPI_Offset)CHUNK_SIZE * (MPI_Offset)sizeof(unsigned char); + VRFY((filesize >= est_filesize), "file size check"); +#endif + } + + /* Make sure all processes are done before exiting this routine. Otherwise, + * other tests may start and change the test data file before some processes + * of this test are still accessing the file. + */ + + MPI_Barrier(MPI_COMM_WORLD); +} + +/* + * This program performs three different types of parallel access. It writes on + * the entire dataset, it extends the dataset to nchunks*CHUNK_SIZE, and it only + * opens the dataset. At the end, it verifies the size of the dataset to be + * consistent with argument 'chunk_factor'. + */ +static void +parallel_access_dataset(const char *filename, int chunk_factor, access_type action, hid_t *file_id, + hid_t *dataset) +{ + /* HDF5 gubbins */ + hid_t memspace, dataspace; /* HDF5 file identifier */ + hid_t access_plist; /* HDF5 ID for file access property list */ + herr_t hrc; /* HDF5 return code */ + hsize_t size[1]; + + hsize_t chunk_dims[1] = {CHUNK_SIZE}; + hsize_t count[1]; + hsize_t stride[1]; + hsize_t block[1]; + hsize_t offset[1]; /* Selection offset within dataspace */ + hsize_t dims[1]; + hsize_t maxdims[1]; + + /* Variables used in reading data back */ + char buffer[CHUNK_SIZE]; + int i; + long nchunks; +#if 0 + /* MPI Gubbins */ + MPI_Offset filesize, /* actual file size */ + est_filesize; /* estimated file size */ +#endif + + /* Initialize MPI */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + nchunks = chunk_factor * mpi_size; + + /* Set up MPIO file access property lists */ + access_plist = H5Pcreate(H5P_FILE_ACCESS); + VRFY((access_plist >= 0), ""); + + hrc = H5Pset_fapl_mpio(access_plist, MPI_COMM_WORLD, MPI_INFO_NULL); + VRFY((hrc >= 0), ""); + + /* Open the file */ + if (*file_id < 0) { + *file_id = H5Fopen(filename, H5F_ACC_RDWR, access_plist); + VRFY((*file_id >= 0), ""); + } + + /* Open dataset*/ + if (*dataset < 0) { + *dataset = H5Dopen2(*file_id, DSET_NAME, H5P_DEFAULT); + VRFY((*dataset >= 0), ""); + } + + /* Make sure all processes are done before continuing. Otherwise, one + * process could change the dataset extent before another finishes opening + * it, resulting in only some of the processes calling H5Dset_extent(). */ + MPI_Barrier(MPI_COMM_WORLD); + + memspace = H5Screate_simple(1, chunk_dims, NULL); + VRFY((memspace >= 0), ""); + + dataspace = H5Dget_space(*dataset); + VRFY((dataspace >= 0), ""); + + size[0] = (hsize_t)nchunks * CHUNK_SIZE; + + switch (action) { + + /* all chunks are written by all the processes in an interleaved way*/ + case write_all: + + HDmemset(buffer, mpi_rank + 1, CHUNK_SIZE); + count[0] = 1; + stride[0] = 1; + block[0] = chunk_dims[0]; + for (i = 0; i < nchunks / mpi_size; i++) { + offset[0] = (hsize_t)(i * mpi_size + mpi_rank) * chunk_dims[0]; + + hrc = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, offset, stride, count, block); + VRFY((hrc >= 0), ""); + + /* Write the buffer out */ + hrc = H5Dwrite(*dataset, H5T_NATIVE_UCHAR, memspace, dataspace, H5P_DEFAULT, buffer); + VRFY((hrc >= 0), "H5Dwrite"); + } + + break; + + /* only extends the dataset */ + case extend_only: + /* check if new size is larger than old size */ + hrc = H5Sget_simple_extent_dims(dataspace, dims, maxdims); + VRFY((hrc >= 0), ""); + + /* Extend dataset*/ + if (size[0] > dims[0]) { + hrc = H5Dset_extent(*dataset, size); + VRFY((hrc >= 0), ""); + } + break; + + /* only opens the *dataset */ + case open_only: + break; + default: + HDassert(0); + } + + /* Close up */ + hrc = H5Dclose(*dataset); + VRFY((hrc >= 0), ""); + *dataset = -1; + + hrc = H5Sclose(dataspace); + VRFY((hrc >= 0), ""); + + hrc = H5Sclose(memspace); + VRFY((hrc >= 0), ""); + + hrc = H5Fclose(*file_id); + VRFY((hrc >= 0), ""); + *file_id = -1; + +#if 0 + /* verify file size */ + filesize = get_filesize(filename); + est_filesize = (MPI_Offset)nchunks * (MPI_Offset)CHUNK_SIZE * (MPI_Offset)sizeof(unsigned char); + VRFY((filesize >= est_filesize), "file size check"); +#endif + + /* Can close some plists */ + hrc = H5Pclose(access_plist); + VRFY((hrc >= 0), ""); + + /* Make sure all processes are done before exiting this routine. Otherwise, + * other tests may start and change the test data file before some processes + * of this test are still accessing the file. + */ + MPI_Barrier(MPI_COMM_WORLD); +} + +/* + * This routine verifies the data written in the dataset. It does one of the + * three cases according to the value of parameter `write_pattern'. + * 1. it returns correct fill values though the dataset has not been written; + * 2. it still returns correct fill values though only a small part is written; + * 3. it returns correct values when the whole dataset has been written in an + * interleaved pattern. + */ +static void +verify_data(const char *filename, int chunk_factor, write_type write_pattern, int vclose, hid_t *file_id, + hid_t *dataset) +{ + /* HDF5 gubbins */ + hid_t dataspace, memspace; /* HDF5 file identifier */ + hid_t access_plist; /* HDF5 ID for file access property list */ + herr_t hrc; /* HDF5 return code */ + + hsize_t chunk_dims[1] = {CHUNK_SIZE}; + hsize_t count[1]; + hsize_t stride[1]; + hsize_t block[1]; + hsize_t offset[1]; /* Selection offset within dataspace */ + /* Variables used in reading data back */ + char buffer[CHUNK_SIZE]; + int value, i; + int index_l; + long nchunks; + /* Initialize MPI */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + nchunks = chunk_factor * mpi_size; + + /* Set up MPIO file access property lists */ + access_plist = H5Pcreate(H5P_FILE_ACCESS); + VRFY((access_plist >= 0), ""); + + hrc = H5Pset_fapl_mpio(access_plist, MPI_COMM_WORLD, MPI_INFO_NULL); + VRFY((hrc >= 0), ""); + + /* Open the file */ + if (*file_id < 0) { + *file_id = H5Fopen(filename, H5F_ACC_RDWR, access_plist); + VRFY((*file_id >= 0), ""); + } + + /* Open dataset*/ + if (*dataset < 0) { + *dataset = H5Dopen2(*file_id, DSET_NAME, H5P_DEFAULT); + VRFY((*dataset >= 0), ""); + } + + memspace = H5Screate_simple(1, chunk_dims, NULL); + VRFY((memspace >= 0), ""); + + dataspace = H5Dget_space(*dataset); + VRFY((dataspace >= 0), ""); + + /* all processes check all chunks. */ + count[0] = 1; + stride[0] = 1; + block[0] = chunk_dims[0]; + for (i = 0; i < nchunks; i++) { + /* reset buffer values */ + HDmemset(buffer, -1, CHUNK_SIZE); + + offset[0] = (hsize_t)i * chunk_dims[0]; + + hrc = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, offset, stride, count, block); + VRFY((hrc >= 0), ""); + + /* Read the chunk */ + hrc = H5Dread(*dataset, H5T_NATIVE_UCHAR, memspace, dataspace, H5P_DEFAULT, buffer); + VRFY((hrc >= 0), "H5Dread"); + + /* set expected value according the write pattern */ + switch (write_pattern) { + case all: + value = i % mpi_size + 1; + break; + case none: + value = 0; + break; + case sec_last: + if (i == nchunks - 2) + value = 100; + else + value = 0; + break; + default: + HDassert(0); + } + + /* verify content of the chunk */ + for (index_l = 0; index_l < CHUNK_SIZE; index_l++) + VRFY((buffer[index_l] == value), "data verification"); + } + + hrc = H5Sclose(dataspace); + VRFY((hrc >= 0), ""); + + hrc = H5Sclose(memspace); + VRFY((hrc >= 0), ""); + + /* Can close some plists */ + hrc = H5Pclose(access_plist); + VRFY((hrc >= 0), ""); + + /* Close up */ + if (vclose) { + hrc = H5Dclose(*dataset); + VRFY((hrc >= 0), ""); + *dataset = -1; + + hrc = H5Fclose(*file_id); + VRFY((hrc >= 0), ""); + *file_id = -1; + } + + /* Make sure all processes are done before exiting this routine. Otherwise, + * other tests may start and change the test data file before some processes + * of this test are still accessing the file. + */ + MPI_Barrier(MPI_COMM_WORLD); +} + +/* + * Test following possible scenarios, + * Case 1: + * Sequential create a file and dataset with H5D_ALLOC_TIME_EARLY and large + * size, no write, close, reopen in parallel, read to verify all return + * the fill value. + * Case 2: + * Sequential create a file and dataset with H5D_ALLOC_TIME_EARLY but small + * size, no write, close, reopen in parallel, extend to large size, then close, + * then reopen in parallel and read to verify all return the fill value. + * Case 3: + * Sequential create a file and dataset with H5D_ALLOC_TIME_EARLY and large + * size, write just a small part of the dataset (second to the last), close, + * then reopen in parallel, read to verify all return the fill value except + * those small portion that has been written. Without closing it, writes + * all parts of the dataset in a interleave pattern, close it, and reopen + * it, read to verify all data are as written. + */ +void +test_chunk_alloc(void) +{ + const char *filename; + hid_t file_id, dataset; + + file_id = dataset = -1; + + /* Initialize MPI */ + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + + /* Make sure the connector supports the API functions being tested */ + if (!(vol_cap_flags_g & H5VL_CAP_FLAG_FILE_BASIC) || !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_BASIC) || + !(vol_cap_flags_g & H5VL_CAP_FLAG_DATASET_MORE)) { + if (MAINPROCESS) { + puts("SKIPPED"); + printf(" API functions for basic file, dataset, or dataset more aren't supported with this " + "connector\n"); + fflush(stdout); + } + + return; + } + + filename = (const char *)PARATESTFILE /* GetTestParameters() */; + if (VERBOSE_MED) + HDprintf("Extend Chunked allocation test on file %s\n", filename); + + /* Case 1 */ + /* Create chunked dataset without writing anything.*/ + create_chunked_dataset(filename, CHUNK_FACTOR, none); + /* reopen dataset in parallel and check for file size */ + parallel_access_dataset(filename, CHUNK_FACTOR, open_only, &file_id, &dataset); + /* reopen dataset in parallel, read and verify the data */ + verify_data(filename, CHUNK_FACTOR, none, CLOSE, &file_id, &dataset); + + /* Case 2 */ + /* Create chunked dataset without writing anything */ + create_chunked_dataset(filename, 20, none); + /* reopen dataset in parallel and only extend it */ + parallel_access_dataset(filename, CHUNK_FACTOR, extend_only, &file_id, &dataset); + /* reopen dataset in parallel, read and verify the data */ + verify_data(filename, CHUNK_FACTOR, none, CLOSE, &file_id, &dataset); + + /* Case 3 */ + /* Create chunked dataset and write in the second to last chunk */ + create_chunked_dataset(filename, CHUNK_FACTOR, sec_last); + /* Reopen dataset in parallel, read and verify the data. The file and dataset are not closed*/ + verify_data(filename, CHUNK_FACTOR, sec_last, NO_CLOSE, &file_id, &dataset); + /* All processes write in all the chunks in a interleaved way */ + parallel_access_dataset(filename, CHUNK_FACTOR, write_all, &file_id, &dataset); + /* reopen dataset in parallel, read and verify the data */ + verify_data(filename, CHUNK_FACTOR, all, CLOSE, &file_id, &dataset); +} |