/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- * vim:expandtab:shiftwidth=8:tabstop=8: */ /******************************************************************************\ * * * Copyright (c) 2003, The Regents of the University of California * * See the file COPYRIGHT for a complete copyright notice and license. * * * ******************************************************************************** * * Implement abstract I/O interface for Parallel NetCDF (NCMPI). * \******************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include "ior.h" #include "iordef.h" #include "aiori.h" #include "utilities.h" #define NUM_DIMS 3 /* number of dimensions to data set */ /* * NCMPI_CHECK will display a custom error message and then exit the program */ #define NCMPI_CHECK(NCMPI_RETURN, MSG) do { \ \ if (NCMPI_RETURN < 0) { \ fprintf(stdout, "** error **\n"); \ fprintf(stdout, "ERROR in %s (line %d): %s.\n", \ __FILE__, __LINE__, MSG); \ fprintf(stdout, "ERROR: %s.\n", ncmpi_strerror(NCMPI_RETURN)); \ fprintf(stdout, "** exiting **\n"); \ exit(-1); \ } \ } while(0) /**************************** P R O T O T Y P E S *****************************/ static int GetFileMode(int flags); static aiori_fd_t *NCMPI_Create(char *, int iorflags, aiori_mod_opt_t *); static aiori_fd_t *NCMPI_Open(char *, int iorflags, aiori_mod_opt_t *); static IOR_offset_t NCMPI_Xfer(int, aiori_fd_t *, IOR_size_t *, IOR_offset_t, IOR_offset_t, aiori_mod_opt_t *); static void NCMPI_Close(aiori_fd_t *, aiori_mod_opt_t *); static void NCMPI_Delete(char *, aiori_mod_opt_t *); static char *NCMPI_GetVersion(); static void NCMPI_Fsync(aiori_fd_t *, aiori_mod_opt_t *); static IOR_offset_t NCMPI_GetFileSize(aiori_mod_opt_t *, char *); static int NCMPI_Access(const char *, int, aiori_mod_opt_t *); /************************** D E C L A R A T I O N S ***************************/ static aiori_xfer_hint_t * hints = NULL; static void NCMPI_xfer_hints(aiori_xfer_hint_t * params){ hints = params; MPIIO_xfer_hints(params); } typedef struct { int showHints; /* show hints */ char * hintsFileName; /* full name for hints file */ /* runtime variables */ int var_id; /* variable id handle for data set */ int firstReadCheck; int startDataSet; } ncmpi_options_t; static option_help * NCMPI_options(aiori_mod_opt_t ** init_backend_options, aiori_mod_opt_t * init_values){ ncmpi_options_t * o = malloc(sizeof(ncmpi_options_t)); if (init_values != NULL){ memcpy(o, init_values, sizeof(ncmpi_options_t)); }else{ memset(o, 0, sizeof(ncmpi_options_t)); } *init_backend_options = (aiori_mod_opt_t*) o; option_help h [] = { {0, "mpiio.hintsFileName","Full name for hints file", OPTION_OPTIONAL_ARGUMENT, 's', & o->hintsFileName}, {0, "mpiio.showHints", "Show MPI hints", OPTION_FLAG, 'd', & o->showHints}, LAST_OPTION }; option_help * help = malloc(sizeof(h)); memcpy(help, h, sizeof(h)); return help; } ior_aiori_t ncmpi_aiori = { .name = "NCMPI", .name_legacy = NULL, .create = NCMPI_Create, .open = NCMPI_Open, .xfer = NCMPI_Xfer, .close = NCMPI_Close, .delete = NCMPI_Delete, .get_version = NCMPI_GetVersion, .fsync = NCMPI_Fsync, .get_file_size = NCMPI_GetFileSize, .statfs = aiori_posix_statfs, .mkdir = aiori_posix_mkdir, .rmdir = aiori_posix_rmdir, .access = NCMPI_Access, .stat = aiori_posix_stat, .get_options = NCMPI_options, .xfer_hints = NCMPI_xfer_hints, }; /***************************** F U N C T I O N S ******************************/ /* * Create and open a file through the NCMPI interface. */ static aiori_fd_t *NCMPI_Create(char *testFileName, int iorflags, aiori_mod_opt_t * param) { int *fd; int fd_mode; MPI_Info mpiHints = MPI_INFO_NULL; ncmpi_options_t * o = (ncmpi_options_t*) param; /* read and set MPI file hints from hintsFile */ SetHints(&mpiHints, o->hintsFileName); if (rank == 0 && o->showHints) { fprintf(stdout, "\nhints passed to MPI_File_open() {\n"); ShowHints(&mpiHints); fprintf(stdout, "}\n"); } fd = (int *)malloc(sizeof(int)); if (fd == NULL) ERR("malloc() failed"); fd_mode = GetFileMode(iorflags); NCMPI_CHECK(ncmpi_create(testComm, testFileName, fd_mode, mpiHints, fd), "cannot create file"); /* free up the mpiHints object */ if (mpiHints != MPI_INFO_NULL) MPI_CHECK(MPI_Info_free(&mpiHints), "cannot free file info"); #if defined(PNETCDF_VERSION_MAJOR) && (PNETCDF_VERSION_MAJOR > 1 || PNETCDF_VERSION_MINOR >= 2) /* ncmpi_get_file_info is first available in 1.2.0 */ if (rank == 0 && o->showHints) { MPI_Info info_used; MPI_CHECK(ncmpi_get_file_info(*fd, &info_used), "cannot inquire file info"); /* print the MPI file hints currently used */ fprintf(stdout, "\nhints returned from opened file {\n"); ShowHints(&info_used); fprintf(stdout, "}\n"); MPI_CHECK(MPI_Info_free(&info_used), "cannot free file info"); } #endif return (aiori_fd_t*)(fd); } /* * Open a file through the NCMPI interface. */ static aiori_fd_t *NCMPI_Open(char *testFileName, int iorflags, aiori_mod_opt_t * param) { int *fd; int fd_mode; MPI_Info mpiHints = MPI_INFO_NULL; ncmpi_options_t * o = (ncmpi_options_t*) param; /* read and set MPI file hints from hintsFile */ SetHints(&mpiHints, o->hintsFileName); if (rank == 0 && o->showHints) { fprintf(stdout, "\nhints passed to MPI_File_open() {\n"); ShowHints(&mpiHints); fprintf(stdout, "}\n"); } fd = (int *)malloc(sizeof(int)); if (fd == NULL) ERR("malloc() failed"); fd_mode = GetFileMode(iorflags); NCMPI_CHECK(ncmpi_open(testComm, testFileName, fd_mode, mpiHints, fd), "cannot open file"); /* free up the mpiHints object */ if (mpiHints != MPI_INFO_NULL) MPI_CHECK(MPI_Info_free(&mpiHints), "cannot free file info"); #if defined(PNETCDF_VERSION_MAJOR) && (PNETCDF_VERSION_MAJOR > 1 || PNETCDF_VERSION_MINOR >= 2) /* ncmpi_get_file_info is first available in 1.2.0 */ if (rank == 0 && o->showHints) { MPI_Info info_used; MPI_CHECK(ncmpi_get_file_info(*fd, &info_used), "cannot inquire file info"); /* print the MPI file hints currently used */ fprintf(stdout, "\nhints returned from opened file {\n"); ShowHints(&info_used); fprintf(stdout, "}\n"); MPI_CHECK(MPI_Info_free(&info_used), "cannot free file info"); } #endif return (aiori_fd_t*)(fd); } /* * Write or read access to file using the NCMPI interface. */ static IOR_offset_t NCMPI_Xfer(int access, aiori_fd_t *fd, IOR_size_t * buffer, IOR_offset_t transferSize, IOR_offset_t offset, aiori_mod_opt_t * param) { signed char *bufferPtr = (signed char *)buffer; ncmpi_options_t * o = (ncmpi_options_t*) param; int var_id, dim_id[NUM_DIMS]; MPI_Offset bufSize[NUM_DIMS], offsets[NUM_DIMS]; IOR_offset_t segmentPosition; int segmentNum, transferNum; /* determine by offset if need to start data set */ if (hints->filePerProc == TRUE) { segmentPosition = (IOR_offset_t) 0; } else { segmentPosition = (IOR_offset_t) ((rank + rankOffset) % hints->numTasks) * hints->blockSize; } if ((int)(offset - segmentPosition) == 0) { o->startDataSet = TRUE; /* * 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) { o->firstReadCheck = ! o->firstReadCheck; } } if (o->startDataSet == TRUE && (access != READCHECK || o->firstReadCheck == TRUE)) { if (access == WRITE) { int numTransfers = hints->blockSize / hints->transferSize; /* reshape 1D array to 3D array: [segmentCount*numTasks][numTransfers][transferSize] Requirement: none of these dimensions should be > 4G, */ NCMPI_CHECK(ncmpi_def_dim (*(int *)fd, "segments_times_np", NC_UNLIMITED, &dim_id[0]), "cannot define data set dimensions"); NCMPI_CHECK(ncmpi_def_dim (*(int *)fd, "number_of_transfers", numTransfers, &dim_id[1]), "cannot define data set dimensions"); NCMPI_CHECK(ncmpi_def_dim (*(int *)fd, "transfer_size", hints->transferSize, &dim_id[2]), "cannot define data set dimensions"); NCMPI_CHECK(ncmpi_def_var (*(int *)fd, "data_var", NC_BYTE, NUM_DIMS, dim_id, &var_id), "cannot define data set variables"); NCMPI_CHECK(ncmpi_enddef(*(int *)fd), "cannot close data set define mode"); } else { NCMPI_CHECK(ncmpi_inq_varid (*(int *)fd, "data_var", &var_id), "cannot retrieve data set variable"); } if (hints->collective == FALSE) { NCMPI_CHECK(ncmpi_begin_indep_data(*(int *)fd), "cannot enable independent data mode"); } o->var_id = var_id; o->startDataSet = FALSE; } var_id = o->var_id; /* calculate the segment number */ segmentNum = offset / (hints->numTasks * hints->blockSize); /* calculate the transfer number in each block */ transferNum = offset % hints->blockSize / hints->transferSize; /* read/write the 3rd dim of the dataset, each is of amount param->transferSize */ bufSize[0] = 1; bufSize[1] = 1; bufSize[2] = transferSize; offsets[0] = segmentNum * hints->numTasks + rank; offsets[1] = transferNum; offsets[2] = 0; /* access the file */ if (access == WRITE) { /* WRITE */ if (hints->collective) { NCMPI_CHECK(ncmpi_put_vara_schar_all (*(int *)fd, var_id, offsets, bufSize, bufferPtr), "cannot write to data set"); } else { NCMPI_CHECK(ncmpi_put_vara_schar (*(int *)fd, var_id, offsets, bufSize, bufferPtr), "cannot write to data set"); } } else { /* READ or CHECK */ if (hints->collective == TRUE) { NCMPI_CHECK(ncmpi_get_vara_schar_all (*(int *)fd, var_id, offsets, bufSize, bufferPtr), "cannot read from data set"); } else { NCMPI_CHECK(ncmpi_get_vara_schar (*(int *)fd, var_id, offsets, bufSize, bufferPtr), "cannot read from data set"); } } return (transferSize); } /* * Perform fsync(). */ static void NCMPI_Fsync(aiori_fd_t *fd, aiori_mod_opt_t * param) { } /* * Close a file through the NCMPI interface. */ static void NCMPI_Close(aiori_fd_t *fd, aiori_mod_opt_t * param) { if (hints->collective == FALSE) { NCMPI_CHECK(ncmpi_end_indep_data(*(int *)fd), "cannot disable independent data mode"); } NCMPI_CHECK(ncmpi_close(*(int *)fd), "cannot close file"); free(fd); } /* * Delete a file through the NCMPI interface. */ static void NCMPI_Delete(char *testFileName, aiori_mod_opt_t * param) { return(MPIIO_Delete(testFileName, param)); } /* * Determine api version. */ static char* NCMPI_GetVersion() { return (char *)ncmpi_inq_libvers(); } /* * Return the correct file mode for NCMPI. */ static int GetFileMode(int flags) { int fd_mode = 0; /* set IOR file flags to NCMPI flags */ /* -- file open flags -- */ if (flags & IOR_RDONLY) { fd_mode |= NC_NOWRITE; } if (flags & IOR_WRONLY) { WARN("File write only not implemented in NCMPI"); } if (flags & IOR_RDWR) { fd_mode |= NC_WRITE; } if (flags & IOR_APPEND) { WARN("File append not implemented in NCMPI"); } if (flags & IOR_CREAT) { fd_mode |= NC_CLOBBER; } if (flags & IOR_EXCL) { WARN("Exclusive access not implemented in NCMPI"); } if (flags & IOR_TRUNC) { WARN("File truncation not implemented in NCMPI"); } if (flags & IOR_DIRECT) { WARN("O_DIRECT not implemented in NCMPI"); } /* to enable > 4GB file size */ fd_mode |= NC_64BIT_OFFSET; return (fd_mode); } /* * Use MPIIO call to get file size. */ static IOR_offset_t NCMPI_GetFileSize(aiori_mod_opt_t * opt, char *testFileName) { return(MPIIO_GetFileSize(opt, testFileName)); } /* * Use MPIIO call to check for access. */ static int NCMPI_Access(const char *path, int mode, aiori_mod_opt_t *param) { return(MPIIO_Access(path, mode, param)); }