mdtest/src/C/aiori-HDF5.c

582 lines
22 KiB
C

/******************************************************************************\
* *
* Copyright (c) 2003, The Regents of the University of California *
* See the file COPYRIGHT for a complete copyright notice and license. *
* *
********************************************************************************
*
* CVS info:
* $RCSfile: aiori-HDF5.c,v $
* $Revision: 1.2 $
* $Date: 2008/12/02 17:12:14 $
* $Author: rklundt $
*
* Purpose:
* Implementation of abstract I/O interface for HDF5.
*
\******************************************************************************/
#include "aiori.h" /* abstract IOR interface */
#include <errno.h> /* sys_errlist */
#include <stdio.h> /* only for fprintf() */
#include <stdlib.h>
#include <sys/stat.h>
#include <hdf5.h>
#define NUM_DIMS 1 /* number of dimensions to data set */
/******************************************************************************/
/*
* HDF5_CHECK will display a custom error message and then exit the program
*/
/*
* should use MPI_Abort(), not exit(), in this macro; some versions of
* MPI, however, hang with HDF5 property lists et al. left unclosed
*/
/*
* for versions later than hdf5-1.6, the H5Eget_[major|minor]() functions
* have been deprecated and replaced with H5Eget_msg()
*/
#if H5_VERS_MAJOR > 1 && H5_VERS_MINOR > 6
#define HDF5_CHECK(HDF5_RETURN, MSG) do { \
char resultString[1024]; \
\
if (HDF5_RETURN < 0) { \
fprintf(stdout, "** error **\n"); \
fprintf(stdout, "ERROR in %s (line %d): %s.\n", \
__FILE__, __LINE__, MSG); \
strcpy(resultString, H5Eget_major((H5E_major_t)HDF5_RETURN)); \
if (strcmp(resultString, "Invalid major error number") != 0) \
fprintf(stdout, "HDF5 %s\n", resultString); \
strcpy(resultString, H5Eget_minor((H5E_minor_t)HDF5_RETURN)); \
if (strcmp(resultString, "Invalid minor error number") != 0) \
fprintf(stdout, "%s\n", resultString); \
fprintf(stdout, "** exiting **\n"); \
exit(-1); \
} \
} while(0)
#else /* ! (H5_VERS_MAJOR > 1 && H5_VERS_MINOR > 6) */
#define HDF5_CHECK(HDF5_RETURN, MSG) do { \
char resultString[1024]; \
\
if (HDF5_RETURN < 0) { \
fprintf(stdout, "** error **\n"); \
fprintf(stdout, "ERROR in %s (line %d): %s.\n", \
__FILE__, __LINE__, MSG); \
/* \
* H5Eget_msg(hid_t mesg_id, H5E_type_t* mesg_type, \
* char* mesg, size_t size) \
*/ \
fprintf(stdout, "** exiting **\n"); \
exit(-1); \
} \
} while(0)
#endif /* H5_VERS_MAJOR > 1 && H5_VERS_MINOR > 6 */
/**************************** P R O T O T Y P E S *****************************/
IOR_offset_t SeekOffset_HDF5 (void *, IOR_offset_t, IOR_param_t *);
void SetHints (MPI_Info *, char *);
void SetupDataSet_HDF5(void *, IOR_param_t *);
void ShowHints (MPI_Info *);
/************************** D E C L A R A T I O N S ***************************/
extern int errno, /* error number */
rank,
rankOffset,
verbose; /* verbose output */
extern MPI_Comm testComm;
static hid_t xferPropList; /* xfer property list */
hid_t dataSet; /* data set id */
hid_t dataSpace; /* data space id */
hid_t fileDataSpace; /* file data space id */
hid_t memDataSpace; /* memory data space id */
int newlyOpenedFile; /* newly opened file */
/***************************** F U N C T I O N S ******************************/
/******************************************************************************/
/*
* Create and open a file through the HDF5 interface.
*/
void *
IOR_Create_HDF5(char * testFileName,
IOR_param_t * param)
{
return IOR_Open_HDF5(testFileName, param);
} /* IOR_Create_HDF5() */
/******************************************************************************/
/*
* Open a file through the HDF5 interface.
*/
void *
IOR_Open_HDF5(char * testFileName,
IOR_param_t * param)
{
hid_t accessPropList,
createPropList;
hsize_t memStart[NUM_DIMS],
dataSetDims[NUM_DIMS],
memStride[NUM_DIMS],
memCount[NUM_DIMS],
memBlock[NUM_DIMS],
memDataSpaceDims[NUM_DIMS];
int tasksPerDataSet;
unsigned fd_mode = (unsigned)0;
hid_t *fd;
MPI_Comm comm;
MPI_Info mpiHints = MPI_INFO_NULL;
fd = (hid_t *)malloc(sizeof(hid_t));
if (fd == NULL) ERR("Unable to malloc file descriptor");
/*
* HDF5 uses different flags than those for POSIX/MPIIO
*/
if (param->open == WRITE) { /* WRITE flags */
param->openFlags = IOR_TRUNC;
} else { /* READ or check WRITE/READ flags */
param->openFlags = IOR_RDONLY;
}
/* set IOR file flags to HDF5 flags */
/* -- file open flags -- */
if (param->openFlags & IOR_RDONLY) {fd_mode |= H5F_ACC_RDONLY;}
if (param->openFlags & IOR_WRONLY) {
fprintf(stdout, "File write only not implemented in HDF5\n");
}
if (param->openFlags & IOR_RDWR) {fd_mode |= H5F_ACC_RDWR;}
if (param->openFlags & IOR_APPEND) {
fprintf(stdout, "File append not implemented in HDF5\n");
}
if (param->openFlags & IOR_CREAT) {fd_mode |= H5F_ACC_CREAT;}
if (param->openFlags & IOR_EXCL) {fd_mode |= H5F_ACC_EXCL;}
if (param->openFlags & IOR_TRUNC) {fd_mode |= H5F_ACC_TRUNC;}
if (param->openFlags & IOR_DIRECT) {
fprintf(stdout, "O_DIRECT not implemented in HDF5\n");
}
/* set up file creation property list */
createPropList = H5Pcreate(H5P_FILE_CREATE);
HDF5_CHECK(createPropList, "cannot create file creation property list");
/* set size of offset and length used to address HDF5 objects */
HDF5_CHECK(H5Pset_sizes(createPropList, sizeof(hsize_t), sizeof(hsize_t)),
"cannot set property list properly");
/* set up file access property list */
accessPropList = H5Pcreate(H5P_FILE_ACCESS);
HDF5_CHECK(accessPropList, "cannot create file access property list");
/*
* someday HDF5 implementation will allow subsets of MPI_COMM_WORLD
*/
/* store MPI communicator info for the file access property list */
if (param->filePerProc) {
comm = MPI_COMM_SELF;
} else {
comm = testComm;
}
SetHints(&mpiHints, param->hintsFileName);
/*
* note that with MP_HINTS_FILTERED=no, all key/value pairs will
* be in the info object. The info object that is attached to
* the file during MPI_File_open() will only contain those pairs
* deemed valid by the implementation.
*/
/* show hints passed to file */
if (rank == 0 && param->showHints) {
fprintf(stdout, "\nhints passed to access property list {\n");
ShowHints(&mpiHints);
fprintf(stdout, "}\n");
}
HDF5_CHECK(H5Pset_fapl_mpio(accessPropList, comm, mpiHints),
"cannot set file access property list");
/* set alignment */
HDF5_CHECK(H5Pset_alignment(accessPropList, param->setAlignment,
param->setAlignment), "cannot set alignment");
/* open file */
if (param->open == WRITE) { /* WRITE */
*fd = H5Fcreate(testFileName, fd_mode,
createPropList, accessPropList);
HDF5_CHECK(*fd, "cannot create file");
} else { /* READ or CHECK */
*fd = H5Fopen(testFileName, fd_mode, accessPropList);
HDF5_CHECK(*fd, "cannot open file");
}
/* show hints actually attached to file handle */
if (param->showHints || (1) /* WEL - this needs fixing */) {
if (rank == 0 && (param->showHints) /* WEL - this needs fixing */) {
WARN("showHints not working for HDF5");
}
} else {
MPI_Info mpiHintsCheck = MPI_INFO_NULL;
hid_t apl;
apl = H5Fget_access_plist(*fd);
HDF5_CHECK(H5Pget_fapl_mpio(apl, &comm, &mpiHintsCheck),
"cannot get info object through HDF5");
if (rank == 0) {
fprintf(stdout,
"\nhints returned from opened file (HDF5) {\n");
ShowHints(&mpiHintsCheck);
fprintf(stdout, "}\n");
if (1 == 1) { /* request the MPIIO file handle and its hints */
MPI_File * fd_mpiio;
HDF5_CHECK(H5Fget_vfd_handle(*fd, apl, (void **)&fd_mpiio),
"cannot get MPIIO file handle");
MPI_CHECK(MPI_File_get_info(*fd_mpiio, &mpiHintsCheck),
"cannot get info object through MPIIO");
fprintf(stdout,
"\nhints returned from opened file (MPIIO) {\n");
ShowHints(&mpiHintsCheck);
fprintf(stdout, "}\n");
}
}
MPI_CHECK(MPI_Barrier(testComm), "barrier error");
}
/* this is necessary for resetting various parameters
needed for reopening and checking the file */
newlyOpenedFile = TRUE;
HDF5_CHECK(H5Pclose(createPropList), "cannot close creation property list");
HDF5_CHECK(H5Pclose(accessPropList), "cannot close access property list");
/* create property list for serial/parallel access */
xferPropList = H5Pcreate(H5P_DATASET_XFER);
HDF5_CHECK(xferPropList, "cannot create transfer property list");
/* set data transfer mode */
if (param->collective) {
HDF5_CHECK(H5Pset_dxpl_mpio(xferPropList, H5FD_MPIO_COLLECTIVE),
"cannot set collective data transfer mode");
} else {
HDF5_CHECK(H5Pset_dxpl_mpio(xferPropList, H5FD_MPIO_INDEPENDENT),
"cannot set independent data transfer mode");
}
/* set up memory data space for transfer */
memStart[0] = (hsize_t)0;
memCount[0] = (hsize_t)1;
memStride[0] = (hsize_t)(param->transferSize / sizeof(IOR_size_t));
memBlock[0] = (hsize_t)(param->transferSize / sizeof(IOR_size_t));
memDataSpaceDims[0] = (hsize_t)param->transferSize;
memDataSpace = H5Screate_simple(NUM_DIMS, memDataSpaceDims, NULL);
HDF5_CHECK(memDataSpace, "cannot create simple memory data space");
/* define hyperslab for memory data space */
HDF5_CHECK(H5Sselect_hyperslab(memDataSpace, H5S_SELECT_SET,
memStart, memStride, memCount, memBlock),
"cannot create hyperslab");
/* set up parameters for fpp or different dataset count */
if (param->filePerProc) {
tasksPerDataSet = 1;
} else {
if (param->individualDataSets) {
/* each task in segment has single data set */
tasksPerDataSet = 1;
} else {
/* share single data set across all tasks in segment */
tasksPerDataSet = param->numTasks;
}
}
dataSetDims[0] = (hsize_t)((param->blockSize / sizeof(IOR_size_t))
* tasksPerDataSet);
/* create a simple data space containing information on size
and shape of data set, and open it for access */
dataSpace = H5Screate_simple(NUM_DIMS, dataSetDims, NULL);
HDF5_CHECK(dataSpace, "cannot create simple data space");
return(fd);
} /* IOR_Open_HDF5() */
/******************************************************************************/
/*
* Write or read access to file using the HDF5 interface.
*/
IOR_offset_t
IOR_Xfer_HDF5(int access,
void * fd,
IOR_size_t * buffer,
IOR_offset_t length,
IOR_param_t * param)
{
static int firstReadCheck = FALSE,
startNewDataSet;
IOR_offset_t segmentPosition,
segmentSize;
/*
* this toggle is for the read check operation, which passes through
* this function twice; note that this function will open a data set
* only on the first read check and close only on the second
*/
if (access == READCHECK) {
if (firstReadCheck == TRUE) {
firstReadCheck = FALSE;
} else {
firstReadCheck = TRUE;
}
}
/* determine by offset if need to start new data set */
if (param->filePerProc == TRUE) {
segmentPosition = (IOR_offset_t)0;
segmentSize = param->blockSize;
} else {
segmentPosition = (IOR_offset_t)((rank + rankOffset) % param->numTasks)
* param->blockSize;
segmentSize = (IOR_offset_t)(param->numTasks) * param->blockSize;
}
if ((IOR_offset_t)((param->offset - segmentPosition) % segmentSize) == 0) {
/*
* ordinarily start a new data set, unless this is the
* second pass through during a read check
*/
startNewDataSet = TRUE;
if (access == READCHECK && firstReadCheck != TRUE) {
startNewDataSet = FALSE;
}
}
/* create new data set */
if (startNewDataSet == TRUE) {
/* if just opened this file, no data set to close yet */
if (newlyOpenedFile != TRUE) {
HDF5_CHECK(H5Dclose(dataSet), "cannot close data set");
HDF5_CHECK(H5Sclose(fileDataSpace),
"cannot close file data space");
}
SetupDataSet_HDF5(fd, param);
}
SeekOffset_HDF5(fd, param->offset, param);
/* this is necessary to reset variables for reaccessing file */
startNewDataSet = FALSE;
newlyOpenedFile = FALSE;
/* access the file */
if (access == WRITE) { /* WRITE */
HDF5_CHECK(H5Dwrite(dataSet, H5T_NATIVE_LLONG,
memDataSpace, fileDataSpace,
xferPropList, buffer),
"cannot write to data set");
} else { /* READ or CHECK */
HDF5_CHECK(H5Dread(dataSet, H5T_NATIVE_LLONG,
memDataSpace, fileDataSpace,
xferPropList, buffer),
"cannot read from data set");
}
return(length);
} /* IOR_Xfer_HDF5() */
/******************************************************************************/
/*
* Perform fsync().
*/
void
IOR_Fsync_HDF5(void * fd, IOR_param_t * param)
{
;
} /* IOR_Fsync_HDF5() */
/******************************************************************************/
/*
* Close a file through the HDF5 interface.
*/
void
IOR_Close_HDF5(void * fd,
IOR_param_t * param)
{
if (param->fd_fppReadCheck == NULL) {
HDF5_CHECK(H5Dclose(dataSet), "cannot close data set");
HDF5_CHECK(H5Sclose(dataSpace), "cannot close data space");
HDF5_CHECK(H5Sclose(fileDataSpace), "cannot close file data space");
HDF5_CHECK(H5Sclose(memDataSpace), "cannot close memory data space");
HDF5_CHECK(H5Pclose(xferPropList),
" cannot close transfer property list");
}
HDF5_CHECK(H5Fclose(*(hid_t *)fd), "cannot close file");
free(fd);
} /* IOR_Close_HDF5() */
/******************************************************************************/
/*
* Delete a file through the HDF5 interface.
*/
void
IOR_Delete_HDF5(char * testFileName, IOR_param_t * param)
{
if (unlink(testFileName) != 0) WARN("cannot delete file");
} /* IOR_Delete_HDF5() */
/******************************************************************************/
/*
* Determine api version.
*/
void
IOR_SetVersion_HDF5(IOR_param_t *test)
{
unsigned major, minor, release;
if (H5get_libversion(&major, &minor, &release) < 0) {
WARN("cannot get HDF5 library version");
} else {
sprintf(test->apiVersion, "%s-%u.%u.%u",
test->api, major, minor, release);
}
#ifndef H5_HAVE_PARALLEL
strcat(test->apiVersion, " (Serial)");
#else /* H5_HAVE_PARALLEL */
strcat(test->apiVersion, " (Parallel)");
#endif /* not H5_HAVE_PARALLEL */
} /* IOR_SetVersion_HDF5() */
/************************ L O C A L F U N C T I O N S ***********************/
/******************************************************************************/
/*
* Seek to offset in file using the HDF5 interface and set up hyperslab.
*/
IOR_offset_t
SeekOffset_HDF5(void *fd,
IOR_offset_t offset,
IOR_param_t * param)
{
IOR_offset_t segmentSize;
hsize_t hsStride[NUM_DIMS],
hsCount[NUM_DIMS],
hsBlock[NUM_DIMS];
hsize_t hsStart[NUM_DIMS];
if (param->filePerProc == TRUE) {
segmentSize = (IOR_offset_t)param->blockSize;
} else {
segmentSize = (IOR_offset_t)(param->numTasks) * param->blockSize;
}
/* create a hyperslab representing the file data space */
if (param->individualDataSets) {
/* start at zero offset if not */
hsStart[0] = (hsize_t)((offset % param->blockSize)
/ sizeof(IOR_size_t));
} else {
/* start at a unique offset if shared */
hsStart[0] = (hsize_t)((offset % segmentSize) / sizeof(IOR_size_t));
}
hsCount[0] = (hsize_t)1;
hsStride[0] = (hsize_t)(param->transferSize / sizeof(IOR_size_t));
hsBlock[0] = (hsize_t)(param->transferSize / sizeof(IOR_size_t));
/* retrieve data space from data set for hyperslab */
fileDataSpace = H5Dget_space(dataSet);
HDF5_CHECK(fileDataSpace, "cannot get data space from data set");
HDF5_CHECK(H5Sselect_hyperslab(fileDataSpace, H5S_SELECT_SET,
hsStart, hsStride, hsCount, hsBlock),
"cannot select hyperslab");
return(offset);
} /* SeekOffset_HDF5() */
/******************************************************************************/
/*
* Create HDF5 data set.
*/
void
SetupDataSet_HDF5(void * fd,
IOR_param_t * param)
{
char dataSetName[MAX_STR];
hid_t dataSetPropList;
int dataSetID;
static int dataSetSuffix = 0;
/* may want to use an extendable dataset (H5S_UNLIMITED) someday */
/* may want to use a chunked dataset (H5S_CHUNKED) someday */
/* need to reset suffix counter if newly-opened file */
if (newlyOpenedFile) dataSetSuffix = 0;
/* may want to use individual access to each data set someday */
if (param->individualDataSets) {
dataSetID = (rank + rankOffset) % param->numTasks;
} else {
dataSetID = 0;
}
sprintf(dataSetName, "%s-%04d.%04d", "Dataset", dataSetID, dataSetSuffix++);
if (param->open == WRITE) { /* WRITE */
/* create data set */
dataSetPropList = H5Pcreate(H5P_DATASET_CREATE);
/* check if hdf5 available */
#if defined (H5_VERS_MAJOR) && defined (H5_VERS_MINOR)
/* no-fill option not available until hdf5-1.6.x */
#if (H5_VERS_MAJOR > 0 && H5_VERS_MINOR > 5)
if (param->noFill == TRUE) {
if (rank == 0 && verbose >= VERBOSE_1) {
fprintf(stdout, "\nusing 'no fill' option\n");
}
HDF5_CHECK(H5Pset_fill_time(dataSetPropList,
H5D_FILL_TIME_NEVER),
"cannot set fill time for property list");
}
#else
char errorString[MAX_STR];
sprintf(errorString, "'no fill' option not available in %s", test->apiVersion);
ERR(errorString);
#endif
#else
WARN("unable to determine HDF5 version for 'no fill' usage");
#endif
dataSet = H5Dcreate(*(hid_t *)fd, dataSetName, H5T_NATIVE_LLONG,
dataSpace, dataSetPropList);
HDF5_CHECK(dataSet, "cannot create data set");
} else { /* READ or CHECK */
dataSet = H5Dopen(*(hid_t *)fd, dataSetName);
HDF5_CHECK(dataSet, "cannot create data set");
}
} /* SetupDataSet_HDF5() */
/******************************************************************************/
/*
* Use MPIIO call to get file size.
*/
IOR_offset_t
IOR_GetFileSize_HDF5(IOR_param_t * test,
MPI_Comm testComm,
char * testFileName)
{
return(IOR_GetFileSize_MPIIO(test, testComm, testFileName));
} /* IOR_GetFileSize_HDF5() */