From 0a9939cad19530a076da9fe8f01ae0bb940509f2 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Sun, 29 Sep 2024 19:19:26 -0500 Subject: [PATCH 001/194] Adding a MT Queue and thread pool Adding a multithreaded queue and a thread pool. Also adding util functions to use the new thread pool for asynchronous tasks. These new capabilities are not used by the library right now (although some interfaces have been modified/added to support usage in future) Adding a thread pool for asynchronously processing async_op tasks. * Allows queuing async tasks of pio_async_op_t type * Leverages the Multi-threaded queue, PIO_mtq, to keep track of async ops * The instances of the thread pool is managed via a thread pool manager. * Currently the number of async threads is set to 1 * Also adding a simple unit test for the thread pool. Adding a multi-threaded queue that will be eventually used for queueing asynchronous I/O tasks. * Using C++11 threading framework and synchronization primitives to implement the multi-threaded queue. - Multiple threads can access the queue without any explicit synchronization (all required synchronization is handled by the queue) - Functions to enqueue/dequeue data in queue - Function to signal threads waiting on dequeuing data from the queue is also available (SIG_STOP : stop waiting on queue, SIG_COMPLETE : complete dequeing existing items and exit when when the queue is empty) - Function to provide size (instantaneous) of the queue Adding configure option PIO_USE_ASYNC_WR_THREAD to enable/disable asynchronous write threads Implementing the necessary framework to add asynchronous operations to a file or I/O system. Also adding unit tests for multithreaded queue & thread pool --- CMakeLists.txt | 5 + src/clib/CMakeLists.txt | 12 +- src/clib/pio.h | 97 +++ src/clib/pio_darray.cpp | 2 +- src/clib/pio_file.cpp | 22 + src/clib/pio_internal.h | 26 +- src/clib/pio_rearrange.cpp | 6 +- src/clib/pio_spmd.cpp | 96 +++ src/clib/spio_async_mtq.hpp | 167 +++++ src/clib/spio_async_tpool.cpp | 164 +++++ src/clib/spio_async_tpool.hpp | 38 ++ src/clib/spio_async_tpool_cint.h | 12 + src/clib/spio_async_utils.cpp | 932 ++++++++++++++++++++++++++ src/clib/spio_async_utils.hpp | 27 + tests/cunit/CMakeLists.txt | 13 + tests/cunit/test_async_mtq.cpp | 639 ++++++++++++++++++ tests/cunit/test_async_mtq_signal.cpp | 484 +++++++++++++ tests/cunit/test_async_tpool.cpp | 217 ++++++ tests/cunit/test_rearr.c | 9 +- 19 files changed, 2958 insertions(+), 10 deletions(-) create mode 100644 src/clib/spio_async_mtq.hpp create mode 100644 src/clib/spio_async_tpool.cpp create mode 100644 src/clib/spio_async_tpool.hpp create mode 100644 src/clib/spio_async_tpool_cint.h create mode 100644 src/clib/spio_async_utils.cpp create mode 100644 src/clib/spio_async_utils.hpp create mode 100644 tests/cunit/test_async_mtq.cpp create mode 100644 tests/cunit/test_async_mtq_signal.cpp create mode 100644 tests/cunit/test_async_tpool.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c50239e83c..dd2172f8fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,7 @@ option (PIO_USE_MALLOC "Use native malloc (instead of bget package)" OFF) option (PIO_USE_INDEP_MODE "Use PnetCDF independent data mode" ON) option (PIO_MICRO_TIMING "Enable internal micro timers" OFF) option (PIO_SAVE_DECOMPS "Dump the decomposition information" OFF) +option (PIO_USE_ASYNC_WR_THREAD "Use an asynchronous thread for writes (Requires C++11 support)" OFF) option (PIO_LIMIT_CACHED_IO_REGIONS "Limit the number of non-contiguous regions in an IO process" OFF) option (WITH_PNETCDF "Require the use of PnetCDF" ON) option (WITH_NETCDF "Require the use of NetCDF" ON) @@ -158,6 +159,10 @@ else() message (STATUS "Disabling saving I/O decompositions (default)") endif() +if(PIO_USE_ASYNC_WR_THREAD) + message(STATUS "Using asynchronous I/O thread for writes") +endif() + if(PIO_LIMIT_CACHED_IO_REGIONS) set(LIMIT_CACHED_IO_REGIONS 1) if(NOT DEFINED PIO_MAX_CACHED_IO_REGIONS) diff --git a/src/clib/CMakeLists.txt b/src/clib/CMakeLists.txt index 76c92f1937..39e38330b6 100644 --- a/src/clib/CMakeLists.txt +++ b/src/clib/CMakeLists.txt @@ -34,9 +34,8 @@ set (pio_api_src api/spio_put_varm_api.cpp api/spio_put_vars_api.cpp) - -# Add sources for libpioc.a -add_library (pioc ${pio_api_src} +# PIO lib source +set (pio_lib_src topology.cpp pio_mpi_timer.cpp pio_timer.cpp pio_file.cpp pioc_support.cpp pio_lists.cpp pio_print.cpp pioc.cpp pioc_sc.cpp pio_spmd.cpp pio_rearrange.cpp pio_nc4.cpp bget.cpp @@ -46,6 +45,13 @@ add_library (pioc ${pio_api_src} spio_tracer.cpp spio_tracer_mdata.cpp spio_tracer_decomp.cpp spio_rearrange_any.cpp) +if(PIO_USE_ASYNC_WR_THREAD) + list(APPEND pio_lib_src spio_async_tpool.cpp spio_async_utils.cpp) +endif() + +# Add sources for libpioc.a +add_library (pioc ${pio_api_src} ${pio_lib_src}) + #============================================================================== # FIND EXTERNAL LIBRARIES/DEPENDENCIES #============================================================================== diff --git a/src/clib/pio.h b/src/clib/pio.h index af0d35cc1c..477acd0195 100644 --- a/src/clib/pio.h +++ b/src/clib/pio.h @@ -336,6 +336,43 @@ typedef struct mtimer_info *mtimer_t; /* Forward decl of hash map used for ADIOS reads */ struct spio_hmap; +/* Fwd declaration to use back pointer to var_desc_t in viobuf_cache */ +struct var_desc_t; + +/** The viobuf_cache is used to cache the rearranged data for the + * variable. The iobuf inside the cache is freed when the data + * is written out. + */ +typedef struct viobuf_cache +{ + /* Pointer to user buffer, ubuf points to internal PIO + * buffer that caches the user data + */ + void *ubuf; + size_t ubuf_sz; + /* Pointer to buffer containing the rearranged data */ + void *iobuf; + size_t iobuf_sz; + /* Pointer to fillvalue for this iobuf */ + void *fillvalue; + size_t fillvalue_sz; + /* Variable record/frame number corresponding to this + * buffer. + * Note: Multiple frames for a variable can be cached + * at a time in a list of viobuf_cache s + */ + int rec_num; + /* Any outstanding request associated with this cache */ + /* Used to keep track of a write request for the iobuf */ + int req; + /* Back pointer to the var_desc that contains this cache */ + struct var_desc_t *vdesc; + /* The next iobuf cache for this variable, each iobuf + * cache corresponds to a record/frame of the variable + */ + struct viobuf_cache *next; +} viobuf_cache_t; + /** * Variable description structure. */ @@ -371,6 +408,11 @@ typedef struct var_desc_t /** Number of requests bending with pnetcdf. */ int nreqs; + /** Data buffers (to store rearranged data) for this var */ + /** Data buffers are stored in a singly linked list */ + viobuf_cache_t *viobuf_lhead; + viobuf_cache_t *viobuf_ltail; + /* Holds the fill value of this var. */ void *fillvalue; @@ -639,6 +681,42 @@ typedef struct io_desc_t struct io_desc_t *next; } io_desc_t; +/** + * PIO asynchronous operation types + */ +typedef enum pio_async_op_type +{ + PIO_ASYNC_INVALID_OP = 0, + PIO_ASYNC_REARR_OP, + PIO_ASYNC_PNETCDF_WRITE_OP, + PIO_ASYNC_FILE_WRITE_OPS, + PIO_ASYNC_NUM_OP_TYPES +} pio_async_op_type_t; + +/** + * PIO asynchronous op + */ +typedef struct pio_async_op +{ + pio_async_op_type_t op_type; + void *pdata; + /* Blocking wait function for this async op + * param 1 : A user defined data pointer + * return : PIO_NOERR on success, pio error code on failure + */ + int (*wait)(void *); + /* Non-blocking function for making progress on this async op + * param 1 : A user defined data pointer + * param 2 : Pointer to a flag that is set to true if async op + * is complete, false otherwise + * return : PIO_NOERR on success, pio error code on failure + */ + int (*poke)(void *, int *); + /* Free function for user defined pdata */ + void (*free)(void *); + struct pio_async_op *next; +} pio_async_op_t; + /* Forward decl for I/O file summary stats info */ struct spio_io_fstats_summary; @@ -788,6 +866,12 @@ typedef struct iosystem_desc_t /** I/O statistics associated with this I/O system */ struct spio_io_fstats_summary *io_fstats; + /* Number of pending async operations on this iosystem */ + int nasync_pend_ops; + + /* List of pending async operations on this iosystem */ + pio_async_op_t *async_pend_ops; + /** Pointer to the next iosystem_desc_t in the list. */ struct iosystem_desc_t *next; } iosystem_desc_t; @@ -1183,6 +1267,19 @@ typedef struct file_desc_t /** I/O statistics associated with this file */ struct spio_io_fstats_summary *io_fstats; + /* Number of pending async operations on this file */ + int nasync_pend_ops; + + /* List of pending async operations on this file */ + pio_async_op_t *async_pend_ops; + + /** Total number of pending ops on this file, including + * nasync_pend_ops. In the case where nasync_pend_ops == 0 + * npend_ops shows any other pending ops (e.g. non-blocking + * write done of rearranged data, still need to wait + * on it) */ + int npend_ops; + /** Pointer to the next file_desc_t in the list of open files. */ struct file_desc_t *next; diff --git a/src/clib/pio_darray.cpp b/src/clib/pio_darray.cpp index 0e84dfcb48..ef9e86bb89 100644 --- a/src/clib/pio_darray.cpp +++ b/src/clib/pio_darray.cpp @@ -384,7 +384,7 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar } /* Move data from compute to IO tasks. */ - if ((ierr = rearrange_comp2io(ios, iodesc, array, mv_iobuf, nvars))) + if ((ierr = rearrange_comp2io(ios, iodesc, file, array, mv_iobuf, nvars))) { GPTLstop("PIO:PIOc_write_darray_multi"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); diff --git a/src/clib/pio_file.cpp b/src/clib/pio_file.cpp index f71f42d60c..c9d2ba4b82 100644 --- a/src/clib/pio_file.cpp +++ b/src/clib/pio_file.cpp @@ -445,6 +445,28 @@ static int sync_file(int ncid) return PIO_NOERR; } +/* Close the file ("hard close") + * @param ios: Pointer to the iosystem_desc + * @param file: Pointer to the file_desc for the file + * @returns PIO_NOERR for success, a pio error code otherwise + */ +int PIO_hard_closefile(iosystem_desc_t *ios, file_desc_t *file, + bool sync_with_ioprocs) +{ + assert(0); +} + +/* "Soft close" the file + * The function assumes that only writes are pending on this file + * @param ios: Pointer to the iosystem_desc + * @param file: Pointer to the file_desc for the file + * @returns PIO_NOERR for success, a pio error code otherwise + */ +int PIO_soft_closefile(iosystem_desc_t *ios, file_desc_t *file) +{ + assert(0); +} + /** * Close a file previously opened with PIO. * diff --git a/src/clib/pio_internal.h b/src/clib/pio_internal.h index 78d3c2b276..c5cc734e51 100644 --- a/src/clib/pio_internal.h +++ b/src/clib/pio_internal.h @@ -70,6 +70,16 @@ extern "C" { bool isend; } pio_swapm_defaults; + /** swapm request */ + typedef struct pio_swapm_req + { + MPI_Request *rcvids; + int nrcvids; + + MPI_Request *sndids; + int nsndids; + } pio_swapm_req; + /* Handle an error in the PIO library. */ #ifdef __GNUC__ /* Specify that pio_err() uses printf style formatting. This @@ -128,6 +138,9 @@ extern "C" { int openfile_int(int iosysid, int *ncidp, int *iotype, const char *filename, int mode, int retry); + /* Close the file ("hard close") */ + int PIO_hard_closefile(iosystem_desc_t *ios, file_desc_t *file, bool sync_with_ioprocs); + iosystem_desc_t *pio_get_iosystem_from_id(int iosysid); int pio_add_to_iosystem_list(iosystem_desc_t *ios, MPI_Comm comm); @@ -180,6 +193,15 @@ extern "C" { void *recvbuf, const int *recvcounts, const int *rdispls, const MPI_Datatype *recvtypes, MPI_Comm comm, const rearr_comm_fc_opt_t *fc); + /* Non blocking wait for pio swapm user request */ + int pio_swapm_iwait(void *p, int *flag); + + /* Blocking wait for pio swapm user request */ + int pio_swapm_wait(void *p); + + /* Free a pio swapm request */ + void pio_swapm_req_free(void *p); + void PIO_Offset_size(MPI_Datatype *dtype, int *tsize); PIO_Offset GCDblocksize(int arrlen, const PIO_Offset *arr_in); @@ -228,8 +250,8 @@ extern "C" { int rearrange_io2comp(iosystem_desc_t *ios, io_desc_t *iodesc, const void *sbuf, void *rbuf); /* Move data from compute tasks to IO tasks. */ - int rearrange_comp2io(iosystem_desc_t *ios, io_desc_t *iodesc, const void *sbuf, void *rbuf, - int nvars); + int rearrange_comp2io(iosystem_desc_t *ios, io_desc_t *iodesc, file_desc_t *file, + const void *sbuf, void *rbuf, int nvars); /* Allocate and initialize storage for decomposition information. */ int malloc_iodesc(iosystem_desc_t *ios, int piotype, int ndims, io_desc_t **iodesc); diff --git a/src/clib/pio_rearrange.cpp b/src/clib/pio_rearrange.cpp index 89a51532b6..ad5b68125d 100644 --- a/src/clib/pio_rearrange.cpp +++ b/src/clib/pio_rearrange.cpp @@ -848,8 +848,8 @@ int compute_counts(iosystem_desc_t *ios, io_desc_t *iodesc, * @returns 0 on success, error code otherwise. * @author Jim Edwards */ -int rearrange_comp2io(iosystem_desc_t *ios, io_desc_t *iodesc, const void *sbuf, - void *rbuf, int nvars) +int rearrange_comp2io(iosystem_desc_t *ios, io_desc_t *iodesc, file_desc_t *file, + const void *sbuf, void *rbuf, int nvars) { int ntasks; /* Number of tasks in communicator. */ int niotasks; /* Number of IO tasks. */ @@ -2785,7 +2785,7 @@ void performance_tune_rearranger(iosystem_desc_t *ios, io_desc_t *iodesc) if ((mpierr = MPI_Barrier(mycomm))) return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); GPTLstamp(&wall[0], &usr[0], &sys[0]); - rearrange_comp2io(ios, iodesc, cbuf, ibuf, 1); + rearrange_comp2io(ios, iodesc, file, cbuf, ibuf, 1); rearrange_io2comp(ios, iodesc, ibuf, cbuf); GPTLstamp(&wall[1], &usr[1], &sys[1]); mintime = wall[1]-wall[0]; diff --git a/src/clib/pio_spmd.cpp b/src/clib/pio_spmd.cpp index 4ef329410b..6499c04314 100644 --- a/src/clib/pio_spmd.cpp +++ b/src/clib/pio_spmd.cpp @@ -465,6 +465,102 @@ int pio_swapm(const void *sendbuf, const int *sendcounts, const int *sdispls, co return PIO_NOERR; } +/** + * Non-blocking wait on swapm request + * @param p User swapm request (the request passed to pio_swapm() call) + * @param flag Pointer to a flag that holds the status of the user request. + * The flag is 0 if the request is pending and 1 if the request is completed + * @returns PIO_NOERR on success, a pio error code otherwise + * - Similar to MPI_Testall(), makes progress on all requests + */ +int pio_swapm_iwait(void *p, int *flag) +{ + pio_swapm_req *ureq = (pio_swapm_req *)p; + int mpierr; + + assert((ureq != NULL) && (flag != NULL)); + *flag = 1; + if(ureq->nrcvids != 0) + { + mpierr = MPI_Testall(ureq->nrcvids, ureq->rcvids, flag, MPI_STATUSES_IGNORE); + if(mpierr != MPI_SUCCESS) + { + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + + if(*flag == 1) + { + free(ureq->rcvids); + ureq->nrcvids = 0; + } + } + if(ureq->nsndids != 0) + { + mpierr = MPI_Testall(ureq->nsndids, ureq->sndids, flag, MPI_STATUSES_IGNORE); + if(mpierr != MPI_SUCCESS) + { + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + + if(*flag == 1) + { + free(ureq->sndids); + ureq->nsndids = 0; + } + } + return PIO_NOERR; +} + +/** + * Blocking wait on user swapm request + * @param p User swapm request (the request passed to pio_swapm() call) + * @returns PIO_NOERR on success, a pio error code otherwise + * - Similar to MPI_Waitall(), waits for the request to complete + */ +int pio_swapm_wait(void *p) +{ + pio_swapm_req *ureq = (pio_swapm_req *)p; + int mpierr; + + assert(ureq != NULL); + if(ureq->nrcvids != 0) + { + mpierr = MPI_Waitall(ureq->nrcvids, ureq->rcvids, MPI_STATUSES_IGNORE); + if(mpierr != MPI_SUCCESS) + { + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + + ureq->nrcvids = 0; + } + if(ureq->nsndids != 0) + { + mpierr = MPI_Waitall(ureq->nsndids, ureq->sndids, MPI_STATUSES_IGNORE); + if(mpierr != MPI_SUCCESS) + { + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + + ureq->nsndids = 0; + } + return PIO_NOERR; +} + +/* + * Free a pio swapm user request + * @param p pointer to the pio swapm user request + */ +void pio_swapm_req_free(void *p) +{ + pio_swapm_req *ureq = (pio_swapm_req *)p; + if(ureq != NULL) + { + free(ureq->rcvids); + free(ureq->sndids); + free(ureq); + } +} + /** * Provides the functionality of MPI_Gatherv with flow control * options. This function is not currently used, but we hope it will diff --git a/src/clib/spio_async_mtq.hpp b/src/clib/spio_async_mtq.hpp new file mode 100644 index 0000000000..9c83987b5b --- /dev/null +++ b/src/clib/spio_async_mtq.hpp @@ -0,0 +1,167 @@ +#ifndef _SPIO_ASYNC_MTQ_HPP_ +#define _SPIO_ASYNC_MTQ_HPP_ + +#include +#include +#include +#include +#include +#include +extern "C"{ +#include "pio_internal.h" +} // extern "C" + +namespace PIO_Util{ + +template +class PIO_mtq{ + public: + typedef enum SigTypes{ + PIO_MTQ_SIG_INVALID=1, + /* Stop processing elements in the queue */ + PIO_MTQ_SIG_STOP, + /* Complete processing elements in queue and quit */ + PIO_MTQ_SIG_COMPLETE + }SigTypes_t; + PIO_mtq(); + void enqueue(const T& val); + int dequeue(T &val); + void signal(SigTypes_t sig); + int size(void ) const; + + template + friend std::ostream & operator<<(std::ostream &ostr, PIO_mtq &mtq); + private: + void thread_yield(std::unique_lock &lk) const; + std::mutex mtx_; + std::queue queue_; + std::condition_variable cv_; + SigTypes_t sig_; + std::condition_variable cv_sig_; +}; + +template +PIO_mtq::PIO_mtq():sig_(PIO_mtq::PIO_MTQ_SIG_INVALID) +{ + LOG((2, "PIO_mtq:PIO_mtq: Creating MT queue")); +} + +template +void PIO_mtq::enqueue(const T& val) +{ + std::unique_lock lk(mtx_); + LOG((2, "PIO_mtq:enqueue: Enqueing val to mtq")); + queue_.push(val); + lk.unlock(); + cv_.notify_all(); +} + +template +int PIO_mtq::dequeue(T &val) +{ + std::unique_lock lk(mtx_); + do{ + LOG((2, "PIO_mtq:dequeue: Waiting for dequeueing val from mtq...")); + while(queue_.empty() && (sig_ == PIO_MTQ_SIG_INVALID)){ + cv_.wait(lk, [this]{ return (queue_.empty() && (sig_ == PIO_MTQ_SIG_INVALID));}); + /* + cv_.wait_for(lk, DEFAULT_TIMEOUT, + [this]{ return (queue_.empty() && (sig_ == PIO_MTQ_SIG_INVALID));}); + */ + /* At least on Linux (Ubuntu 4.5.0-040500-generic) just waiting on the condition + * variable (with/without timeouts) does not allow other threads to acquire + * the lock. So we explicitly unlock, sleep for 0 seconds and reacquire the + * lock to allow other threads to be able to get scheduled and acquire the lock + */ + thread_yield(lk); + } + if(sig_ == PIO_MTQ_SIG_STOP){ + LOG((2, "PIO_mtq:dequeue: Received STOP signal on mtq (exiting...)")); + return 1; + } + else if(sig_ == PIO_MTQ_SIG_COMPLETE){ + if(queue_.empty()){ + /* Reset signal */ + sig_ = PIO_MTQ_SIG_INVALID; + lk.unlock(); + /* Notify threads that all async ops are complete */ + cv_sig_.notify_all(); + lk.lock(); + } + else{ + break; + } + } + else{ + break; + } + }while(true); + val = queue_.front(); + queue_.pop(); + LOG((2, "PIO_mtq:dequeue: Successfully dequeued val from mtq")); + lk.unlock(); + return 0; +} + +template +void PIO_mtq::signal(PIO_mtq::SigTypes_t sig) +{ + std::unique_lock lk(mtx_); + sig_ = sig; + lk.unlock(); + cv_.notify_all(); + + lk.lock(); + if(sig == PIO_MTQ_SIG_COMPLETE){ + LOG((2, "PIO_mtq:signal: Received PIO_MTQ_SIG_COMPLETE, Waiting for async ops to complete")); + /* Wait for all async ops in the queue to complete */ + while(sig_ == PIO_MTQ_SIG_COMPLETE){ + cv_sig_.wait(lk, [this]{ return (sig_ == PIO_MTQ_SIG_COMPLETE);}); + thread_yield(lk); + } + } + lk.unlock(); +} + +template +int PIO_mtq::size(void ) const +{ + int sz = 0; + std::unique_lock lk(mtx_); + sz = queue_.size(); + lk.unlock(); + return sz; +} + +template +void PIO_mtq::thread_yield(std::unique_lock &lk) const +{ + /* At least on Linux (Ubuntu 4.5.0-040500-generic) just waiting on the condition + * variable (with/without timeouts) does not allow other threads to acquire + * the lock. So we explicitly unlock, sleep for 0 seconds and reacquire the + * lock to allow other threads to be able to get scheduled and acquire the lock + */ + const std::chrono::milliseconds ZERO_TIMEOUT = std::chrono::milliseconds(0); + lk.unlock(); + //LOG((2, "PIO_mtq:thread_yield: Yielding for 0 secs")); + std::this_thread::sleep_for(ZERO_TIMEOUT); + lk.lock(); +} + +template +std::ostream &operator<<(std::ostream &ostr, PIO_Util::PIO_mtq &q) +{ + std::unique_lock lk(q.mtx_); + /* We need to copy the queue since it is not iterable */ + std::queue tq = q.queue_; + while(!tq.empty()){ + ostr << tq.front() << ", "; + tq.pop(); + } + lk.unlock(); + return ostr; +} + +} // namespace PIO_Util + +#endif // _SPIO_ASYNC_MTQ_HPP_ diff --git a/src/clib/spio_async_tpool.cpp b/src/clib/spio_async_tpool.cpp new file mode 100644 index 0000000000..f57236aa58 --- /dev/null +++ b/src/clib/spio_async_tpool.cpp @@ -0,0 +1,164 @@ +#include +#include +#include +extern "C"{ +#include "pio_config.h" +} // extern "C" +#include "spio_async_mtq.hpp" +#include "spio_async_tpool.hpp" +extern "C"{ +#include "pio_internal.h" +#include "spio_async_tpool_cint.h" +} // extern "C" + +int pio_async_init_cnt = 0; +PIO_Util::PIO_async_tpool *PIO_Util::PIO_async_tpool_manager::tpool_ = NULL; +static PIO_Util::PIO_async_tpool_manager tpool_mgr; + +void PIO_Util::PIO_async_tpool::enqueue(pio_async_op_t *op) +{ + assert(op); + LOG((2, "PIO_async_tpool:enqueue: Enqueing async op, kind = %s", + (op->op_type == PIO_ASYNC_REARR_OP) ? "PIO_ASYNC_REARR_OP" : + ((op->op_type == PIO_ASYNC_PNETCDF_WRITE_OP) ? "PIO_ASYNC_PNETCDF_WRITE_OP" : + ((op->op_type == PIO_ASYNC_FILE_WRITE_OPS) ? "PIO_ASYNC_FILE_WRITE_OPS" : + "UNKNOWN")))); + mtq_.enqueue(op); +} + +void PIO_Util::PIO_async_tpool::finalize(void ) +{ + mtq_.signal(PIO_Util::PIO_mtq::PIO_MTQ_SIG_COMPLETE); +} + +PIO_Util::PIO_async_tpool::PIO_async_tpool(int nthreads) +{ + LOG((2, "PIO_async_tpool:PIO_async_tpool: Creating %d threads", nthreads)); + for(int i=0; i::PIO_MTQ_SIG_STOP); + for(std::vector::iterator iter = pool_threads_.begin(); + iter != pool_threads_.end(); ++iter){ + if(iter->joinable()){ + iter->join(); + } + } +} + +int PIO_Util::PIO_async_tpool::dequeue_and_process( + PIO_Util::PIO_async_tpool *tpool) +{ + int ret = 0; + assert(tpool); + /* Wait in an infinite loop (until the threads receive a signal) for + * pending asynchronous operations queued in the thread pool + */ + do{ + LOG((2, "PIO_async_tpool:dequeue_and_process: Waiting for async ops...")); + pio_async_op_t *op = NULL; + ret = tpool->mtq_.dequeue(op); + if(ret == 0){ + LOG((2, "Tpool processing async op, kind = %s", + (op->op_type == PIO_ASYNC_REARR_OP) ? "PIO_ASYNC_REARR_OP" : + ((op->op_type == PIO_ASYNC_PNETCDF_WRITE_OP) ? "PIO_ASYNC_PNETCDF_WRITE_OP" : + ((op->op_type == PIO_ASYNC_FILE_WRITE_OPS) ? "PIO_ASYNC_FILE_WRITE_OPS" : + "UNKNOWN")))); + /* We currently support only file write ops here */ + assert(op->op_type == PIO_ASYNC_FILE_WRITE_OPS); + ret = op->wait(op->pdata); + if(ret != PIO_NOERR){ + return pio_err(NULL, NULL, PIO_EINTERNAL, __FILE__, __LINE__, + "Internal error dequeuing and processing asynchronous operations in the thread pool. Internal error waiting on asynchronous file write operation"); + } + op->free(op->pdata); + free(op); + } + } while(ret == 0); + + return PIO_NOERR; +} + +PIO_Util::PIO_async_tpool * + PIO_Util::PIO_async_tpool_manager::get_tpool_instance(void ) +{ + /* We need to make NUM_THREADS configurable by the user (compile-time) */ + const int NUM_THREADS = 1; + if(tpool_ == NULL){ + LOG((2, "PIO_async_tpool_manager:get_tpool_instance: Creating new tpool instance")); + tpool_ = new PIO_Util::PIO_async_tpool(NUM_THREADS); + } + else{ + LOG((2, "PIO_async_tpool_manager:get_tpool_instance: Retrieving tpool instance")); + } + return tpool_; +} + +PIO_Util::PIO_async_tpool_manager::~PIO_async_tpool_manager() +{ + if(tpool_){ + LOG((2, "PIO_async_tpool_manager:~PIO_async_tpool_manager: Finalizing tpool")); + tpool_->finalize(); + delete(tpool_); + tpool_ = NULL; + } + else{ + LOG((2, "PIO_async_tpool_manager:~PIO_async_tpool_manager: tpool is already finalized/deleted")); + } +} + +int pio_async_tpool_create(void ) +{ + /* Although creation and deletion of the thread pool is managed by the + * thread pool manager, we still need reference counting to decide on + * when to send signals to async threads to finish queue async ops + * (Note: Multiple iosystems init/finalize but use the same thread pool) + */ + LOG((2, "pio_async_tpool_create: Creating tpool (by ref)")); + pio_async_init_cnt++; + + return PIO_NOERR; +} + +int pio_async_tpool_op_add(pio_async_op_t *op) +{ + int ret; + PIO_Util::PIO_async_tpool *tpool = tpool_mgr.get_tpool_instance(); + assert(tpool); + LOG((2, "pio_async_tpool_op_add(): Adding op")); + tpool->enqueue(op); + + return PIO_NOERR; +} + +int pio_async_tpool_ops_wait(void ) +{ + /* Currently we don't support waiting on async ops, unless we are + * terminating the async threads in *tpool_finalize() + */ + assert(0); +} + +int pio_async_tpool_finalize(void ) +{ + pio_async_init_cnt--; + if(pio_async_init_cnt == 0){ + LOG((2, "pio_async_tpool_finalize: Finalizing tpool instance")); + PIO_Util::PIO_async_tpool *tpool = tpool_mgr.get_tpool_instance(); + assert(tpool); + /* Signal threads waiting on queue to finish up/complete + * the queued async ops and exit + */ + tpool->finalize(); + } + else{ + LOG((2, "pio_async_tpool_finalize: Decrement ref cnt")); + } + + return PIO_NOERR; +} diff --git a/src/clib/spio_async_tpool.hpp b/src/clib/spio_async_tpool.hpp new file mode 100644 index 0000000000..6208228cd4 --- /dev/null +++ b/src/clib/spio_async_tpool.hpp @@ -0,0 +1,38 @@ +#ifndef _SPIO_ASYNC_TPOOL_HPP_ +#define _SPIO_ASYNC_TPOOL_HPP_ + +#include +#include +#include +#include "spio_async_mtq.hpp" +extern "C"{ +#include "pio_internal.h" +#include "spio_async_tpool_cint.h" +} // extern "C" + +namespace PIO_Util{ + +class PIO_async_tpool{ + public: + void enqueue(pio_async_op_t *op); + void finalize(void ); + private: + friend class PIO_async_tpool_manager; + PIO_async_tpool(int nthreads); + ~PIO_async_tpool(); + static int dequeue_and_process(PIO_async_tpool *tpool); + PIO_Util::PIO_mtq mtq_; + std::vector pool_threads_; +}; + +class PIO_async_tpool_manager{ + public: + static PIO_async_tpool *get_tpool_instance(void ); + ~PIO_async_tpool_manager(); + private: + static PIO_async_tpool *tpool_; +}; + +} // namespace PIO_Util + +#endif // _SPIO_ASYNC_TPOOL_HPP_ diff --git a/src/clib/spio_async_tpool_cint.h b/src/clib/spio_async_tpool_cint.h new file mode 100644 index 0000000000..0e1c70a1ed --- /dev/null +++ b/src/clib/spio_async_tpool_cint.h @@ -0,0 +1,12 @@ +#ifndef _PIO_ASYNC_THREAD_H_ +#define _PIO_ASYNC_THREAD_H_ + +#include "pio.h" +#include "pio_internal.h" + +int pio_async_tpool_create(void ); +int pio_async_tpool_op_add(pio_async_op_t *op); +int pio_async_tpool_ops_wait(void ); +int pio_async_tpool_finalize(void ); + +#endif // _PIO_ASYNC_THREAD_H_ diff --git a/src/clib/spio_async_utils.cpp b/src/clib/spio_async_utils.cpp new file mode 100644 index 0000000000..261c26cc90 --- /dev/null +++ b/src/clib/spio_async_utils.cpp @@ -0,0 +1,932 @@ +/** @file + * Support functions for the PIO library. + */ + +#include +#include + +extern "C"{ + +#include +#include +#include +#include +#if PIO_ENABLE_LOGGING +#include +#endif /* PIO_ENABLE_LOGGING */ +#include +#include +#include "pio_timer.h" +#if PIO_USE_ASYNC_WR_THREAD +#include "spio_async_tpool_cint.h" +#endif +#include "spio_async_utils.hpp" + +} // extern "C" + +/* Use this function for op kinds with no wait functions + * We use it to indicate, + * 1) No wait function available + * 2) Make sure that the wait function is not called (a more + * optimized wait function is available, so make sure that + * the wait function for this async op is not called) + */ +int pio_async_wait_func_unavail(void *pdata) +{ + assert(0); +} + +/* Use this function for op kinds with no poke function + * Some asynchronous operations have no poke/test functions + * so any generic code that uses the poke function must + * check the existence of this function before using it + */ +int pio_async_poke_func_unavail(void *pdata, int *flag) +{ + assert(0); +} + +/* Wait for pending asynchronous operations on this file + * This is the generic wait function for waiting on all + * async ops on a file + * @param file Pointer to the file_desc for the file + * Returns PIO_NOERR on success, a pio error code otherwise + */ +int pio_file_async_pend_ops_wait(file_desc_t *file) +{ + int ret; + assert(file != NULL); + + if(file->nasync_pend_ops == 0){ + return PIO_NOERR; + } + + pio_async_op_t *p = file->async_pend_ops, *q=NULL; + while(p){ + LOG((2, "Waiting on async op, kind = %s", + (p->op_type == PIO_ASYNC_REARR_OP) ? "PIO_ASYNC_REARR_OP" : + ((p->op_type == PIO_ASYNC_PNETCDF_WRITE_OP) ? "PIO_ASYNC_PNETCDF_WRITE_OP" : + "UNKNOWN"))); + ret = p->wait(p->pdata); + if(ret != PIO_NOERR){ + return pio_err(NULL, NULL, PIO_EINTERNAL, __FILE__, __LINE__, + "Error waiting for pending asynchronous operation on file, %s (ncid = %d)", pio_get_fname_from_file(file), file->pio_ncid); + } + q = p; + p = p->next; + q->free(q->pdata); + free(q); + } + file->async_pend_ops = NULL; + file->nasync_pend_ops = 0; + + return PIO_NOERR; +} + +#ifdef PIO_MICRO_TIMING +/* A struct to store information on pnetcdf write timers */ +typedef struct pio_async_pnetcdf_wr_timer_info{ + int nvars; + bool *var_timer_was_running; + mtimer_t wait_timer; +} pio_async_pnetcdf_wr_timer_info_t; + +/* Pause all var wr timers, create a temp wait timer and return it */ +int pio_async_pnetcdf_setup_wr_timers(file_desc_t *file, var_desc_t **vdescs, + int nvdescs, + pio_async_pnetcdf_wr_timer_info_t *wr_info) +{ + int ret; + + if(nvdescs == 0){ + return PIO_NOERR; + } + assert(file && vdescs && wr_info); + wr_info->nvars = nvdescs; + wr_info->var_timer_was_running = (bool *)malloc(wr_info->nvars * sizeof(bool)); + if(!wr_info->var_timer_was_running){ + return pio_err(file->iosystem, file, PIO_ENOMEM, __FILE__, __LINE__, + "Setting up asynchronous write timers for the PIO_IOTYPE_PNETCDF I/O type failed on file (%s, ncid=%d). Unable to allocate %lld bytes to store timer state for the multiple variables (number of variables=%d) in the file", pio_get_fname_from_file(file), file->pio_ncid, (unsigned long long) (wr_info->nvars * sizeof(bool)), wr_info->nvars); + } + + /* Timer to keep track of wait time */ + wr_info->wait_timer = mtimer_create("Temp_wait_timer", file->iosystem->my_comm, + "piowaitlog"); + if(!mtimer_is_valid(wr_info->wait_timer)){ + return pio_err(file->iosystem, file, PIO_EINTERNAL, __FILE__, __LINE__, + "Setting up asynchronous write timers for the PIO_IOTYPE_PNETCDF I/O type failed on file (%s, ncid=%d). Unable to create a temporary timer to measure wait time for asynchronous operations on the file", pio_get_fname_from_file(file), file->pio_ncid); + } + + /* Pause all timers */ + for(int i=0; ivar_timer_was_running[i] = false; + assert(vdescs[i]); + if(mtimer_is_valid(vdescs[i]->wr_mtimer)){ + ret = mtimer_pause(vdescs[i]->wr_mtimer, &(wr_info->var_timer_was_running[i])); + if(ret != PIO_NOERR){ + LOG((1, "Unable to pause timer")); + return ret; + } + } + } + + ret = mtimer_start(wr_info->wait_timer); + if(ret != PIO_NOERR){ + LOG((1, "Unable to start the temp wait timer")); + return ret; + } + + return PIO_NOERR; +} + +/* + * 1) Update the variable wr timers with the wait time + * 2) Restart timers (stopped during setup phase), if needed + * 3) Release the wr_info + */ +int pio_async_pnetcdf_finalize_wr_timers(file_desc_t *file, var_desc_t **vdescs, + int nvdescs, + pio_async_pnetcdf_wr_timer_info_t *wr_info) +{ + int ret; + + if(nvdescs == 0){ + return PIO_NOERR; + } + assert(file && vdescs && wr_info); + assert(nvdescs == wr_info->nvars); + + /* Calculate the wait time */ + ret = mtimer_pause(wr_info->wait_timer, NULL); + if(ret != PIO_NOERR){ + LOG((1, "Unable to pause temp wait timer")); + return ret; + } + + double wait_time = 0.0; + ret = mtimer_get_wtime(wr_info->wait_timer, &wait_time); + if(ret != PIO_NOERR){ + LOG((1, "Unable to get time from wait timer")); + return ret; + } + + ret = mtimer_destroy(&(wr_info->wait_timer)); + if(ret != PIO_NOERR){ + LOG((1, "Destroying temp wait timer failed")); + /* Continue */ + } + + /* Find avg wait time per variable */ + wait_time /= nvdescs; + + /* Update timers for vars with the avg wait time */ + for(int i=0; invars; i++){ + ret = mtimer_update(vdescs[i]->wr_mtimer, wait_time); + if(ret != PIO_NOERR){ + LOG((1, "Unable to update var write timer")); + return ret; + } + + /* Wait is now complete - no more async events in progress */ + ret = mtimer_async_event_in_progress(vdescs[i]->wr_mtimer, false); + if(ret != PIO_NOERR){ + LOG((1, "Unable to disable async events for var")); + return ret; + } + + /* If the timer was already running before we paused it in setup phase, + * restart it or else flush it */ + if(wr_info->var_timer_was_running[i]){ + ret = mtimer_resume(vdescs[i]->wr_mtimer); + if(ret != PIO_NOERR){ + LOG((1, "Unable to resume variable write timer")); + return ret; + } + } + else{ + ret = mtimer_flush(vdescs[i]->wr_mtimer, + get_var_desc_str(file->pio_ncid, vdescs[i]->varid, NULL)); + if(ret != PIO_NOERR){ + LOG((1, "Unable to flush timer")); + return ret; + } + } + } + + free(wr_info->var_timer_was_running); + wr_info->var_timer_was_running = NULL; + + return PIO_NOERR; +} +#endif + +/* Reset a vdesc after writing all data associated with it */ +int pio_async_pnetcdf_reset_vdesc(var_desc_t **vdescs, int nvdescs) +{ + /* FIXME: These operations need to be asynchronous */ + for(int i=0; iwb_pend = 0; + if(vdescs[i]->fillbuf){ + brel(vdescs[i]->fillbuf); + vdescs[i]->fillbuf = NULL; + } + } + return PIO_NOERR; +} + +/* Free a variable iobuf cache */ +void pio_viobuf_free(void *p) +{ + viobuf_cache_t *pviobuf = (viobuf_cache_t *)p; + assert(pviobuf); + + /* iobuf can be NULL associated with writes that are just + * fillvalues (these writes don't have individual iobufs, + * they just use a single common buffer associated with + * the vdesc, vdesc->fillbuf + * These dummy viobufs created to represent writes that + * contain only fillvalues (SUBSET) don't have any + * iobuf or fillvalue associated with it + * The dummy viobufs are also used to represent + * ncmpi_bput_* requests and since data is buffered by + * pnetcdf we don't have an iobuf associated with these + * requests + */ + if(pviobuf->iobuf){ + brel(pviobuf->iobuf); + pviobuf->iobuf = NULL; + } + + /* pviobuf->fillvalue is only valid if + * 1) Var has a fillvalue defined in file, vdesc->fillvalue is valid + * or + * 2) iodesc->needsfill is true + */ + if(pviobuf->fillvalue){ + free(pviobuf->fillvalue); + } + + free(p); +} + +/* Optimized wait function for pnetcdf writes */ +/* Instead of waiting for each async op of type, PNETCDF_WRITE_OP, + * wait for the ops collectively + */ +int pio_async_pnetcdf_write_kwait(void *f) +{ + int ret; + file_desc_t *file = (file_desc_t *)f; + assert(file); + assert(file->iotype == PIO_IOTYPE_PNETCDF); + + /* Gather up all requests corresponding to all vdescs associated + * with the pending async ops + * Also delete these async ops from the list since we wait for + * the requests associated with the ops here + * */ + if(file->nasync_pend_ops > 0){ + int nreqs = 0; + int *reqs = (int *)malloc(file->nasync_pend_ops * sizeof(int)); + if(!reqs){ + return pio_err(file->iosystem, file, PIO_ENOMEM, __FILE__, __LINE__, + "Error while waiting for asynchronous writes to complete for the PIO_IOTYPE_PNETCDF I/O type on file (%s, ncid=%d). Unable to allocate %lld bytes to consolidate requests associated with pending asynchronous operations on the file", pio_get_fname_from_file(file), file->pio_ncid, (unsigned long long) (file->nasync_pend_ops * sizeof(int))); + } + int nvdescs = 0; + var_desc_t **vdescs = (var_desc_t **)malloc(file->nasync_pend_ops * sizeof(var_desc_t *)); + if(!vdescs){ + return pio_err(file->iosystem, file, PIO_ENOMEM, __FILE__, __LINE__, + "Error while waiting for asynchronous writes to complete for the PIO_IOTYPE_PNETCDF I/O type on file (%s, ncid=%d). Unable to allocate %lld bytes to keep track of variable descriptors associated with pending asynchronous operations on the file", pio_get_fname_from_file(file), file->pio_ncid, (unsigned long long) (file->nasync_pend_ops * sizeof(var_desc_t *))); + } + + viobuf_cache_t **viobufs = (viobuf_cache_t **) malloc(file->nasync_pend_ops * sizeof(viobuf_cache_t *)); + if(!viobufs){ + return pio_err(file->iosystem, file, PIO_ENOMEM, __FILE__, __LINE__, + "Error while waiting for asynchronous writes to complete for the PIO_IOTYPE_PNETCDF I/O type on file (%s, ncid=%d). Unable to allocate %lld bytes to keep track of buffered data associated with pending asynchronous operations on the file", pio_get_fname_from_file(file), file->pio_ncid, (unsigned long long) (file->nasync_pend_ops * sizeof(viobuf_cache_t *))); + } + + pio_async_op_t *p = file->async_pend_ops, *q=NULL; + pio_async_op_t *prev = file->async_pend_ops; + while(p){ + if(p->op_type == PIO_ASYNC_PNETCDF_WRITE_OP){ + viobuf_cache_t *pviobuf = (viobuf_cache_t *)(p->pdata); + assert(pviobuf); + + reqs[nreqs] = pviobuf->req; + viobufs[nreqs] = pviobuf; + nreqs++; + + vdescs[nvdescs] = pviobuf->vdesc; + nvdescs++; + + q = p->next; + /* Free node */ + free(p); + /* p == file->async_pend_ops => First node */ + if(p == file->async_pend_ops){ + /* Update head and prev */ + file->async_pend_ops = q; + prev = q; + } + else{ + /* Skip node p, already deleted */ + prev->next = q; + } + p = q; + } + else{ + /* Ignore op kinds/types that are not pnetcdf writes */ + prev = p; + p = p->next; + } + } + + /* We don't expect any other pending operations when writes are + * pending on this file + * This was a constraint that was introduced by resuing a + * single file buffer, file->iobuf, for rearrange and write. + * So a write needed to complete before a rearrange occurs. + * FIXME: Since this is no longer a constraint for async writes + * investigate on how to relax the constraint + */ + assert(nreqs <= file->nasync_pend_ops); + LOG((2, "pio_async_pnetcdf_write_kwait(): nreqs= %d, file->nasync_pend_ops= %d\n", + nreqs, file->nasync_pend_ops)); + +#ifdef PIO_MICRO_TIMING + pio_async_pnetcdf_wr_timer_info_t wr_info; + ret = pio_async_pnetcdf_setup_wr_timers(file, vdescs, nvdescs, &wr_info); + if(ret != PIO_NOERR){ + LOG((1, "Initializing var write timers failed")); + return ret; + } +#endif + + /* Wait on all requests in one call */ + /* We don't care about the status of each request, we + * only care whether wait succeeded or not + * Requires pnetcdf ver >= 1.7.0 to support a + * NULL value for the status array + */ + ret = ncmpi_wait_all(file->fh, nreqs, reqs, NULL); + if(ret != NC_NOERR){ + return pio_err(file->iosystem, file, ret, __FILE__, __LINE__, + "Error while waiting for asynchronous writes to complete for the PIO_IOTYPE_PNETCDF I/O type on file (%s, ncid=%d). Internal I/O library error while waiting for pending PnetCDF operations.", pio_get_fname_from_file(file), file->pio_ncid); + } + + for(int i=0; iiosystem, file, PIO_EINTERNAL, __FILE__, __LINE__, + "Error while waiting for asynchronous writes to complete for the PIO_IOTYPE_PNETCDF I/O type on file (%s, ncid=%d). Resetting variable descriptors associated with the completed asynchronous operations failed", pio_get_fname_from_file(file), file->pio_ncid); + } + + free(viobufs); + free(vdescs); + free(reqs); + + file->nasync_pend_ops -= nreqs; + } + + return PIO_NOERR; +} + +/* Wait only for rearr async ops on a file */ +int pio_async_rearr_kwait(void *f) +{ + int ret; + file_desc_t *file = (file_desc_t *)f; + assert(file); + + if(file->nasync_pend_ops > 0){ + int nreqs = 0; + pio_async_op_t *p = file->async_pend_ops, *q=NULL; + pio_async_op_t *prev = file->async_pend_ops; + while(p){ + if(p->op_type == PIO_ASYNC_REARR_OP){ + nreqs++; + ret = p->wait(p->pdata); + if(ret != PIO_NOERR){ + LOG((1, "Waiting for rearr async op failed")); + return pio_err(file->iosystem, file, PIO_EINTERNAL, + __FILE__, __LINE__, + "Internal error while waiting for asynchronous rearrangement operations (number of pending ops = %d) on file (%s, ncid=%d)", file->nasync_pend_ops, pio_get_fname_from_file(file), file->pio_ncid); + } + p->free(p->pdata); + q = p->next; + /* Free node */ + free(p); + /* p == file->async_pend_ops => First node */ + if(p == file->async_pend_ops){ + /* Update head and prev to delete/skip node p */ + file->async_pend_ops = q; + prev = q; + } + else{ + /* Delete node p, already freed */ + prev->next = q; + } + p = q; + } + else{ + /* Ignore op kinds/types that are not pnetcdf writes */ + prev = p; + p = p->next; + } + } + file->nasync_pend_ops -= nreqs; + } + + return PIO_NOERR; +} + +/* Optimized wait functions for different async op kinds/types on a file */ +typedef int (*file_async_pend_ops_kwait_func_t) (void *file); +static file_async_pend_ops_kwait_func_t + file_async_pend_ops_kwait_funcs[PIO_ASYNC_NUM_OP_TYPES] = { + /* PIO_ASYNC_INVALID_OP */ + pio_async_wait_func_unavail, + /* PIO_ASYNC_REARR_OP */ + pio_async_rearr_kwait, + /* PIO_ASYNC_PNETCDF_WRITE_OP */ + pio_async_pnetcdf_write_kwait + }; + +/* Wait for pending asynchronous operations of kind, op_kind, on this file + * @param file Pointer to the file_desc for the file + * Returns PIO_NOERR on success, a pio error code otherwise + */ +int pio_file_async_pend_ops_kwait(file_desc_t *file, pio_async_op_type_t op_kind) +{ + assert(file); + assert((op_kind > PIO_ASYNC_INVALID_OP) + && (op_kind < PIO_ASYNC_NUM_OP_TYPES)); + + int ret = file_async_pend_ops_kwait_funcs[op_kind](file); + if(ret != PIO_NOERR){ + return pio_err(NULL, NULL, PIO_EINTERNAL, __FILE__, __LINE__, + "Internal error while waiting for pending asynchronous operations on file (%s, ncid=%d)", pio_get_fname_from_file(file), file->pio_ncid); + } + + return PIO_NOERR; +} + +/* Add an async op to the list of pending ops for a file + * @param file Pointer to the file_desc for the file + * @param op_type Type of asynchronous operation added + * @param pdata Pointer to user defined data for this async op + * Returns PIO_NOERR on success, a pio error code otherwise + */ +int pio_file_async_pend_op_add(file_desc_t *file, + pio_async_op_type_t op_type, void *pdata) +{ + assert(file != NULL); + assert((op_type > PIO_ASYNC_INVALID_OP) + && (op_type < PIO_ASYNC_NUM_OP_TYPES)); + assert(pdata != NULL); + + pio_async_op_t *pnew = (pio_async_op_t *) calloc(1, sizeof(pio_async_op_t)); + if(pnew == NULL){ + return pio_err(NULL, NULL, PIO_ENOMEM, __FILE__, __LINE__, + "Adding an asynchronous operation to file (%s, ncid=%d) failed. Unable to allocate %lld bytes to cache the asynchronous operation", pio_get_fname_from_file(file), file->pio_ncid, (unsigned long long) (sizeof(pio_async_op_t))); + } + + pnew->op_type = op_type; + pnew->pdata = pdata; + if(op_type == PIO_ASYNC_REARR_OP){ + pnew->wait = pio_swapm_wait; + pnew->poke = pio_swapm_iwait; + pnew->free = pio_swapm_req_free; + } + else if(op_type == PIO_ASYNC_PNETCDF_WRITE_OP){ + /* Don't wait on individual ops, do coll wait on all ops */ + pnew->wait = pio_async_wait_func_unavail; + /* PnetCDF does not have a non-blocking test/poke function */ + pnew->poke = pio_async_poke_func_unavail; + pnew->free = pio_viobuf_free; + } + pnew->next = file->async_pend_ops; + + file->async_pend_ops = pnew; + file->nasync_pend_ops++; + + return PIO_NOERR; +} + +/* Start rearranging data pointed to by buf and cache the rearranged + * data. The rearranged data is cached in the ioprocs and the data + * pointed to by buf is expected to be valid until the rearrange + * operation completes. + * Note: Called by all procs + */ +int pio_var_rearr_and_cache(file_desc_t *file, var_desc_t *vdesc, + io_desc_t *iodesc, void *buf, + size_t buflen, void *fillvalue, int rec_num) +{ + int ierr; + iosystem_desc_t *ios; + + LOG((2, "pio_var_rearr_and_cache : file=%p, vdesc=%p, iodesc=%p, rec_num=%d\n", + file, vdesc, iodesc, rec_num)); + /* Note: buf can be NULL or buflen can be 0 if a compute process + * has no data to send to io procs + */ + assert(file && vdesc && iodesc && ((rec_num >= -1))); + ios = file->iosystem; + assert(ios); + + void *sbuf = buf; + void *rbuf = NULL; + viobuf_cache_t *pnew = NULL; + /* iodesc->maxiobuflen can be zero if all procs have + * no data to receive from other procs in a subset + * of procs (SUBSET rearranger) + */ + if((ios->ioproc) && (iodesc->maxiobuflen > 0)){ + /* viobuf cache list keeps track of iobuf that contains the + * rearranged data + */ + viobuf_cache_t *p = vdesc->viobuf_ltail; + pnew = (viobuf_cache_t *)calloc(1, sizeof(viobuf_cache_t)); + if(!pnew){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Error while queueing asynchronous operation to start rearranging of data on file (%s, ncid=%d). Unable to allocate %lld bytes for internal data structure to keep track of cached user data", pio_get_fname_from_file(file), file->pio_ncid, (unsigned long long) (sizeof(viobuf_cache_t))); + } + + pnew->ubuf = buf; + pnew->ubuf_sz = buflen; + /* Allocate mem for rearranged data, since different procs could + * potentially have different amount of rearranged data (SUBSET) + * allocate memory for max memory required among all procs, + * i.e., maxiobuflen + */ + pnew->iobuf_sz = iodesc->mpitype_size * iodesc->maxiobuflen; + pnew->iobuf = bget(pnew->iobuf_sz); + if(!(pnew->iobuf)){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Error while queueing asynchronous operation to start rearranging of data on file (%s, ncid=%d). Unable to allocate %lld bytes for caching rearranged data", pio_get_fname_from_file(file), file->pio_ncid, (unsigned long long) (pnew->iobuf_sz)); + } + rbuf = pnew->iobuf; + pnew->fillvalue = NULL; + pnew->fillvalue_sz = 0; + if(iodesc->needsfill){ + pnew->fillvalue = malloc(iodesc->mpitype_size); + if(!(pnew->fillvalue)){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Error while queueing asynchronous operation to start rearranging of data on file (%s, ncid=%d). Unable to allocate %lld bytes for caching fillvalue associated with user data", pio_get_fname_from_file(file), file->pio_ncid, (unsigned long long) (iodesc->mpitype_size)); + } + pnew->fillvalue_sz = iodesc->mpitype_size; + assert(fillvalue || vdesc->fillvalue); + if(fillvalue){ + /* Use the given fillvalue (explicit fillvalue specified + * by the user + */ + memcpy(pnew->fillvalue, fillvalue, iodesc->mpitype_size); + } + else{ + /* Use default fillvalue for the variable */ + memcpy(pnew->fillvalue, vdesc->fillvalue, iodesc->mpitype_size); + } + } + + /* For the BOX rearranger we need contiguous blocks of data on + * each io process, including the fill values. Only data that + * are not fillvalues are transferred from compute to io procs, + * so init the buffer, to store rearranged data, with fill + * values + */ + if(iodesc->needsfill && (iodesc->rearranger == PIO_REARR_BOX)){ + assert(pnew->fillvalue); + for(int i=0; imaxiobuflen; i++){ + memcpy(&((char *)pnew->iobuf)[iodesc->mpitype_size * i], + pnew->fillvalue, iodesc->mpitype_size); + } + } + + pnew->rec_num = rec_num; + /* The requests associated with data rearrangemnent is handled + * by separate async operations. These reqs are used to keep + * track of writes (after data rearrangement) using iobuf + */ + pnew->req = PIO_REQ_NULL; + pnew->vdesc = vdesc; + } + + /* Start rearrange of the data - asynchronous op, so will return before + * rearrange is complete + */ + int nvars = 1; + ierr = rearrange_comp2io(ios, iodesc, file, sbuf, rbuf, nvars); + if(ierr != PIO_NOERR){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Error while rearranging data from compute processes to I/O processes before writing it out to file (%s, ncid=%d). Internal error occured while rearranging data", pio_get_fname_from_file(file), file->pio_ncid); + } + + if((ios->ioproc) && (iodesc->maxiobuflen > 0)){ + /* Add the new node to the end of the list */ + if(vdesc->viobuf_ltail){ + vdesc->viobuf_ltail->next = pnew; + vdesc->viobuf_ltail = pnew; + } + else{ + /* First node */ + vdesc->viobuf_ltail = pnew; + } + /* First node in the list, update the head */ + if(!(vdesc->viobuf_lhead)){ + vdesc->viobuf_lhead = vdesc->viobuf_ltail; + } + } + + return PIO_NOERR; +} + +/* Get the cached data associated with a variable + */ +int pio_var_get_cache_data(var_desc_t *vdesc, int rec, void **buf, size_t *buflen) +{ + /* Use pio_var_del_cache_data that returns the iobuf and deletes the cache + * instead + */ + assert(0); +} + +/* Remove the cached viobuf corresponding to rec_num for a variable defined by vdesc + * The removed viobuf_cache is returned via pviobuf + * Note : Only called from io procs (to get the cached rearranged data) + */ +int pio_var_rem_cache_data(var_desc_t *vdesc, int rec_num, viobuf_cache_t **pviobuf) +{ + viobuf_cache_t *p = vdesc->viobuf_lhead; + viobuf_cache_t *prev = p; + + assert(vdesc && (rec_num >= -1) && pviobuf); + + /* We expect the list to have at least one element */ + assert(vdesc->viobuf_lhead && vdesc->viobuf_ltail); + *pviobuf = NULL; + + /* If the frames/records are accessed/deleted in the same order as they + * were added this search will always end at the head + */ + while(p && (p->rec_num != rec_num)){ + prev = p; + p = p->next; + } + + /* We assume that the search always succeeds */ + assert(p); + + *pviobuf = p; + + /* Delete node from list */ + if(vdesc->viobuf_lhead == vdesc->viobuf_ltail){ + /* Single node in the list */ + vdesc->viobuf_lhead = NULL; + vdesc->viobuf_ltail = NULL; + } + else{ + if(p == vdesc->viobuf_lhead){ + vdesc->viobuf_lhead = p->next; + } + + if(p == vdesc->viobuf_ltail){ + vdesc->viobuf_ltail = prev; + } + + prev->next = p->next; + } + + return PIO_NOERR; +} + +/* A helper function to copy rearranged data corresponding to variables + * specified by varids array to a single buffer (and the var frames + * referred by the frames array). + * The varids array can have duplicates, where the corresponding + * element in the frames array have different values + * The dest buffer is expected to be a contiguous region of valid + * values, rearranged as specified by iodesc + * This helper function is used by serial writes to copy data corresponding + * to multiple variables to a single buffer, this makes transferring data for + * multiple variables more efficient (compared to separately transferring + * data for each variable) + * Note: The function expects that data rearrangement is already complete + * and the rearranged data is available in viodesc caches in var_desc + */ +int pio_file_compact_and_copy_rearr_data(void *dest, size_t dest_sz, + io_desc_t *iodesc, file_desc_t *file, const int *varids, + const int *frames, int nvars) +{ + int ret; + size_t off = 0; + size_t rem_sz = dest_sz; + + for(int i=0; ivarlist + varids[i], + cur_frame, &pviobuf); + if(ret != PIO_NOERR){ + return pio_err(file->iosystem, file, ret, __FILE__, __LINE__, + "Error while compacting and copying rearranged data for asynchronous writes for %d variables on file (%s, ncid=%d). Getting internal buffer with rearranged data for var %d failed", nvars, pio_get_fname_from_file(file), file->pio_ncid, i); + } + assert(pviobuf); + + /* Copy this iobuf to dest buffer */ + /* Note that for each variable we only copy iodesc->llen values, that + * contain the valid values. Each pviobuf->iobuf is of size + * pviobuf->iobuf_sz (== iodesc->maxiobuflen) + * >= iodesc->llen * iodesc->mpitype_size. + */ + size_t iobuf_sz = iodesc->mpitype_size * iodesc->llen; + assert(rem_sz >= iobuf_sz); + memcpy((void *) ((char *)dest + off), pviobuf->iobuf, iobuf_sz); + off += iobuf_sz; + rem_sz -= iobuf_sz; + + pio_viobuf_free(pviobuf); + } + + return PIO_NOERR; +} + +/* Wait for all pending asynchronous operations on this iosystem + * This is the generic wait function for waiting on all + * async ops on an iosystem + * @param iosys Pointer to the iosystem_desc for the iosystem + * Returns PIO_NOERR on success, a pio error code otherwise + */ +int pio_iosys_async_pend_ops_wait(iosystem_desc_t *iosys) +{ + int ret; + assert(iosys != NULL); + + if(iosys->nasync_pend_ops == 0){ + return PIO_NOERR; + } + + pio_async_op_t *p = iosys->async_pend_ops, *q=NULL; + while(p){ + LOG((2, "Waiting on async op, kind = %s", + (p->op_type == PIO_ASYNC_REARR_OP) ? "PIO_ASYNC_REARR_OP" : + ((p->op_type == PIO_ASYNC_PNETCDF_WRITE_OP) ? "PIO_ASYNC_PNETCDF_WRITE_OP" : + ((p->op_type == PIO_ASYNC_FILE_WRITE_OPS) ? "PIO_ASYNC_FILE_WRITE_OPS" : + "UNKNOWN")))); + assert(p->op_type == PIO_ASYNC_FILE_WRITE_OPS); + ret = p->wait(p->pdata); + if(ret != PIO_NOERR){ + return pio_err(NULL, NULL, PIO_EINTERNAL, __FILE__, __LINE__, + "Internal error waiting for pending asynchronous operations on iosystem (iosysid=%d). Waiting for an asynchronous operation failed.", iosys->iosysid); + } + q = p; + p = p->next; + q->free(q->pdata); + free(q); + } + iosys->async_pend_ops = NULL; + iosys->nasync_pend_ops = 0; + + return PIO_NOERR; +} + +/* Wait for all pending asynchronous operations on a file + * This is the generic wait function for waiting on all + * async ops a file + * @param pdata Pointer to user data (pointer to file_desc + * corresponding to a file) + * Returns PIO_NOERR on success, a pio error code otherwise + */ +int pio_file_async_pend_op_wait(void *pdata) +{ + int ret; + assert(pdata != NULL); + + file_desc_t *file = (file_desc_t *)pdata; + if(file->nasync_pend_ops == 0){ + return PIO_NOERR; + } + + /* We only wait for pending pnetcdf writes. So the caller + * needs to make sure that no data rearrangement ops are + * pending */ + ret = pio_file_async_pend_ops_kwait(file, PIO_ASYNC_PNETCDF_WRITE_OP); + if(ret != PIO_NOERR){ + return pio_err(file->iosystem, file, ret, __FILE__, __LINE__, + "Internal error while waiting for pending asynchronous write operations on file (%s, ncid=%d) for the PIO_IOTYPE_PNETCDF iotype", pio_get_fname_from_file(file), file->pio_ncid); + } + + file->wb_pend = 0; + file->npend_ops = 0; + + return PIO_NOERR; +} + +/* Free file_desc and close the file + * @param pdata Pointer to user data (pointer to file_desc + * corresponding to a file) + */ +void pio_file_close_and_free(void *pdata) +{ + int ret; + assert(pdata != NULL); + + file_desc_t *file = (file_desc_t *)pdata; + bool sync_with_ioprocs = false; + ret = PIO_hard_closefile(file->iosystem, file, sync_with_ioprocs); + if(ret != PIO_NOERR){ + LOG((1, "Closing file (id=%d) failed (ignoring the error)", file->pio_ncid)); + } +} + + +/* Add an async op to the list of pending ops for an iosystem + * @param iosys Pointer to the iosystem_desc + * @param op_type Type of asynchronous operation added + * @param pdata Pointer to user defined data for this async op + * Returns PIO_NOERR on success, a pio error code otherwise + */ +int pio_iosys_async_pend_op_add(iosystem_desc_t *iosys, + pio_async_op_type_t op_type, void *pdata) +{ + assert(iosys != NULL); + assert((op_type > PIO_ASYNC_INVALID_OP) + && (op_type < PIO_ASYNC_NUM_OP_TYPES)); + assert(pdata != NULL); + assert(op_type == PIO_ASYNC_FILE_WRITE_OPS); + + pio_async_op_t *pnew = (pio_async_op_t *) calloc(1, sizeof(pio_async_op_t)); + if(pnew == NULL){ + return pio_err(NULL, NULL, PIO_ENOMEM, __FILE__, __LINE__, + "Internal error while adding a pending asynchronous operations on the iosystem (iosysid=%d). Unable to allocate %lld bytes to keep track of the asynchronous operation", iosys->iosysid, (unsigned long long) (sizeof(pio_async_op_t))); + } + + pnew->op_type = op_type; + pnew->pdata = pdata; + if(op_type == PIO_ASYNC_FILE_WRITE_OPS){ + pnew->wait = pio_file_async_pend_op_wait; + /* File writes do not have a non-blocking test/poke function */ + pnew->poke = pio_async_poke_func_unavail; + pnew->free = pio_file_close_and_free; + } + pnew->next = iosys->async_pend_ops; + + iosys->async_pend_ops = pnew; + iosys->nasync_pend_ops++; + + return PIO_NOERR; +} + +#if PIO_USE_ASYNC_WR_THREAD +/* Add an async op to the list of pending ops in the thread pool + * @param iosys Pointer to the iosystem_desc + * @param op_type Type of asynchronous operation added + * @param pdata Pointer to user defined data for this async op + * Returns PIO_NOERR on success, a pio error code otherwise + */ +int pio_tpool_async_pend_op_add(iosystem_desc_t *iosys, + pio_async_op_type_t op_type, void *pdata) +{ + int ret; + assert(iosys != NULL); + assert((op_type > PIO_ASYNC_INVALID_OP) + && (op_type < PIO_ASYNC_NUM_OP_TYPES)); + assert(pdata != NULL); + assert(op_type == PIO_ASYNC_FILE_WRITE_OPS); + + pio_async_op_t *pnew = (pio_async_op_t *) calloc(1, sizeof(pio_async_op_t)); + if(pnew == NULL){ + return pio_err(NULL, NULL, PIO_ENOMEM, __FILE__, __LINE__, + "Internal error while adding asynchronous pending operation to the thread pool (iosystem = %d). Unable to allocate %lld bytes to keep track of the asynchronous operation", iosys->iosysid, (unsigned long long) sizeof(pio_async_op_t)); + } + + pnew->op_type = op_type; + pnew->pdata = pdata; + if(op_type == PIO_ASYNC_FILE_WRITE_OPS){ + pnew->wait = pio_file_async_pend_op_wait; + /* File writes do not have a non-blocking test/poke function */ + pnew->poke = pio_async_poke_func_unavail; + pnew->free = pio_file_close_and_free; + } + + ret = pio_async_tpool_op_add(pnew); + if(ret != PIO_NOERR){ + LOG((1, "Adding file pending ops to tpool failed, ret = %d", ret)); + return pio_err(iosys, NULL, ret, __FILE__, __LINE__, + "Internal error while adding asynchronous pending operation to the thread pool (iosystem = %d). Adding the asynchronous operation failed", iosys->iosysid); + } + + return PIO_NOERR; +} +#endif // PIO_USE_ASYNC_WR_THREAD diff --git a/src/clib/spio_async_utils.hpp b/src/clib/spio_async_utils.hpp new file mode 100644 index 0000000000..11244959d0 --- /dev/null +++ b/src/clib/spio_async_utils.hpp @@ -0,0 +1,27 @@ +#ifndef _SPIO_ASYNC_UTILS_HPP_ +#define _SPIO_ASYNC_UTILS_HPP_ + +#include +#include +#include + +int pio_file_async_pend_ops_wait(file_desc_t *file); +int pio_file_async_pend_op_add(file_desc_t *file, + pio_async_op_type_t op_type, void *pdata); +int pio_var_rearr_and_cache(file_desc_t *file, var_desc_t *vdesc, + io_desc_t *iodesc, void *buf, + size_t buflen, void *fillvalue, int rec_num); +int pio_var_rem_cache_data(var_desc_t *vdesc, int rec_num, viobuf_cache_t **pviobuf); +int pio_file_compact_and_copy_rearr_data(void *dest, size_t dest_sz, + io_desc_t *iodesc, file_desc_t *file, const int *varids, + const int *frames, int nvars); + +int pio_iosys_async_pend_op_add(iosystem_desc_t *iosys, + pio_async_op_type_t op_type, void *pdata); +#if PIO_USE_ASYNC_WR_THREAD +int pio_tpool_async_pend_op_add(iosystem_desc_t *iosys, + pio_async_op_type_t op_type, void *pdata); +#endif // PIO_USE_ASYNC_WR_THREAD + +#endif // _SPIO_ASYNC_UTILS_HPP_ + diff --git a/tests/cunit/CMakeLists.txt b/tests/cunit/CMakeLists.txt index ff6c39d6b5..ffab15df73 100644 --- a/tests/cunit/CMakeLists.txt +++ b/tests/cunit/CMakeLists.txt @@ -109,6 +109,13 @@ add_spio_executable(test_req_block_wait TRUE "" test_req_block_wait.c test_commo add_dependencies (tests test_spmd test_spio_ltimer test_spio_serializer test_spio_tree test_spio_file_mvcache test_sdecomp_regex test_req_block_wait) +if(PIO_USE_ASYNC_WR_THREAD) + add_spio_executable (test_mtq TRUE "" test_async_mtq.cpp test_common.c) + add_spio_executable (test_mtq_signal TRUE "" test_async_mtq_signal.cpp test_common.c) + add_spio_executable (test_mtq_pool TRUE "" test_async_tpool.cpp test_common.c) + add_dependencies(tests test_mtq test_mtq_signal test_mtq_pool) +endif() + # Test Timeout in seconds. if (PIO_VALGRIND_CHECK) set (DEFAULT_TEST_TIMEOUT 480) @@ -129,6 +136,12 @@ add_test(NAME test_spio_tree COMMAND test_spio_tree) add_test(NAME test_spio_file_mvcache COMMAND test_spio_file_mvcache) add_test(NAME test_sdecomp_regex COMMAND test_sdecomp_regex) +if(PIO_USE_ASYNC_WR_THREAD) + add_test(NAME test_mtq COMMAND test_mtq) + add_test(NAME test_mtq_signal COMMAND test_mtq_signal) + add_test(NAME test_mtq_pool COMMAND test_mtq_pool) +endif() + if (PIO_USE_MPISERIAL) add_test(NAME test_pioc COMMAND test_pioc) diff --git a/tests/cunit/test_async_mtq.cpp b/tests/cunit/test_async_mtq.cpp new file mode 100644 index 0000000000..0764a79d2f --- /dev/null +++ b/tests/cunit/test_async_mtq.cpp @@ -0,0 +1,639 @@ +#include +#include +#include +#include +#include +#include "spio_async_mtq.hpp" +extern "C"{ +#include +#include +#include +} + +#define LOG_RANK0(rank, ...) \ + do{ \ + if(rank == 0) \ + { \ + fprintf(stderr, __VA_ARGS__); \ + } \ + }while(0); + +static const int FAIL = -1; + +class UType{ + public: + int i; + float f; +}; + +/* Test creating a multi-threaded queue */ +int test_create_mtq(void ) +{ + PIO_Util::PIO_mtq qi; + PIO_Util::PIO_mtq qf; + + class TestClass{ + int i; + float f; + }; + + PIO_Util::PIO_mtq qt; + + return PIO_NOERR; +} + +/* Util function to enqueue data in elems to q */ +template +void thread_enq(PIO_Util::PIO_mtq &q, const std::vector &elems, + const std::chrono::seconds &delay) +{ + for(typename std::vector::const_iterator citer = elems.cbegin(); + citer != elems.cend(); ++citer){ + if(delay.count() != 0){ + std::this_thread::sleep_for(delay); + } + q.enqueue(*citer); + //std::cout << "Enqueued item : " << *citer << "\n"; + } +} + +/* Util function to dequeue nelems from q and store in elems */ +template +void thread_deq(PIO_Util::PIO_mtq &q, std::vector &elems, + const std::chrono::seconds &delay) +{ + int nelems = elems.size(); + for(int i=0; i 0) && (nthreads > 0)); + int nelems_per_thread = max_elems_in_q/nthreads; + int nelems_last_thread = max_elems_in_q - nelems_per_thread * (nthreads - 1); + + /* Enqueue multiple elems from different threads and dequeue to make + * sure that the elems are in the queue + */ + + /* Generate input vals */ + PIO_Util::PIO_mtq qi; + std::vector > ivals; + std::vector > ovals; + for(int i=0; i ivals_ithread; + std::vector ovals_ithread; + if(!is_last_thread){ + ivals_ithread.resize(nelems_per_thread); + ovals_ithread.resize(nelems_per_thread); + } + else{ + ivals_ithread.resize(nelems_last_thread); + ovals_ithread.resize(nelems_last_thread); + } + int sval = i * nelems_per_thread; + std::generate(ivals_ithread.begin(), ivals_ithread.end(), [&sval]{return sval++; }); + ivals.push_back(ivals_ithread); + std::fill(ovals_ithread.begin(), ovals_ithread.end(), -1); + ovals.push_back(ovals_ithread); + } + + /* Enqueue */ + std::vector tpool_enq, tpool_deq; + for(int i=0; i, std::ref(qi), std::ref(ivals[i]), enqueue_delay)); + } + + /* Wait for enqueue operations to complete */ + if(!concurrent_enq_deq){ + for(int i=0; i, std::ref(qi), std::ref(ovals[i]), dequeue_delay)); + } + + /* Wait for enqueue operations to complete */ + for(int i=0; i elem_in_q(max_elems_in_q, false); + for(int i=0; i= max_elems_in_q)){ + /* Invalid element in queue */ + LOG_RANK0(wrank, "Invalid element (%d) in queue\n", idx); + return PIO_EINTERNAL; + } + /* Mark that the element was in the queue */ + elem_in_q[idx] = true; + } + } + + for(int i=0; ii << "," << putype->f << "), "; + return ostr; +} + +/* Test enqueue and dequeue operations in a multi-threaded queue containing + * a user defined type */ +int test_enq_deq_utype(int wrank, const int max_elems_in_q, const int nthreads) +{ + assert((max_elems_in_q > 0) && (nthreads > 0)); + int nelems_per_thread = max_elems_in_q/nthreads; + int nelems_last_thread = max_elems_in_q - nelems_per_thread * (nthreads - 1); + + /* Enqueue multiple elems from different threads and dequeue to make + * sure that the elems are in the queue + */ + + /* Generate input vals */ + PIO_Util::PIO_mtq qu; + std::vector > ivals; + std::vector > ovals; + for(int i=0; i ivals_ithread; + std::vector ovals_ithread; + if(!is_last_thread){ + ivals_ithread.resize(nelems_per_thread); + ovals_ithread.resize(nelems_per_thread); + } + else{ + ivals_ithread.resize(nelems_last_thread); + ovals_ithread.resize(nelems_last_thread); + } + int sval = i * nelems_per_thread; + std::generate(ivals_ithread.begin(), ivals_ithread.end(), + [&sval]{ UType t; + t.f = static_cast(sval); + t.i = sval++; + return t; }); + ivals.push_back(ivals_ithread); + UType invalid_val; + invalid_val.i = -1; + invalid_val.f = -1.0; + std::fill(ovals_ithread.begin(), ovals_ithread.end(), invalid_val); + ovals.push_back(ovals_ithread); + } + + /* Enqueue */ + std::vector tpool; + for(int i=0; i, std::ref(qu), std::ref(ivals[i]), std::chrono::seconds(0))); + } + + /* Wait for enqueue operations to complete */ + for(int i=0; i, std::ref(qu), std::ref(ovals[i]), std::chrono::seconds(0))); + } + + /* Wait for enqueue operations to complete */ + for(int i=0; i elem_in_q(max_elems_in_q, false); + for(int i=0; i= max_elems_in_q)){ + /* Invalid element in queue */ + LOG_RANK0(wrank, "Invalid element (%d) in queue\n", idx); + return PIO_EINTERNAL; + } + if(static_cast(foval) != ioval){ + /* Invalid element in queue */ + LOG_RANK0(wrank, "Invalid element (%d) in queue\n", idx); + return PIO_EINTERNAL; + } + /* Mark that the element was in the queue */ + elem_in_q[idx] = true; + } + } + + for(int i=0; i 0) && (nthreads > 0)); + int nelems_per_thread = max_elems_in_q/nthreads; + int nelems_last_thread = max_elems_in_q - nelems_per_thread * (nthreads - 1); + + /* Enqueue multiple elems from different threads and dequeue to make + * sure that the elems are in the queue + */ + + /* Generate input vals */ + PIO_Util::PIO_mtq qu; + std::vector > ivals; + std::vector > ovals; + for(int i=0; i ivals_ithread; + std::vector ovals_ithread; + if(!is_last_thread){ + ivals_ithread.resize(nelems_per_thread); + ovals_ithread.resize(nelems_per_thread); + } + else{ + ivals_ithread.resize(nelems_last_thread); + ovals_ithread.resize(nelems_last_thread); + } + int sval = i * nelems_per_thread; + std::generate(ivals_ithread.begin(), ivals_ithread.end(), + [&sval]{ UType *pt = new UType(); + pt->f = static_cast(sval); + pt->i = sval++; + return pt; }); + ivals.push_back(ivals_ithread); + UType invalid_val; + invalid_val.i = -1; + invalid_val.f = -1.0; + std::fill(ovals_ithread.begin(), ovals_ithread.end(), &invalid_val); + ovals.push_back(ovals_ithread); + } + + /* Enqueue */ + std::vector tpool; + for(int i=0; i, std::ref(qu), std::ref(ivals[i]),std::chrono::seconds(0))); + } + + /* Wait for enqueue operations to complete */ + for(int i=0; i, std::ref(qu), std::ref(ovals[i]), std::chrono::seconds(0))); + } + + /* Wait for enqueue operations to complete */ + for(int i=0; i elem_in_q(max_elems_in_q, false); + for(int i=0; ii; + int idx = ioval; + float foval = ((ovals[i])[j])->f; + if((idx < 0) || (idx >= max_elems_in_q)){ + /* Invalid element in queue */ + LOG_RANK0(wrank, "Invalid element (%d) in queue\n", idx); + return PIO_EINTERNAL; + } + if(static_cast(foval) != ioval){ + /* Invalid element in queue */ + LOG_RANK0(wrank, "Invalid element (%d) in queue\n", idx); + return PIO_EINTERNAL; + } + delete((ovals[i])[j]); + /* Mark that the element was in the queue */ + elem_in_q[idx] = true; + } + } + + for(int i=0; i= 0) && (wsz > 0) && num_errors); + + /* Test creating a multi threaded queue - the queue is empty */ + try{ + ret = test_create_mtq(); + } + catch(...){ + ret = PIO_EINTERNAL; + } + if(ret != PIO_NOERR) + { + LOG_RANK0(wrank, "test_create_mtq() FAILED, ret = %d\n", ret); + nerrs++; + } + else{ + LOG_RANK0(wrank, "test_create_mtq() PASSED\n"); + } + + /* Test enqueueing 10 ints into a queue using 2 threads, the ints are + * removed from the queue and the results are verified + */ + try{ + ret = test_enq_deq_int(wrank, 10, 2, + std::chrono::seconds(0), + std::chrono::seconds(0), false); + } + catch(...){ + ret = PIO_EINTERNAL; + } + if(ret != PIO_NOERR) + { + LOG_RANK0(wrank, "test_enq_deq_int(10 elems, 2 threads, no delay, deq after enq) FAILED, ret = %d\n", ret); + nerrs++; + } + else{ + LOG_RANK0(wrank, "test_enq_deq_int(10 elems, 2 threads, no delay, deq after enq) PASSED\n"); + } + + /* Test enqueueing 100 ints into a queue using 4 threads, the ints are + * removed from the queue and the results are verified + */ + try{ + ret = test_enq_deq_int(wrank, 100, 4, + std::chrono::seconds(0), + std::chrono::seconds(0), false); + } + catch(...){ + ret = PIO_EINTERNAL; + } + if(ret != PIO_NOERR) + { + LOG_RANK0(wrank, "test_enq_deq_int(100 elems, 4 threads, no delay, deq after enq) FAILED, ret = %d\n", ret); + nerrs++; + } + else{ + LOG_RANK0(wrank, "test_enq_deq_int(100 elems, 4 threads, no delay, deq after enq) PASSED\n"); + } + + /* Test enqueueing 10 user defined elems into a queue using 2 threads, + * the elems are removed from the queue and the results are verified + */ + try{ + ret = test_enq_deq_utype(wrank, 10, 2); + } + catch(...){ + ret = PIO_EINTERNAL; + } + if(ret != PIO_NOERR) + { + LOG_RANK0(wrank, "test_enq_deq_utype(10 elems, 2 threads) FAILED, ret = %d\n", ret); + nerrs++; + } + else{ + LOG_RANK0(wrank, "test_enq_deq_utype(10 elems, 2 threads) PASSED\n"); + } + + /* Test enqueueing 100 user defined elems into a queue using 4 threads, + * the elems are removed from the queue and the results are verified + */ + try{ + ret = test_enq_deq_utype(wrank, 100, 4); + } + catch(...){ + ret = PIO_EINTERNAL; + } + if(ret != PIO_NOERR) + { + LOG_RANK0(wrank, "test_enq_deq_utype(100 elems, 4 threads) FAILED, ret = %d\n", ret); + nerrs++; + } + else{ + LOG_RANK0(wrank, "test_enq_deq_utype(100 elems, 4 threads) PASSED\n"); + } + + /* Test enqueueing 10 ptr to user defined elems into a queue using 2 threads, + * the elems are removed from the queue and the results are verified + */ + try{ + ret = test_enq_deq_putype(wrank, 10, 2); + } + catch(...){ + ret = PIO_EINTERNAL; + } + if(ret != PIO_NOERR) + { + LOG_RANK0(wrank, "test_enq_deq_putype(10 elems, 2 threads) FAILED, ret = %d\n", ret); + nerrs++; + } + else{ + LOG_RANK0(wrank, "test_enq_deq_putype(10 elems, 2 threads) PASSED\n"); + } + + /* Test enqueueing 100 ptr to user defined elems into a queue using 4 threads, + * the elems are removed from the queue and the results are verified + */ + try{ + ret = test_enq_deq_putype(wrank, 100, 4); + } + catch(...){ + ret = PIO_EINTERNAL; + } + if(ret != PIO_NOERR) + { + LOG_RANK0(wrank, "test_enq_deq_putype(100 elems, 4 threads) FAILED, ret = %d\n", ret); + nerrs++; + } + else{ + LOG_RANK0(wrank, "test_enq_deq_putype(100 elems, 4 threads) PASSED\n"); + } + + /* Test enqueueing 20 ints into a queue using 2 threads, the ints are + * removed from the queue and the results are verified + * The enqueue and dequeue operations happen on separate threads (2 threads + * enqueue data - with a delay of 1s btw queuing elements and 2 threads + * dequeue data - no delay) + * Slow producer, fast consumer + */ + try{ + ret = test_enq_deq_int(wrank, 20, 2, + std::chrono::seconds(1), + std::chrono::seconds(0), true); + } + catch(...){ + ret = PIO_EINTERNAL; + } + if(ret != PIO_NOERR) + { + LOG_RANK0(wrank, "test_enq_deq_int(20 elems, 2 threads, 1s delay for queueing data, concurrent deq enq) FAILED, ret = %d\n", ret); + nerrs++; + } + else{ + LOG_RANK0(wrank, "test_enq_deq_int(20 elems, 2 threads, 1s delay for queueing data, concurrent deq enq) PASSED\n"); + } + + /* Test enqueueing 20 ints into a queue using 4 threads, the ints are + * removed from the queue and the results are verified + * The enqueue and dequeue operations happen on separate threads (4 threads + * enqueue data - with a delay of 1s btw queuing elements and 4 threads + * dequeue data - no delay) + * Slow producer, fast consumer + */ + try{ + ret = test_enq_deq_int(wrank, 20, 4, + std::chrono::seconds(1), + std::chrono::seconds(0), true); + } + catch(...){ + ret = PIO_EINTERNAL; + } + if(ret != PIO_NOERR) + { + LOG_RANK0(wrank, "test_enq_deq_int(20 elems, 4 threads, 1s delay for queueing data, concurrent deq enq) FAILED, ret = %d\n", ret); + nerrs++; + } + else{ + LOG_RANK0(wrank, "test_enq_deq_int(20 elems, 4 threads, 1s delay for queueing data, concurrent deq enq) PASSED\n"); + } + + *num_errors += nerrs; + return nerrs; +} + +int main(int argc, char *argv[]) +{ + int ret; + int wrank, wsz; + int num_errors; +#ifdef TIMING +#ifndef TIMING_INTERNAL + ret = GPTLinitialize(); + if(ret != 0) + { + LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + + ret = MPI_Init(&argc, &argv); + if(ret != MPI_SUCCESS) + { + LOG_RANK0(wrank, "MPI_Init() FAILED, ret = %d\n", ret); + return ret; + } + + ret = MPI_Comm_rank(MPI_COMM_WORLD, &wrank); + if(ret != MPI_SUCCESS) + { + LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); + return ret; + } + ret = MPI_Comm_size(MPI_COMM_WORLD, &wsz); + if(ret != MPI_SUCCESS) + { + LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); + return ret; + } + + num_errors = 0; + ret = test_driver(MPI_COMM_WORLD, wrank, wsz, &num_errors); + if(ret != 0) + { + LOG_RANK0(wrank, "Test driver FAILED\n"); + return FAIL; + } + else{ + LOG_RANK0(wrank, "All tests PASSED\n"); + } + + MPI_Finalize(); + +#ifdef TIMING +#ifndef TIMING_INTERNAL + ret = GPTLfinalize(); + if(ret != 0) + { + LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + + if(num_errors != 0) + { + LOG_RANK0(wrank, "Total errors = %d\n", num_errors); + return FAIL; + } + return 0; +} diff --git a/tests/cunit/test_async_mtq_signal.cpp b/tests/cunit/test_async_mtq_signal.cpp new file mode 100644 index 0000000000..8d7a5241d7 --- /dev/null +++ b/tests/cunit/test_async_mtq_signal.cpp @@ -0,0 +1,484 @@ +#include +#include +#include +#include +#include +#include "spio_async_mtq.hpp" +extern "C"{ +#include +#include +#include +} + +#define LOG_RANK0(rank, ...) \ + do{ \ + if(rank == 0) \ + { \ + fprintf(stderr, __VA_ARGS__); \ + } \ + }while(0); + +static const int FAIL = -1; + +class UType{ + public: + int i; + float f; +}; + +/* Util function to enqueue data in elems to q */ +template +void thread_enq(PIO_Util::PIO_mtq &q, const std::vector &elems, + const std::chrono::seconds &delay) +{ + for(typename std::vector::const_iterator citer = elems.cbegin(); + citer != elems.cend(); ++citer){ + if(delay.count() != 0){ + std::this_thread::sleep_for(delay); + } + q.enqueue(*citer); + //std::cout << "Enqueued : " << *citer << "\n"; + } +} + +/* Util function to dequeue nelems from q and store in elems */ +template +void thread_deq(PIO_Util::PIO_mtq &q, std::vector &elems, + const std::chrono::seconds &delay) +{ + int nelems = elems.size(); + for(int i=0; i +void thread_signal(PIO_Util::PIO_mtq &q, + typename PIO_Util::PIO_mtq::SigTypes_t sig, + const std::chrono::seconds &delay) +{ + if(delay.count() != 0){ + std::this_thread::sleep_for(delay); + } + q.signal(sig); + if(sig == PIO_Util::PIO_mtq::PIO_MTQ_SIG_COMPLETE){ + q.signal(PIO_Util::PIO_mtq::PIO_MTQ_SIG_STOP); + } +} + +std::ostream &operator<<(std::ostream &ostr, const UType &utype) +{ + ostr << "(" << utype.i << "," << utype.f << "), "; + return ostr; +} + +std::ostream &operator<<(std::ostream &ostr, const UType *putype) +{ + ostr << "(" << putype->i << "," << putype->f << "), "; + return ostr; +} + +/* Test sending signals to waiting dequeue threads in a multi-threaded queue containing + * ints */ +int test_signal_mtq(int wrank, const int max_elems_in_q, const int nthreads, + PIO_Util::PIO_mtq::SigTypes_t sig, + const std::chrono::seconds &enqueue_delay, + const std::chrono::seconds &dequeue_delay, + bool use_signal_thread) +{ + assert((max_elems_in_q > 0) && (nthreads > 0)); + int nelems_per_thread = max_elems_in_q/nthreads; + int nelems_last_thread = max_elems_in_q - nelems_per_thread * (nthreads - 1); + + /* Enqueue multiple elems from different threads and dequeue to make + * sure that the elems are in the queue + */ + + /* Generate input vals */ + PIO_Util::PIO_mtq qi; + std::vector > ivals; + std::vector > ovals; + for(int i=0; i ivals_ithread; + std::vector ovals_ithread; + if(!is_last_thread){ + ivals_ithread.resize(nelems_per_thread); + /* The size is +1 so that we wait for more elements than in the queue */ + ovals_ithread.resize(nelems_per_thread + 1); + } + else{ + ivals_ithread.resize(nelems_last_thread); + /* The size is +1 so that we wait for more elements than in the queue */ + ovals_ithread.resize(nelems_last_thread + 1); + } + int sval = i * nelems_per_thread; + std::generate(ivals_ithread.begin(), ivals_ithread.end(), [&sval]{return sval++; }); + ivals.push_back(ivals_ithread); + std::fill(ovals_ithread.begin(), ovals_ithread.end(), -1); + ovals.push_back(ovals_ithread); + } + + /* Enqueue */ + std::vector tpool; + for(int i=0; i, std::ref(qi), std::ref(ivals[i]), enqueue_delay)); + } + + /* Wait for enqueue operations to complete */ + for(int i=0; i, std::ref(qi), std::ref(ovals[i]), dequeue_delay)); + } + + /* Wait for enqueue operations to complete */ + std::thread *sig_thread = NULL; + if(!use_signal_thread){ + /* Signal all threads so that they exit once the queue is empty */ + qi.signal(sig); + if(sig == PIO_Util::PIO_mtq::PIO_MTQ_SIG_COMPLETE){ + qi.signal(PIO_Util::PIO_mtq::PIO_MTQ_SIG_STOP); + } + } + else{ + /* If there is delay specified during dequeueing data, set the delay so + * that approx half of the data is dequeued by each thread before sending + * the signal + */ + std::chrono::seconds sig_thread_delay = dequeue_delay * ovals[0].size() / 2; + sig_thread = new std::thread(thread_signal, std::ref(qi), sig, sig_thread_delay); + } + for(int i=0; ijoin(); + delete sig_thread; + } + tpool.clear(); + + /* Verify that we dequeued all elements in the queue */ + std::vector elem_in_q(max_elems_in_q, false); + for(int i=0; i= max_elems_in_q)){ + /* Invalid element in queue */ + LOG_RANK0(wrank, "Invalid element (%d) in queue\n", idx); + return PIO_EINTERNAL; + } + /* Note that some threads may not be able to get ovals[i].size() + * elements from the queue. These entries will be -1 on that + * thread. Ignore these entries + */ + if(idx != -1){ + /* Mark that the element was in the queue */ + elem_in_q[idx] = true; + } + } + } + + /* A SIG_STOP abnormally terminates the threads, the queue is not + * completely used up, so we should not be verifying the contents + * here. + */ + if(sig != PIO_Util::PIO_mtq::PIO_MTQ_SIG_STOP){ + for(int i=0; i= 0) && (wsz > 0) && num_errors); + + /* Test signalling waiting threads (the threads wait for 11 elements but we + * only queue 10) - both threads are waiting and the main thread signals + * all the threads to quit + * Test SIG_COMPLETE + */ + try{ + ret = test_signal_mtq(wrank, 10, 2, + PIO_Util::PIO_mtq::PIO_MTQ_SIG_COMPLETE, + std::chrono::seconds(0), + std::chrono::seconds(0), + false); + } + catch(...){ + ret = PIO_EINTERNAL; + } + if(ret != PIO_NOERR) + { + LOG_RANK0(wrank, "test_signal_mtq(10 elems, 2 threads, SIG_COMPLETE, no delays, no signalthread) FAILED, ret = %d\n", ret); + nerrs++; + } + else{ + LOG_RANK0(wrank, "test_signal_mtq(10 elems, 2 threads, SIG_COMPLETE, no delays, no signalthread) PASSED\n"); + } + + /* Test signalling waiting threads (the threads wait for 101 elements but we + * only queue 100) - all 4 threads are waiting and the main thread signals + * all the threads to quit + * Test SIG_COMPLETE + */ + try{ + ret = test_signal_mtq(wrank, 100, 4, + PIO_Util::PIO_mtq::PIO_MTQ_SIG_COMPLETE, + std::chrono::seconds(0), + std::chrono::seconds(0), + false); + } + catch(...){ + ret = PIO_EINTERNAL; + } + if(ret != PIO_NOERR) + { + LOG_RANK0(wrank, "test_signal_mtq(100 elems, 4 threads, SIG_COMPLETE, no delays, no signalthread) FAILED, ret = %d\n", ret); + nerrs++; + } + else{ + LOG_RANK0(wrank, "test_signal_mtq(100 elems, 4 threads, SIG_COMPLETE, no delays, no signalthread) PASSED\n"); + } + + /* Test signalling waiting threads (the threads wait for 11 elements but we + * only queue 10) - both threads are waiting and the main thread signals + * all the threads to quit + * Test SIG_STOP + */ + try{ + ret = test_signal_mtq(wrank, 10, 2, + PIO_Util::PIO_mtq::PIO_MTQ_SIG_STOP, + std::chrono::seconds(0), + std::chrono::seconds(0), + false); + } + catch(...){ + ret = PIO_EINTERNAL; + } + if(ret != PIO_NOERR) + { + LOG_RANK0(wrank, "test_signal_mtq(10 elems, 2 threads, SIG_STOP, no delays, no signalthread) FAILED, ret = %d\n", ret); + nerrs++; + } + else{ + LOG_RANK0(wrank, "test_signal_mtq(10 elems, 2 threads, SIG_STOP, no delays, no signalthread) PASSED\n"); + } + + /* Test signalling waiting threads (the threads wait for 101 elements but we + * only queue 100) - all 4 threads are waiting and the main thread signals + * all the threads to quit + * Test SIG_STOP + */ + try{ + ret = test_signal_mtq(wrank, 100, 4, + PIO_Util::PIO_mtq::PIO_MTQ_SIG_STOP, + std::chrono::seconds(0), + std::chrono::seconds(0), + false); + } + catch(...){ + ret = PIO_EINTERNAL; + } + if(ret != PIO_NOERR) + { + LOG_RANK0(wrank, "test_signal_mtq(100 elems, 4 threads, SIG_STOP, no delays, no signalthread) FAILED, ret = %d\n", ret); + nerrs++; + } + else{ + LOG_RANK0(wrank, "test_signal_mtq(100 elems, 4 threads, SIG_STOP, no delays, no signalthread) PASSED\n"); + } + + /* Test signalling waiting threads (the threads wait for 21 elements but we + * only queue 20) - all 4 threads are waiting and the main thread signals + * all the threads to quit + * Test SIG_COMPLETE, with a delay of 1 sec when dequeueing data + */ + try{ + ret = test_signal_mtq(wrank, 20, 4, + PIO_Util::PIO_mtq::PIO_MTQ_SIG_COMPLETE, + std::chrono::seconds(0), + std::chrono::seconds(1), + false); + } + catch(...){ + ret = PIO_EINTERNAL; + } + if(ret != PIO_NOERR) + { + LOG_RANK0(wrank, "test_signal_mtq(20 elems, 4 threads, SIG_COMPLETE, 1s delay deq, no signalthread) FAILED, ret = %d\n", ret); + nerrs++; + } + else{ + LOG_RANK0(wrank, "test_signal_mtq(20 elems, 4 threads, SIG_COMPLETE, 1s delay deq, no signalthread) PASSED\n"); + } + + /* Test signalling waiting threads (the threads wait for 21 elements but we + * only queue 20) - all 4 threads are waiting and the main thread signals + * all the threads to quit + * Test SIG_STOP, with a delay of 1 sec when dequeueing data + */ + try{ + ret = test_signal_mtq(wrank, 20, 4, + PIO_Util::PIO_mtq::PIO_MTQ_SIG_STOP, + std::chrono::seconds(0), + std::chrono::seconds(1), + false); + } + catch(...){ + ret = PIO_EINTERNAL; + } + if(ret != PIO_NOERR) + { + LOG_RANK0(wrank, "test_signal_mtq(20 elems, 4 threads, SIG_STOP, 1s delay deq, no signalthread) FAILED, ret = %d\n", ret); + nerrs++; + } + else{ + LOG_RANK0(wrank, "test_signal_mtq(20 elems, 4 threads, SIG_STOP, 1s delay deq, no signalthread) PASSED\n"); + } + + /* Test signalling waiting threads (the threads wait for 21 elements but we + * only queue 20) - all 4 threads are waiting and the main thread signals + * all the threads to quit + * Test SIG_COMPLETE, with a delay of 1 sec when dequeueing data + * The signal is sent from a separate thread + */ + try{ + ret = test_signal_mtq(wrank, 20, 4, + PIO_Util::PIO_mtq::PIO_MTQ_SIG_COMPLETE, + std::chrono::seconds(0), + std::chrono::seconds(1), + true); + } + catch(...){ + ret = PIO_EINTERNAL; + } + if(ret != PIO_NOERR) + { + LOG_RANK0(wrank, "test_signal_mtq(20 elems, 4 threads, SIG_COMPLETE, 1s delay deq, using signalthread) FAILED, ret = %d\n", ret); + nerrs++; + } + else{ + LOG_RANK0(wrank, "test_signal_mtq(20 elems, 4 threads, SIG_COMPLETE, 1s delay deq, using signalthread) PASSED\n"); + } + + /* Test signalling waiting threads (the threads wait for 21 elements but we + * only queue 20) - all 4 threads are waiting and the main thread signals + * all the threads to quit + * Test SIG_STOP, with a delay of 1 sec when dequeueing data + * The signal is sent from a separate thread + */ + try{ + ret = test_signal_mtq(wrank, 20, 4, + PIO_Util::PIO_mtq::PIO_MTQ_SIG_STOP, + std::chrono::seconds(0), + std::chrono::seconds(1), + true); + } + catch(...){ + ret = PIO_EINTERNAL; + } + if(ret != PIO_NOERR) + { + LOG_RANK0(wrank, "test_signal_mtq(20 elems, 4 threads, SIG_STOP, 1s delay deq, using signalthread) FAILED, ret = %d\n", ret); + nerrs++; + } + else{ + LOG_RANK0(wrank, "test_signal_mtq(20 elems, 4 threads, SIG_STOP, 1s delay deq, using signalthread) PASSED\n"); + } + + *num_errors += nerrs; + return nerrs; +} + +int main(int argc, char *argv[]) +{ + int ret; + int wrank, wsz; + int num_errors; +#ifdef TIMING +#ifndef TIMING_INTERNAL + ret = GPTLinitialize(); + if(ret != 0) + { + LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + + ret = MPI_Init(&argc, &argv); + if(ret != MPI_SUCCESS) + { + LOG_RANK0(wrank, "MPI_Init() FAILED, ret = %d\n", ret); + return ret; + } + + ret = MPI_Comm_rank(MPI_COMM_WORLD, &wrank); + if(ret != MPI_SUCCESS) + { + LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); + return ret; + } + ret = MPI_Comm_size(MPI_COMM_WORLD, &wsz); + if(ret != MPI_SUCCESS) + { + LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); + return ret; + } + + num_errors = 0; + ret = test_driver(MPI_COMM_WORLD, wrank, wsz, &num_errors); + if(ret != 0) + { + LOG_RANK0(wrank, "Test driver FAILED\n"); + return FAIL; + } + else{ + LOG_RANK0(wrank, "All tests PASSED\n"); + } + + MPI_Finalize(); + +#ifdef TIMING +#ifndef TIMING_INTERNAL + ret = GPTLfinalize(); + if(ret != 0) + { + LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + + if(num_errors != 0) + { + LOG_RANK0(wrank, "Total errors = %d\n", num_errors); + return FAIL; + } + return 0; +} diff --git a/tests/cunit/test_async_tpool.cpp b/tests/cunit/test_async_tpool.cpp new file mode 100644 index 0000000000..e8969e3e3f --- /dev/null +++ b/tests/cunit/test_async_tpool.cpp @@ -0,0 +1,217 @@ +#include +#include +#include +#include +#include +#include "spio_async_mtq.hpp" +#include "spio_async_tpool.hpp" +extern "C"{ +#include +#include +#include +} + +#define LOG_RANK0(rank, ...) \ + do{ \ + if(rank == 0) \ + { \ + fprintf(stderr, __VA_ARGS__); \ + } \ + }while(0); + +static const int FAIL = -1; + +class UType{ + public: + int nwaits; +}; + +std::ostream &operator<<(std::ostream &ostr, const UType &utype) +{ + ostr << "(" << utype.nwaits << "), "; + return ostr; +} + +std::ostream &operator<<(std::ostream &ostr, const UType *putype) +{ + ostr << "(" << putype->nwaits << "), "; + return ostr; +} + +int pio_utype_wait(void *pdata) +{ + UType *ut = static_cast(pdata); + assert(ut); + + ut->nwaits++; + return PIO_NOERR; +} + +int pio_poke_func_unavail(void *pdata, int *) +{ + assert(0); + return PIO_NOERR; +} + +void pio_noop_free(void *pdata) +{ +} + +/* Enqueue op */ +int tpool_enq_putype(int wrank, const int max_elems_in_q, std::vector &udata) +{ + assert((wrank >= 0) && (max_elems_in_q > 0)); + + PIO_Util::PIO_async_tpool_manager tpool_mgr; + PIO_Util::PIO_async_tpool *tpool = tpool_mgr.get_tpool_instance(); + + for(int i=0; iop_type = PIO_ASYNC_FILE_WRITE_OPS; + op->pdata = &(udata[i]); + op->wait = pio_utype_wait; + op->poke = pio_poke_func_unavail; + op->free = pio_noop_free; + tpool->enqueue(op); + } + + /* tpool is managed by the tpool manager - no delete/free reqd */ + + return PIO_NOERR; +} + +/* Test enqueue and dequeue operations in a multi-threaded queue containing + * pointers to user defined types */ +int test_tpool_putype(int wrank, const int max_elems_in_q) +{ + int ret = PIO_NOERR; + assert((wrank >= 0) && (max_elems_in_q > 0)); + + std::vector udata; + for(int i=0; i= 0) && (wsz > 0) && num_errors); + + /* Test enqueueing 10 ptr to user defined elems into the thread pool, + */ + try{ + ret = test_tpool_putype(wrank, 10); + } + catch(...){ + ret = PIO_EINTERNAL; + } + if(ret != PIO_NOERR) + { + LOG_RANK0(wrank, "test_tpool_putype(10 elems) FAILED, ret = %d\n", ret); + nerrs++; + } + else{ + LOG_RANK0(wrank, "test_tpool_putype(10 elems) PASSED\n"); + } + + + *num_errors += nerrs; + return nerrs; +} + +int main(int argc, char *argv[]) +{ + int ret; + int wrank, wsz; + int num_errors; +#ifdef TIMING +#ifndef TIMING_INTERNAL + ret = GPTLinitialize(); + if(ret != 0) + { + LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + + ret = MPI_Init(&argc, &argv); + if(ret != MPI_SUCCESS) + { + LOG_RANK0(wrank, "MPI_Init() FAILED, ret = %d\n", ret); + return ret; + } + + ret = MPI_Comm_rank(MPI_COMM_WORLD, &wrank); + if(ret != MPI_SUCCESS) + { + LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); + return ret; + } + ret = MPI_Comm_size(MPI_COMM_WORLD, &wsz); + if(ret != MPI_SUCCESS) + { + LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); + return ret; + } + + num_errors = 0; + ret = test_driver(MPI_COMM_WORLD, wrank, wsz, &num_errors); + if(ret != 0) + { + LOG_RANK0(wrank, "Test driver FAILED\n"); + return FAIL; + } + else{ + LOG_RANK0(wrank, "All tests PASSED\n"); + } + + MPI_Finalize(); + +#ifdef TIMING +#ifndef TIMING_INTERNAL + ret = GPTLfinalize(); + if(ret != 0) + { + LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + + if(num_errors != 0) + { + LOG_RANK0(wrank, "Total errors = %d\n", num_errors); + return FAIL; + } + return 0; +} diff --git a/tests/cunit/test_rearr.c b/tests/cunit/test_rearr.c index 26b2267a9c..9dc7cc215c 100644 --- a/tests/cunit/test_rearr.c +++ b/tests/cunit/test_rearr.c @@ -1052,6 +1052,7 @@ int test_rearrange_comp2io(MPI_Comm test_comm, int my_rank) { iosystem_desc_t *ios; io_desc_t *iodesc; + file_desc_t *file; void *sbuf = NULL; void *rbuf = NULL; int nvars = 1; @@ -1077,6 +1078,9 @@ int test_rearrange_comp2io(MPI_Comm test_comm, int my_rank) if (!(iodesc = calloc(1, sizeof(io_desc_t)))) return PIO_ENOMEM; + if (!(file = calloc(1, sizeof(file_desc_t)))) + return PIO_ENOMEM; + ios->ioproc = 1; ios->compproc = 1; ios->io_rank = my_rank; @@ -1092,6 +1096,9 @@ int test_rearrange_comp2io(MPI_Comm test_comm, int my_rank) iodesc->mpitype = MPI_INT; iodesc->stype = NULL; /* Array of MPI types will be created here. */ + file->iosystem = ios; + file->fh = -1; + /* The two rearrangers create a different number of send types. */ int num_send_types = iodesc->rearranger == PIO_REARR_BOX ? ios->num_iotasks : 1; @@ -1133,7 +1140,7 @@ int test_rearrange_comp2io(MPI_Comm test_comm, int my_rank) return ret; /* Run the function to test. */ - if ((ret = rearrange_comp2io(ios, iodesc, sbuf, rbuf, nvars))) + if ((ret = rearrange_comp2io(ios, iodesc, file, sbuf, rbuf, nvars))) return ret; printf("returned from rearrange_comp2io\n"); From 0a02593d30a63ef9f5ea03d49a609c94fefecc49 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Sun, 29 Sep 2024 21:35:43 -0500 Subject: [PATCH 002/194] Moving C unit test sources to CPP Moving all C unit test sources from C to CXX (foo.c -> foo.cpp). Tyepcasting returns from malloc()/calloc() appropriately (reqd for C++) & fixing the fillvalue arg to PIOc_write_darray_multi() in the tests --- tests/cunit/CMakeLists.txt | 64 ++++++++-------- ...est_async_3proc.c => test_async_3proc.cpp} | 0 ...est_async_4proc.c => test_async_4proc.cpp} | 0 ...t_async_simple.c => test_async_simple.cpp} | 0 .../cunit/{test_common.c => test_common.cpp} | 2 +- .../cunit/{test_darray.c => test_darray.cpp} | 16 ++-- .../{test_darray_1d.c => test_darray_1d.cpp} | 0 .../{test_darray_3d.c => test_darray_3d.cpp} | 2 +- ...t_darray_async.c => test_darray_async.cpp} | 0 ...sync_many.c => test_darray_async_many.cpp} | 0 ..._simple.c => test_darray_async_simple.cpp} | 0 ...t_darray_multi.c => test_darray_multi.cpp} | 2 +- ...ay_multivar.c => test_darray_multivar.cpp} | 0 ..._multivar2.c => test_darray_multivar2.cpp} | 2 +- ...decomp_uneven.c => test_decomp_uneven.cpp} | 2 +- .../{test_decomps.c => test_decomps.cpp} | 2 +- ...{test_intercomm2.c => test_intercomm2.cpp} | 0 .../{test_iosystem2.c => test_iosystem2.cpp} | 0 ...em2_simple.c => test_iosystem2_simple.cpp} | 0 ...2_simple2.c => test_iosystem2_simple2.cpp} | 0 .../{test_iosystem3.c => test_iosystem3.cpp} | 2 +- ...em3_simple.c => test_iosystem3_simple.cpp} | 0 ...3_simple2.c => test_iosystem3_simple2.cpp} | 0 tests/cunit/{test_pioc.c => test_pioc.cpp} | 14 ++-- .../{test_pioc_fill.c => test_pioc_fill.cpp} | 0 ...est_pioc_putget.c => test_pioc_putget.cpp} | 0 ...{test_pioc_unlim.c => test_pioc_unlim.cpp} | 2 +- tests/cunit/{test_rearr.c => test_rearr.cpp} | 76 +++++++++---------- ...q_block_wait.c => test_req_block_wait.cpp} | 4 +- .../cunit/{test_shared.c => test_shared.cpp} | 2 +- tests/cunit/{test_spmd.c => test_spmd.cpp} | 0 31 files changed, 96 insertions(+), 96 deletions(-) rename tests/cunit/{test_async_3proc.c => test_async_3proc.cpp} (100%) rename tests/cunit/{test_async_4proc.c => test_async_4proc.cpp} (100%) rename tests/cunit/{test_async_simple.c => test_async_simple.cpp} (100%) rename tests/cunit/{test_common.c => test_common.cpp} (99%) rename tests/cunit/{test_darray.c => test_darray.cpp} (94%) rename tests/cunit/{test_darray_1d.c => test_darray_1d.cpp} (100%) rename tests/cunit/{test_darray_3d.c => test_darray_3d.cpp} (99%) rename tests/cunit/{test_darray_async.c => test_darray_async.cpp} (100%) rename tests/cunit/{test_darray_async_many.c => test_darray_async_many.cpp} (100%) rename tests/cunit/{test_darray_async_simple.c => test_darray_async_simple.cpp} (100%) rename tests/cunit/{test_darray_multi.c => test_darray_multi.cpp} (99%) rename tests/cunit/{test_darray_multivar.c => test_darray_multivar.cpp} (100%) rename tests/cunit/{test_darray_multivar2.c => test_darray_multivar2.cpp} (99%) rename tests/cunit/{test_decomp_uneven.c => test_decomp_uneven.cpp} (99%) rename tests/cunit/{test_decomps.c => test_decomps.cpp} (99%) rename tests/cunit/{test_intercomm2.c => test_intercomm2.cpp} (100%) rename tests/cunit/{test_iosystem2.c => test_iosystem2.cpp} (100%) rename tests/cunit/{test_iosystem2_simple.c => test_iosystem2_simple.cpp} (100%) rename tests/cunit/{test_iosystem2_simple2.c => test_iosystem2_simple2.cpp} (100%) rename tests/cunit/{test_iosystem3.c => test_iosystem3.cpp} (99%) rename tests/cunit/{test_iosystem3_simple.c => test_iosystem3_simple.cpp} (100%) rename tests/cunit/{test_iosystem3_simple2.c => test_iosystem3_simple2.cpp} (100%) rename tests/cunit/{test_pioc.c => test_pioc.cpp} (99%) rename tests/cunit/{test_pioc_fill.c => test_pioc_fill.cpp} (100%) rename tests/cunit/{test_pioc_putget.c => test_pioc_putget.cpp} (100%) rename tests/cunit/{test_pioc_unlim.c => test_pioc_unlim.cpp} (99%) rename tests/cunit/{test_rearr.c => test_rearr.cpp} (94%) rename tests/cunit/{test_req_block_wait.c => test_req_block_wait.cpp} (99%) rename tests/cunit/{test_shared.c => test_shared.cpp} (98%) rename tests/cunit/{test_spmd.c => test_spmd.cpp} (100%) diff --git a/tests/cunit/CMakeLists.txt b/tests/cunit/CMakeLists.txt index ffab15df73..80c370b1a2 100644 --- a/tests/cunit/CMakeLists.txt +++ b/tests/cunit/CMakeLists.txt @@ -64,55 +64,55 @@ endif () # Exclude tests that require more than 1 procs when using the MPI serial library if (NOT PIO_USE_MPISERIAL) - add_spio_executable (test_intercomm2 TRUE "" test_intercomm2.c test_common.c) - add_spio_executable (test_async_simple TRUE "" test_async_simple.c test_common.c) - add_spio_executable (test_async_3proc TRUE "" test_async_3proc.c test_common.c) - add_spio_executable (test_async_4proc TRUE "" test_async_4proc.c test_common.c) - add_spio_executable (test_iosystem2_simple TRUE "" test_iosystem2_simple.c test_common.c) - add_spio_executable (test_iosystem2_simple2 TRUE "" test_iosystem2_simple2.c test_common.c) - add_spio_executable (test_iosystem2 TRUE "" test_iosystem2.c test_common.c) - add_spio_executable (test_iosystem3_simple TRUE "" test_iosystem3_simple.c test_common.c) - add_spio_executable (test_iosystem3_simple2 TRUE "" test_iosystem3_simple2.c test_common.c) - add_spio_executable (test_iosystem3 TRUE "" test_iosystem3.c test_common.c) - add_spio_executable (test_pioc TRUE "" test_pioc.c test_common.c test_shared.c) - add_spio_executable (test_pioc_unlim TRUE "" test_pioc_unlim.c test_common.c test_shared.c) - add_spio_executable (test_pioc_putget TRUE "" test_pioc_putget.c test_common.c test_shared.c) - add_spio_executable (test_pioc_fill TRUE "" test_pioc_fill.c test_common.c test_shared.c) - add_spio_executable (test_darray TRUE "" test_darray.c test_common.c) - add_spio_executable (test_darray_multi TRUE "" test_darray_multi.c test_common.c) - add_spio_executable (test_darray_multivar TRUE "" test_darray_multivar.c test_common.c) - add_spio_executable (test_darray_multivar2 TRUE "" test_darray_multivar2.c test_common.c) - add_spio_executable (test_darray_1d TRUE "" test_darray_1d.c test_common.c) - add_spio_executable (test_darray_3d TRUE "" test_darray_3d.c test_common.c) - add_spio_executable (test_decomp_uneven TRUE "" test_decomp_uneven.c test_common.c) - add_spio_executable (test_decomps TRUE "" test_decomps.c test_common.c) - add_spio_executable (test_rearr TRUE "" test_rearr.c test_common.c) + add_spio_executable (test_intercomm2 TRUE "" test_intercomm2.cpp test_common.cpp) + add_spio_executable (test_async_simple TRUE "" test_async_simple.cpp test_common.cpp) + add_spio_executable (test_async_3proc TRUE "" test_async_3proc.cpp test_common.cpp) + add_spio_executable (test_async_4proc TRUE "" test_async_4proc.cpp test_common.cpp) + add_spio_executable (test_iosystem2_simple TRUE "" test_iosystem2_simple.cpp test_common.cpp) + add_spio_executable (test_iosystem2_simple2 TRUE "" test_iosystem2_simple2.cpp test_common.cpp) + add_spio_executable (test_iosystem2 TRUE "" test_iosystem2.cpp test_common.cpp) + add_spio_executable (test_iosystem3_simple TRUE "" test_iosystem3_simple.cpp test_common.cpp) + add_spio_executable (test_iosystem3_simple2 TRUE "" test_iosystem3_simple2.cpp test_common.cpp) + add_spio_executable (test_iosystem3 TRUE "" test_iosystem3.cpp test_common.cpp) + add_spio_executable (test_pioc TRUE "" test_pioc.cpp test_common.cpp test_shared.cpp) + add_spio_executable (test_pioc_unlim TRUE "" test_pioc_unlim.cpp test_common.cpp test_shared.cpp) + add_spio_executable (test_pioc_putget TRUE "" test_pioc_putget.cpp test_common.cpp test_shared.cpp) + add_spio_executable (test_pioc_fill TRUE "" test_pioc_fill.cpp test_common.cpp test_shared.cpp) + add_spio_executable (test_darray TRUE "" test_darray.cpp test_common.cpp) + add_spio_executable (test_darray_multi TRUE "" test_darray_multi.cpp test_common.cpp) + add_spio_executable (test_darray_multivar TRUE "" test_darray_multivar.cpp test_common.cpp) + add_spio_executable (test_darray_multivar2 TRUE "" test_darray_multivar2.cpp test_common.cpp) + add_spio_executable (test_darray_1d TRUE "" test_darray_1d.cpp test_common.cpp) + add_spio_executable (test_darray_3d TRUE "" test_darray_3d.cpp test_common.cpp) + add_spio_executable (test_decomp_uneven TRUE "" test_decomp_uneven.cpp test_common.cpp) + add_spio_executable (test_decomps TRUE "" test_decomps.cpp test_common.cpp) + add_spio_executable (test_rearr TRUE "" test_rearr.cpp test_common.cpp) add_dependencies (tests test_intercomm2 test_async_simple test_async_3proc test_async_4proc test_iosystem2_simple test_iosystem2_simple2 test_iosystem2 test_iosystem3_simple test_iosystem3_simple2 test_iosystem3 test_pioc test_pioc_unlim test_pioc_putget test_pioc_fill test_darray test_darray_multi test_darray_multivar test_darray_multivar2 test_darray_1d test_darray_3d test_decomp_uneven test_decomps test_rearr) if (PIO_USE_MALLOC) - add_spio_executable (test_darray_async_simple TRUE "" test_darray_async_simple.c test_common.c) - add_spio_executable (test_darray_async TRUE "" test_darray_async.c test_common.c) - add_spio_executable (test_darray_async_many TRUE "" test_darray_async_many.c test_common.c) + add_spio_executable (test_darray_async_simple TRUE "" test_darray_async_simple.cpp test_common.cpp) + add_spio_executable (test_darray_async TRUE "" test_darray_async.cpp test_common.cpp) + add_spio_executable (test_darray_async_many TRUE "" test_darray_async_many.cpp test_common.cpp) add_dependencies (tests test_darray_async_simple test_darray_async test_darray_async_many) endif () endif () -add_spio_executable (test_spmd TRUE "" test_spmd.c test_common.c) +add_spio_executable (test_spmd TRUE "" test_spmd.cpp test_common.cpp) add_spio_executable (test_spio_ltimer TRUE "" test_spio_ltimer.cpp) add_spio_executable (test_spio_serializer TRUE "" test_spio_serializer.cpp) add_spio_executable (test_spio_tree TRUE "" test_spio_tree.cpp) add_spio_executable (test_spio_file_mvcache TRUE "" test_spio_file_mvcache.cpp) -add_spio_executable (test_sdecomp_regex TRUE "" test_sdecomp_regex.cpp test_common.c) -add_spio_executable(test_req_block_wait TRUE "" test_req_block_wait.c test_common.c) +add_spio_executable (test_sdecomp_regex TRUE "" test_sdecomp_regex.cpp test_common.cpp) +add_spio_executable(test_req_block_wait TRUE "" test_req_block_wait.cpp test_common.cpp) add_dependencies (tests test_spmd test_spio_ltimer test_spio_serializer test_spio_tree test_spio_file_mvcache test_sdecomp_regex test_req_block_wait) if(PIO_USE_ASYNC_WR_THREAD) - add_spio_executable (test_mtq TRUE "" test_async_mtq.cpp test_common.c) - add_spio_executable (test_mtq_signal TRUE "" test_async_mtq_signal.cpp test_common.c) - add_spio_executable (test_mtq_pool TRUE "" test_async_tpool.cpp test_common.c) + add_spio_executable (test_mtq TRUE "" test_async_mtq.cpp test_common.cpp) + add_spio_executable (test_mtq_signal TRUE "" test_async_mtq_signal.cpp test_common.cpp) + add_spio_executable (test_mtq_pool TRUE "" test_async_tpool.cpp test_common.cpp) add_dependencies(tests test_mtq test_mtq_signal test_mtq_pool) endif() diff --git a/tests/cunit/test_async_3proc.c b/tests/cunit/test_async_3proc.cpp similarity index 100% rename from tests/cunit/test_async_3proc.c rename to tests/cunit/test_async_3proc.cpp diff --git a/tests/cunit/test_async_4proc.c b/tests/cunit/test_async_4proc.cpp similarity index 100% rename from tests/cunit/test_async_4proc.c rename to tests/cunit/test_async_4proc.cpp diff --git a/tests/cunit/test_async_simple.c b/tests/cunit/test_async_simple.cpp similarity index 100% rename from tests/cunit/test_async_simple.c rename to tests/cunit/test_async_simple.cpp diff --git a/tests/cunit/test_common.c b/tests/cunit/test_common.cpp similarity index 99% rename from tests/cunit/test_common.c rename to tests/cunit/test_common.cpp index 3465a8d9f9..3069a6185c 100644 --- a/tests/cunit/test_common.c +++ b/tests/cunit/test_common.cpp @@ -1149,7 +1149,7 @@ int create_decomposition_2d(int ntasks, int my_rank, int iosysid, int *dim_len_2 elements_per_pe = dim_len_2d[0] * dim_len_2d[1] / ntasks; /* Allocate space for the decomposition array. */ - if (!(compdof = malloc(elements_per_pe * sizeof(PIO_Offset)))) + if (!(compdof = (PIO_Offset *) malloc(elements_per_pe * sizeof(PIO_Offset)))) return PIO_ENOMEM; /* Describe the decomposition. This is a 1-based array, so add 1! */ diff --git a/tests/cunit/test_darray.c b/tests/cunit/test_darray.cpp similarity index 94% rename from tests/cunit/test_darray.c rename to tests/cunit/test_darray.cpp index 6ee5779052..e98e1bbca6 100644 --- a/tests/cunit/test_darray.c +++ b/tests/cunit/test_darray.cpp @@ -180,27 +180,27 @@ int test_darray(int iosysid, int ioid, int num_flavors, int *flavor, int my_rank /* These will not work. */ if (PIOc_write_darray_multi(ncid + TEST_VAL_42, &varid, ioid, 1, arraylen, test_data, &frame, - fillvalue, flushtodisk) != PIO_EBADID) + (const void **) &fillvalue, flushtodisk) != PIO_EBADID) ERR(ERR_WRONG); if (PIOc_write_darray_multi(ncid, NULL, ioid, 1, arraylen, test_data, &frame, - fillvalue, flushtodisk) != PIO_EINVAL) + (const void **) &fillvalue, flushtodisk) != PIO_EINVAL) ERR(ERR_WRONG); if (PIOc_write_darray_multi(ncid, &varid, ioid + TEST_VAL_42, 1, arraylen, test_data, &frame, - fillvalue, flushtodisk) != PIO_EBADID) + (const void **) &fillvalue, flushtodisk) != PIO_EBADID) ERR(ERR_WRONG); if (PIOc_write_darray_multi(ncid, &varid, ioid, -1, arraylen, test_data, &frame, - fillvalue, flushtodisk) != PIO_EINVAL) + (const void **) &fillvalue, flushtodisk) != PIO_EINVAL) ERR(ERR_WRONG); /* if (PIOc_write_darray_multi(ncid, &varid, ioid, 1, arraylen, test_data, NULL, */ - /* fillvalue, flushtodisk) != PIO_EINVAL) */ + /* &fillvalue, flushtodisk) != PIO_EINVAL) */ /* ERR(ERR_WRONG); */ if (PIOc_write_darray_multi(ncid, &varid_big, ioid, 1, arraylen, test_data, &frame, - fillvalue, flushtodisk) != PIO_EINVAL) + (const void **) &fillvalue, flushtodisk) != PIO_EINVAL) ERR(ERR_WRONG); /* Write the data with the _multi function. */ if ((ret = PIOc_write_darray_multi(ncid, &varid, ioid, 1, arraylen, test_data, &frame, - fillvalue, flushtodisk))) + (const void **) &fillvalue, flushtodisk))) ERR(ret); } @@ -259,7 +259,7 @@ int test_darray(int iosysid, int ioid, int num_flavors, int *flavor, int my_rank else { if (PIOc_write_darray_multi(ncid2, &varid, ioid, 1, arraylen, test_data, &frame, - fillvalue, flushtodisk) != PIO_EPERM) + (const void **) &fillvalue, flushtodisk) != PIO_EPERM) ERR(ERR_WRONG); } diff --git a/tests/cunit/test_darray_1d.c b/tests/cunit/test_darray_1d.cpp similarity index 100% rename from tests/cunit/test_darray_1d.c rename to tests/cunit/test_darray_1d.cpp diff --git a/tests/cunit/test_darray_3d.c b/tests/cunit/test_darray_3d.cpp similarity index 99% rename from tests/cunit/test_darray_3d.c rename to tests/cunit/test_darray_3d.cpp index 578f8fbd5d..69d90f5f9b 100644 --- a/tests/cunit/test_darray_3d.c +++ b/tests/cunit/test_darray_3d.cpp @@ -82,7 +82,7 @@ int create_decomposition_3d(int ntasks, int my_rank, int iosysid, int *ioid) elements_per_pe = X_DIM_LEN * Y_DIM_LEN * Z_DIM_LEN / ntasks; /* Allocate space for the decomposition array. */ - if (!(compdof = malloc(elements_per_pe * sizeof(PIO_Offset)))) + if (!(compdof = (PIO_Offset *) malloc(elements_per_pe * sizeof(PIO_Offset)))) return PIO_ENOMEM; /* Describe the decomposition. */ diff --git a/tests/cunit/test_darray_async.c b/tests/cunit/test_darray_async.cpp similarity index 100% rename from tests/cunit/test_darray_async.c rename to tests/cunit/test_darray_async.cpp diff --git a/tests/cunit/test_darray_async_many.c b/tests/cunit/test_darray_async_many.cpp similarity index 100% rename from tests/cunit/test_darray_async_many.c rename to tests/cunit/test_darray_async_many.cpp diff --git a/tests/cunit/test_darray_async_simple.c b/tests/cunit/test_darray_async_simple.cpp similarity index 100% rename from tests/cunit/test_darray_async_simple.c rename to tests/cunit/test_darray_async_simple.cpp diff --git a/tests/cunit/test_darray_multi.c b/tests/cunit/test_darray_multi.cpp similarity index 99% rename from tests/cunit/test_darray_multi.c rename to tests/cunit/test_darray_multi.cpp index 5cf94dc3d1..d78b0d7a83 100644 --- a/tests/cunit/test_darray_multi.c +++ b/tests/cunit/test_darray_multi.cpp @@ -275,7 +275,7 @@ int test_darray(int iosysid, int ioid, int num_flavors, int *flavor, int my_rank /* Write the data with the _multi function. */ if ((ret = PIOc_write_darray_multi(ncid, varid, ioid, NVAR, arraylen, test_data, frame, - fillvalue, flushtodisk))) + (const void **)&fillvalue, flushtodisk))) ERR(ret); /* Close the netCDF file. */ diff --git a/tests/cunit/test_darray_multivar.c b/tests/cunit/test_darray_multivar.cpp similarity index 100% rename from tests/cunit/test_darray_multivar.c rename to tests/cunit/test_darray_multivar.cpp diff --git a/tests/cunit/test_darray_multivar2.c b/tests/cunit/test_darray_multivar2.cpp similarity index 99% rename from tests/cunit/test_darray_multivar2.c rename to tests/cunit/test_darray_multivar2.cpp index c4d4c7f311..d4f9adc750 100644 --- a/tests/cunit/test_darray_multivar2.c +++ b/tests/cunit/test_darray_multivar2.cpp @@ -181,7 +181,7 @@ int create_decomposition_2d_2(int ntasks, int my_rank, int iosysid, int *dim_len elements_per_pe = dim_len_2d[0] * dim_len_2d[1] / ntasks; /* Allocate space for the decomposition array. */ - if (!(compdof = malloc(elements_per_pe * sizeof(PIO_Offset)))) + if (!(compdof = (PIO_Offset *) malloc(elements_per_pe * sizeof(PIO_Offset)))) return PIO_ENOMEM; /* Describe the decomposition. This is a 1-based array, so add 1! */ diff --git a/tests/cunit/test_decomp_uneven.c b/tests/cunit/test_decomp_uneven.cpp similarity index 99% rename from tests/cunit/test_decomp_uneven.c rename to tests/cunit/test_decomp_uneven.cpp index 655c6b91b7..6354ce148a 100644 --- a/tests/cunit/test_decomp_uneven.c +++ b/tests/cunit/test_decomp_uneven.cpp @@ -61,7 +61,7 @@ int create_decomposition_3d(int ntasks, int my_rank, int iosysid, int *dim_len, printf("%d elements_per_pe = %lld remainder = %lld\n", my_rank, elements_per_pe, remainder); /* Allocate space for the decomposition array. */ - if (!(compdof = malloc(elements_per_pe * sizeof(PIO_Offset)))) + if (!(compdof = (PIO_Offset *)malloc(elements_per_pe * sizeof(PIO_Offset)))) return PIO_ENOMEM; /* Describe the decomposition. */ diff --git a/tests/cunit/test_decomps.c b/tests/cunit/test_decomps.cpp similarity index 99% rename from tests/cunit/test_decomps.c rename to tests/cunit/test_decomps.cpp index 92f07ae781..c233de3565 100644 --- a/tests/cunit/test_decomps.c +++ b/tests/cunit/test_decomps.cpp @@ -72,7 +72,7 @@ int test_decomp1(int iosysid, int my_rank, MPI_Comm test_comm) /* The compdof array contains a mapping for this task into the * global data array. */ - if (!(compdof = malloc(elements_per_pe * sizeof(PIO_Offset)))) + if (!(compdof = (PIO_Offset *) malloc(elements_per_pe * sizeof(PIO_Offset)))) return PIO_ENOMEM; for (int i = 0; i < elements_per_pe; i++) compdof[i] = my_rank * elements_per_pe + i + 1; diff --git a/tests/cunit/test_intercomm2.c b/tests/cunit/test_intercomm2.cpp similarity index 100% rename from tests/cunit/test_intercomm2.c rename to tests/cunit/test_intercomm2.cpp diff --git a/tests/cunit/test_iosystem2.c b/tests/cunit/test_iosystem2.cpp similarity index 100% rename from tests/cunit/test_iosystem2.c rename to tests/cunit/test_iosystem2.cpp diff --git a/tests/cunit/test_iosystem2_simple.c b/tests/cunit/test_iosystem2_simple.cpp similarity index 100% rename from tests/cunit/test_iosystem2_simple.c rename to tests/cunit/test_iosystem2_simple.cpp diff --git a/tests/cunit/test_iosystem2_simple2.c b/tests/cunit/test_iosystem2_simple2.cpp similarity index 100% rename from tests/cunit/test_iosystem2_simple2.c rename to tests/cunit/test_iosystem2_simple2.cpp diff --git a/tests/cunit/test_iosystem3.c b/tests/cunit/test_iosystem3.cpp similarity index 99% rename from tests/cunit/test_iosystem3.c rename to tests/cunit/test_iosystem3.cpp index 53b0c63b67..738c93a861 100644 --- a/tests/cunit/test_iosystem3.c +++ b/tests/cunit/test_iosystem3.cpp @@ -100,7 +100,7 @@ int check_file(MPI_Comm comm, int iosysid, int format, int ncid, char *filename, /* Check the attribute. Null terminating byte deliberately ignored * to match fortran code. */ - if (!(att_data = malloc(strlen(filename) * sizeof(char)))) + if (!(att_data = (char *) malloc(strlen(filename) * sizeof(char)))) return PIO_ENOMEM; if ((ret = PIOc_get_att(ncid, varid, attname, att_data))) return ret; diff --git a/tests/cunit/test_iosystem3_simple.c b/tests/cunit/test_iosystem3_simple.cpp similarity index 100% rename from tests/cunit/test_iosystem3_simple.c rename to tests/cunit/test_iosystem3_simple.cpp diff --git a/tests/cunit/test_iosystem3_simple2.c b/tests/cunit/test_iosystem3_simple2.cpp similarity index 100% rename from tests/cunit/test_iosystem3_simple2.c rename to tests/cunit/test_iosystem3_simple2.cpp diff --git a/tests/cunit/test_pioc.c b/tests/cunit/test_pioc.cpp similarity index 99% rename from tests/cunit/test_pioc.c rename to tests/cunit/test_pioc.cpp index b66637ef30..255cffc9e9 100644 --- a/tests/cunit/test_pioc.c +++ b/tests/cunit/test_pioc.cpp @@ -97,7 +97,7 @@ int create_decomposition(int ntasks, int my_rank, int iosysid, int dim1_len, int elements_per_pe = dim1_len / ntasks; /* Allocate space for the decomposition array. */ - if (!(compdof = malloc(elements_per_pe * sizeof(PIO_Offset)))) + if (!(compdof = (PIO_Offset *) malloc(elements_per_pe * sizeof(PIO_Offset)))) return PIO_ENOMEM; /* Describe the decomposition. The new init_decomp uses a 0-based @@ -464,24 +464,24 @@ int check_error_strings(int my_rank, int num_tries, int *errcode, int ret; /* Try each test code. */ - for (int try = 0; try < num_tries; try++) + for (int i = 0; i < num_tries; i++) { char errstr[PIO_MAX_NAME + 1]; /* Get the error string for this errcode. */ - if ((ret = PIOc_strerror(errcode[try], errstr, PIO_MAX_NAME))) + if ((ret = PIOc_strerror(errcode[i], errstr, PIO_MAX_NAME))) return ret; - printf("%d for errcode = %d message = %s\n", my_rank, errcode[try], errstr); + printf("%d for errcode = %d message = %s\n", my_rank, errcode[i], errstr); /* Check that it was as expected. */ - if (strncmp(errstr, expected[try], strlen(expected[try]))) + if (strncmp(errstr, expected[i], strlen(expected[i]))) { - printf("%d expected %s got %s\n", my_rank, expected[try], errstr); + printf("%d expected %s got %s\n", my_rank, expected[i], errstr); return ERR_AWFUL; } if (!my_rank) - printf("%d errcode = %d passed\n", my_rank, errcode[try]); + printf("%d errcode = %d passed\n", my_rank, errcode[i]); } return PIO_NOERR; diff --git a/tests/cunit/test_pioc_fill.c b/tests/cunit/test_pioc_fill.cpp similarity index 100% rename from tests/cunit/test_pioc_fill.c rename to tests/cunit/test_pioc_fill.cpp diff --git a/tests/cunit/test_pioc_putget.c b/tests/cunit/test_pioc_putget.cpp similarity index 100% rename from tests/cunit/test_pioc_putget.c rename to tests/cunit/test_pioc_putget.cpp diff --git a/tests/cunit/test_pioc_unlim.c b/tests/cunit/test_pioc_unlim.cpp similarity index 99% rename from tests/cunit/test_pioc_unlim.c rename to tests/cunit/test_pioc_unlim.cpp index da4cbeb5fd..f96a51a69e 100644 --- a/tests/cunit/test_pioc_unlim.c +++ b/tests/cunit/test_pioc_unlim.cpp @@ -72,7 +72,7 @@ int create_decomposition(int ntasks, int my_rank, int iosysid, int dim1_len, elements_per_pe = X_DIM_LEN * Y_DIM_LEN / ntasks; /* Allocate space for the decomposition array. */ - if (!(compdof = malloc(elements_per_pe * sizeof(PIO_Offset)))) + if (!(compdof = (PIO_Offset *) malloc(elements_per_pe * sizeof(PIO_Offset)))) return PIO_ENOMEM; /* Describe the decomposition. This is a 1-based array, so add 1! */ diff --git a/tests/cunit/test_rearr.c b/tests/cunit/test_rearr.cpp similarity index 94% rename from tests/cunit/test_rearr.c rename to tests/cunit/test_rearr.cpp index 9dc7cc215c..35605a31bf 100644 --- a/tests/cunit/test_rearr.c +++ b/tests/cunit/test_rearr.cpp @@ -415,12 +415,12 @@ int test_determine_fill(MPI_Comm test_comm) int ret; /* Initialize ios. */ - if (!(ios = calloc(1, sizeof(iosystem_desc_t)))) + if (!(ios = (iosystem_desc_t *) calloc(1, sizeof(iosystem_desc_t)))) return PIO_ENOMEM; ios->union_comm = test_comm; /* Set up iodesc for test. */ - if (!(iodesc = calloc(1, sizeof(io_desc_t)))) + if (!(iodesc = (io_desc_t *) calloc(1, sizeof(io_desc_t)))) return PIO_ENOMEM; iodesc->ndims = 1; iodesc->rearranger = PIO_REARR_SUBSET; @@ -548,11 +548,11 @@ int test_define_iodesc_datatypes() /* Allocate space for arrays in iodesc that will be filled in * define_iodesc_datatypes(). */ - if (!(iodesc.rcount = malloc(iodesc.nrecvs * sizeof(int)))) + if (!(iodesc.rcount = (int *) malloc(iodesc.nrecvs * sizeof(int)))) return PIO_ENOMEM; - if (!(iodesc.rfrom = malloc(iodesc.nrecvs * sizeof(int)))) + if (!(iodesc.rfrom = (int *) malloc(iodesc.nrecvs * sizeof(int)))) return PIO_ENOMEM; - if (!(iodesc.rindex = malloc(1 * sizeof(PIO_Offset)))) + if (!(iodesc.rindex = (PIO_Offset *) malloc(1 * sizeof(PIO_Offset)))) return PIO_ENOMEM; iodesc.rindex[0] = 0; iodesc.rcount[0] = 1; @@ -562,9 +562,9 @@ int test_define_iodesc_datatypes() /* The two rearrangers create a different number of send types. */ int num_send_types = iodesc.rearranger == PIO_REARR_BOX ? ios.num_iotasks : 1; - if (!(iodesc.sindex = malloc(num_send_types * sizeof(PIO_Offset)))) + if (!(iodesc.sindex = (PIO_Offset *) malloc(num_send_types * sizeof(PIO_Offset)))) return PIO_ENOMEM; - if (!(iodesc.scount = malloc(num_send_types * sizeof(int)))) + if (!(iodesc.scount = (int *) malloc(num_send_types * sizeof(int)))) return PIO_ENOMEM; for (int st = 0; st < num_send_types; st++) { @@ -608,7 +608,7 @@ int test_compute_counts(MPI_Comm test_comm, int my_rank) int ret; /* Initialize ios. */ - if (!(ios = calloc(1, sizeof(iosystem_desc_t)))) + if (!(ios = (iosystem_desc_t *) calloc(1, sizeof(iosystem_desc_t)))) return PIO_ENOMEM; ios->num_iotasks = TARGET_NTASKS; @@ -617,17 +617,17 @@ int test_compute_counts(MPI_Comm test_comm, int my_rank) ios->ioproc = 1; ios->compproc = 1; ios->union_comm = test_comm; - if (!(ios->ioranks = malloc(TARGET_NTASKS * sizeof(int)))) + if (!(ios->ioranks = (int *) malloc(TARGET_NTASKS * sizeof(int)))) return PIO_ENOMEM; for (int t = 0; t < TARGET_NTASKS; t++) ios->ioranks[t] = t; - if (!(ios->compranks = calloc(ios->num_comptasks, sizeof(int)))) + if (!(ios->compranks = (int *) calloc(ios->num_comptasks, sizeof(int)))) return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, "Error allocating memory for comp ranks"); for (int i = 0; i < TARGET_NTASKS; i++) ios->compranks[i] = i; /* Initialize iodesc. */ - if (!(iodesc = calloc(1, sizeof(io_desc_t)))) + if (!(iodesc = (io_desc_t *) calloc(1, sizeof(io_desc_t)))) return PIO_ENOMEM; iodesc->rearranger = PIO_REARR_BOX; iodesc->ndof = TARGET_NTASKS; @@ -700,11 +700,11 @@ int test_box_rearrange_create(MPI_Comm test_comm, int my_rank) int ret; /* Allocate IO system info struct for this test. */ - if (!(ios = calloc(1, sizeof(iosystem_desc_t)))) + if (!(ios = (iosystem_desc_t *) calloc(1, sizeof(iosystem_desc_t)))) return PIO_ENOMEM; /* Allocate IO desc struct for this test. */ - if (!(iodesc = calloc(1, sizeof(io_desc_t)))) + if (!(iodesc = (io_desc_t *) calloc(1, sizeof(io_desc_t)))) return PIO_ENOMEM; /* Default rearranger options. */ @@ -724,11 +724,11 @@ int test_box_rearrange_create(MPI_Comm test_comm, int my_rank) ios->num_iotasks = 4; ios->num_comptasks = 4; ios->num_uniontasks = 4; - if (!(ios->ioranks = calloc(ios->num_iotasks, sizeof(int)))) + if (!(ios->ioranks = (int *) calloc(ios->num_iotasks, sizeof(int)))) return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, "Error allocating memory for ioranks"); for (int i = 0; i < TARGET_NTASKS; i++) ios->ioranks[i] = i; - if (!(ios->compranks = calloc(ios->num_comptasks, sizeof(int)))) + if (!(ios->compranks = (int *) calloc(ios->num_comptasks, sizeof(int)))) return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, "Error allocating memory for compranks"); for (int i = 0; i < TARGET_NTASKS; i++) ios->compranks[i] = i; @@ -815,11 +815,11 @@ int test_box_rearrange_create_2(MPI_Comm test_comm, int my_rank) int ret; /* Allocate IO system info struct for this test. */ - if (!(ios = calloc(1, sizeof(iosystem_desc_t)))) + if (!(ios = (iosystem_desc_t *) calloc(1, sizeof(iosystem_desc_t)))) return PIO_ENOMEM; /* Allocate IO desc struct for this test. */ - if (!(iodesc = calloc(1, sizeof(io_desc_t)))) + if (!(iodesc = (io_desc_t *) calloc(1, sizeof(io_desc_t)))) return PIO_ENOMEM; /* Default rearranger options. */ @@ -842,11 +842,11 @@ int test_box_rearrange_create_2(MPI_Comm test_comm, int my_rank) ios->num_iotasks = 4; ios->num_comptasks = 4; ios->num_uniontasks = 4; - if (!(ios->ioranks = calloc(ios->num_iotasks, sizeof(int)))) + if (!(ios->ioranks = (int *) calloc(ios->num_iotasks, sizeof(int)))) return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, "Error allocating memory for ioranks"); for (int i = 0; i < TARGET_NTASKS; i++) ios->ioranks[i] = i; - if (!(ios->compranks = calloc(ios->num_comptasks, sizeof(int)))) + if (!(ios->compranks = (int *) calloc(ios->num_comptasks, sizeof(int)))) return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, "Error allocating memory for compranks"); for (int i = 0; i < TARGET_NTASKS; i++) ios->compranks[i] = i; @@ -931,11 +931,11 @@ int test_box_rearrange_create_3(MPI_Comm test_comm, int my_rank) int ret; /* Allocate IO system info struct for this test. */ - if (!(ios = calloc(1, sizeof(iosystem_desc_t)))) + if (!(ios = (iosystem_desc_t *) calloc(1, sizeof(iosystem_desc_t)))) return PIO_ENOMEM; /* Allocate IO desc struct for this test. */ - if (!(iodesc = calloc(1, sizeof(io_desc_t)))) + if (!(iodesc = (io_desc_t *) calloc(1, sizeof(io_desc_t)))) return PIO_ENOMEM; /* Default rearranger options. */ @@ -958,11 +958,11 @@ int test_box_rearrange_create_3(MPI_Comm test_comm, int my_rank) ios->num_iotasks = TARGET_NTASKS; ios->num_comptasks = TARGET_NTASKS; ios->num_uniontasks = TARGET_NTASKS; - if (!(ios->ioranks = calloc(ios->num_iotasks, sizeof(int)))) + if (!(ios->ioranks = (int *) calloc(ios->num_iotasks, sizeof(int)))) return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, "Error allocating memory for ioranks"); for (int i = 0; i < ios->num_iotasks; i++) ios->ioranks[i] = i; - if (!(ios->compranks = calloc(ios->num_comptasks, sizeof(int)))) + if (!(ios->compranks = (int *) calloc(ios->num_comptasks, sizeof(int)))) return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, "Error allocating memory for compranks"); for (int i = 0; i < ios->num_comptasks; i++) ios->compranks[i] = i; @@ -1017,11 +1017,11 @@ int test_default_subset_partition(MPI_Comm test_comm, int my_rank) int ret; /* Allocate IO system info struct for this test. */ - if (!(ios = calloc(1, sizeof(iosystem_desc_t)))) + if (!(ios = (iosystem_desc_t *) calloc(1, sizeof(iosystem_desc_t)))) return PIO_ENOMEM; /* Allocate IO desc struct for this test. */ - if (!(iodesc = calloc(1, sizeof(io_desc_t)))) + if (!(iodesc = (io_desc_t *) calloc(1, sizeof(io_desc_t)))) return PIO_ENOMEM; ios->ioproc = 1; @@ -1065,20 +1065,20 @@ int test_rearrange_comp2io(MPI_Comm test_comm, int my_rank) int ret; /* Allocate some space for data. */ - if (!(sbuf = calloc(4, sizeof(int)))) + if (!(sbuf = (int *) calloc(4, sizeof(int)))) return PIO_ENOMEM; - if (!(rbuf = calloc(4, sizeof(int)))) + if (!(rbuf = (int *) calloc(4, sizeof(int)))) return PIO_ENOMEM; /* Allocate IO system info struct for this test. */ - if (!(ios = calloc(1, sizeof(iosystem_desc_t)))) + if (!(ios = (iosystem_desc_t *) calloc(1, sizeof(iosystem_desc_t)))) return PIO_ENOMEM; /* Allocate IO desc struct for this test. */ - if (!(iodesc = calloc(1, sizeof(io_desc_t)))) + if (!(iodesc = (io_desc_t *) calloc(1, sizeof(io_desc_t)))) return PIO_ENOMEM; - if (!(file = calloc(1, sizeof(file_desc_t)))) + if (!(file = (file_desc_t *) calloc(1, sizeof(file_desc_t)))) return PIO_ENOMEM; ios->ioproc = 1; @@ -1117,11 +1117,11 @@ int test_rearrange_comp2io(MPI_Comm test_comm, int my_rank) /* Set up the IO task info for the test. */ ios->union_rank = my_rank; ios->num_comptasks = 4; - if (!(ios->ioranks = calloc(ios->num_iotasks, sizeof(int)))) + if (!(ios->ioranks = (int *) calloc(ios->num_iotasks, sizeof(int)))) return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, "Error allocating memory for ioranks"); for (int i = 0; i < TARGET_NTASKS; i++) ios->ioranks[i] = i; - if (!(ios->compranks = calloc(ios->num_comptasks, sizeof(int)))) + if (!(ios->compranks = (int *) calloc(ios->num_comptasks, sizeof(int)))) return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, "Error allocating memory for compranks"); for (int i = 0; i < TARGET_NTASKS; i++) ios->compranks[i] = i; @@ -1196,17 +1196,17 @@ int test_rearrange_io2comp(MPI_Comm test_comm, int my_rank) int ret; /* Allocate some space for data. */ - if (!(sbuf = calloc(4, sizeof(int)))) + if (!(sbuf = (int *) calloc(4, sizeof(int)))) return PIO_ENOMEM; - if (!(rbuf = calloc(4, sizeof(int)))) + if (!(rbuf = (int *) calloc(4, sizeof(int)))) return PIO_ENOMEM; /* Allocate IO system info struct for this test. */ - if (!(ios = calloc(1, sizeof(iosystem_desc_t)))) + if (!(ios = (iosystem_desc_t *) calloc(1, sizeof(iosystem_desc_t)))) return PIO_ENOMEM; /* Allocate IO desc struct for this test. */ - if (!(iodesc = calloc(1, sizeof(io_desc_t)))) + if (!(iodesc = (io_desc_t *) calloc(1, sizeof(io_desc_t)))) return PIO_ENOMEM; ios->ioproc = 1; @@ -1246,11 +1246,11 @@ int test_rearrange_io2comp(MPI_Comm test_comm, int my_rank) ios->num_iotasks = 4; ios->num_comptasks = 4; ios->num_uniontasks = 4; - if (!(ios->ioranks = calloc(ios->num_iotasks, sizeof(int)))) + if (!(ios->ioranks = (int *) calloc(ios->num_iotasks, sizeof(int)))) return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, "Error allocating memory for ioranks"); for (int i = 0; i < TARGET_NTASKS; i++) ios->ioranks[i] = i; - if (!(ios->compranks = calloc(ios->num_comptasks, sizeof(int)))) + if (!(ios->compranks = (int *) calloc(ios->num_comptasks, sizeof(int)))) return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, "Error allocating memory for compranks"); for (int i = 0; i < TARGET_NTASKS; i++) ios->compranks[i] = i; diff --git a/tests/cunit/test_req_block_wait.c b/tests/cunit/test_req_block_wait.cpp similarity index 99% rename from tests/cunit/test_req_block_wait.c rename to tests/cunit/test_req_block_wait.cpp index a9c8e800dc..c68e7592c4 100644 --- a/tests/cunit/test_req_block_wait.c +++ b/tests/cunit/test_req_block_wait.cpp @@ -129,8 +129,8 @@ int test_setup(MPI_Comm comm, int rank, int sz, assert((comm != MPI_COMM_NULL) && (rank >= 0) && (sz > 0) && pios && pfile); - *pios = calloc(1, sizeof(iosystem_desc_t)); - *pfile = calloc(1, sizeof(file_desc_t)); + *pios = (iosystem_desc_t *) calloc(1, sizeof(iosystem_desc_t)); + *pfile = (file_desc_t *) calloc(1, sizeof(file_desc_t)); iosystem_desc_t *ios = *pios; file_desc_t *file = *pfile; diff --git a/tests/cunit/test_shared.c b/tests/cunit/test_shared.cpp similarity index 98% rename from tests/cunit/test_shared.c rename to tests/cunit/test_shared.cpp index 0926e0be9f..36bc007d04 100644 --- a/tests/cunit/test_shared.c +++ b/tests/cunit/test_shared.cpp @@ -104,7 +104,7 @@ int test_no_async2(int my_rank, int num_flavors, int *flavor, MPI_Comm test_comm /* Describe the decomposition. This is a 0-based array, so don't add 1! */ elements_per_pe = x_dim_len * y_dim_len / target_ntasks; - if (!(compdof = malloc(elements_per_pe * sizeof(PIO_Offset)))) + if (!(compdof = (PIO_Offset *) malloc(elements_per_pe * sizeof(PIO_Offset)))) return PIO_ENOMEM; for (int i = 0; i < elements_per_pe; i++) compdof[i] = my_rank * elements_per_pe + i; diff --git a/tests/cunit/test_spmd.c b/tests/cunit/test_spmd.cpp similarity index 100% rename from tests/cunit/test_spmd.c rename to tests/cunit/test_spmd.cpp From 12cb666f64d664c50dda8542d1a135dbd6f8f492 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Sun, 29 Sep 2024 22:06:21 -0500 Subject: [PATCH 003/194] Moving internal types from pio.h to pio_types.hpp Moving internal types from pio.h, which is exposed to the user, to pio_types.hpp, that is internal to the library --- src/clib/pio.h | 894 -------------------------------- src/clib/pio_internal.h | 1 + src/clib/pio_types.hpp | 944 ++++++++++++++++++++++++++++++++++ src/clib/spio_rearrange_any.h | 2 +- 4 files changed, 946 insertions(+), 895 deletions(-) create mode 100644 src/clib/pio_types.hpp diff --git a/src/clib/pio.h b/src/clib/pio.h index 477acd0195..dcf68adf3a 100644 --- a/src/clib/pio.h +++ b/src/clib/pio.h @@ -328,153 +328,6 @@ typedef PIO_OFFSET_C_TYPENAME PIO_Offset; #define PIO_EHDF5ERR (-700) #endif -#ifdef PIO_MICRO_TIMING -/** Some fwd declarations to avoid including internal headers */ -typedef struct mtimer_info *mtimer_t; -#endif - -/* Forward decl of hash map used for ADIOS reads */ -struct spio_hmap; - -/* Fwd declaration to use back pointer to var_desc_t in viobuf_cache */ -struct var_desc_t; - -/** The viobuf_cache is used to cache the rearranged data for the - * variable. The iobuf inside the cache is freed when the data - * is written out. - */ -typedef struct viobuf_cache -{ - /* Pointer to user buffer, ubuf points to internal PIO - * buffer that caches the user data - */ - void *ubuf; - size_t ubuf_sz; - /* Pointer to buffer containing the rearranged data */ - void *iobuf; - size_t iobuf_sz; - /* Pointer to fillvalue for this iobuf */ - void *fillvalue; - size_t fillvalue_sz; - /* Variable record/frame number corresponding to this - * buffer. - * Note: Multiple frames for a variable can be cached - * at a time in a list of viobuf_cache s - */ - int rec_num; - /* Any outstanding request associated with this cache */ - /* Used to keep track of a write request for the iobuf */ - int req; - /* Back pointer to the var_desc that contains this cache */ - struct var_desc_t *vdesc; - /* The next iobuf cache for this variable, each iobuf - * cache corresponds to a record/frame of the variable - */ - struct viobuf_cache *next; -} viobuf_cache_t; - -/** - * Variable description structure. - */ -typedef struct var_desc_t -{ - /* Variable ID. */ - int varid; - - /* Variable name - cached */ - char vname[PIO_MAX_NAME + 1]; - - /* Variable description */ - char vdesc[PIO_MAX_NAME + 1]; - - /* Non-zero if this is a record var (i.e. uses unlimited - * dimension). */ - int rec_var; - - /* Number of dimensions for this variable - cached data */ - int ndims; - - /** The record number to be written. Ignored if there is no - * unlimited dimension. */ - int record; - - /** FIXME: Combine request related members to a separate struct */ - /** ID of each outstanding pnetcdf request for this variable. */ - int *request; - - /** Size of each outstanding pnetcdf request for this variable */ - PIO_Offset *request_sz; - - /** Number of requests bending with pnetcdf. */ - int nreqs; - - /** Data buffers (to store rearranged data) for this var */ - /** Data buffers are stored in a singly linked list */ - viobuf_cache_t *viobuf_lhead; - viobuf_cache_t *viobuf_ltail; - - /* Holds the fill value of this var. */ - void *fillvalue; - - /* The PIO data type (PIO_INT, PIO_FLOAT, etc.) */ - int pio_type; - - /* The size of the data type (2 for PIO_SHORT, 4 for PIO_INT, etc.) */ - PIO_Offset type_size; - - /* Size of one record of the variable (number of bytes)*/ - PIO_Offset vrsize; - - /* Bytes pending to be read */ - PIO_Offset rb_pend; - - /* Bytes pending to be written out */ - PIO_Offset wb_pend; - -#ifdef PIO_MICRO_TIMING - mtimer_t rd_mtimer; - mtimer_t rd_rearr_mtimer; - - mtimer_t wr_mtimer; - mtimer_t wr_rearr_mtimer; -#endif - - /** Non-zero if fill mode is turned on for this var. */ - int use_fill; - - /** Buffer that contains the holegrid fill values used to fill in - * missing sections of data when using the subset rearranger. */ - void *fillbuf; -} var_desc_t; - -/** - * IO region structure. - * - * Each IO region is a unit of data which can be described using start - * and count arrays. Each IO task may in general have multiple io - * regions per variable. The box rearranger will have at most one io - * region per variable. - * - * The write from a particular IO task is divided into 1 or more - * regions each of which can be described using start and count. The - * io_region typedef is a linked list of those regions. - */ -typedef struct io_region -{ - /** The offset from the beginning of the data buffer to the - * beginning of this region. */ - int loffset; - - /** Start array for this region. */ - PIO_Offset *start; - - /** Count array for this region. */ - PIO_Offset *count; - - /** Pointer to the next io_region in the list. */ - struct io_region *next; -} io_region; - /** * Rearranger comm type. The rearranger option values must match the * definitions in the fortran interface. @@ -548,753 +401,6 @@ typedef struct rearr_opt rearr_comm_fc_opt_t io2comp; } rearr_opt_t; -/** - * IO descriptor structure. - * - * This structure defines the mapping for a given variable between - * compute and IO decomposition. - */ -typedef struct io_desc_t -{ - /** The ID of this io_desc_t. */ - int ioid; - - /** The length of the decomposition map. */ - int maplen; - - /** A 1-D array with iodesc->maplen elements, which are the - * 1-based mappings to the global array for that task. */ - PIO_Offset *map; - - /** Number of tasks involved in the communication between comp and - * io tasks. */ - int nrecvs; - - /** Local size of the decomposition array on the compute node. */ - int ndof; - - /** All vars included in this io_desc_t have the same number of - * dimensions. */ - int ndims; - - /** An array of size ndims with the length of each dimension. */ - int *dimlen; - - /** The actual number of IO tasks participating. */ - int num_aiotasks; - - /** The rearranger in use for this variable. */ - int rearranger; - - /** Maximum number of regions in the decomposition. */ - int maxregions; - - /** Does this decomp leave holes in the field (true) or write - * everywhere (false) */ - bool needsfill; - - /** The maximum number of bytes of this iodesc before flushing. */ - int maxbytes; - - /** The PIO type of the data. */ - int piotype; - - /** The size of one element of the piotype. */ - int piotype_size; - - /** The MPI type of the data. */ - MPI_Datatype mpitype; - - /** The size in bytes of a datum of MPI type mpitype. */ - int mpitype_size; - - /** Length of the iobuffer on this task for a single field on the - * IO node. The arrays from compute nodes gathered and rearranged - * to the io-nodes (which are sometimes collocated with compute - * nodes), each io task contains data from the compmap of one or - * more compute tasks in the iomap array. */ - PIO_Offset llen; - - /** Maximum llen participating. */ - PIO_Offset maxiobuflen; - - /** Array (length nrecvs) of computation tasks received from. */ - int *rfrom; - - /** Array (length nrecvs) of counts of data to be received from - * each computation task by the IO tasks. */ - int *rcount; - - /** Array (length numiotasks) of data counts to send to each task - * in the communication in pio_swapm(). */ - int *scount; - - /** Array (length ndof) for the BOX rearranger with the index - * for computation taks (send side during writes). */ - PIO_Offset *sindex; - - /** Index for the IO tasks (receive side during writes). */ - PIO_Offset *rindex; - - /** Array (of length nrecvs) of receive MPI types in pio_swapm() call. */ - MPI_Datatype *rtype; - - /** Array of send MPI types in pio_swapm() call. */ - MPI_Datatype *stype; - - /** Number of send MPI types in pio_swapm() call. */ - int num_stypes; - - /** Used when writing fill data. */ - int holegridsize; - - /** max holegridsize across all io tasks, needed for netcdf and netcdf4c serial */ - int maxholegridsize; - - /** Used when writing fill data. */ - int maxfillregions; - - /** Linked list of regions. */ - io_region *firstregion; - - /** Used when writing fill data. */ - io_region *fillregion; - - /** Rearranger flow control options - * (handshake, non-blocking sends, pending requests) - */ - rearr_opt_t rearr_opts; - - /** In the subset communicator each io task is associated with a - * unique group of comp tasks this is the communicator for that - * group. */ - MPI_Comm subset_comm; - -#if PIO_SAVE_DECOMPS - /* Indicates whether this iodesc has been saved to disk (the - * decomposition is dumped to disk) - */ - bool is_saved; -#endif - - /** Pointer to the next io_desc_t in the list. */ - struct io_desc_t *next; -} io_desc_t; - -/** - * PIO asynchronous operation types - */ -typedef enum pio_async_op_type -{ - PIO_ASYNC_INVALID_OP = 0, - PIO_ASYNC_REARR_OP, - PIO_ASYNC_PNETCDF_WRITE_OP, - PIO_ASYNC_FILE_WRITE_OPS, - PIO_ASYNC_NUM_OP_TYPES -} pio_async_op_type_t; - -/** - * PIO asynchronous op - */ -typedef struct pio_async_op -{ - pio_async_op_type_t op_type; - void *pdata; - /* Blocking wait function for this async op - * param 1 : A user defined data pointer - * return : PIO_NOERR on success, pio error code on failure - */ - int (*wait)(void *); - /* Non-blocking function for making progress on this async op - * param 1 : A user defined data pointer - * param 2 : Pointer to a flag that is set to true if async op - * is complete, false otherwise - * return : PIO_NOERR on success, pio error code on failure - */ - int (*poke)(void *, int *); - /* Free function for user defined pdata */ - void (*free)(void *); - struct pio_async_op *next; -} pio_async_op_t; - -/* Forward decl for I/O file summary stats info */ -struct spio_io_fstats_summary; - -/** - * IO system descriptor structure. - * - * This structure contains the general IO subsystem data and MPI - * structure - */ -typedef struct iosystem_desc_t -{ - /** The ID of this iosystem_desc_t. This will be obtained by - * calling PIOc_Init_Intercomm() or PIOc_Init_Intracomm(). */ - int iosysid; - - /* I/O System name */ - char sname[PIO_MAX_NAME + 1]; - - /** This is an MPI intra communicator that includes all the tasks in - * both the IO and the computation communicators. */ - MPI_Comm union_comm; - - /** This is an MPI intra communicator that includes all the tasks - * involved in IO. */ - MPI_Comm io_comm; - - /** This is an MPI intra communicator that includes all the tasks - * involved in computation. */ - MPI_Comm comp_comm; - - /** This is an MPI inter communicator between IO communicator and - * computation communicator. */ - MPI_Comm intercomm; - - /** This is a copy (but not an MPI copy) of either the comp (for - * non-async) or the union (for async) communicator. */ - MPI_Comm my_comm; - - /** This MPI group contains the processors involved in - * computation. */ - MPI_Group compgroup; - - /** This MPI group contains the processors involved in I/O. */ - MPI_Group iogroup; - - /** The number of tasks in the IO communicator. */ - int num_iotasks; - - /** The number of tasks in the computation communicator. */ - int num_comptasks; - - /** The number of tasks in the union communicator (will be - * num_comptasks for non-async, num_comptasks + num_iotasks for - * async). */ - int num_uniontasks; - - /** Rank of this task in the union communicator. */ - int union_rank; - - /** The rank of this process in the computation communicator, or -1 - * if this process is not part of the computation communicator. */ - int comp_rank; - - /** The rank of this process in the IO communicator, or -1 if this - * process is not part of the IO communicator. */ - int io_rank; - - /** Set to MPI_ROOT if this task is the master of IO communicator, 0 - * otherwise. */ - int iomaster; - - /** Set to MPI_ROOT if this task is the master of comp communicator, 0 - * otherwise. */ - int compmaster; - - /** Rank of IO root task (which is rank 0 in io_comm) in the union - * communicator. Will always be 0 for async situations. */ - int ioroot; - - /** Rank of computation root task (which is rank 0 in - * comm_comms[cmp]) in the union communicator. Will always = number - * of IO tasks in async situations. */ - int comproot; - - /** An array of the ranks of all IO tasks within the union - * communicator. */ - int *ioranks; - - /** An array of the ranks of all computation tasks within the - * union communicator. */ - int *compranks; - - /** Controls handling errors. */ - int error_handler; - - /** The rearranger decides which parts of a distributed array are - * handled by which IO tasks. */ - int default_rearranger; - - /** True if asynchronous interface is in use. */ - bool async; - - /** True if this task is a member of the IO communicator. */ - bool ioproc; - - /** True if this task is a member of a computation - * communicator. */ - bool compproc; - - /** MPI Info object. */ - MPI_Info info; - - /** Async I/O service message info */ - struct async_ios_msg_info_{ - int seq_num; - int prev_msg; - } async_ios_msg_info; - - /** Index of this component in the list of components. */ - int comp_idx; - - /** Rearranger options. */ - rearr_opt_t rearr_opts; - -#ifdef _ADIOS2 - /* ADIOS handles */ - adios2_adios *adiosH; /* Handle for ADIOS write */ - adios2_adios *adios_readerH; /* Handle for ADIOS read */ - int adios_io_process; - MPI_Comm adios_comm; - int adios_rank, num_adiostasks; - /* Block merging setup */ - MPI_Comm block_comm; - int block_myrank, block_nprocs; - #ifdef _SPIO_ADIOS_USE_COMPRESSION - /* ADIOS operator for applying a specific lossless compression method (e.g., Blosc2, BZip2) */ - adios2_operator* lossless_compression_operator; - int adios_lossless_compression_method; - #ifdef _SPIO_ADIOS_USE_LOSSY_COMPRESSION - /* ADIOS operator for applying a specific lossy compression method (e.g., SZ, MGARD, ZFP) */ - adios2_operator* lossy_compression_operator; - int adios_lossy_compression_method; - #endif - #endif -#endif - - /** I/O statistics associated with this I/O system */ - struct spio_io_fstats_summary *io_fstats; - - /* Number of pending async operations on this iosystem */ - int nasync_pend_ops; - - /* List of pending async operations on this iosystem */ - pio_async_op_t *async_pend_ops; - - /** Pointer to the next iosystem_desc_t in the list. */ - struct iosystem_desc_t *next; -} iosystem_desc_t; - -/** - * The multi buffer holds data from one or more variables. Data are - * accumulated in the multi-buffer. - */ -typedef struct wmulti_buffer -{ - /** The ID that describes the decomposition, as returned from - * PIOc_Init_Decomp(). */ - int ioid; - - /** Non-zero if this is a buffer for a record var. */ - int recordvar; - - /** Number of arrays of data in the multibuffer. Each array had - * data for one var or record. When multibuffer is flushed, all - * arrays are written and num_arrays returns to zero. */ - int num_arrays; - - /** Size of this variables data on local task. All vars in the - * multi-buffer have the same size. */ - int arraylen; - - /** Array of varids. */ - int *vid; - - /** An array of current record numbers, for record vars. One - * element per variable. */ - int *frame; - - /** Array of fill values used for each var. */ - void *fillvalue; - - /** Pointer to the data. */ - void *data; - - /** Pointer to the next multi-buffer in the list. */ - struct wmulti_buffer *next; -} wmulti_buffer; - -#ifdef _ADIOS2 -/* Interval map for ADIOS read */ -typedef struct adios_interval_map_t -{ - int n_adios_steps; - short **map; -} adios_interval_map_t; - -/* Maximum char array length to store "darray" or "put_var", for ADIOS read */ -#define NC_OP_TAG_MAX_LEN 8 - -/** Variable definition information saved at pioc_def_var, - * so that ADIOS can define the variable at write time when - * local dimensions and offsets are known. - */ -typedef struct adios_var_desc_t -{ - /** Variable name */ - char * name; - - /** NC type give at def_var time */ - int nc_type; - - /** Type converted from NC type to adios type */ - adios2_type adios_type; - size_t adios_type_size; - - /** Number of dimensions */ - int ndims; - - /** Global dims (dim var ids) */ - int * gdimids; - - /** Number of attributes defined for this variable */ - int nattrs; - - /** ADIOS varID, if it has already been defined. - * We avoid defining again when writing multiple records over time - */ - adios2_variable* adios_varid; // 0: undefined yet - - /* to handle PIOc_setframe with different decompositions */ - adios2_variable* decomp_varid; - adios2_variable* frame_varid; - adios2_variable* fillval_varid; - adios2_variable* num_block_writers_varid; - - /* to handle multi-dimensional temporal variables */ - adios2_variable* start_varid; - adios2_variable* count_varid; - - /* to buffer decomp id, frame id, fill value, and writer blocks */ - int32_t *decomp_buffer; - int32_t *frame_buffer; - char *fillval_buffer; - int32_t fillval_size; - int32_t *num_wb_buffer; - int32_t decomp_cnt, frame_cnt, fillval_cnt, num_wb_cnt; - int32_t max_buffer_cnt; - - /* Simplified version of an interval map implementation - * index is a frame_id and the value is the adios_step */ - adios_interval_map_t* interval_map; /* For ADIOS read */ - - /* Is this variable written with put_var or darray? */ - char nc_op_tag[NC_OP_TAG_MAX_LEN]; /* For ADIOS read */ -} adios_var_desc_t; - -/* Track attributes */ -typedef struct adios_att_desc_t -{ - /** Attribute name */ - char *att_name; - - /** NC type give at def_att time */ - nc_type att_type; - - /** length of attribute value */ - PIO_Offset att_len; - - /** ncid of the attribute */ - int att_ncid; - - /** attribute varid */ - int att_varid; - - /** Type converted from NC type to adios type */ - adios2_type adios_type; -} adios_att_desc_t; - -#ifdef _SPIO_ADIOS_USE_COMPRESSION -enum ADIOS_COMPRESSION_METHOD -{ - ADIOS_COMPRESSION_METHOD_BLOSC2 = 1, - - ADIOS_COMPRESSION_METHOD_BZIP2 = 2, - - ADIOS_COMPRESSION_METHOD_MGARD = 3, - - ADIOS_COMPRESSION_METHOD_SZ = 4, - - ADIOS_COMPRESSION_METHOD_ZFP = 5 -}; -#endif -#endif /* _ADIOS2 */ - -#ifdef _HDF5 -typedef struct hdf5_dim_desc_t -{ - /** Dimension name */ - char* name; - - /** Dimension length */ - PIO_Offset len; - - /** True if the dimension has a coordinate variable */ - bool has_coord_var; - - hid_t hdf5_dataset_id; -} hdf5_dim_desc_t; - -typedef struct hdf5_var_desc_t -{ - /** Variable name */ - char* name; - - /* Alternative name for a non-coordinate variable with the same name as a dimension */ - char* alt_name; - - /** NC type give at def_var time */ - int nc_type; - - /** Type converted from NC type to HDF5 type */ - hid_t hdf5_type; - - /** Number of dimensions */ - int ndims; - - /** Dimension IDs of the variable */ - int* hdf5_dimids; - - /** True if the variable is a coordinate variable */ - bool is_coord_var; - - hid_t hdf5_dataset_id; -} hdf5_var_desc_t; - -typedef struct hdf5_att_desc_t -{ - /** Attribute name */ - char *att_name; - - /** NC type give at def_att time */ - nc_type att_type; - - /** length of attribute value */ - PIO_Offset att_len; - - /** ncid of the attribute */ - int att_ncid; - - /** attribute varid */ - int att_varid; -} hdf5_att_desc_t; -#endif - -/** - * File descriptor structure. - * - * This structure holds information associated with each open file - */ -typedef struct file_desc_t -{ - /** The IO system ID used to open this file. */ - iosystem_desc_t *iosystem; - - /** The ncid returned for this file by the underlying library - * (netcdf or pnetcdf). */ - int fh; - -#ifdef _ADIOS2 - /** Save the filename, now just for printing it at close */ - char *filename; - - /** ADIOS file handler is 64bit integer */ - adios2_engine *engineH; - - /** Check if begin_step has been invoked. It is used to invoke end_step **/ - int begin_step_called; - int num_step_calls;; - int max_step_calls; - - /* - * Used to call adios2_end_step to avoid buffer overflow in MPI_Gatherv - * during ADIOS metadata write operation. - * - * if num_written_blocks * BLOCK_METADATA_SIZE >= BLOCK_COUNT_THRESHOLD, call adios2_end_step - * (Not implemented in this version. adios2_end_step is called if num_step_calls >= max_step_calls (= PIO_MAX_CACHED_STEPS_FOR_ADIOS)) - */ - unsigned int num_written_blocks; - - int write_decomp_id; - int write_frame_id; - int write_fillval_id; - - /** Handler for ADIOS group (of variables) */ - adios2_io *ioH; - - /** ADIOS output transport method name, POSIX or MPI_AGGREGATE */ - char transport[PIO_MAX_NAME]; - - /** Parameters for the transport method, required for MPI_AGGREGATE. - * Created automatically from the application setup */ - char params[PIO_MAX_NAME]; - - /** Need to store the dim names for finding them and using them when defining variables */ - char *dim_names[PIO_MAX_DIMS]; - PIO_Offset dim_values[PIO_MAX_DIMS]; - - /** Number of dim vars defined */ - int num_dim_vars; - - /** Variable information, max PIO_MAX_VARS variables allowed */ - struct adios_var_desc_t adios_vars[PIO_MAX_VARS]; - - /** Number of vars defined */ - int num_vars; - - /** Number of global attributes defined. Needed to support PIOc_inq_nattrs() */ - int num_gattrs; - - /* all procs rank, etc */ - MPI_Comm all_comm; - int all_rank, num_alltasks; - - /* ADIOS rank, etc */ - int adios_io_process; - MPI_Comm adios_comm; - int adios_rank, num_adiostasks; - - /* Merging distributed array blocks to reduce I/O overhead */ - /* Grouping of processes for block merging */ - MPI_Comm block_comm; - int block_myrank, block_nprocs; - int *block_list; - - /* Buffers for merging distributed array blocks */ - unsigned int *array_counts; - unsigned int array_counts_size; - unsigned int *array_disp; - unsigned int array_disp_size; - char *block_array; - size_t block_array_size; - - /* Track attributes */ - /** attribute information. Allow PIO_MAX_VARS for now. */ - struct adios_att_desc_t adios_attrs[PIO_MAX_ATTRS]; - int num_attrs; - - int fillmode; - - /* Handle PIO_Offset */ - int pio_offset_size; - adios2_type pio_offset_type; - - /** Array for decompositions that has been written already (must write only once) */ - int n_written_ioids; - int written_ioids[PIO_MAX_ADIOS_DECOMPS]; /* written_ioids[N] = ioid if that decomp has been already written, */ - - /** Store current frameid for end_step in PIO_setframe */ - int current_frame; - - /* Some caches (hash tables) for ADIOS read */ - struct spio_hmap *cache_data_blocks; - struct spio_hmap *cache_block_sizes; - struct spio_hmap *cache_darray_info; - - char io_name_reader[PIO_MAX_NAME + 1]; /* Name of io object, for ADIOS read */ - size_t adios_reader_num_decomp_blocks; /* Number of decomposition blocks, for ADIOS read */ - - /* Indicates whether the decomposition maps (for ADIOS write) need to be stored in BP files. Default is true. */ - bool store_adios_decomp; -#endif /* _ADIOS2 */ - -#ifdef _HDF5 - hid_t hdf5_file_id; - - /* Collective dataset transfer property list, used by H5Dwrite */ - hid_t dxplid_coll; - - /* Independent dataset transfer property list, used by H5Dwrite */ - hid_t dxplid_indep; - - struct hdf5_dim_desc_t hdf5_dims[PIO_MAX_DIMS]; - - /** Number of dims defined */ - int hdf5_num_dims; - - struct hdf5_var_desc_t hdf5_vars[PIO_MAX_VARS]; - - /** Number of vars defined */ - int hdf5_num_vars; - - struct hdf5_att_desc_t hdf5_attrs[PIO_MAX_ATTRS]; - - /** Number of attrs defined */ - int hdf5_num_attrs; - - /** Number of global attrs defined */ - int hdf5_num_gattrs; -#endif /* _HDF5 */ - - /* File name - cached */ - char fname[PIO_MAX_NAME + 1]; - - /** The ncid that will be returned to the user. */ - int pio_ncid; - - /** The PIO_TYPE value that was used to open this file. */ - int iotype; - - /** List of variables in this file (deprecated). */ - struct var_desc_t varlist[PIO_MAX_VARS]; - - /* Number of unlimited dim ids, if no unlimited id present = 0 */ - int num_unlim_dimids; - - /* Unlimited dim ids, if no unlimited id present = NULL */ - int *unlim_dimids; - - /** Mode used when file was opened. */ - int mode; - - /** The wmulti_buffer is used to aggregate multiple variables with - * the same communication pattern prior to a write. */ - struct wmulti_buffer buffer; - - /* Bytes pending to be read on this file*/ - PIO_Offset rb_pend; - - /* Bytes pending to be written out for this file */ - PIO_Offset wb_pend; - - /** Data buffer per IO decomposition for this file. */ - /** Cache for storing data corresponding to multiple - * variables binned on the I/O decomposition used by - * the variable */ - void *mvcache; - - /** I/O statistics associated with this file */ - struct spio_io_fstats_summary *io_fstats; - - /* Number of pending async operations on this file */ - int nasync_pend_ops; - - /* List of pending async operations on this file */ - pio_async_op_t *async_pend_ops; - - /** Total number of pending ops on this file, including - * nasync_pend_ops. In the case where nasync_pend_ops == 0 - * npend_ops shows any other pending ops (e.g. non-blocking - * write done of rearranged data, still need to wait - * on it) */ - int npend_ops; - - /** Pointer to the next file_desc_t in the list of open files. */ - struct file_desc_t *next; - - /** True if this task should participate in IO (only true for one - * task with netcdf serial files. */ - int do_io; - - /** True if we need reserve some extra space in the header when - * creating NetCDF files to accommodate anticipated changes. */ - bool reserve_extra_header_space; - - /** True if this is an existing file reopened */ - bool is_reopened; -} file_desc_t; - /** * These are the supported methods of reading/writing input/output * files. The PnetCDF, NetCDF and HDF5 libraries output data in the diff --git a/src/clib/pio_internal.h b/src/clib/pio_internal.h index c5cc734e51..3ea45ca70a 100644 --- a/src/clib/pio_internal.h +++ b/src/clib/pio_internal.h @@ -32,6 +32,7 @@ #endif #include #include "spio_ltimer.h" +#include "pio_types.hpp" #if defined(__cplusplus) extern "C" { diff --git a/src/clib/pio_types.hpp b/src/clib/pio_types.hpp new file mode 100644 index 0000000000..bbbb76ed40 --- /dev/null +++ b/src/clib/pio_types.hpp @@ -0,0 +1,944 @@ +#ifndef __PIO_TYPES_HPP__ +#define __PIO_TYPES_HPP__ + +#include +#include +#include +#include + +#ifdef MPI_SERIAL +#if defined(__cplusplus) +extern "C" { +#endif +#endif + +#include + +#ifdef MPI_SERIAL +#if defined(__cplusplus) +} +#endif +#endif + +#include "pio_config.h" + +#ifdef _NETCDF +#include +#ifdef _NETCDF4 +#include +#endif +#endif + +#ifdef _PNETCDF +#include +#endif + +#ifdef _ADIOS2 +#include +#include +#include +#include +#include +#endif + +#ifdef _HDF5 +#include +#include +#include +#endif + +#ifdef PIO_MICRO_TIMING +/** Some fwd declarations to avoid including internal headers */ +typedef struct mtimer_info *mtimer_t; +#endif + +/* Forward decl of hash map used for ADIOS reads */ +struct spio_hmap; + +/* Fwd declaration to use back pointer to var_desc_t in viobuf_cache */ +struct var_desc_t; + +/** The viobuf_cache is used to cache the rearranged data for the + * variable. The iobuf inside the cache is freed when the data + * is written out. + */ +typedef struct viobuf_cache +{ + /* Pointer to user buffer, ubuf points to internal PIO + * buffer that caches the user data + */ + void *ubuf; + size_t ubuf_sz; + /* Pointer to buffer containing the rearranged data */ + void *iobuf; + size_t iobuf_sz; + /* Pointer to fillvalue for this iobuf */ + void *fillvalue; + size_t fillvalue_sz; + /* Variable record/frame number corresponding to this + * buffer. + * Note: Multiple frames for a variable can be cached + * at a time in a list of viobuf_cache s + */ + int rec_num; + /* Any outstanding request associated with this cache */ + /* Used to keep track of a write request for the iobuf */ + int req; + /* Back pointer to the var_desc that contains this cache */ + struct var_desc_t *vdesc; + /* The next iobuf cache for this variable, each iobuf + * cache corresponds to a record/frame of the variable + */ + struct viobuf_cache *next; +} viobuf_cache_t; + +/** + * Variable description structure. + */ +typedef struct var_desc_t +{ + /* Variable ID. */ + int varid; + + /* Variable name - cached */ + char vname[PIO_MAX_NAME + 1]; + + /* Variable description */ + char vdesc[PIO_MAX_NAME + 1]; + + /* Non-zero if this is a record var (i.e. uses unlimited + * dimension). */ + int rec_var; + + /* Number of dimensions for this variable - cached data */ + int ndims; + + /** The record number to be written. Ignored if there is no + * unlimited dimension. */ + int record; + + /** FIXME: Combine request related members to a separate struct */ + /** ID of each outstanding pnetcdf request for this variable. */ + int *request; + + /** Size of each outstanding pnetcdf request for this variable */ + PIO_Offset *request_sz; + + /** Number of requests bending with pnetcdf. */ + int nreqs; + + /** Data buffers (to store rearranged data) for this var */ + /** Data buffers are stored in a singly linked list */ + viobuf_cache_t *viobuf_lhead; + viobuf_cache_t *viobuf_ltail; + + /* Holds the fill value of this var. */ + void *fillvalue; + + /* The PIO data type (PIO_INT, PIO_FLOAT, etc.) */ + int pio_type; + + /* The size of the data type (2 for PIO_SHORT, 4 for PIO_INT, etc.) */ + PIO_Offset type_size; + + /* Size of one record of the variable (number of bytes)*/ + PIO_Offset vrsize; + + /* Bytes pending to be read */ + PIO_Offset rb_pend; + + /* Bytes pending to be written out */ + PIO_Offset wb_pend; + +#ifdef PIO_MICRO_TIMING + mtimer_t rd_mtimer; + mtimer_t rd_rearr_mtimer; + + mtimer_t wr_mtimer; + mtimer_t wr_rearr_mtimer; +#endif + + /** Non-zero if fill mode is turned on for this var. */ + int use_fill; + + /** Buffer that contains the holegrid fill values used to fill in + * missing sections of data when using the subset rearranger. */ + void *fillbuf; +} var_desc_t; + +/** + * IO region structure. + * + * Each IO region is a unit of data which can be described using start + * and count arrays. Each IO task may in general have multiple io + * regions per variable. The box rearranger will have at most one io + * region per variable. + * + * The write from a particular IO task is divided into 1 or more + * regions each of which can be described using start and count. The + * io_region typedef is a linked list of those regions. + */ +typedef struct io_region +{ + /** The offset from the beginning of the data buffer to the + * beginning of this region. */ + int loffset; + + /** Start array for this region. */ + PIO_Offset *start; + + /** Count array for this region. */ + PIO_Offset *count; + + /** Pointer to the next io_region in the list. */ + struct io_region *next; +} io_region; + +/** + * IO descriptor structure. + * + * This structure defines the mapping for a given variable between + * compute and IO decomposition. + */ +typedef struct io_desc_t +{ + /** The ID of this io_desc_t. */ + int ioid; + + /** The length of the decomposition map. */ + int maplen; + + /** A 1-D array with iodesc->maplen elements, which are the + * 1-based mappings to the global array for that task. */ + PIO_Offset *map; + + /** Number of tasks involved in the communication between comp and + * io tasks. */ + int nrecvs; + + /** Local size of the decomposition array on the compute node. */ + int ndof; + + /** All vars included in this io_desc_t have the same number of + * dimensions. */ + int ndims; + + /** An array of size ndims with the length of each dimension. */ + int *dimlen; + + /** The actual number of IO tasks participating. */ + int num_aiotasks; + + /** The rearranger in use for this variable. */ + int rearranger; + + /** Maximum number of regions in the decomposition. */ + int maxregions; + + /** Does this decomp leave holes in the field (true) or write + * everywhere (false) */ + bool needsfill; + + /** The maximum number of bytes of this iodesc before flushing. */ + int maxbytes; + + /** The PIO type of the data. */ + int piotype; + + /** The size of one element of the piotype. */ + int piotype_size; + + /** The MPI type of the data. */ + MPI_Datatype mpitype; + + /** The size in bytes of a datum of MPI type mpitype. */ + int mpitype_size; + + /** Length of the iobuffer on this task for a single field on the + * IO node. The arrays from compute nodes gathered and rearranged + * to the io-nodes (which are sometimes collocated with compute + * nodes), each io task contains data from the compmap of one or + * more compute tasks in the iomap array. */ + PIO_Offset llen; + + /** Maximum llen participating. */ + PIO_Offset maxiobuflen; + + /** Array (length nrecvs) of computation tasks received from. */ + int *rfrom; + + /** Array (length nrecvs) of counts of data to be received from + * each computation task by the IO tasks. */ + int *rcount; + + /** Array (length numiotasks) of data counts to send to each task + * in the communication in pio_swapm(). */ + int *scount; + + /** Array (length ndof) for the BOX rearranger with the index + * for computation taks (send side during writes). */ + PIO_Offset *sindex; + + /** Index for the IO tasks (receive side during writes). */ + PIO_Offset *rindex; + + /** Array (of length nrecvs) of receive MPI types in pio_swapm() call. */ + MPI_Datatype *rtype; + + /** Array of send MPI types in pio_swapm() call. */ + MPI_Datatype *stype; + + /** Number of send MPI types in pio_swapm() call. */ + int num_stypes; + + /** Used when writing fill data. */ + int holegridsize; + + /** max holegridsize across all io tasks, needed for netcdf and netcdf4c serial */ + int maxholegridsize; + + /** Used when writing fill data. */ + int maxfillregions; + + /** Linked list of regions. */ + io_region *firstregion; + + /** Used when writing fill data. */ + io_region *fillregion; + + /** Rearranger flow control options + * (handshake, non-blocking sends, pending requests) + */ + rearr_opt_t rearr_opts; + + /** In the subset communicator each io task is associated with a + * unique group of comp tasks this is the communicator for that + * group. */ + MPI_Comm subset_comm; + +#if PIO_SAVE_DECOMPS + /* Indicates whether this iodesc has been saved to disk (the + * decomposition is dumped to disk) + */ + bool is_saved; +#endif + + /** Pointer to the next io_desc_t in the list. */ + struct io_desc_t *next; +} io_desc_t; + +/** + * PIO asynchronous operation types + */ +typedef enum pio_async_op_type +{ + PIO_ASYNC_INVALID_OP = 0, + PIO_ASYNC_REARR_OP, + PIO_ASYNC_PNETCDF_WRITE_OP, + PIO_ASYNC_FILE_WRITE_OPS, + PIO_ASYNC_NUM_OP_TYPES +} pio_async_op_type_t; + +/** + * PIO asynchronous op + */ +typedef struct pio_async_op +{ + pio_async_op_type_t op_type; + void *pdata; + /* Blocking wait function for this async op + * param 1 : A user defined data pointer + * return : PIO_NOERR on success, pio error code on failure + */ + int (*wait)(void *); + /* Non-blocking function for making progress on this async op + * param 1 : A user defined data pointer + * param 2 : Pointer to a flag that is set to true if async op + * is complete, false otherwise + * return : PIO_NOERR on success, pio error code on failure + */ + int (*poke)(void *, int *); + /* Free function for user defined pdata */ + void (*free)(void *); + struct pio_async_op *next; +} pio_async_op_t; + +/* Forward decl for I/O file summary stats info */ +struct spio_io_fstats_summary; + +/** + * IO system descriptor structure. + * + * This structure contains the general IO subsystem data and MPI + * structure + */ +typedef struct iosystem_desc_t +{ + /** The ID of this iosystem_desc_t. This will be obtained by + * calling PIOc_Init_Intercomm() or PIOc_Init_Intracomm(). */ + int iosysid; + + /* I/O System name */ + char sname[PIO_MAX_NAME + 1]; + + /** This is an MPI intra communicator that includes all the tasks in + * both the IO and the computation communicators. */ + MPI_Comm union_comm; + + /** This is an MPI intra communicator that includes all the tasks + * involved in IO. */ + MPI_Comm io_comm; + + /** This is an MPI intra communicator that includes all the tasks + * involved in computation. */ + MPI_Comm comp_comm; + + /** This is an MPI inter communicator between IO communicator and + * computation communicator. */ + MPI_Comm intercomm; + + /** This is a copy (but not an MPI copy) of either the comp (for + * non-async) or the union (for async) communicator. */ + MPI_Comm my_comm; + + /** This MPI group contains the processors involved in + * computation. */ + MPI_Group compgroup; + + /** This MPI group contains the processors involved in I/O. */ + MPI_Group iogroup; + + /** The number of tasks in the IO communicator. */ + int num_iotasks; + + /** The number of tasks in the computation communicator. */ + int num_comptasks; + + /** The number of tasks in the union communicator (will be + * num_comptasks for non-async, num_comptasks + num_iotasks for + * async). */ + int num_uniontasks; + + /** Rank of this task in the union communicator. */ + int union_rank; + + /** The rank of this process in the computation communicator, or -1 + * if this process is not part of the computation communicator. */ + int comp_rank; + + /** The rank of this process in the IO communicator, or -1 if this + * process is not part of the IO communicator. */ + int io_rank; + + /** Set to MPI_ROOT if this task is the master of IO communicator, 0 + * otherwise. */ + int iomaster; + + /** Set to MPI_ROOT if this task is the master of comp communicator, 0 + * otherwise. */ + int compmaster; + + /** Rank of IO root task (which is rank 0 in io_comm) in the union + * communicator. Will always be 0 for async situations. */ + int ioroot; + + /** Rank of computation root task (which is rank 0 in + * comm_comms[cmp]) in the union communicator. Will always = number + * of IO tasks in async situations. */ + int comproot; + + /** An array of the ranks of all IO tasks within the union + * communicator. */ + int *ioranks; + + /** An array of the ranks of all computation tasks within the + * union communicator. */ + int *compranks; + + /** Controls handling errors. */ + int error_handler; + + /** The rearranger decides which parts of a distributed array are + * handled by which IO tasks. */ + int default_rearranger; + + /** True if asynchronous interface is in use. */ + bool async; + + /** True if this task is a member of the IO communicator. */ + bool ioproc; + + /** True if this task is a member of a computation + * communicator. */ + bool compproc; + + /** MPI Info object. */ + MPI_Info info; + + /** Async I/O service message info */ + struct async_ios_msg_info_{ + int seq_num; + int prev_msg; + } async_ios_msg_info; + + /** Index of this component in the list of components. */ + int comp_idx; + + /** Rearranger options. */ + rearr_opt_t rearr_opts; + +#ifdef _ADIOS2 + /* ADIOS handles */ + adios2_adios *adiosH; /* Handle for ADIOS write */ + adios2_adios *adios_readerH; /* Handle for ADIOS read */ + int adios_io_process; + MPI_Comm adios_comm; + int adios_rank, num_adiostasks; + /* Block merging setup */ + MPI_Comm block_comm; + int block_myrank, block_nprocs; + #ifdef _SPIO_ADIOS_USE_COMPRESSION + /* ADIOS operator for applying a specific lossless compression method (e.g., Blosc2, BZip2) */ + adios2_operator* lossless_compression_operator; + int adios_lossless_compression_method; + #ifdef _SPIO_ADIOS_USE_LOSSY_COMPRESSION + /* ADIOS operator for applying a specific lossy compression method (e.g., SZ, MGARD, ZFP) */ + adios2_operator* lossy_compression_operator; + int adios_lossy_compression_method; + #endif + #endif +#endif + + /** I/O statistics associated with this I/O system */ + struct spio_io_fstats_summary *io_fstats; + + /* Number of pending async operations on this iosystem */ + int nasync_pend_ops; + + /* List of pending async operations on this iosystem */ + pio_async_op_t *async_pend_ops; + + /** Pointer to the next iosystem_desc_t in the list. */ + struct iosystem_desc_t *next; +} iosystem_desc_t; + +/** + * The multi buffer holds data from one or more variables. Data are + * accumulated in the multi-buffer. + */ +typedef struct wmulti_buffer +{ + /** The ID that describes the decomposition, as returned from + * PIOc_Init_Decomp(). */ + int ioid; + + /** Non-zero if this is a buffer for a record var. */ + int recordvar; + + /** Number of arrays of data in the multibuffer. Each array had + * data for one var or record. When multibuffer is flushed, all + * arrays are written and num_arrays returns to zero. */ + int num_arrays; + + /** Size of this variables data on local task. All vars in the + * multi-buffer have the same size. */ + int arraylen; + + /** Array of varids. */ + int *vid; + + /** An array of current record numbers, for record vars. One + * element per variable. */ + int *frame; + + /** Array of fill values used for each var. */ + void *fillvalue; + + /** Pointer to the data. */ + void *data; + + /** Pointer to the next multi-buffer in the list. */ + struct wmulti_buffer *next; +} wmulti_buffer; + +#ifdef _ADIOS2 +/* Interval map for ADIOS read */ +typedef struct adios_interval_map_t +{ + int n_adios_steps; + short **map; +} adios_interval_map_t; + +/* Maximum char array length to store "darray" or "put_var", for ADIOS read */ +#define NC_OP_TAG_MAX_LEN 8 + +/** Variable definition information saved at pioc_def_var, + * so that ADIOS can define the variable at write time when + * local dimensions and offsets are known. + */ +typedef struct adios_var_desc_t +{ + /** Variable name */ + char * name; + + /** NC type give at def_var time */ + int nc_type; + + /** Type converted from NC type to adios type */ + adios2_type adios_type; + size_t adios_type_size; + + /** Number of dimensions */ + int ndims; + + /** Global dims (dim var ids) */ + int * gdimids; + + /** Number of attributes defined for this variable */ + int nattrs; + + /** ADIOS varID, if it has already been defined. + * We avoid defining again when writing multiple records over time + */ + adios2_variable* adios_varid; // 0: undefined yet + + /* to handle PIOc_setframe with different decompositions */ + adios2_variable* decomp_varid; + adios2_variable* frame_varid; + adios2_variable* fillval_varid; + adios2_variable* num_block_writers_varid; + + /* to handle multi-dimensional temporal variables */ + adios2_variable* start_varid; + adios2_variable* count_varid; + + /* to buffer decomp id, frame id, fill value, and writer blocks */ + int32_t *decomp_buffer; + int32_t *frame_buffer; + char *fillval_buffer; + int32_t fillval_size; + int32_t *num_wb_buffer; + int32_t decomp_cnt, frame_cnt, fillval_cnt, num_wb_cnt; + int32_t max_buffer_cnt; + + /* Simplified version of an interval map implementation + * index is a frame_id and the value is the adios_step */ + adios_interval_map_t* interval_map; /* For ADIOS read */ + + /* Is this variable written with put_var or darray? */ + char nc_op_tag[NC_OP_TAG_MAX_LEN]; /* For ADIOS read */ +} adios_var_desc_t; + +/* Track attributes */ +typedef struct adios_att_desc_t +{ + /** Attribute name */ + char *att_name; + + /** NC type give at def_att time */ + nc_type att_type; + + /** length of attribute value */ + PIO_Offset att_len; + + /** ncid of the attribute */ + int att_ncid; + + /** attribute varid */ + int att_varid; + + /** Type converted from NC type to adios type */ + adios2_type adios_type; +} adios_att_desc_t; + +#ifdef _SPIO_ADIOS_USE_COMPRESSION +enum ADIOS_COMPRESSION_METHOD +{ + ADIOS_COMPRESSION_METHOD_BLOSC2 = 1, + + ADIOS_COMPRESSION_METHOD_BZIP2 = 2, + + ADIOS_COMPRESSION_METHOD_MGARD = 3, + + ADIOS_COMPRESSION_METHOD_SZ = 4, + + ADIOS_COMPRESSION_METHOD_ZFP = 5 +}; +#endif +#endif /* _ADIOS2 */ + +#ifdef _HDF5 +typedef struct hdf5_dim_desc_t +{ + /** Dimension name */ + char* name; + + /** Dimension length */ + PIO_Offset len; + + /** True if the dimension has a coordinate variable */ + bool has_coord_var; + + hid_t hdf5_dataset_id; +} hdf5_dim_desc_t; + +typedef struct hdf5_var_desc_t +{ + /** Variable name */ + char* name; + + /* Alternative name for a non-coordinate variable with the same name as a dimension */ + char* alt_name; + + /** NC type give at def_var time */ + int nc_type; + + /** Type converted from NC type to HDF5 type */ + hid_t hdf5_type; + + /** Number of dimensions */ + int ndims; + + /** Dimension IDs of the variable */ + int* hdf5_dimids; + + /** True if the variable is a coordinate variable */ + bool is_coord_var; + + hid_t hdf5_dataset_id; +} hdf5_var_desc_t; + +typedef struct hdf5_att_desc_t +{ + /** Attribute name */ + char *att_name; + + /** NC type give at def_att time */ + nc_type att_type; + + /** length of attribute value */ + PIO_Offset att_len; + + /** ncid of the attribute */ + int att_ncid; + + /** attribute varid */ + int att_varid; +} hdf5_att_desc_t; +#endif + +/** + * File descriptor structure. + * + * This structure holds information associated with each open file + */ +typedef struct file_desc_t +{ + /** The IO system ID used to open this file. */ + iosystem_desc_t *iosystem; + + /** The ncid returned for this file by the underlying library + * (netcdf or pnetcdf). */ + int fh; + +#ifdef _ADIOS2 + /** Save the filename, now just for printing it at close */ + char *filename; + + /** ADIOS file handler is 64bit integer */ + adios2_engine *engineH; + + /** Check if begin_step has been invoked. It is used to invoke end_step **/ + int begin_step_called; + int num_step_calls;; + int max_step_calls; + + /* + * Used to call adios2_end_step to avoid buffer overflow in MPI_Gatherv + * during ADIOS metadata write operation. + * + * if num_written_blocks * BLOCK_METADATA_SIZE >= BLOCK_COUNT_THRESHOLD, call adios2_end_step + * (Not implemented in this version. adios2_end_step is called if num_step_calls >= max_step_calls (= PIO_MAX_CACHED_STEPS_FOR_ADIOS)) + */ + unsigned int num_written_blocks; + + int write_decomp_id; + int write_frame_id; + int write_fillval_id; + + /** Handler for ADIOS group (of variables) */ + adios2_io *ioH; + + /** ADIOS output transport method name, POSIX or MPI_AGGREGATE */ + char transport[PIO_MAX_NAME]; + + /** Parameters for the transport method, required for MPI_AGGREGATE. + * Created automatically from the application setup */ + char params[PIO_MAX_NAME]; + + /** Need to store the dim names for finding them and using them when defining variables */ + char *dim_names[PIO_MAX_DIMS]; + PIO_Offset dim_values[PIO_MAX_DIMS]; + + /** Number of dim vars defined */ + int num_dim_vars; + + /** Variable information, max PIO_MAX_VARS variables allowed */ + struct adios_var_desc_t adios_vars[PIO_MAX_VARS]; + + /** Number of vars defined */ + int num_vars; + + /** Number of global attributes defined. Needed to support PIOc_inq_nattrs() */ + int num_gattrs; + + /* all procs rank, etc */ + MPI_Comm all_comm; + int all_rank, num_alltasks; + + /* ADIOS rank, etc */ + int adios_io_process; + MPI_Comm adios_comm; + int adios_rank, num_adiostasks; + + /* Merging distributed array blocks to reduce I/O overhead */ + /* Grouping of processes for block merging */ + MPI_Comm block_comm; + int block_myrank, block_nprocs; + int *block_list; + + /* Buffers for merging distributed array blocks */ + unsigned int *array_counts; + unsigned int array_counts_size; + unsigned int *array_disp; + unsigned int array_disp_size; + char *block_array; + size_t block_array_size; + + /* Track attributes */ + /** attribute information. Allow PIO_MAX_VARS for now. */ + struct adios_att_desc_t adios_attrs[PIO_MAX_ATTRS]; + int num_attrs; + + int fillmode; + + /* Handle PIO_Offset */ + int pio_offset_size; + adios2_type pio_offset_type; + + /** Array for decompositions that has been written already (must write only once) */ + int n_written_ioids; + int written_ioids[PIO_MAX_ADIOS_DECOMPS]; /* written_ioids[N] = ioid if that decomp has been already written, */ + + /** Store current frameid for end_step in PIO_setframe */ + int current_frame; + + /* Some caches (hash tables) for ADIOS read */ + struct spio_hmap *cache_data_blocks; + struct spio_hmap *cache_block_sizes; + struct spio_hmap *cache_darray_info; + + char io_name_reader[PIO_MAX_NAME + 1]; /* Name of io object, for ADIOS read */ + size_t adios_reader_num_decomp_blocks; /* Number of decomposition blocks, for ADIOS read */ + + /* Indicates whether the decomposition maps (for ADIOS write) need to be stored in BP files. Default is true. */ + bool store_adios_decomp; +#endif /* _ADIOS2 */ + +#ifdef _HDF5 + hid_t hdf5_file_id; + + /* Collective dataset transfer property list, used by H5Dwrite */ + hid_t dxplid_coll; + + /* Independent dataset transfer property list, used by H5Dwrite */ + hid_t dxplid_indep; + + struct hdf5_dim_desc_t hdf5_dims[PIO_MAX_DIMS]; + + /** Number of dims defined */ + int hdf5_num_dims; + + struct hdf5_var_desc_t hdf5_vars[PIO_MAX_VARS]; + + /** Number of vars defined */ + int hdf5_num_vars; + + struct hdf5_att_desc_t hdf5_attrs[PIO_MAX_ATTRS]; + + /** Number of attrs defined */ + int hdf5_num_attrs; + + /** Number of global attrs defined */ + int hdf5_num_gattrs; +#endif /* _HDF5 */ + + /* File name - cached */ + char fname[PIO_MAX_NAME + 1]; + + /** The ncid that will be returned to the user. */ + int pio_ncid; + + /** The PIO_TYPE value that was used to open this file. */ + int iotype; + + /** List of variables in this file (deprecated). */ + struct var_desc_t varlist[PIO_MAX_VARS]; + + /* Number of unlimited dim ids, if no unlimited id present = 0 */ + int num_unlim_dimids; + + /* Unlimited dim ids, if no unlimited id present = NULL */ + int *unlim_dimids; + + /** Mode used when file was opened. */ + int mode; + + /** The wmulti_buffer is used to aggregate multiple variables with + * the same communication pattern prior to a write. */ + struct wmulti_buffer buffer; + + /* Bytes pending to be read on this file*/ + PIO_Offset rb_pend; + + /* Bytes pending to be written out for this file */ + PIO_Offset wb_pend; + + /** Data buffer per IO decomposition for this file. */ + /** Cache for storing data corresponding to multiple + * variables binned on the I/O decomposition used by + * the variable */ + void *mvcache; + + /** I/O statistics associated with this file */ + struct spio_io_fstats_summary *io_fstats; + + /* Number of pending async operations on this file */ + int nasync_pend_ops; + + /* List of pending async operations on this file */ + pio_async_op_t *async_pend_ops; + + /** Total number of pending ops on this file, including + * nasync_pend_ops. In the case where nasync_pend_ops == 0 + * npend_ops shows any other pending ops (e.g. non-blocking + * write done of rearranged data, still need to wait + * on it) */ + int npend_ops; + + /** Pointer to the next file_desc_t in the list of open files. */ + struct file_desc_t *next; + + /** True if this task should participate in IO (only true for one + * task with netcdf serial files. */ + int do_io; + + /** True if we need reserve some extra space in the header when + * creating NetCDF files to accommodate anticipated changes. */ + bool reserve_extra_header_space; + + /** True if this is an existing file reopened */ + bool is_reopened; +} file_desc_t; + +#endif // __PIO_TYPES_HPP__ diff --git a/src/clib/spio_rearrange_any.h b/src/clib/spio_rearrange_any.h index 47145ccce1..605d2da0ee 100644 --- a/src/clib/spio_rearrange_any.h +++ b/src/clib/spio_rearrange_any.h @@ -3,7 +3,7 @@ #include "pio_config.h" #include "pio.h" -//#include "pio_internal.h" +#include "pio_internal.h" #if defined(__cplusplus) extern "C" { From 2c5e93b6e0c641f855b77cbcb1b5e4b843c0461d Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 30 Sep 2024 21:47:29 -0500 Subject: [PATCH 004/194] Replacing custom lists with C++ STL ds Replacing custom implementation of singly linked lists with STL maps for storing global collection of files/iosystems/iodescs. Moving to maps should allow for fast searches in the collection without resorting to custom hacks (e.g. caching the pointer to the last node). --- src/clib/pio_lists.cpp | 536 ++++++++++++++++---------------------- tests/cunit/test_spmd.cpp | 10 +- 2 files changed, 233 insertions(+), 313 deletions(-) diff --git a/src/clib/pio_lists.cpp b/src/clib/pio_lists.cpp index 0e9b5f37eb..4d40698fc4 100644 --- a/src/clib/pio_lists.cpp +++ b/src/clib/pio_lists.cpp @@ -2,23 +2,33 @@ * @file * PIO list functions. */ +#include +#include +#include +#include #include #include #include #ifdef PIO_MICRO_TIMING #include "pio_timer.h" #endif -#include -#include #include "spio_file_mvcache.h" #include "spio_io_summary.h" #include "spio_hash.h" -static io_desc_t *pio_iodesc_list = NULL; -static io_desc_t *current_iodesc = NULL; -static iosystem_desc_t *pio_iosystem_list = NULL; -static file_desc_t *pio_file_list = NULL; -static file_desc_t *current_file = NULL; +namespace SPIO_Util{ + namespace SPIO_Lists{ + namespace GVars{ + std::map pio_iodesc_list; + std::map pio_iosystem_list; + std::map pio_file_list; + } + } +} + +/* Arbitrary start ids for structures */ +const int PIO_FILE_START_ID = 16; +const int PIO_IOSYSTEM_START_ID = 2048; /** * Add a new entry to the global list of open files. @@ -26,174 +36,141 @@ static file_desc_t *current_file = NULL; * This function guarantees that files (id of the * files) are unique across the comm provided * - * @param file pointer to the file_desc_t struct for the new file. + * @param file Pointer to the file_desc_t struct for the file. * @param comm MPI Communicator across which the files * need to be unique * @returns The id for the file added to the list */ -#define PIO_FILE_START_ID 16 int pio_add_to_file_list(file_desc_t *file, MPI_Comm comm) { - /* Using an arbitrary start id for file ids helps - * in debugging, to distinguish between ids assigned - * to different structures in the code - * Also note that NetCDF ids start at 4, PnetCDF ids - * start at 0 and NetCDF4 ids start at 65xxx - */ - static int pio_file_next_id = PIO_FILE_START_ID; - file_desc_t *cfile; - - assert(file); - - if(comm != MPI_COMM_NULL) - { - int tmp_id = pio_file_next_id; - int mpierr = MPI_Allreduce(&tmp_id, &pio_file_next_id, 1, MPI_INT, MPI_MAX, comm); - assert(mpierr == MPI_SUCCESS); - } - file->pio_ncid = pio_file_next_id; - pio_file_next_id++; - /* This file will be at the end of the list, and have no next. */ - file->next = NULL; - - /* Get a pointer to the global list of files. */ - cfile = pio_file_list; - - /* Keep a global pointer to the current file. */ - current_file = file; - - /* If there is nothing in the list, then file will be the first - * entry. Otherwise, move to end of the list. */ - if (!cfile) - pio_file_list = file; - else - { - while (cfile->next) - cfile = cfile->next; - cfile->next = file; - } + static int pio_file_next_id = PIO_FILE_START_ID; + + assert(file); + LOG((2, "pio_add_to_file_list file = %p", file)); - return file->pio_ncid; + if(comm != MPI_COMM_NULL){ + int tmp_id = pio_file_next_id; + int mpierr = MPI_Allreduce(&tmp_id, &pio_file_next_id, 1, MPI_INT, MPI_MAX, comm); + assert(mpierr == MPI_SUCCESS); + } + file->pio_ncid = pio_file_next_id; + pio_file_next_id++; + + SPIO_Util::SPIO_Lists::GVars::pio_file_list.insert({file->pio_ncid, file}); + LOG((2, "file %p (%s, pio_ncid=%d) added to list", + file, pio_get_fname_from_file(file), file->pio_ncid)); + + return file->pio_ncid; } /** - * Given ncid, find the file_desc_t data for an open file. The ncid - * used is the interally generated pio_ncid. + * Get the file structure (file_desc_t) associated with the file id * - * @param ncid the PIO assigned ncid of the open file. - * @param cfile1 pointer to a pointer to a file_desc_t. The pointer - * will get a copy of the pointer to the file info. + * @param ncid The file id associated with the file being looked up + * @param pfile Pointer to the file structure pointer to contain the + * returned file structure pointer * * @returns 0 for success, error code otherwise. - * @author Ed Hartnett */ -int pio_get_file(int ncid, file_desc_t **cfile1) +int pio_get_file(int ncid, file_desc_t **pfile) { - file_desc_t *cfile = NULL; + LOG((2, "pio_get_file ncid = %d", ncid)); + + file_desc_t *file = NULL; + + if(ncid == PIO_GLOBAL){ + /* Don't handle error, return a pio_err(), here since this function is called for + * PIO_GLOBAL and in that case is handled by the caller */ + return PIO_EBADID; + } - LOG((2, "pio_get_file ncid = %d", ncid)); + try{ + file = SPIO_Util::SPIO_Lists::GVars::pio_file_list.at(ncid); + } catch(const std::out_of_range &e){ + return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, + "Searching for file (ncid=%d) in internal file list failed. Invalid file id provided", ncid); + } - /* Caller must provide this. */ - if (!cfile1) - return PIO_EINVAL; + if(pfile){ + assert(file && file->iosystem && iotype_is_valid(file->iotype)); + *pfile = file; + } - /* Find the file pointer. */ - if (current_file && current_file->pio_ncid == ncid) - cfile = current_file; - else - for (cfile = pio_file_list; cfile; cfile = cfile->next) - if (cfile->pio_ncid == ncid) - { - current_file = cfile; - break; - } + return PIO_NOERR; +} - /* If not found, return error. */ - if (!cfile) - return PIO_EBADID; +/** + * Free a file structure (file_desc_t) + * + * @param file Pointer to the file structure (file_desc_t) + * associated with the file + * @returns 0 for success, error code otherwise + */ +int pio_free_file(file_desc_t *file) +{ + assert(file); - /* We depend on every file having a pointer to the iosystem. */ - if (!cfile->iosystem) - return PIO_EINVAL; + LOG((2, "pio_free_file(%s, ncid=%d)", pio_get_fname_from_file(file), file->pio_ncid)); + /* Free any fill values that were allocated. */ + for (int v = 0; v < PIO_MAX_VARS; v++){ + if (file->varlist[v].fillvalue){ + free(file->varlist[v].fillvalue); + } +#ifdef PIO_MICRO_TIMING + mtimer_destroy(&(file->varlist[v].rd_mtimer)); + mtimer_destroy(&(file->varlist[v].rd_rearr_mtimer)); + mtimer_destroy(&(file->varlist[v].wr_mtimer)); + mtimer_destroy(&(file->varlist[v].wr_rearr_mtimer)); +#endif + } - /* Let's just ensure we have a valid IO type. */ - pioassert(iotype_is_valid(cfile->iotype), "invalid IO type", __FILE__, __LINE__); + free(file->unlim_dimids); + free(file->io_fstats); + spio_file_mvcache_finalize(file); - /* Copy pointer to file info. */ - *cfile1 = cfile; +#ifdef _ADIOS2 + if (file->cache_data_blocks != NULL){ + /* This call also frees file->cache_data_blocks */ + file->cache_data_blocks->free(file->cache_data_blocks); + } + + if (file->cache_block_sizes != NULL){ + /* This call also frees file->cache_block_sizes */ + file->cache_block_sizes->free(file->cache_block_sizes); + } + + if (file->cache_darray_info != NULL){ + /* This call also frees file->cache_darray_info */ + file->cache_darray_info->free(file->cache_darray_info); + } +#endif - return PIO_NOERR; + /* Free the memory used for this file. */ + free(file); + + return PIO_NOERR; } /** * Delete a file from the list of open files. + * Note: The file is deleted from the list & freed * - * @param ncid ID of file to delete from list + * @param ncid The file id associated with the file to be deleted * @returns 0 for success, error code otherwise - * @author Jim Edwards, Ed Hartnett */ int pio_delete_file_from_list(int ncid) { - file_desc_t *cfile, *pfile = NULL; - - /* Look through list of open files. */ - for (cfile = pio_file_list; cfile; cfile = cfile->next) - { - if (cfile->pio_ncid == ncid) - { - if (!pfile) - pio_file_list = cfile->next; - else - pfile->next = cfile->next; - - if (current_file == cfile) - current_file = pfile; - - /* Free any fill values that were allocated. */ - for (int v = 0; v < PIO_MAX_VARS; v++) - { - if (cfile->varlist[v].fillvalue) - free(cfile->varlist[v].fillvalue); -#ifdef PIO_MICRO_TIMING - mtimer_destroy(&(cfile->varlist[v].rd_mtimer)); - mtimer_destroy(&(cfile->varlist[v].rd_rearr_mtimer)); - mtimer_destroy(&(cfile->varlist[v].wr_mtimer)); - mtimer_destroy(&(cfile->varlist[v].wr_rearr_mtimer)); -#endif - } + LOG((2, "pio_delete_file_from_list(ncid=%d)", ncid)); + std::map::iterator iter = SPIO_Util::SPIO_Lists::GVars::pio_file_list.find(ncid); + if(iter == SPIO_Util::SPIO_Lists::GVars::pio_file_list.end()){ + return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, + "Deleting file (ncid=%d) from internal list failed. Invalid file id provided", ncid); + } - free(cfile->unlim_dimids); - free(cfile->io_fstats); - spio_file_mvcache_finalize(cfile); - /* Free the memory used for this file. */ -#ifdef _ADIOS2 - if (cfile->cache_data_blocks != NULL) - { - /* This call also frees cfile->cache_data_blocks */ - cfile->cache_data_blocks->free(cfile->cache_data_blocks); - } - - if (cfile->cache_block_sizes != NULL) - { - /* This call also frees cfile->cache_block_sizes */ - cfile->cache_block_sizes->free(cfile->cache_block_sizes); - } - - if (cfile->cache_darray_info != NULL) - { - /* This call also frees cfile->cache_darray_info */ - cfile->cache_darray_info->free(cfile->cache_darray_info); - } -#endif - free(cfile); - - return PIO_NOERR; - } - pfile = cfile; - } + file_desc_t *file = (*iter).second; + SPIO_Util::SPIO_Lists::GVars::pio_file_list.erase(iter); - /* No file was found. */ - return PIO_EBADID; + return pio_free_file(file); } /** Print I/O stats for all files in the iosystem @@ -211,239 +188,182 @@ int pio_delete_file_from_list(int ncid) */ int spio_write_all_file_iostats(iosystem_desc_t *iosysp) { - int ret = PIO_NOERR; - for(file_desc_t *pf = pio_file_list; pf; pf = pf->next) - { - if(pf->iosystem == iosysp) - { - assert(pf->iosystem->iosysid == iosysp->iosysid); - ret = spio_write_file_io_summary(pf); - if(ret != PIO_NOERR) - { - return ret; - } - } + for(std::map::iterator iter = + SPIO_Util::SPIO_Lists::GVars::pio_file_list.begin(); + iter != SPIO_Util::SPIO_Lists::GVars::pio_file_list.end(); ++iter){ + if(iter->second->iosystem == iosysp){ + assert(iter->second->iosystem->iosysid == iosysp->iosysid); + return spio_write_file_io_summary(iter->second); } - return ret; + } + return PIO_NOERR; } /** - * Delete iosystem info from list. + * Delete iosystem (iosytem_desc_t) from the global list of + * available iosystems * - * @param piosysid the iosysid to delete + * @param iosysid The id of the iosystem to delete * @returns 0 on success, error code otherwise - * @author Jim Edwards */ -int pio_delete_iosystem_from_list(int piosysid) +int pio_delete_iosystem_from_list(int iosysid) { - iosystem_desc_t *ciosystem, *piosystem = NULL; - - LOG((1, "pio_delete_iosystem_from_list piosysid = %d", piosysid)); - - for (ciosystem = pio_iosystem_list; ciosystem; ciosystem = ciosystem->next) - { - LOG((3, "ciosystem->iosysid = %d", ciosystem->iosysid)); - if (ciosystem->iosysid == piosysid) - { - if (piosystem == NULL) - pio_iosystem_list = ciosystem->next; - else - piosystem->next = ciosystem->next; - free(ciosystem); - return PIO_NOERR; - } - piosystem = ciosystem; - } - return PIO_EBADID; + LOG((2, "pio_delete_iosystem_from_list(iosysid=%d)", iosysid)); + std::map::iterator iter = + SPIO_Util::SPIO_Lists::GVars::pio_iosystem_list.find(iosysid); + if(iter != SPIO_Util::SPIO_Lists::GVars::pio_iosystem_list.end()){ + iosystem_desc_t *iosys = (*iter).second; + free(iosys); + SPIO_Util::SPIO_Lists::GVars::pio_iosystem_list.erase(iter); + } + else{ + return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, + "Deleting iosystem (iosysid=%d) from the internal global list failed. Invalid iosystem id provided", iosysid); + } + return PIO_NOERR; } /** - * Add iosystem info to a global list. + * Add iosystem (iosystem_desc_t) to a global list. * This function guarantees that iosystems (ioid of the * iosystems) are unique across the comm provided * - * @param ios pointer to the iosystem_desc_t info to add. + * @param ios Pointer to the iosystem info (iosystem_desc_t) + * to add to the list. * @param comm MPI Communicator across which the iosystems * need to be unique - * @returns the id of the newly added iosystem. + * @returns The id of the newly added iosystem. */ -#define PIO_IOSYSTEM_START_ID 2048 int pio_add_to_iosystem_list(iosystem_desc_t *ios, MPI_Comm comm) { - /* Using an arbitrary start id for iosystem ids helps - * in debugging, to distinguish between ids assigned - * to different structures in the code - */ - static int pio_iosystem_next_ioid = PIO_IOSYSTEM_START_ID; - iosystem_desc_t *cios; - - assert(ios); - - if(comm != MPI_COMM_NULL) - { - int tmp_id = pio_iosystem_next_ioid; - int mpierr = MPI_Allreduce(&tmp_id, &pio_iosystem_next_ioid, 1, MPI_INT, MPI_MAX, comm); - assert(mpierr == MPI_SUCCESS); - } - ios->iosysid = pio_iosystem_next_ioid; - pio_iosystem_next_ioid += 1; - - ios->next = NULL; - cios = pio_iosystem_list; - if (!cios) - pio_iosystem_list = ios; - else - { - while (cios->next) - { - cios = cios->next; - } - cios->next = ios; - } + static int pio_iosystem_next_ioid = PIO_IOSYSTEM_START_ID; + + assert(ios); + LOG((2, "pio_add_to_iosystem_list(ios=%p)", ios)); - return ios->iosysid; + if(comm != MPI_COMM_NULL){ + int tmp_id = pio_iosystem_next_ioid; + int mpierr = MPI_Allreduce(&tmp_id, &pio_iosystem_next_ioid, 1, + MPI_INT, MPI_MAX, comm); + assert(mpierr == MPI_SUCCESS); + } + ios->iosysid = pio_iosystem_next_ioid; + pio_iosystem_next_ioid++; + + SPIO_Util::SPIO_Lists::GVars::pio_iosystem_list.insert({ios->iosysid, ios}); + LOG((2, "iosystem %p (iosysid=%d) added to the global list", ios, ios->iosysid)); + + return ios->iosysid; } /** - * Get iosystem info from list. + * Get iosystem info (iosystem_desc_t) from the global list of available + * iosystems. * - * @param iosysid id of the iosystem + * @param iosysid The id of the iosystem to lookup * @returns pointer to iosystem_desc_t, or NULL if not found. - * @author Jim Edwards */ iosystem_desc_t *pio_get_iosystem_from_id(int iosysid) { - iosystem_desc_t *ciosystem; - - LOG((2, "pio_get_iosystem_from_id iosysid = %d", iosysid)); + LOG((2, "pio_get_iosystem_from_id(iosysid=%d)", iosysid)); - for (ciosystem = pio_iosystem_list; ciosystem; ciosystem = ciosystem->next) - if (ciosystem->iosysid == iosysid) - return ciosystem; + iosystem_desc_t *ios = NULL; + try{ + ios = SPIO_Util::SPIO_Lists::GVars::pio_iosystem_list.at(iosysid); + } catch(const std::out_of_range &e){ + LOG((1, "Finding iosytem corresponding to iosysid = %d failed. Invalid iosystem id provided", iosysid)); + } - return NULL; + return ios; } /** - * Count the number of open iosystems. + * Get the number of open/available/valid iosystems. * - * @param niosysid pointer that will get the number of open iosystems. + * @param niosysid Pointer to integer that will receive the number of + * valid iosystems * @returns 0 for success. - * @author Jim Edwards */ -int pio_num_iosystem(int *niosysid) +int pio_num_iosystem(int *niosys) { - int count = 0; + assert(niosys); - /* Count the elements in the list. */ - for (iosystem_desc_t *c = pio_iosystem_list; c; c = c->next) - count++; + *niosys = static_cast(SPIO_Util::SPIO_Lists::GVars::pio_iosystem_list.size()); - /* Return count to caller via pointer. */ - if (niosysid) - *niosysid = count; - - return PIO_NOERR; + return PIO_NOERR; } /** - * Add an iodesc to a global list. + * Add an I/O descriptor (io_desc_t) to the global + * list of valid iodescs. * This function guarantees that iodescs (id of the * iodescs) are unique across the comm provided * - * @param io_desc_t pointer to data to add to list. + * @param io_desc_t Pointer to the I/O descriptor (io_desc_t) + * to add to the list * @param comm MPI Communicator across which the iosystems * need to be unique * @returns the ioid of the newly added iodesc. */ int pio_add_to_iodesc_list(io_desc_t *iodesc, MPI_Comm comm) { - /* Using an arbitrary start id for iodesc ids helps - * in debugging, to distinguish between ids assigned - * to different structures in the code - */ - static int pio_iodesc_next_id = PIO_IODESC_START_ID; - io_desc_t *ciodesc = pio_iodesc_list; - - if(comm != MPI_COMM_NULL) - { - int tmp_id = pio_iodesc_next_id; - int mpierr = MPI_Allreduce(&tmp_id, &pio_iodesc_next_id, 1, MPI_INT, MPI_MAX, comm); - assert(mpierr == MPI_SUCCESS); - } - iodesc->ioid = pio_iodesc_next_id; - pio_iodesc_next_id++; - iodesc->next = NULL; - - /* Add to the global list */ - if (pio_iodesc_list == NULL) - pio_iodesc_list = iodesc; - else - { - /* pio_desc_list has atleast one node */ - while(ciodesc->next) - { - ciodesc = ciodesc->next; - } - ciodesc->next = iodesc; - } - current_iodesc = iodesc; - - return iodesc->ioid; + static int pio_iodesc_next_id = PIO_IODESC_START_ID; + + assert(iodesc); + LOG((2, "pio_add_to_iodesc_list(iodesc=%p)", iodesc)); + + if(comm != MPI_COMM_NULL){ + int tmp_id = pio_iodesc_next_id; + int mpierr = MPI_Allreduce(&tmp_id, &pio_iodesc_next_id, 1, MPI_INT, MPI_MAX, comm); + assert(mpierr == MPI_SUCCESS); + } + iodesc->ioid = pio_iodesc_next_id; + pio_iodesc_next_id++; + + SPIO_Util::SPIO_Lists::GVars::pio_iodesc_list.insert({iodesc->ioid, iodesc}); + LOG((2, "Added iodesc %p (ioid=%d) to the global list", iodesc, iodesc->ioid)); + return iodesc->ioid; } /** - * Get an iodesc. + * Get the I/O descriptor (io_desc_t) associated with a I/O descriptor id. * - * @param ioid ID of iodesc to get. - * @returns pointer to the iodesc struc. - * @author Jim Edwards + * @param ioid The id of the I/O descriptor (io_desc_t) to lookup + * @returns Pointer to the I/O descriptor (io_desc_t) associated with the id */ io_desc_t *pio_get_iodesc_from_id(int ioid) { - io_desc_t *ciodesc = NULL; - - /* Do we already have a pointer to it? */ - if (current_iodesc && current_iodesc->ioid == ioid) - return current_iodesc; + LOG((2, "pio_get_iodesc_from_id(ioid=%d)", ioid)); - /* Find the decomposition in the list. */ - for (ciodesc = pio_iodesc_list; ciodesc; ciodesc = ciodesc->next) - if (ciodesc->ioid == ioid) - { - current_iodesc = ciodesc; - break; - } + io_desc_t *iodesc = NULL; + try{ + iodesc = SPIO_Util::SPIO_Lists::GVars::pio_iodesc_list.at(ioid); + } catch(const std::out_of_range &e){ + LOG((1, "Finding I/O descriptor corresponding to ioid = %d failed. Invalid I/O descriptor id provided", ioid)); + } - return ciodesc; + return iodesc; } /** - * Delete an iodesc. + * Delete a I/O descriptor from the global list of valid I/O descriptors * - * @param ioid ID of iodesc to delete. + * @param ioid The id of the I/O descriptor (io_desc_t) to delete * @returns 0 on success, error code otherwise. - * @author Jim Edwards + * @author Jayesh Krishna */ int pio_delete_iodesc_from_list(int ioid) { - io_desc_t *ciodesc, *piodesc = NULL; - - for (ciodesc = pio_iodesc_list; ciodesc; ciodesc = ciodesc->next) - { - if (ciodesc->ioid == ioid) - { - if (piodesc == NULL) - pio_iodesc_list = ciodesc->next; - else - piodesc->next = ciodesc->next; - - if (current_iodesc == ciodesc) - current_iodesc = pio_iodesc_list; - free(ciodesc); - return PIO_NOERR; - } - piodesc = ciodesc; - } - return PIO_EBADID; + LOG((2, "pio_delete_iodesc_from_list(ioid=%d)", ioid)); + std::map::iterator iter = SPIO_Util::SPIO_Lists::GVars::pio_iodesc_list.find(ioid); + if(iter != SPIO_Util::SPIO_Lists::GVars::pio_iodesc_list.end()){ + io_desc_t *iodesc = (*iter).second; + free(iodesc); + SPIO_Util::SPIO_Lists::GVars::pio_iodesc_list.erase(iter); + } + else{ + return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, + "Deleting I/O descriptor info (ioid=%d) from internal global list failed. Invalid I/O descriptor id provided", ioid); + } + return PIO_NOERR; } diff --git a/tests/cunit/test_spmd.cpp b/tests/cunit/test_spmd.cpp index d8ef5967e3..aa3bb1c9ca 100644 --- a/tests/cunit/test_spmd.cpp +++ b/tests/cunit/test_spmd.cpp @@ -202,15 +202,15 @@ int test_lists() file_desc_t *fdesc; /* Test that bad input is correctly rejected. */ - if (pio_delete_iodesc_from_list(42) != PIO_EBADID) + if (pio_delete_iodesc_from_list(42) == PIO_NOERR) return ERR_WRONG; - if (pio_delete_iosystem_from_list(42) != PIO_EBADID) + if (pio_delete_iosystem_from_list(42) == PIO_NOERR) return ERR_WRONG; - if (pio_delete_file_from_list(42) != PIO_EBADID) + if (pio_delete_file_from_list(42) == PIO_NOERR) return ERR_WRONG; - if (pio_get_file(42, NULL) != PIO_EINVAL) + if (pio_get_file(42, NULL) == PIO_NOERR) return ERR_WRONG; - if (pio_get_file(42, &fdesc) != PIO_EBADID) + if (pio_get_file(42, &fdesc) == PIO_NOERR) return ERR_WRONG; return 0; } From 5911eacdeb189e6dd4de47f29f64f56b5aff1b4c Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 18 Nov 2024 11:02:27 -0600 Subject: [PATCH 005/194] Add missing free for file in cunit test Adding a missing free for file struct allocated in the unit test --- tests/cunit/test_rearr.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cunit/test_rearr.cpp b/tests/cunit/test_rearr.cpp index 35605a31bf..4dbd37caf1 100644 --- a/tests/cunit/test_rearr.cpp +++ b/tests/cunit/test_rearr.cpp @@ -1172,6 +1172,7 @@ int test_rearrange_comp2io(MPI_Comm test_comm, int my_rank) free(ior1); free(ios->ioranks); free(ios->compranks); + free(file); free(iodesc); free(ios); free(sbuf); From 9ec1f680384021314d02b840ec1d369cb19249f8 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 18 Nov 2024 11:03:30 -0600 Subject: [PATCH 006/194] Explicitly delete stale files after finalize Explicitly deleting state files in the global file list after all I/O systems are finalized. --- src/clib/pio_lists.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/clib/pio_lists.cpp b/src/clib/pio_lists.cpp index 4d40698fc4..abef1f549a 100644 --- a/src/clib/pio_lists.cpp +++ b/src/clib/pio_lists.cpp @@ -21,6 +21,10 @@ namespace SPIO_Util{ namespace GVars{ std::map pio_iodesc_list; std::map pio_iosystem_list; + /* This list is independent of the I/O system because users only provide the + * file id during a call - hence instead of deducing the I/O system that the file + * belongs to, the file list is separate from the I/O system (list) + */ std::map pio_file_list; } } @@ -199,6 +203,21 @@ int spio_write_all_file_iostats(iosystem_desc_t *iosysp) return PIO_NOERR; } +static int finalize_file_list(void ) +{ + /* No valid I/O systems, clear out the file list */ + for(std::map::iterator fiter = + SPIO_Util::SPIO_Lists::GVars::pio_file_list.begin(); + fiter != SPIO_Util::SPIO_Lists::GVars::pio_file_list.end(); ++fiter){ + file_desc_t *file = (*fiter).second; + pio_free_file(file); + } + + SPIO_Util::SPIO_Lists::GVars::pio_file_list.clear(); + + return PIO_NOERR; +} + /** * Delete iosystem (iosytem_desc_t) from the global list of * available iosystems @@ -215,6 +234,12 @@ int pio_delete_iosystem_from_list(int iosysid) iosystem_desc_t *iosys = (*iter).second; free(iosys); SPIO_Util::SPIO_Lists::GVars::pio_iosystem_list.erase(iter); + if(SPIO_Util::SPIO_Lists::GVars::pio_iosystem_list.size() == 0){ + /* Unfortunately in some cases not all procs cleanup the files as needed + * e.g. PIO_RETURN_ERROR + non-I/O procs on a create file call + */ + return finalize_file_list(); + } } else{ return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, From 756a559b8dce8bcd7b14c7cceca0cadfb1b55dff Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 18 Nov 2024 11:05:22 -0600 Subject: [PATCH 007/194] Adding a GPTL wrapper Adding a GPTL wrapper class to automatically stop the timer during func return. --- src/clib/spio_gptl_utils.hpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/clib/spio_gptl_utils.hpp diff --git a/src/clib/spio_gptl_utils.hpp b/src/clib/spio_gptl_utils.hpp new file mode 100644 index 0000000000..762a678ca4 --- /dev/null +++ b/src/clib/spio_gptl_utils.hpp @@ -0,0 +1,21 @@ +#ifndef __SPIO_GPTL_UTILS_HPP__ +#define __SPIO_GPTL_UTILS_HPP__ + +#include "pio_config.h" +#include "pio.h" +#include "pio_internal.h" + +#include + +namespace SPIO_Util{ + namespace GPTL_Util{ + class GPTL_wrapper{ + public: + GPTL_wrapper(const char *gptl_timer_name):gptl_timer_name_(gptl_timer_name){ GPTLstart(gptl_timer_name); } + ~GPTL_wrapper(){ GPTLstop(gptl_timer_name_.c_str()); } + private: + const std::string gptl_timer_name_; + }; + } // namespace GPTL_Util +} // namespace SPIO_Util +#endif // __SPIO_GPTL_UTILS_HPP__ From 643decd63d0baa2e5b0c803745b772f8d075dec2 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 18 Nov 2024 11:07:15 -0600 Subject: [PATCH 008/194] Adding gather/scatter/alltoall utils Adding util functions to perform custom gather/scatter/alltoall. All of the util functions include handshake support. The alltoall functions also include flow control support. The alltoall funcs were refactored from the old implementation of altoall (pio_swapm) The gather functions support receiving different types from the sending procs and the scatter functions support sending different types to the receiving procs. --- src/clib/pio_rearr_utils.cpp | 980 +++++++++++++++++++++++++++++++++++ src/clib/pio_rearr_utils.hpp | 41 ++ 2 files changed, 1021 insertions(+) create mode 100644 src/clib/pio_rearr_utils.cpp create mode 100644 src/clib/pio_rearr_utils.hpp diff --git a/src/clib/pio_rearr_utils.cpp b/src/clib/pio_rearr_utils.cpp new file mode 100644 index 0000000000..269122875d --- /dev/null +++ b/src/clib/pio_rearr_utils.cpp @@ -0,0 +1,980 @@ +#include "pio_rearr_utils.hpp" +#include "spio_gptl_utils.hpp" +#include + +namespace SPIO_Util{ + namespace Rearr_Util{ + int isend_hs(int to_proc, MPI_Comm comm, int comm_rank, int comm_sz, MPI_Request &req) + { + /* Tag identifies who the data is from */ + int tag = comm_sz + comm_rank; + char hs = 'h'; + + return MPI_Isend(&hs, 1, MPI_CHAR, to_proc, tag, comm, &req); + } + + int irecv_hs(int from_proc, MPI_Comm comm, int comm_rank, int comm_sz, MPI_Request &req) + { + /* Tag identifies who the data is from */ + int tag = comm_sz + from_proc; + char hs; + + return MPI_Irecv(&hs, 1, MPI_CHAR, from_proc, tag, comm, &req); + } + + }// namespace Rearr_Util +}// namespace SPIO_Util + +int SPIO_Util::Rearr_Util::gatherw(const void *sendbuf, int sendcount, + MPI_Datatype sendtype, + void *recvbuf, const std::vector &recvcounts, + const std::vector &rdispls, + const std::vector &recvtypes, + int root, MPI_Comm comm, const rearr_comm_fc_opt_t *fc) +{ + int ret = PIO_NOERR, comm_rank = -1, comm_sz = 0; + + SPIO_Util::GPTL_Util::GPTL_wrapper("PIO:SPIO_Util::Rearr_Util::gatherw"); + + //assert((sendcount == 0) || sendbuf); + + ret = MPI_Comm_rank(comm, &comm_rank); + if(ret != MPI_SUCCESS){ + return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); + } + + ret = MPI_Comm_size(comm, &comm_sz); + if(ret != MPI_SUCCESS){ + return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); + } + + if(comm_rank == root){ + /* No data to gather, return */ + /* FIXME: Handle erroneous calls with senders trying to send data with invalid/null recvbuf */ + if(!recvbuf){ + return PIO_NOERR; + } + } + else{ + if(!sendbuf || (sendcount == 0)){ + return PIO_NOERR; + } + } + + /* Post the receives on root, send a handshake to indicate that receives are posted and + * send the data to root. + */ + + /* Post recv for handshake - to indicate gather buffer is ready - on all non-root procs */ + if(comm_rank != root){ + MPI_Request hs_req, send_req; + MPI_Status hs_status, send_status; + + /* Tag identifies the sender */ + int tag = comm_sz + comm_rank; + + ret = irecv_hs(root, comm, comm_rank, comm_sz, hs_req); + if(ret != PIO_NOERR){ + return pio_err(NULL, NULL, ret, __FILE__, __LINE__, + "Posting handshake for gather failed on proc (%d), comm = (id=%x, sz=%d)", + comm_rank, comm, comm_sz); + } + + ret = MPI_Wait(&hs_req, &hs_status); + if(ret != MPI_SUCCESS){ + /* FIXME: Take a look at the status too */ + return pio_err(NULL, NULL, ret, __FILE__, __LINE__, + "Waiting on handshake for gather failed on proc (%d), comm = (id=%x, sz=%d)", + comm_rank, comm, comm_sz); + } + + /* The non-blocking nature of the send can be used in future to avoid blocking on gather */ + /* Send the data to root */ + ret = MPI_Isend(sendbuf, sendcount, sendtype, root, tag, comm, &send_req); + if(ret != PIO_NOERR){ + return pio_err(NULL, NULL, ret, __FILE__, __LINE__, + "Posting send for data to gather failed on proc (%d), comm = (id=%x, sz=%d)", + comm_rank, comm, comm_sz); + } + + /* We are blocking on the gather now, but this could change in future */ + ret = MPI_Wait(&send_req, &send_status); + if(ret != MPI_SUCCESS){ + /* FIXME: Take a look at the status too */ + return pio_err(NULL, NULL, ret, __FILE__, __LINE__, + "Waiting on sending data for gather failed on proc (%d), comm = (id=%x, sz=%d)", + comm_rank, comm, comm_sz); + } + } + else{ + assert((recvcounts.size() == rdispls.size()) && (rdispls.size() == recvtypes.size())); + assert(recvcounts.size() == static_cast(comm_sz)); + + /* Post receives for the data to gather */ + std::vector recv_reqs(comm_sz, MPI_REQUEST_NULL); + for(int i=0; i < comm_sz; i++){ + if(recvcounts[i] > 0){ + /* Tag identifies who the data is from - the sender */ + int tag = comm_sz + i; + ret = MPI_Irecv(static_cast(recvbuf) + rdispls[i], recvcounts[i], recvtypes[i], + i, tag, comm, &recv_reqs[i]); + if(ret != PIO_NOERR){ + return pio_err(NULL, NULL, ret, __FILE__, __LINE__, + "Posting recv for data from proc %d to gather failed on proc (%d), comm = (id=%x, sz=%d)", + i, comm_rank, comm, comm_sz); + } + } + } + + /* Send data to self */ + MPI_Request send_req = MPI_REQUEST_NULL; + if(sendcount > 0){ + /* Tag identifies who the data is from - the sender */ + int send_tag = comm_sz + comm_rank; + ret = MPI_Isend(sendbuf, sendcount, sendtype, root, send_tag, comm, &send_req); + if(ret != MPI_SUCCESS){ + return pio_err(NULL, NULL, ret, __FILE__, __LINE__, + "Posting send for data to gather failed on proc (%d), comm = (id=%x, sz=%d)", + comm_rank, comm, comm_sz); + } + } + + /* Send handshakes */ + std::vector hs_reqs(comm_sz, MPI_REQUEST_NULL); + for(int i=0; i < comm_sz; i++){ + if(i == root){ + /* We don't need handshake for root process - since recvs are already posted before sends + * on the root + */ + continue; + } + if(recvcounts[i] > 0){ + ret = isend_hs(i, comm, comm_rank, comm_sz, hs_reqs[i]); + if(ret != MPI_SUCCESS){ + return pio_err(NULL, NULL, ret, __FILE__, __LINE__, + "Posting send for handshake from root (%d) to proc (%d), comm = (id=%x, sz=%d)", + comm_rank, i, comm, comm_sz); + } + } + } + + /* Wait on sent data, handshakes & then receives - gather the data */ + ret = MPI_Wait(&send_req, MPI_STATUS_IGNORE); + if(ret == MPI_SUCCESS){ + ret = MPI_Waitall(static_cast(hs_reqs.size()), hs_reqs.data(), MPI_STATUSES_IGNORE); + if(ret == MPI_SUCCESS){ + ret = MPI_Waitall(static_cast(recv_reqs.size()), recv_reqs.data(), MPI_STATUSES_IGNORE); + } + } + + if(ret != MPI_SUCCESS){ + return pio_err(NULL, NULL, ret, __FILE__, __LINE__, + "Waiting on data/handshakes/recvs failed on root process(%d), comm = (id=%x, sz=%d)", + comm_rank, comm, comm_sz); + } + } + + return ret; +} + +int SPIO_Util::Rearr_Util::scatterw(const void *sendbuf, const std::vector &sendcounts, + const std::vector &sdispls, + const std::vector &sendtypes, + void *recvbuf, int recvcount, + MPI_Datatype recvtype, + int root, MPI_Comm comm, const rearr_comm_fc_opt_t *fc) +{ + int ret = PIO_NOERR, comm_rank = -1, comm_sz = 0; + + SPIO_Util::GPTL_Util::GPTL_wrapper("PIO:SPIO_Util::Rearr_Util::scatterw"); + + ret = MPI_Comm_rank(comm, &comm_rank); + if(ret != MPI_SUCCESS){ + return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); + } + + ret = MPI_Comm_size(comm, &comm_sz); + if(ret != MPI_SUCCESS){ + return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); + } + + if(comm_rank == root){ + /* No data to scatter, return */ + /* FIXME: Handle erroneous calls with receivers waiting for data etc */ + if(!sendbuf){ + return PIO_NOERR; + } + } + else{ + if(!recvbuf || (recvcount == 0)){ + return PIO_NOERR; + } + } + + /* Post the receives on compute procs, send a handshake to indicate that receives are posted and + * send the data from root. + */ + + /* Send handshake - to indicate scatter recv buffer is ready - on all non-root procs */ + if(comm_rank != root){ + MPI_Request hs_req, recv_req; + MPI_Status hs_status, recv_status; + + /* Tag identifies the sender */ + int tag = comm_sz + root; + + /* Post recv for data from root */ + ret = MPI_Irecv(recvbuf, recvcount, recvtype, root, tag, comm, &recv_req); + if(ret != PIO_NOERR){ + return pio_err(NULL, NULL, ret, __FILE__, __LINE__, + "Posting recv for data for scatter failed on proc (%d), comm = (id=%x, sz=%d)", + comm_rank, comm, comm_sz); + } + + /* Send handshake to root to indicate that recv has been posted */ + ret = isend_hs(root, comm, comm_rank, comm_sz, hs_req); + if(ret != PIO_NOERR){ + return pio_err(NULL, NULL, ret, __FILE__, __LINE__, + "Posting handshake for scatter failed on proc (%d), comm = (id=%x, sz=%d)", + comm_rank, comm, comm_sz); + } + + ret = MPI_Wait(&hs_req, &hs_status); + if(ret != MPI_SUCCESS){ + /* FIXME: Take a look at the status too */ + return pio_err(NULL, NULL, ret, __FILE__, __LINE__, + "Waiting on handshake, sent to root, for scatter failed on proc (%d), comm = (id=%x, sz=%d)", + comm_rank, comm, comm_sz); + } + + /* We are blocking on scatter data from root now, but this could change in future */ + ret = MPI_Wait(&recv_req, &recv_status); + if(ret != MPI_SUCCESS){ + /* FIXME: Take a look at the status too */ + return pio_err(NULL, NULL, ret, __FILE__, __LINE__, + "Waiting on receiving data for scatter failed on proc (%d), comm = (id=%x, sz=%d)", + comm_rank, comm, comm_sz); + } + } + else{ + assert((sendcounts.size() == sdispls.size()) && (sdispls.size() == sendtypes.size())); + assert(sendcounts.size() == static_cast(comm_sz)); + + /* Wait for handshakes from processes - to indicate that recvs are posted for the scatter data */ + /* Post receives for handshakes */ + std::vector hs_reqs(comm_sz, MPI_REQUEST_NULL); + for(int i=0; i < comm_sz; i++){ + if(i == root){ + /* We don't need handshake for root process - since recvs are posted before sends + * on the root + */ + continue; + } + if(sendcounts[i] > 0){ + ret = irecv_hs(i, comm, comm_rank, comm_sz, hs_reqs[i]); + if(ret != MPI_SUCCESS){ + return pio_err(NULL, NULL, ret, __FILE__, __LINE__, + "Posting recv for handshake to root (%d) from proc (%d), comm = (id=%x, sz=%d)", + comm_rank, i, comm, comm_sz); + } + } + } + + /* Wait on handshakes from procs */ + ret = MPI_Waitall(static_cast(hs_reqs.size()), hs_reqs.data(), MPI_STATUSES_IGNORE); + if(ret != MPI_SUCCESS){ + return pio_err(NULL, NULL, ret, __FILE__, __LINE__, + "Receiving handshakes on root (%d) failed, comm = (id=%x, sz=%d)", + comm_rank, comm, comm_sz); + } + + /* Post recv for the data from scatter */ + /* Tag identifies the sender */ + int tag = comm_sz + root; + MPI_Request recv_req = MPI_REQUEST_NULL; + + /* Post recv for data from self/root */ + if(recvcount > 0){ + ret = MPI_Irecv(recvbuf, recvcount, recvtype, root, tag, comm, &recv_req); + if(ret != PIO_NOERR){ + return pio_err(NULL, NULL, ret, __FILE__, __LINE__, + "Posting recv for data from self for scatter failed on root proc (%d), comm = (id=%x, sz=%d)", + comm_rank, comm, comm_sz); + } + } + + /* Send the data - scatter data to procs */ + std::vector send_reqs(comm_sz, MPI_REQUEST_NULL); + for(int i=0; i < comm_sz; i++){ + if(sendcounts[i] > 0){ + /* Tag identifies who the data is from - the sender */ + int tag = comm_sz + root; + ret = MPI_Isend(static_cast(sendbuf) + sdispls[i], sendcounts[i], sendtypes[i], + i, tag, comm, &send_reqs[i]); + if(ret != PIO_NOERR){ + return pio_err(NULL, NULL, ret, __FILE__, __LINE__, + "Posting send for data to proc %d for scatter failed on proc (%d), comm = (id=%x, sz=%d)", + i, comm_rank, comm, comm_sz); + } + } + } + + /* Wait on sends to other processes and then wait on data received from self */ + ret = MPI_Waitall(static_cast(send_reqs.size()), send_reqs.data(), MPI_STATUSES_IGNORE); + if(ret == MPI_SUCCESS){ + ret = MPI_Wait(&recv_req, MPI_STATUS_IGNORE); + } + if(ret != MPI_SUCCESS){ + return pio_err(NULL, NULL, ret, __FILE__, __LINE__, + "Waiting on data/recvs failed on root process(%d), comm = (id=%x, sz=%d)", + comm_rank, comm, comm_sz); + } + } + + return ret; +} + +/* FIXME: Refactor all the functions below */ +namespace SPIO_Util{ + namespace Rearr_Util{ + static inline int ceil2(int i) + { + int p = 1; + while(p < i){ + p *= 2; + } + + return(p); + } + + static inline int pair(int np, int p, int k) + { + int q = (p + 1) ^ k ; + int pair = (q > np - 1) ? -1 : q; + return pair; + } + } +} + +int SPIO_Util::Rearr_Util::alltoallw(const void *sendbuf, const int *sendcounts, + const int *sdispls, const MPI_Datatype *sendtypes, + void *recvbuf, const int *recvcounts, + const int *rdispls, const MPI_Datatype *recvtypes, + MPI_Comm comm, const rearr_comm_fc_opt_t *fc) +{ + int ntasks; /* Number of tasks in communicator comm. */ + int my_rank; /* Rank of this task in comm. */ + int tag; + int offset_t; + int steps; + int istep; + int rstep; + int p; + int maxreq; + int maxreqh; + int hs = 1; /* Used for handshaking. */ + void *ptr; + MPI_Status status; /* Not actually used - replace with MPI_STATUSES_IGNORE. */ + int mpierr; /* Return code from MPI functions. */ + + SPIO_Util::GPTL_Util::GPTL_wrapper("PIO:SPIO_Util::Rearr_Util::alltoallw"); + LOG((2, "pio_swapm fc->hs = %d fc->isend = %d fc->max_pend_req = %d", fc->hs, + fc->isend, fc->max_pend_req)); + + /* Get my rank and size of communicator. */ + if((mpierr = MPI_Comm_size(comm, &ntasks))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + if((mpierr = MPI_Comm_rank(comm, &my_rank))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + + LOG((2, "ntasks = %d my_rank = %d", ntasks, my_rank)); + + /* Now we know the size of these arrays. */ + int swapids[ntasks]; + MPI_Request rcvids[ntasks]; + MPI_Request sndids[ntasks]; + MPI_Request hs_rcvids[ntasks]; + + /* If fc->max_pend_req == 0 no throttling is requested and the default + * mpi_alltoallw function is used. */ + if(fc->max_pend_req == 0){ + /* Some MPI implementations (some vers of OpenMPI, MPICH 4.0 etc) do not + * allow passing MPI_DATATYPE_NULL to comm functions (MPI_Alltoallw) even + * though the send or recv length is 0, so using a dummy MPI type instead + * of MPI_DATATYPE_NULL + */ + MPI_Datatype dummy_dt = MPI_CHAR; + MPI_Datatype sndtypes[ntasks], rcvtypes[ntasks]; + for(int i = 0; i < ntasks; i++){ + sndtypes[i] = sendtypes[i]; + if(sndtypes[i] == MPI_DATATYPE_NULL){ + sndtypes[i] = dummy_dt; + } + rcvtypes[i] = recvtypes[i]; + if(rcvtypes[i] == MPI_DATATYPE_NULL){ + rcvtypes[i] = dummy_dt; + } + } + + /* Call the MPI alltoall without flow control. */ + LOG((3, "Calling MPI_Alltoallw without flow control.")); + if((mpierr = MPI_Alltoallw(sendbuf, sendcounts, sdispls, sndtypes, recvbuf, + recvcounts, rdispls, rcvtypes, comm))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + return PIO_NOERR; + } + + /* an index for communications tags */ + offset_t = ntasks; + + /* Send to self. */ + if(sendcounts[my_rank] > 0){ + void *sptr, *rptr; + tag = my_rank + offset_t; + sptr = (char *)sendbuf + sdispls[my_rank]; + rptr = (char *)recvbuf + rdispls[my_rank]; + +#ifdef ONEWAY + /* If ONEWAY is true we will post mpi_sendrecv comms instead + * of irecv/send. */ + if((mpierr = MPI_Sendrecv(sptr, sendcounts[my_rank],sendtypes[my_rank], + my_rank, tag, rptr, recvcounts[my_rank], recvtypes[my_rank], + my_rank, tag, comm, &status))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } +#else + if((mpierr = MPI_Irecv(rptr, recvcounts[my_rank], recvtypes[my_rank], + my_rank, tag, comm, rcvids))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + if((mpierr = MPI_Send(sptr, sendcounts[my_rank], sendtypes[my_rank], + my_rank, tag, comm))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + + if((mpierr = MPI_Wait(rcvids, &status))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } +#endif + } + + LOG((2, "Done sending to self... sending to other procs")); + + /* When send to self is complete there is nothing left to do if + * ntasks==1. */ + if(ntasks == 1){ + return PIO_NOERR; + } + + for(int i = 0; i < ntasks; i++){ + rcvids[i] = MPI_REQUEST_NULL; + swapids[i] = 0; + } + + if(fc->isend){ + for (int i = 0; i < ntasks; i++){ + sndids[i] = MPI_REQUEST_NULL; + } + } + + if(fc->hs){ + for(int i = 0; i < ntasks; i++){ + hs_rcvids[i] = MPI_REQUEST_NULL; + } + } + + steps = 0; + for(istep = 0; istep < SPIO_Util::Rearr_Util::ceil2(ntasks) - 1; istep++){ + p = SPIO_Util::Rearr_Util::pair(ntasks, istep, my_rank); + if(p >= 0 && (sendcounts[p] > 0 || recvcounts[p] > 0)){ + swapids[steps++] = p; + } + } + + LOG((3, "steps=%d", steps)); + + if(steps == 0){ + return PIO_NOERR; + } + + if(steps == 1){ + maxreq = 1; + maxreqh = 1; + } + else{ + if(fc->max_pend_req == PIO_REARR_COMM_UNLIMITED_PEND_REQ){ + maxreq = steps; + maxreqh = steps; + } + else if(fc->max_pend_req > 1 && fc->max_pend_req < steps){ + maxreq = fc->max_pend_req; + maxreqh = maxreq / 2; + } + else if(fc->max_pend_req == 1){ + /* Note that steps >= 2 here */ + maxreq = 2; + maxreqh = 1; + } + else{ + maxreq = steps; + maxreqh = steps; + } + } + + LOG((2, "fc->max_pend_req=%d, maxreq=%d, maxreqh=%d", fc->max_pend_req, maxreq, maxreqh)); + + /* If handshaking is in use, do a nonblocking recieve to listen + * for it. */ + if(fc->hs){ + for(istep = 0; istep < maxreq; istep++){ + p = swapids[istep]; + if(sendcounts[p] > 0){ + tag = my_rank + offset_t; + if((mpierr = MPI_Irecv(&hs, 1, MPI_INT, p, tag, comm, hs_rcvids + istep))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + } + } + } + + /* Post up to maxreq irecv's. */ + for(istep = 0; istep < maxreq; istep++){ + p = swapids[istep]; + if(recvcounts[p] > 0){ + tag = p + offset_t; + ptr = (char *)recvbuf + rdispls[p]; + + if((mpierr = MPI_Irecv(ptr, recvcounts[p], recvtypes[p], p, tag, comm, + rcvids + istep))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + + if(fc->hs){ + if((mpierr = MPI_Send(&hs, 1, MPI_INT, p, tag, comm))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + } + } + } + + /* Tell the paired task that this tasks' has posted it's irecvs'. */ + rstep = maxreq; + for(istep = 0; istep < steps; istep++){ + p = swapids[istep]; + if(sendcounts[p] > 0){ + tag = my_rank + offset_t; + /* If handshake is enabled don't post sends until the + * receiving task has posted recvs. */ + if(fc->hs){ + if((mpierr = MPI_Wait(hs_rcvids + istep, &status))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + hs_rcvids[istep] = MPI_REQUEST_NULL; + } + ptr = (char *)sendbuf + sdispls[p]; + + /* On some software stacks MPI_Irsend() is either not available, not + * a major issue anymore, or is buggy. With PIO1 we have found that + * although the code correctly posts receives before the irsends, + * on some systems (software stacks) the code hangs. However the + * code works fine with isends. The _USE_MPI_RSEND macro should be + * used to use mpi_irsends, the default is mpi_isend + */ + if(fc->hs && fc->isend){ +#ifndef _USE_MPI_RSEND + if((mpierr = MPI_Isend(ptr, sendcounts[p], sendtypes[p], p, tag, comm, + sndids + istep))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } +#else + if((mpierr = MPI_Irsend(ptr, sendcounts[p], sendtypes[p], p, tag, comm, + sndids + istep))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } +#endif + } + else if(fc->isend){ + if((mpierr = MPI_Isend(ptr, sendcounts[p], sendtypes[p], p, tag, comm, + sndids + istep))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + } + else{ + if((mpierr = MPI_Send(ptr, sendcounts[p], sendtypes[p], p, tag, comm))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + } + } + + /* We did comms in sets of size max_reqs, if istep > maxreqh-1 + * then there is a remainder that must be handled. */ + if(istep > maxreqh - 1){ + p = istep - maxreqh; + if(rcvids[p] != MPI_REQUEST_NULL){ + if((mpierr = MPI_Wait(rcvids + p, &status))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + rcvids[p] = MPI_REQUEST_NULL; + } + if(rstep < steps){ + p = swapids[rstep]; + if(fc->hs && sendcounts[p] > 0){ + tag = my_rank + offset_t; + if((mpierr = MPI_Irecv(&hs, 1, MPI_INT, p, tag, comm, hs_rcvids+rstep))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + } + if(recvcounts[p] > 0){ + tag = p + offset_t; + + ptr = (char *)recvbuf + rdispls[p]; + if((mpierr = MPI_Irecv(ptr, recvcounts[p], recvtypes[p], p, tag, comm, rcvids + rstep))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + if(fc->hs){ + if((mpierr = MPI_Send(&hs, 1, MPI_INT, p, tag, comm))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + } + } + rstep++; + } + } + } + + /* If steps > 0 there could still be outstanding messages, wait for + * them here. */ + if(steps > 0){ + LOG((2, "Waiting for outstanding msgs")); + if((mpierr = MPI_Waitall(steps, rcvids, MPI_STATUSES_IGNORE))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + if(fc->isend){ + if((mpierr = MPI_Waitall(steps, sndids, MPI_STATUSES_IGNORE))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + } + } + + return PIO_NOERR; +} + +/* FIXME: Refactor alltoall and alltoallw to combine common code */ +int SPIO_Util::Rearr_Util::alltoall(const void *sendbuf, int sendcount, + MPI_Datatype sendtype, + void *recvbuf, int recvcount, + MPI_Datatype recvtype, + MPI_Comm comm, const rearr_comm_fc_opt_t *fc) +{ + int ntasks; /* Number of tasks in communicator comm. */ + int my_rank; /* Rank of this task in comm. */ + int tag; + int offset_t; + int steps; + int istep; + int rstep; + int p; + int maxreq; + int maxreqh; + int hs = 1; /* Used for handshaking. */ + void *ptr; + MPI_Status status; /* Not actually used - replace with MPI_STATUSES_IGNORE. */ + int mpierr; /* Return code from MPI functions. */ + + int sendtype_sz = 0, recvtype_sz = 0; + + if(sendtype != MPI_DATATYPE_NULL){ + if((mpierr = MPI_Type_size(sendtype, &sendtype_sz))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + } + + if(recvtype != MPI_DATATYPE_NULL){ + if((mpierr = MPI_Type_size(recvtype, &recvtype_sz))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + } + + SPIO_Util::GPTL_Util::GPTL_wrapper("PIO:SPIO_Util::Rearr_Util::alltoallw"); + LOG((2, "pio_swapm fc->hs = %d fc->isend = %d fc->max_pend_req = %d", fc->hs, + fc->isend, fc->max_pend_req)); + + /* Get my rank and size of communicator. */ + if((mpierr = MPI_Comm_size(comm, &ntasks))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + if((mpierr = MPI_Comm_rank(comm, &my_rank))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + + LOG((2, "ntasks = %d my_rank = %d", ntasks, my_rank)); + + /* Now we know the size of these arrays. */ + int swapids[ntasks]; + MPI_Request rcvids[ntasks]; + MPI_Request sndids[ntasks]; + MPI_Request hs_rcvids[ntasks]; + + /* If fc->max_pend_req == 0 no throttling is requested and the default + * mpi_alltoallw function is used. */ + if(fc->max_pend_req == 0){ + /* Some MPI implementations (some vers of OpenMPI, MPICH 4.0 etc) do not + * allow passing MPI_DATATYPE_NULL to comm functions (MPI_Alltoall) even + * though the send or recv length is 0, so using a dummy MPI type instead + * of MPI_DATATYPE_NULL + */ + MPI_Datatype dummy_dt = MPI_CHAR; + MPI_Datatype tmp_sendtype = sendtype, tmp_recvtype = recvtype; + if(tmp_sendtype == MPI_DATATYPE_NULL){ + tmp_sendtype = dummy_dt; + } + if(tmp_recvtype == MPI_DATATYPE_NULL){ + tmp_recvtype = dummy_dt; + } + + /* Call the MPI alltoall without flow control. */ + LOG((3, "Calling MPI_Alltoall without flow control.")); + if((mpierr = MPI_Alltoall(sendbuf, sendcount, tmp_sendtype, + recvbuf, recvcount, tmp_recvtype, comm))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + return PIO_NOERR; + } + + /* an index for communications tags */ + offset_t = ntasks; + + /* Send to self. */ + if(sendcount > 0){ + void *sptr, *rptr; + tag = my_rank + offset_t; + sptr = (char *)sendbuf + my_rank * sendcount * sendtype_sz; + rptr = (char *)recvbuf + my_rank * recvcount * recvtype_sz; + +#ifdef ONEWAY + /* If ONEWAY is true we will post mpi_sendrecv comms instead + * of irecv/send. */ + if((mpierr = MPI_Sendrecv(sptr, sendcount,sendtype, + my_rank, tag, rptr, recvcount, recvtype, + my_rank, tag, comm, &status))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } +#else + if((mpierr = MPI_Irecv(rptr, recvcount, recvtype, + my_rank, tag, comm, rcvids))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + if((mpierr = MPI_Send(sptr, sendcount, sendtype, + my_rank, tag, comm))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + + if((mpierr = MPI_Wait(rcvids, &status))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } +#endif + } + + LOG((2, "Done sending to self... sending to other procs")); + + /* When send to self is complete there is nothing left to do if + * ntasks==1. */ + if(ntasks == 1){ + return PIO_NOERR; + } + + for(int i = 0; i < ntasks; i++){ + rcvids[i] = MPI_REQUEST_NULL; + swapids[i] = 0; + } + + if(fc->isend){ + for (int i = 0; i < ntasks; i++){ + sndids[i] = MPI_REQUEST_NULL; + } + } + + if(fc->hs){ + for(int i = 0; i < ntasks; i++){ + hs_rcvids[i] = MPI_REQUEST_NULL; + } + } + + steps = 0; + for(istep = 0; istep < SPIO_Util::Rearr_Util::ceil2(ntasks) - 1; istep++){ + p = SPIO_Util::Rearr_Util::pair(ntasks, istep, my_rank); + if(p >= 0 && (sendcount > 0 || recvcount > 0)){ + swapids[steps++] = p; + } + } + + LOG((3, "steps=%d", steps)); + + if(steps == 0){ + return PIO_NOERR; + } + + if(steps == 1){ + maxreq = 1; + maxreqh = 1; + } + else{ + if(fc->max_pend_req == PIO_REARR_COMM_UNLIMITED_PEND_REQ){ + maxreq = steps; + maxreqh = steps; + } + else if(fc->max_pend_req > 1 && fc->max_pend_req < steps){ + maxreq = fc->max_pend_req; + maxreqh = maxreq / 2; + } + else if(fc->max_pend_req == 1){ + /* Note that steps >= 2 here */ + maxreq = 2; + maxreqh = 1; + } + else{ + maxreq = steps; + maxreqh = steps; + } + } + + LOG((2, "fc->max_pend_req=%d, maxreq=%d, maxreqh=%d", fc->max_pend_req, maxreq, maxreqh)); + + /* If handshaking is in use, do a nonblocking recieve to listen + * for it. */ + if(fc->hs){ + for(istep = 0; istep < maxreq; istep++){ + p = swapids[istep]; + if(sendcount > 0){ + tag = my_rank + offset_t; + if((mpierr = MPI_Irecv(&hs, 1, MPI_INT, p, tag, comm, hs_rcvids + istep))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + } + } + } + + /* Post up to maxreq irecv's. */ + for(istep = 0; istep < maxreq; istep++){ + p = swapids[istep]; + if(recvcount > 0){ + tag = p + offset_t; + ptr = (char *)recvbuf + p * recvcount * recvtype_sz; + + if((mpierr = MPI_Irecv(ptr, recvcount, recvtype, p, tag, comm, + rcvids + istep))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + + if(fc->hs){ + if((mpierr = MPI_Send(&hs, 1, MPI_INT, p, tag, comm))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + } + } + } + + /* Tell the paired task that this tasks' has posted it's irecvs'. */ + rstep = maxreq; + for(istep = 0; istep < steps; istep++){ + p = swapids[istep]; + if(sendcount > 0){ + tag = my_rank + offset_t; + /* If handshake is enabled don't post sends until the + * receiving task has posted recvs. */ + if(fc->hs){ + if((mpierr = MPI_Wait(hs_rcvids + istep, &status))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + hs_rcvids[istep] = MPI_REQUEST_NULL; + } + ptr = (char *)sendbuf + p * sendcount * sendtype_sz; + + /* On some software stacks MPI_Irsend() is either not available, not + * a major issue anymore, or is buggy. With PIO1 we have found that + * although the code correctly posts receives before the irsends, + * on some systems (software stacks) the code hangs. However the + * code works fine with isends. The _USE_MPI_RSEND macro should be + * used to use mpi_irsends, the default is mpi_isend + */ + if(fc->hs && fc->isend){ +#ifndef _USE_MPI_RSEND + if((mpierr = MPI_Isend(ptr, sendcount, sendtype, p, tag, comm, + sndids + istep))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } +#else + if((mpierr = MPI_Irsend(ptr, sendcount, sendtype, p, tag, comm, + sndids + istep))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } +#endif + } + else if(fc->isend){ + if((mpierr = MPI_Isend(ptr, sendcount, sendtype, p, tag, comm, + sndids + istep))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + } + else{ + if((mpierr = MPI_Send(ptr, sendcount, sendtype, p, tag, comm))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + } + } + + /* We did comms in sets of size max_reqs, if istep > maxreqh-1 + * then there is a remainder that must be handled. */ + if(istep > maxreqh - 1){ + p = istep - maxreqh; + if(rcvids[p] != MPI_REQUEST_NULL){ + if((mpierr = MPI_Wait(rcvids + p, &status))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + rcvids[p] = MPI_REQUEST_NULL; + } + if(rstep < steps){ + p = swapids[rstep]; + if(fc->hs && sendcount > 0){ + tag = my_rank + offset_t; + if((mpierr = MPI_Irecv(&hs, 1, MPI_INT, p, tag, comm, hs_rcvids+rstep))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + } + if(recvcount > 0){ + tag = p + offset_t; + + ptr = (char *)recvbuf + p * recvcount * recvtype_sz; + if((mpierr = MPI_Irecv(ptr, recvcount, recvtype, p, tag, comm, rcvids + rstep))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + if(fc->hs){ + if((mpierr = MPI_Send(&hs, 1, MPI_INT, p, tag, comm))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + } + } + rstep++; + } + } + } + + /* If steps > 0 there could still be outstanding messages, wait for + * them here. */ + if(steps > 0){ + LOG((2, "Waiting for outstanding msgs")); + if((mpierr = MPI_Waitall(steps, rcvids, MPI_STATUSES_IGNORE))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + if(fc->isend){ + if((mpierr = MPI_Waitall(steps, sndids, MPI_STATUSES_IGNORE))){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } + } + } + + return PIO_NOERR; +} diff --git a/src/clib/pio_rearr_utils.hpp b/src/clib/pio_rearr_utils.hpp new file mode 100644 index 0000000000..77e6b5b2cf --- /dev/null +++ b/src/clib/pio_rearr_utils.hpp @@ -0,0 +1,41 @@ +#ifndef __PIO_REARR_UTILS_HPP__ +#define __PIO_REARR_UTILS_HPP__ + +#include "pio_config.h" +#include "pio.h" +#include "pio_internal.h" +#include "pio_types.hpp" + +#include + +namespace SPIO_Util{ + namespace Rearr_Util{ + int gatherw(const void *sendbuf, int sendcount, + MPI_Datatype sendtype, + void *recvbuf, const std::vector &recvcounts, + const std::vector &rdispls, + const std::vector &recvtypes, + int root, MPI_Comm comm, const rearr_comm_fc_opt_t *fc); + int scatterw(const void *sendbuf, const std::vector &sendcounts, + const std::vector &sdispls, + const std::vector &sendtypes, + void *recvbuf, int recvcount, + MPI_Datatype recvtype, + int root, MPI_Comm comm, const rearr_comm_fc_opt_t *fc); + + int alltoallw(const void *sendbuf, const int *sendcounts, + const int *sdispls, const MPI_Datatype *sendtypes, + void *recvbuf, const int *recvcounts, + const int *rdispls, const MPI_Datatype *recvtypes, + MPI_Comm comm, const rearr_comm_fc_opt_t *fc); + + int alltoall(const void *sendbuf, int sendcount, + MPI_Datatype sendtype, + void *recvbuf, int recvcount, + MPI_Datatype recvtype, + MPI_Comm comm, const rearr_comm_fc_opt_t *fc); + + } // namespace Rearr_Util +} // namespace SPIO_Util + +#endif // __PIO_REARR_UTILS_HPP__ From 81bcf161f176c26e9caf501f9a4a659d3bc69ea9 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 18 Nov 2024 11:10:53 -0600 Subject: [PATCH 009/194] Adding some debug utils Adding some debug util functions to print 1d vectors. --- src/clib/spio_dbg_utils.hpp | 56 +++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 src/clib/spio_dbg_utils.hpp diff --git a/src/clib/spio_dbg_utils.hpp b/src/clib/spio_dbg_utils.hpp new file mode 100644 index 0000000000..474474fba6 --- /dev/null +++ b/src/clib/spio_dbg_utils.hpp @@ -0,0 +1,56 @@ +#ifndef __SPIO_DBG_UTILS_HPP__ +#define __SPIO_DBG_UTILS_HPP__ + +#include "pio_config.h" +#include "pio.h" +#include "pio_internal.h" +#include "pio_types.hpp" + +#include +#include +#include +#include +#include + +namespace SPIO_Util{ + namespace Dbg_Util{ + + /* Debug print a vector */ + template + void print_1dvec(const std::vector &v) + { + std::ostringstream ostr; + ostr << "["; + std::copy(v.cbegin(), v.cend(), std::ostream_iterator(ostr, ",")); + ostr << "]"; + std::cout << ostr.str().c_str() << "\n" << std::flush; + } + + /* Debug print a vector of vectors */ + template + void print_1dvec(std::initializer_list > vecs) + { + std::ostringstream ostr; + for(typename std::initializer_list >::iterator citer = vecs.begin(); + citer != vecs.end(); ++citer){ + ostr << "["; + std::copy((*citer).cbegin(), (*citer).cend(), std::ostream_iterator(ostr, ",")); + ostr << "] "; + } + std::cout << ostr.str().c_str() << "\n" << std::flush; + } + + /* Debug print an array */ + template + void print_1dvec(const T *vbegin, const T *vend) + { + std::ostringstream ostr; + ostr << "["; + std::copy(vbegin, vend, std::ostream_iterator(ostr, ",")); + ostr << "]"; + std::cout << ostr.str().c_str() << "\n" << std::flush; + } + } // namespace Dbg_Util +} // namespace SPIO_Util + +#endif // __SPIO_DBG_UTILS_HPP__ From 990fee75eb4c407ea1b4c705574a6809cb978a16 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 18 Nov 2024 11:24:43 -0600 Subject: [PATCH 010/194] Adding a new rearranger, PIO_REARR_CONTIG Adding a new rearranger, PIO_REARR_CONTIG, that performs data rearrangement in two steps, 1) Data aggregation : Data aggregation from compute processes to I/O (aggregating) processes 2) Data rearrangement : Data rearrangement between I/O (aggregating) processes such that each I/O process has a contiguous data chunk --- src/clib/pio_rearr_contig.cpp | 996 ++++++++++++++++++++++++++++++++++ src/clib/pio_rearr_contig.hpp | 152 ++++++ 2 files changed, 1148 insertions(+) create mode 100644 src/clib/pio_rearr_contig.cpp create mode 100644 src/clib/pio_rearr_contig.hpp diff --git a/src/clib/pio_rearr_contig.cpp b/src/clib/pio_rearr_contig.cpp new file mode 100644 index 0000000000..a92d29e67b --- /dev/null +++ b/src/clib/pio_rearr_contig.cpp @@ -0,0 +1,996 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pio_rearr_contig.hpp" +#include "pio_rearr_utils.hpp" +#include "spio_dbg_utils.hpp" + +namespace SPIO_Util{ + template + static void exscan(CIter ibegin, CIter iend, Iter obegin, + typename std::iterator_traits::value_type ival, + std::function::value_type + (typename std::iterator_traits::value_type)> scale_func) + { + typename std::iterator_traits::value_type psum = ival; + for(;ibegin != iend; ++ibegin, ++obegin){ + *obegin = scale_func(psum); + psum += *ibegin; + } + } + + template + static void exscan(CIter ibegin, CIter iend, Iter obegin, + typename std::iterator_traits::value_type ival) + { + typename std::iterator_traits::value_type psum = ival; + for(;ibegin != iend; ++ibegin, ++obegin){ + *obegin = psum; + psum += *ibegin; + } + } + + template + static void vec_map_sort(std::vector &v, const std::vector &map) + { + std::vector vtmp(v); + assert(v.size() == map.size()); + + for(std::size_t i = 0; i < vtmp.size(); i++){ + v[map[i]] = vtmp[i]; + } + } +} // namespace SPIO_Util + +int SPIO::DataRearr::Contig_rearr::init(int pio_type, + const PIO_Offset *compmap, std::size_t compmap_sz, + const int *gdimlen, int ndims, io_desc_t *iodesc) +{ + int ret = PIO_NOERR; + assert(ios_); + + lcompmap_sz_ = compmap_sz; + gdecomp_sz_ = std::accumulate(gdimlen, gdimlen + ndims, 0); + + elem_pio_type_ = pio_type; + ret = find_mpi_type(elem_pio_type_, &elem_mpi_type_, &elem_mpi_type_sz_); + if(ret != PIO_NOERR){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while initializing PIO_REARR_CONTIG. Unable to find MPI type corresponding to PIO type (%d)", pio_type); + } + + /* Calculate gather scatter info for aggregation. Each I/O node is an aggregator */ + + /* Create aggregate comm, rank = 0 in each aggregate comm is an I/O process */ + ret = create_agg_comm(); + if(ret != PIO_NOERR){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while initializing PIO_REARR_CONTIG. Unable to create aggregator comm (iosysid = %d)", ios_->iosysid); + } + + /* Create rearranger comm, dup of I/O comm - contains aggregator/IO procs */ + ret = create_rearr_comm(); + if(ret != PIO_NOERR){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while initializing PIO_REARR_CONTIG. Unable to create rearranger comm (iosysid = %d)", ios_->iosysid); + } + + /* Aggregate compmaps into the aggregating procs */ + std::vector aggcompmap; + std::vector aggcompmap_counts, aggcompmap_displs; + ret = aggregate_compmap(compmap, compmap_sz, aggcompmap, aggcompmap_counts, aggcompmap_displs); + if(ret != PIO_NOERR){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while initializing PIO_REARR_CONTIG. Unable to aggregate local compmaps (iosysid = %d)", ios_->iosysid); + } + + /* Each MPI process sends compmap_sz elements to the aggregating node */ + std::vector to_proc; + ret = get_rearr_toproc_map(aggcompmap, to_proc); + if(ret != PIO_NOERR){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while initializing PIO_REARR_CONTIG. Unable to create to proc map (iosysid = %d)", ios_->iosysid); + } + + /* Set up the types and info required to aggregate data */ + ret = setup_data_agg_info(compmap, compmap_sz, aggcompmap, aggcompmap_counts, aggcompmap_displs, to_proc); + if(ret != PIO_NOERR){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while initializing PIO_REARR_CONTIG. Unable to setup data aggregation (iosysid = %d)", ios_->iosysid); + } + + /* Set up the types and info required to rearrange data */ + ret = setup_data_rearr_info(aggcompmap, to_proc, gdimlen, ndims); + if(ret != PIO_NOERR){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while initializing PIO_REARR_CONTIG. Unable to setup data rearrangement (iosysid = %d)", ios_->iosysid); + } + + is_init_ = true; + + return ret; +} + +int SPIO::DataRearr::Contig_rearr::rearrange_comp2io(const void *sbuf, std::size_t sbuf_sz, + void *rbuf, std::size_t rbuf_sz, int nvars) +{ + int ret = PIO_NOERR; + assert(is_init_); + + /* FIXME: We need a better way to find this info out */ + std::size_t agg_data_nelems = agg_compmap_sorter_.size(); + + /* Aggregate data */ + void *agg_buf = NULL; + std::size_t agg_buf_sz = nvars * agg_data_nelems * elem_mpi_type_sz_; + if(is_agg_root_){ + agg_buf = malloc(agg_buf_sz); + if(!agg_buf){ + return pio_err(ios_, NULL, PIO_ENOMEM, __FILE__, __LINE__, + "Internal error while aggregating data from compute processes to aggregating processes (PIO_REARR_CONTIG). Unable to allocate memory to recv data (%lld bytes) for data aggregation (iosysid = %d)", static_cast (agg_buf_sz), ios_->iosysid); + } + } + + ret = aggregate_data(sbuf, sbuf_sz, agg_buf, agg_buf_sz, nvars); + if(ret != PIO_NOERR){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while aggregating data from compute processes to aggregating processes (PIO_REARR_CONTIG). Data aggregation failed(aggregating buffer size = %lld bytes, receive buffer size = %lld bytes, nvars = %d, iosysid = %d)", static_cast(agg_buf_sz), + static_cast(rbuf_sz), nvars, ios_->iosysid); + } + + /* Rearrange data - aggregate processes to rearrange processes */ + ret = rearrange_data(agg_buf, agg_buf_sz, rbuf, rbuf_sz, nvars, true); + if(ret != PIO_NOERR){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while rearranging data between IO/aggregating processes (PIO_REARR_CONTIG). Data rearrangement failed(aggregating buffer size = %lld bytes, receive buffer size = %lld bytes, nvars = %d, iosysid = %d)", static_cast(agg_buf_sz), + static_cast(rbuf_sz), nvars, ios_->iosysid); + } + + if(agg_buf){ + free(agg_buf); + } + + return ret; +} + +int SPIO::DataRearr::Contig_rearr::aggregate_data(const void *sbuf, std::size_t sbuf_sz, + void *abuf, std::size_t abuf_sz, int nvars) +{ + int ret = PIO_NOERR; + assert(is_init_); + + /* Gather data from compute processes in this aggregating comm to the aggregating/IO process */ + MPI_Datatype agg_stype = agg_gs_info_.stype; + std::vector agg_rtypes_nvars; + + /* FIXME: We need a better way to find this info out */ + std::size_t agg_data_nelems = agg_compmap_sorter_.size(); + assert(abuf_sz == nvars * agg_data_nelems * elem_mpi_type_sz_); + + if(nvars > 1){ + /* We are aggregating a block of variables */ + /* The stride between each block - each variable - is the total size of the data aggregated from + * all compute processes in the aggregator. On the compute procs its a contiguous block of data + * - composed on nvars blocks, such that each block is data corresponding to a single var + */ + if(is_agg_root_){ + MPI_Aint stride_between_vars = static_cast(agg_data_nelems * elem_mpi_type_sz_); + for(std::size_t i = 0; i < agg_gs_info_.rtypes.size(); i++){ + MPI_Datatype agg_rtype = MPI_DATATYPE_NULL; + if(agg_gs_info_.rtypes[i] != MPI_DATATYPE_NULL){ + ret = MPI_Type_hvector(nvars, 1, stride_between_vars, agg_gs_info_.rtypes[i], &agg_rtype); + if(ret == MPI_SUCCESS){ + ret = MPI_Type_commit(&agg_rtype); + } + if(ret != MPI_SUCCESS){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while aggregating data from compute processes to aggregating processes (PIO_REARR_CONTIG). Unable to create vector types to recv data for data aggregation (iosysid = %d)", ios_->iosysid); + } + } + agg_rtypes_nvars.push_back(agg_rtype); + } + } + } + + int scount = (agg_stype != MPI_DATATYPE_NULL) ? nvars : 0; + + ret = SPIO_Util::Rearr_Util::gatherw(sbuf, scount, agg_stype, + abuf, agg_gs_info_.rcounts, agg_data_byte_displs_, + (nvars > 1) ? agg_rtypes_nvars : agg_gs_info_.rtypes, + 0, agg_comm_, NULL); + if(ret != MPI_SUCCESS){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while aggregating data from compute processes to aggregating processes (PIO_REARR_CONTIG). Unable to gather data during data aggregation (iosysid = %d)", ios_->iosysid); + } + + for(std::size_t i = 0; i < agg_rtypes_nvars.size(); i++){ + if(agg_rtypes_nvars[i] != MPI_DATATYPE_NULL){ + MPI_Type_free(&(agg_rtypes_nvars[i])); + } + } + + return ret; +} + +int SPIO::DataRearr::Contig_rearr::disperse_data(const void *abuf, std::size_t abuf_sz, + void *rbuf, std::size_t rbuf_sz, int nvars) +{ + int ret = PIO_NOERR; + assert(is_init_); + + /* When scattering/dispersing data from aggregate process to compute processes, + * agg_gs_info_.stype, the send type used for sending data to aggregating processes during + * aggregation, is now the recv type + * Similarly agg_gs_info_.rtypes, the recv types used for aggregating data on the aggregating + * process from the compute processes, is now the type use to send/disperse data + */ + MPI_Datatype dis_rtype = agg_gs_info_.stype; + std::vector dis_stypes_nvars; + + /* FIXME: We need a better way to find this info out */ + std::size_t agg_data_nelems = agg_compmap_sorter_.size(); + assert(abuf_sz == nvars * agg_data_nelems * elem_mpi_type_sz_); + + if(nvars > 1){ + /* We are dispersing a block of variables */ + /* The stride between each block - each variable - is the total size of the data aggregated from + * all compute processes in the aggregator. On the compute procs its a contiguous block of data + * - composed on nvars blocks, such that each block is data corresponding to a single var + */ + if(is_agg_root_){ + MPI_Aint stride_between_vars = static_cast(agg_data_nelems * elem_mpi_type_sz_); + for(std::size_t i = 0; i < agg_gs_info_.rtypes.size(); i++){ + MPI_Datatype dis_stype = MPI_DATATYPE_NULL; + if(agg_gs_info_.rtypes[i] != MPI_DATATYPE_NULL){ + ret = MPI_Type_hvector(nvars, 1, stride_between_vars, agg_gs_info_.rtypes[i], &dis_stype); + if(ret == MPI_SUCCESS){ + ret = MPI_Type_commit(&dis_stype); + } + if(ret != MPI_SUCCESS){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while dispersing data from aggregating processes to compute processes (PIO_REARR_CONTIG). Unable to create vector types to send data during data dispersion (iosysid = %d)", ios_->iosysid); + } + } + dis_stypes_nvars.push_back(dis_stype); + } + } + } + + int rcount = (dis_rtype != MPI_DATATYPE_NULL) ? nvars : 0; + + ret = SPIO_Util::Rearr_Util::scatterw(abuf, agg_gs_info_.rcounts, + agg_data_byte_displs_, + (nvars > 1) ? dis_stypes_nvars : agg_gs_info_.rtypes, + rbuf, rcount, dis_rtype, + 0, agg_comm_, NULL); + if(ret != MPI_SUCCESS){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while dispersing data from aggregating processes to compute processes (PIO_REARR_CONTIG). Unable to disperse/scatter data during data dispersion (iosysid = %d)", ios_->iosysid); + } + + for(std::size_t i = 0; i < dis_stypes_nvars.size(); i++){ + if(dis_stypes_nvars[i] != MPI_DATATYPE_NULL){ + MPI_Type_free(&(dis_stypes_nvars[i])); + } + } + + return ret; +} + +int SPIO::DataRearr::Contig_rearr::rearrange_io2comp(const void *sbuf, std::size_t sbuf_sz, + void *rbuf, std::size_t rbuf_sz, int nvars) +{ + int ret = PIO_NOERR; + assert(is_init_); + + /* FIXME: We need a better way to find this info out */ + std::size_t agg_data_nelems = agg_compmap_sorter_.size(); + + /* Disperse/scatter data */ + void *agg_buf = NULL; + std::size_t agg_buf_sz = nvars * agg_data_nelems * elem_mpi_type_sz_; + if(is_agg_root_){ + agg_buf = malloc(agg_buf_sz); + if(!agg_buf){ + return pio_err(ios_, NULL, PIO_ENOMEM, __FILE__, __LINE__, + "Internal error while dispersing data from aggregating processes to compute processes (PIO_REARR_CONTIG). Unable to allocate memory to store data (%lld bytes) for data dispersion (iosysid = %d)", static_cast (agg_buf_sz), ios_->iosysid); + } + } + + /* Rearrange data - rearrange processes to aggregate processes */ + ret = rearrange_data(sbuf, sbuf_sz, agg_buf, agg_buf_sz, nvars, false); + if(ret != PIO_NOERR){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while rearranging data between IO/aggregating processes (PIO_REARR_CONTIG). Data rearrangement failed(aggregating buffer size = %lld bytes, receive buffer size = %lld bytes, nvars = %d, iosysid = %d)", static_cast(agg_buf_sz), + static_cast(rbuf_sz), nvars, ios_->iosysid); + } + + ret = disperse_data(agg_buf, agg_buf_sz, rbuf, rbuf_sz, nvars); + if(ret != PIO_NOERR){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while dispersing data from aggregating processes to compute processes (PIO_REARR_CONTIG). Data dispersion/scatter failed(aggregating buffer size = %lld bytes, receive buffer size = %lld bytes, nvars = %d, iosysid = %d)", static_cast(agg_buf_sz), + static_cast(rbuf_sz), nvars, ios_->iosysid); + } + + if(agg_buf){ + free(agg_buf); + } + + return ret; +} + +int SPIO::DataRearr::Contig_rearr::finalize(void ) +{ + int ret = PIO_NOERR; + + /* Free the MPI datatypes used for aggregation and rearrangement */ + /* We ignore the return values from free()s, since we want to free as much as possible here */ + if(agg_gs_info_.stype != MPI_DATATYPE_NULL){ + MPI_Type_free(&(agg_gs_info_.stype)); + } + for(std::size_t i = 0; i < agg_gs_info_.rtypes.size(); i++){ + if(agg_gs_info_.rtypes[i] != MPI_DATATYPE_NULL){ + MPI_Type_free(&(agg_gs_info_.rtypes[i])); + } + } + + for(std::size_t i = 0; i < rearr_alltoall_info_.stypes.size(); i++){ + if(rearr_alltoall_info_.stypes[i] != MPI_DATATYPE_NULL){ + MPI_Type_free(&(rearr_alltoall_info_.stypes[i])); + } + } + + for(std::size_t i = 0; i < rearr_alltoall_info_.rtypes.size(); i++){ + if(rearr_alltoall_info_.rtypes[i] != MPI_DATATYPE_NULL){ + MPI_Type_free(&(rearr_alltoall_info_.rtypes[i])); + } + } + + /* Free aggregate and rearranger comms */ + if(agg_comm_ != MPI_COMM_NULL){ + MPI_Comm_free(&agg_comm_); + } + if(rearr_comm_ != MPI_COMM_NULL){ + MPI_Comm_free(&rearr_comm_); + } + + is_init_ = false; + + return ret; +} + +inline int SPIO::DataRearr::Contig_rearr::create_agg_comm(void ) +{ + int ret = MPI_SUCCESS; + + assert(ios_); + + /* Divide union comm into (ios_->num_iotasks) groups */ + int agg_range_sz = ios_->num_uniontasks/ios_->num_iotasks; + /* Ensure that each group/color gets an I/O process - which is also the aggregating process */ + int color = (ios_->ioproc) ? ios_->io_rank : (ios_->union_rank/agg_range_sz); + /* Put the extra set of procs, after evenly dividing procs among I/O procs, with the last I/O proc */ + color = (color >= ios_->num_iotasks) ? (ios_->num_iotasks - 1) : color; + + /* Each I/O process is rank 0 in the new aggregator comm, and is also the aggregating proc */ + int key = (ios_->ioproc) ? 0 : 1; + + ret = MPI_Comm_split(ios_->union_comm, color, key, &agg_comm_); + if(ret == MPI_SUCCESS){ + is_agg_root_ = (key == 0) ? true : false; + ret = MPI_Comm_size(agg_comm_, &agg_comm_sz_); + } + + return ret; +} + +int SPIO::DataRearr::Contig_rearr::aggregate_compmap(const PIO_Offset *lcompmap, std::size_t lcompmap_sz, + std::vector &gcompmap, + std::vector &gcompmap_counts, + std::vector &gcompmap_displs) +{ + int ret = PIO_NOERR; + assert(ios_ && (agg_comm_ != MPI_COMM_NULL)); + + /* Get the compmap sizes from all procs in this aggregation comm */ + if(is_agg_root_){ + gcompmap_counts.resize(agg_comm_sz_); + gcompmap_displs.resize(agg_comm_sz_); + } + + int send_sz = static_cast(lcompmap_sz); + ret = MPI_Gather(&send_sz, 1, MPI_INT, gcompmap_counts.data(), 1, MPI_INT, 0, agg_comm_); + if(ret != MPI_SUCCESS){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while initializing PIO_REARR_CONTIG. Unable to gather local compmap sizes (iosysid=%d)", ios_->iosysid); + } + + if(is_agg_root_){ + int total_agg_compmap_sz = std::accumulate(gcompmap_counts.cbegin(), gcompmap_counts.cend(), 0); + gcompmap.resize(total_agg_compmap_sz); + + /* Calculate the displacements for local compmaps in the global compmap, gcompmap */ + SPIO_Util::exscan(gcompmap_counts.cbegin(), gcompmap_counts.cend(), gcompmap_displs.begin(), 0); + int elem_type_sz = this->elem_mpi_type_sz_; + agg_data_byte_displs_.resize(gcompmap_displs.size()); + std::transform(gcompmap_displs.cbegin(), gcompmap_displs.cend(), agg_data_byte_displs_.begin(), + [elem_type_sz](int i) { return i * elem_type_sz; } ); + } + + /* Gather local compmaps */ + ret = MPI_Gatherv(lcompmap, lcompmap_sz, PIO_OFFSET, + gcompmap.data(), gcompmap_counts.data(), gcompmap_displs.data(), PIO_OFFSET, + 0, agg_comm_); + if(ret != MPI_SUCCESS){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while initializing PIO_REARR_CONTIG. Unable to gather local compmaps (iosysid=%d)", ios_->iosysid); + } + + return ret; +} + +int SPIO::DataRearr::Contig_rearr::setup_data_agg_info(const PIO_Offset *lcompmap, + std::size_t lcompmap_sz, + const std::vector &gcompmap, + const std::vector &gcompmap_counts, + const std::vector &gcompmap_displs, + const std::vector &to_proc) +{ + int ret = PIO_NOERR; + + assert(ios_); + /* Setup gather scatter info for sending/receiving data from compute procs to + * aggregate/IO procs + * Sending/receiving 1 contiguous array of lcompmap_sz length + */ + agg_gs_info_.stype = MPI_DATATYPE_NULL; + if(lcompmap_sz > 0){ + ret = MPI_Type_contiguous(static_cast(lcompmap_sz), elem_mpi_type_, &(agg_gs_info_.stype)); + if(ret == MPI_SUCCESS){ + ret = MPI_Type_commit(&(agg_gs_info_.stype)); + } + + if(ret != MPI_SUCCESS){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while initializing PIO_REARR_CONTIG. Unable to create/commit contiguous type (size=%d) on compute process for data aggregation (iosysid=%d)", static_cast(lcompmap_sz), ios_->iosysid); + } + } + + if(!is_agg_root_){ + /* Non-aggregating processes use the agg_gs_info_.stype to send data to aggregator process + * and receive data from it + */ + return ret; + } + /* Aggregating process, root in aggregator comm, sends a contiguous array of + * lcompmap_sz length, if its also a compute process, but receives data from + * all non-aggregating procs in the aggregator comm in a way that makes it + * easier to rearrange the data with other aggregating procs - data to send to + * each aggregating proc clustered together such that data sent to an aggregating + * proc is sorted based on the compmap + * The recv type will be calculated later in the function, initializing to NULL + */ + + assert(gcompmap.size() == to_proc.size()); + + /* Sort the indices of gcompmap to a view that we need for data rearrangement between + * aggregator/IO procs + */ + std::vector gcompmap_idx(gcompmap.size()); + std::iota(gcompmap_idx.begin(), gcompmap_idx.end(), 0); + + std::sort(gcompmap_idx.begin(), gcompmap_idx.end(), + [&gcompmap,&to_proc](PIO_Offset a, PIO_Offset b){ + if(to_proc[a] == to_proc[b]){ + /* Sort all data to send to each proc */ + return gcompmap[a] < gcompmap[b]; + } + else{ + /* Aggregate all data to send to a proc together */ + return to_proc[a] < to_proc[b]; + } + }); + + /* Aggregate compmap sorter can be used to sort any user data based on gcompmap */ + agg_compmap_sorter_.resize(gcompmap.size()); + for(std::size_t i = 0; i < gcompmap_idx.size(); i++){ + agg_compmap_sorter_[gcompmap_idx[i]] = i; + } + + ret = init_agg_recv_types(gcompmap_counts, agg_compmap_sorter_); + return ret; +} + +int SPIO::DataRearr::Contig_rearr::init_agg_recv_types(const std::vector &gcompmap_counts, + const std::vector &compmap_sorter) +{ + int ret = PIO_NOERR; + /* The compmap_sorter has the indices of the sorted data (based on to_proc & compmap) + * So look for contiguous ranges in compmap_sorter array + * We need to receive data in the aggregating process such that all data being sent + * to another aggregating process, during rearrangement, is contiguous + * compmap_sorter[i] gives the final intended location of data in index i received on + * the aggregating process from compute processes (the final intended location is such + * that all data sent to to_proc[i] are contiguous) + */ + + std::size_t compmap_sorter_idx = 0; + for(std::vector::const_iterator citer = gcompmap_counts.cbegin(); + citer != gcompmap_counts.cend(); ++citer){ + /* During data aggregation we receive, gcompmap_counts[i] elements from rank i */ + /* We need to keep track of data received in the recv type, so ignore procs that + * have nothing to send */ + if(*citer != 0){ + std::vector counts; + std::vector displs; + std::size_t nelems = static_cast(*citer); + /* The dest range - in the recv buffer of agg process - of elements from this compute proc is : + * compmap_sorter[compmap_sorter_idx, compmap_sorter_idx + nelems) + */ + counts.push_back(1); + displs.push_back(static_cast(compmap_sorter[compmap_sorter_idx] - compmap_sorter_idx)); + assert(compmap_sorter_idx + nelems - 1 < compmap_sorter.size()); + for(std::size_t i = 1; i < nelems; i++){ + int disp = static_cast(compmap_sorter[compmap_sorter_idx + i] - compmap_sorter_idx); + if(disp == displs.back() + counts.back()){ + /* The range in the compmap_sorter is contiguous : receiving contiguous data into recv + * buf from this compute proc + */ + counts.back() += 1; + } + else{ + /* Data from this compute proc is not received contiguously, start a new range */ + counts.push_back(1); + displs.push_back(disp); + } + } + + assert(counts.size() == displs.size()); + MPI_Datatype rtype = MPI_DATATYPE_NULL; + ret = MPI_Type_indexed(static_cast(counts.size()), counts.data(), displs.data(), + elem_mpi_type_, &rtype); + if(ret == MPI_SUCCESS){ + ret = MPI_Type_commit(&rtype); + } + if(ret != MPI_SUCCESS){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while initializing PIO_REARR_CONTIG. Unable to create/commit indexed type (size=%d, nranges=%d) on compute process to recv data for data aggregation (iosysid=%d)", static_cast(nelems), static_cast(counts.size()), ios_->iosysid); + } + agg_gs_info_.rtypes.push_back(rtype); + agg_gs_info_.rcounts.push_back(1); + compmap_sorter_idx += nelems; + } + else{ + agg_gs_info_.rtypes.push_back(MPI_DATATYPE_NULL); + agg_gs_info_.rcounts.push_back(0); + } + } + + return ret; +} + +inline int SPIO::DataRearr::Contig_rearr::create_rearr_comm(void ) +{ + int ret = PIO_NOERR; + assert(ios_); + assert(gdecomp_sz_ > 0); + + if(!ios_->ioproc){ + return ret; + } + + ret = MPI_Comm_dup(ios_->io_comm, &rearr_comm_); + if(ret == MPI_SUCCESS){ + ret = MPI_Comm_size(rearr_comm_, &rearr_comm_sz_); + if(ret == MPI_SUCCESS){ + ret = MPI_Comm_rank(rearr_comm_, &rearr_comm_rank_); + } + } + + if(ret == MPI_SUCCESS){ + rearr_comm_iochunk_sz_ = gdecomp_sz_ / rearr_comm_sz_; + } + + return ret; +} + +int SPIO::DataRearr::Contig_rearr::get_rearr_toproc_map(const std::vector &gcompmap, + std::vector &to_proc) +{ + int ret = PIO_NOERR; + assert(ios_); + + if(!ios_->ioproc){ + return ret; + } + assert(rearr_comm_sz_ > 0); + + to_proc.resize(gcompmap.size()); + for(std::size_t i = 0; i < gcompmap.size(); i++){ + /* Note: The last rearranger proc gets the leftover gcompmap range */ + to_proc[i] = std::min(static_cast(gcompmap[i]/rearr_comm_iochunk_sz_), rearr_comm_sz_ - 1); + } + + return ret; +} + +int SPIO::DataRearr::Contig_rearr::setup_data_rearr_info(std::vector &gcompmap, + std::vector &to_proc, + const int *gdimlen, int ndims) +{ + int ret = PIO_NOERR; + assert(ios_); + + if(!ios_->ioproc){ + return ret; + } + assert(rearr_comm_sz_ > 0); + assert(gcompmap.size() == agg_compmap_sorter_.size()); + assert(to_proc.size() == gcompmap.size()); + + /* Sort gcompmap (the aggregated compmap from compute procs) based on compmap sorter map */ + SPIO_Util::vec_map_sort(gcompmap, agg_compmap_sorter_); + SPIO_Util::vec_map_sort(to_proc, agg_compmap_sorter_); + + /* Exchange information about the data being sent from each process, + * 1) The number of regions (a single region is a contiguous chunk/block of elements/data) + * 2) Start/Count defining each region - We calculate the displacement for each receiving + * proc on the sending proc & send that information instead. For region i, a process sends + * + * displs_i -> The local displacement at which to receive the data on the receiving process + * counts_i -> Number of contiguous elements - size of a contiguous block - of data being sent + * + * The counts & displacements (starts) for all the receiving processes are compiled into a + * single displs_counts_sent[] array. The nregion_infos array specifies the number of region + * infos for each process - nregion_infos[i] specifies the number of region info pairs, + * the number of {displ, count} pairs for rank i - and can be used to traverse the + * displs_counts_sent[] array to find the offset in the displs_counts_sent[] + * array for rank i + * + * Each process sends a contiguous block of data and receives an indexed block of data + * based on the start/count info from each process + */ + std::vector nregion_infos_sent(rearr_comm_sz_, 0); + /* displs_counts_sent[i] = displacement, local to rank k, for region i + * displs_counts_sent[i+1] = size of region i + * displs_counts_sent_rank_offs[k] = offset to displs_counts_sent[] array for regions to send to rank k + */ + std::vector displs_counts_sent; + std::vector displs_counts_sent_rank_offs(rearr_comm_sz_); + + std::size_t to_proc_gcompmap_idx = 0; + if(to_proc.size() > 0){ + assert(gdecomp_sz_ > 0); + /* This aggregating proc has some data to send to other aggregating/IO procs */ + for(int i = 0; (i < rearr_comm_sz_) && (to_proc_gcompmap_idx < to_proc.size()); i++){ + assert(to_proc_gcompmap_idx < to_proc.size()); + assert(to_proc_gcompmap_idx < gcompmap.size()); + displs_counts_sent_rank_offs[i] = + static_cast(displs_counts_sent.size() * sizeof(MPI_Offset)); + /* to_proc is sorted based on rank */ + //PIO_Offset to_proc_start_disp = get_rearr_decomp_map_range(i).first; + PIO_Offset to_proc_start_disp = get_rearr_decomp_map_range(to_proc[to_proc_gcompmap_idx]).first; + while((to_proc_gcompmap_idx < gcompmap.size()) && + (to_proc[to_proc_gcompmap_idx] == i)){ + /* There is some data to send to proc i, find the next contig region to sent to proc i */ + nregion_infos_sent[i] += 2; + /* Add displ - displ is converted to local displ in the receiving process */ + PIO_Offset prev_disp = gcompmap[to_proc_gcompmap_idx++] - to_proc_start_disp; + displs_counts_sent.push_back(prev_disp); + /* Add count */ + displs_counts_sent.push_back(1); + /* Parse the entire contig region */ + while(to_proc_gcompmap_idx < gcompmap.size()){ + PIO_Offset cur_disp = gcompmap[to_proc_gcompmap_idx] - to_proc_start_disp; + if((to_proc[to_proc_gcompmap_idx] != i) || + (cur_disp != prev_disp + 1)){ + break; + } + /* Increment the count for this region */ + displs_counts_sent.back()++; + prev_disp = cur_disp; + to_proc_gcompmap_idx++; + } + } + } + } + + /* Exchange the number of region infos sent/recvd to/from each process */ + std::vector nregion_infos_recvd(rearr_comm_sz_, 0); + ret = SPIO_Util::Rearr_Util::alltoall(nregion_infos_sent.data(), 1, MPI_INT, + nregion_infos_recvd.data(), 1, MPI_INT, + rearr_comm_, &(ios_->rearr_opts.comp2io)); + if(ret != PIO_NOERR){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while initializing PIO_REARR_CONTIG. Unable to exchange number of regions for data rearrangement (iosysid=%d)", ios_->iosysid); + } + + /* Calculate total number of region info pairs received by this process */ + int tot_nregion_infos_recvd = + std::accumulate(nregion_infos_recvd.begin(), nregion_infos_recvd.end(), 0); + + std::vector displs_counts_recvd(tot_nregion_infos_recvd, 0); + std::vector displs_counts_recvd_rank_offs(rearr_comm_sz_); + + SPIO_Util::exscan(nregion_infos_recvd.cbegin(), nregion_infos_recvd.cend(), + displs_counts_recvd_rank_offs.begin(), 0, + [](int off) { return off * sizeof(MPI_Offset); }); + + std::vector info_types(rearr_comm_sz_, MPI_OFFSET); + /* Exchange the info - start/count - of regions sent/recvd to/from each process */ + ret = SPIO_Util::Rearr_Util::alltoallw(displs_counts_sent.data(), nregion_infos_sent.data(), + displs_counts_sent_rank_offs.data(), info_types.data(), + displs_counts_recvd.data(), nregion_infos_recvd.data(), + displs_counts_recvd_rank_offs.data(), info_types.data(), + rearr_comm_, &(ios_->rearr_opts.comp2io)); + if(ret != PIO_NOERR){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while initializing PIO_REARR_CONTIG. Unable to exchange region info for data rearrangement (iosysid=%d)", ios_->iosysid); + } + + /* Create send types for data rearrangement - for each process */ + ret = init_rearr_send_types(nregion_infos_sent, displs_counts_sent); + if(ret != PIO_NOERR){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while initializing PIO_REARR_CONTIG. Unable to create MPI datatypes for sending data for data rearrangement (iosysid=%d)", ios_->iosysid); + } + + /* Create recv types for data rearrangement - for each process based on region info exchanged */ + ret = init_rearr_recvd_types(nregion_infos_recvd, displs_counts_recvd); + if(ret != PIO_NOERR){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while initializing PIO_REARR_CONTIG. Unable to create MPI datatypes for receiving data for data rearrangement (iosysid=%d)", ios_->iosysid); + } + + return ret; +} + +int SPIO::DataRearr::Contig_rearr::init_rearr_send_types( + const std::vector &nregion_infos_sent, + const std::vector &displs_counts_sent) +{ + int ret = PIO_NOERR; + + assert(ios_ && ios_->ioproc); + assert(rearr_comm_sz_ > 0); + assert(nregion_infos_sent.size() == rearr_comm_sz_); + + rearr_alltoall_info_.scounts.reserve(rearr_comm_sz_); + rearr_alltoall_info_.sdispls.reserve(rearr_comm_sz_); + rearr_alltoall_info_.stypes.reserve(rearr_comm_sz_); + + /* Point the idx for the first count in displs_counts_sent[] array */ + std::size_t displs_counts_sent_idx = 1; + std::size_t data_idx = 0; + for(int i = 0; i < rearr_comm_sz_; i++){ + if(nregion_infos_sent[i] != 0){ + assert(nregion_infos_sent[i] > 0); + /* Since we rearrange data sorted on to_proc() - the process to send to during rearr - + * we can send a contiguous chunk/block of data */ + /* Accumulate counts from all regions to get the total size of the contiguous chunk/block + * of data to send to this process, i */ + int data_ranki_idx = static_cast(data_idx); + int nregions = nregion_infos_sent[i] / 2; + int nelems = 0; + /* Add the counts for all regions to get the total elements, nelems, sent to proc i */ + for(int i = 0; i < nregions; i++, displs_counts_sent_idx += 2){ + assert(displs_counts_sent_idx < displs_counts_sent.size()); + nelems += displs_counts_sent[displs_counts_sent_idx]; + } + assert(nelems > 0); + data_idx += nelems; + + MPI_Datatype stype; + ret = MPI_Type_contiguous(nelems, elem_mpi_type_, &stype); + if(ret == MPI_SUCCESS){ + ret = MPI_Type_commit(&stype); + } + + if(ret != MPI_SUCCESS){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while initializing PIO_REARR_CONTIG. Unable to create MPI contig datatype (nelems=%d, sz =%lld) for sending data for data rearrangement (iosysid=%d)", nelems, static_cast(nelems * elem_mpi_type_sz_), ios_->iosysid); + } + + rearr_alltoall_info_.scounts.push_back(1); + rearr_alltoall_info_.sdispls.push_back(data_ranki_idx * elem_mpi_type_sz_); + rearr_alltoall_info_.stypes.push_back(stype); + } + else{ + rearr_alltoall_info_.scounts.push_back(0); + rearr_alltoall_info_.sdispls.push_back(0); + rearr_alltoall_info_.stypes.push_back(MPI_DATATYPE_NULL); + } + } + + return ret; +} + +int SPIO::DataRearr::Contig_rearr::init_rearr_recvd_types( + const std::vector &nregion_infos_recvd, + const std::vector &displs_counts_recvd) +{ + int ret = PIO_NOERR; + + assert(ios_ && ios_->ioproc); + assert(rearr_comm_sz_ > 0); + assert(nregion_infos_recvd.size() == rearr_comm_sz_); + + rearr_alltoall_info_.rcounts.reserve(rearr_comm_sz_); + rearr_alltoall_info_.rdispls.reserve(rearr_comm_sz_); + rearr_alltoall_info_.rtypes.reserve(rearr_comm_sz_); + + assert(displs_counts_recvd.size() % 2 == 0); + + /* Point the idx for the first displ in displs_counts_recvd[] array */ + std::size_t displs_counts_recvd_idx = 0; + std::size_t data_idx = 0; + for(int i = 0; i < rearr_comm_sz_; i++){ + if(nregion_infos_recvd[i] != 0){ + /* We receive an indexed type based on the region info we received from each process */ + int data_ranki_idx = static_cast(data_idx); + int nregions = nregion_infos_recvd[i] / 2; + + assert(nregions > 0); + + std::vector displs; + std::vector counts; + + displs.reserve(nregions); + counts.reserve(nregions); + /* Parse all the regions recvd from rank i and find the displs/counts for each region */ + int nelems = 0; + for(int i = 0; i < nregions; i++, displs_counts_recvd_idx += 2){ + displs.push_back(displs_counts_recvd[displs_counts_recvd_idx]); + counts.push_back(displs_counts_recvd[displs_counts_recvd_idx + 1]); + nelems += displs_counts_recvd[displs_counts_recvd_idx + 1]; + } + + assert(nelems > 0); + data_idx += nelems; + + MPI_Datatype rtype; + ret = MPI_Type_indexed(nregions, counts.data(), displs.data(), elem_mpi_type_, &rtype); + if(ret == MPI_SUCCESS){ + ret = MPI_Type_commit(&rtype); + } + if(ret != MPI_SUCCESS){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while initializing PIO_REARR_CONTIG. Unable to create MPI indexed datatype (nelems=%d, nregions = %d, sz =%lld) for sending data for data rearrangement (iosysid=%d)", nelems, nregions, static_cast(nelems * elem_mpi_type_sz_), ios_->iosysid); + } + + rearr_alltoall_info_.rcounts.push_back(1); + //rearr_alltoall_info_.rdispls.push_back(data_ranki_idx * elem_mpi_type_sz_); + /* The displacements are already built into the indexed type, rtype, received */ + rearr_alltoall_info_.rdispls.push_back(0); + rearr_alltoall_info_.rtypes.push_back(rtype); + } + else{ + rearr_alltoall_info_.rcounts.push_back(0); + rearr_alltoall_info_.rdispls.push_back(0); + rearr_alltoall_info_.rtypes.push_back(MPI_DATATYPE_NULL); + } + } + + return ret; +} + +int SPIO::DataRearr::Contig_rearr::rearrange_data(const void *sbuf, std::size_t sbuf_sz, + void *rbuf, std::size_t rbuf_sz, int nvars, bool agg2rearr) +{ + int ret = PIO_NOERR; + assert(is_init_); + + assert(ios_); + if(!ios_->ioproc){ + return PIO_NOERR; + } + + /* Rearrange read/aggregated data between aggregating/IO processes */ + //MPI_Datatype agg_stype = agg_gs_info_.stype; + //std::vector agg_rtypes_nvars; + std::vector rearr_stypes_nvars, rearr_rtypes_nvars; + + /* FIXME: We need a better way to find this info out */ + std::size_t agg_data_nelems = agg_compmap_sorter_.size(); + //assert(abuf_sz == nvars * agg_data_nelems * elem_mpi_type_sz_); + + if(nvars > 1){ + /* We are rearranging a block of variables */ + /* The stride between each block - data for each variable + * Aggregate procs to rearr procs (write) : + * Each proc sends aggregated data (aggregated from compute processes) and receives + * the contig block of data to write + * Rearr procs to aggregate procs (read) : + * Each proc sends the contig block of data read and each proc receives the aggregated + * block of data that needs to be dispersed to compute processes + */ + MPI_Aint sstride_between_vars = 0, rstride_between_vars = 0; + MPI_Aint stride_between_agg_vars = 0, stride_between_rearr_vars = 0; + + stride_between_agg_vars = agg_data_nelems * elem_mpi_type_sz_; + std::pair map_range = get_rearr_decomp_map_range(rearr_comm_rank_); + stride_between_rearr_vars = + static_cast( (map_range.second - map_range.first) * elem_mpi_type_sz_); + if(agg2rearr){ + /* Rearranging from aggregating procs to rearr procs - data write - comp2io path */ + sstride_between_vars = stride_between_agg_vars; + rstride_between_vars = stride_between_rearr_vars; + } + else{ + /* Rearranging from rearr procs to aggregating procs - data read - io2comp path */ + sstride_between_vars = stride_between_rearr_vars; + rstride_between_vars = stride_between_agg_vars; + } + + rearr_stypes_nvars.reserve(rearr_comm_sz_); + rearr_rtypes_nvars.reserve(rearr_comm_sz_); + assert(rearr_alltoall_info_.stypes.size() == rearr_comm_sz_); + assert(rearr_alltoall_info_.rtypes.size() == rearr_comm_sz_); + for(std::size_t i = 0; i < rearr_comm_sz_; i++){ + MPI_Datatype rearr_stype = MPI_DATATYPE_NULL; + MPI_Datatype rearr_rtype = MPI_DATATYPE_NULL; + /* Send type for block of vars */ + if((agg2rearr && (rearr_alltoall_info_.stypes[i] != MPI_DATATYPE_NULL)) || (!agg2rearr && (rearr_alltoall_info_.rtypes[i] != MPI_DATATYPE_NULL))){ + ret = MPI_Type_hvector(nvars, 1, sstride_between_vars, + (agg2rearr) ? rearr_alltoall_info_.stypes[i] : rearr_alltoall_info_.rtypes[i], &rearr_stype); + if(ret == MPI_SUCCESS){ + ret = MPI_Type_commit(&rearr_stype); + } + if(ret != MPI_SUCCESS){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while rearranging data from aggregating processes to IO processes (PIO_REARR_CONTIG). Unable to create vector types to send data for data aggregation (iosysid = %d, nvars = %d)", ios_->iosysid, nvars); + } + } + /* Recv type for block of vars */ + if((agg2rearr && (rearr_alltoall_info_.rtypes[i] != MPI_DATATYPE_NULL)) || (!agg2rearr && (rearr_alltoall_info_.stypes[i] != MPI_DATATYPE_NULL))){ + ret = MPI_Type_hvector(nvars, 1, rstride_between_vars, + (agg2rearr) ? rearr_alltoall_info_.rtypes[i] : rearr_alltoall_info_.stypes[i], &rearr_rtype); + if(ret == MPI_SUCCESS){ + ret = MPI_Type_commit(&rearr_rtype); + } + if(ret != MPI_SUCCESS){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while rearranging data from aggregating processes to IO processes (PIO_REARR_CONTIG). Unable to create vector types to receive data for data aggregation (iosysid = %d, nvars = %d)", ios_->iosysid, nvars); + } + } + rearr_stypes_nvars.push_back(rearr_stype); + rearr_rtypes_nvars.push_back(rearr_rtype); + } + } + + ret = SPIO_Util::Rearr_Util::alltoallw( + sbuf, + (agg2rearr) ? rearr_alltoall_info_.scounts.data() : rearr_alltoall_info_.rcounts.data(), + (agg2rearr) ? rearr_alltoall_info_.sdispls.data() : rearr_alltoall_info_.rdispls.data(), + (nvars > 1) ? rearr_stypes_nvars.data() : ((agg2rearr) ? rearr_alltoall_info_.stypes.data() : rearr_alltoall_info_.rtypes.data()), + rbuf, + (agg2rearr) ? rearr_alltoall_info_.rcounts.data() : rearr_alltoall_info_.scounts.data(), + (agg2rearr) ? rearr_alltoall_info_.rdispls.data() : rearr_alltoall_info_.sdispls.data(), + (nvars > 1) ? rearr_rtypes_nvars.data() : ((agg2rearr) ? rearr_alltoall_info_.rtypes.data() : rearr_alltoall_info_.stypes.data()), + rearr_comm_, + (agg2rearr) ? &(ios_->rearr_opts.comp2io) : &(ios_->rearr_opts.io2comp)); + if(ret != MPI_SUCCESS){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while aggregating data from compute processes to aggregating processes (PIO_REARR_CONTIG). Unable to gather data during data aggregation (iosysid = %d)", ios_->iosysid); + } + + for(std::size_t i = 0; i < rearr_stypes_nvars.size(); i++){ + if(rearr_stypes_nvars[i] != MPI_DATATYPE_NULL){ + MPI_Type_free(&(rearr_stypes_nvars[i])); + } + } + + for(std::size_t i = 0; i < rearr_rtypes_nvars.size(); i++){ + if(rearr_rtypes_nvars[i] != MPI_DATATYPE_NULL){ + MPI_Type_free(&(rearr_rtypes_nvars[i])); + } + } + + return ret; +} diff --git a/src/clib/pio_rearr_contig.hpp b/src/clib/pio_rearr_contig.hpp new file mode 100644 index 0000000000..2266f1fe07 --- /dev/null +++ b/src/clib/pio_rearr_contig.hpp @@ -0,0 +1,152 @@ +#ifndef __PIO_REARR_CONTIG_HPP__ +#define __PIO_REARR_CONTIG_HPP__ + +#include "pio_config.h" +#include "pio.h" +#include "pio_internal.h" +#include "pio_types.hpp" + +#include +#include +#include + +namespace SPIO{ + namespace DataRearr{ + struct Alltoall_info{ + std::vector scounts; + std::vector sdispls; + std::vector stypes; + + std::vector rcounts; + std::vector rdispls; + std::vector rtypes; + }; + + /* The stype is used by sending/compute processes during data aggregation to the + * aggregating/IO process, + * i.e., when writing data - gathering phase + * The stype is used by receiving/compute processes during data dispersion from the + * aggregating/IO process, + * i.e., when reading data - scatter phase + * Since different - counts/types - amount of data is received from each compute process + * the aggregating process has a receive type for each compute process - rtypes[i] for + * rank i in the aggregating comm + * The rtypes[] is used in the aggregating/IO process for aggregating/gathering data + * from compute processes during data aggregation - gathering phase + * i.e., when writing data + * The rtypes[] is used in the aggregating/IO process for dispersing/scattering data + * to compute processes during data dispersion - scatter phase + * i.e., when reading data + */ + struct GatherScatter_info{ + MPI_Datatype stype; + std::vector rcounts; + std::vector rtypes; + }; + + /* This rearranger, rearranges data from compute processes to I/O processes in two + * phases/steps, + * Phase 1 : Data aggregation (from compute processes to aggregating/IO processes) + * Phase 2 : Data rearrangement (between aggregating/IO processes) + * + * The rearranged data is a contiguous block of data (one block/range of data per I/O + * process) and can be written out to the file system. + * Note: Data caching is done outside the rearranger. The rearranger is passed in + * data (cached data) from multiple variables for data rearrangement. + */ + class Contig_rearr{ + public: + Contig_rearr(iosystem_desc_t *ios):is_init_(false), ios_(ios), iodesc_(NULL), + lcompmap_sz_(0), elem_pio_type_(PIO_NAT), elem_mpi_type_(MPI_DATATYPE_NULL), + elem_mpi_type_sz_(0), agg_comm_(MPI_COMM_NULL), is_agg_root_(false), + agg_comm_sz_(0), rearr_comm_(MPI_COMM_NULL), rearr_comm_sz_(0), + rearr_comm_iochunk_sz_(0){} + int init(int pio_type, const PIO_Offset *compmap, std::size_t compmap_sz, + const int *gdimlen, int ndims, io_desc_t *iodesc); + int rearrange_comp2io(const void *sbuf, std::size_t sbuf_sz, + void *rbuf, std::size_t rbuf_sz, int nvars); + int rearrange_io2comp(const void *sbuf, std::size_t sbuf_sz, + void *rbuf, std::size_t rbuf_sz, int nvars); + int finalize(void ); + private: + bool is_init_; + iosystem_desc_t *ios_; + io_desc_t *iodesc_; + + /* The size of the compmap local to this process */ + PIO_Offset lcompmap_sz_; + /* The global size represented by this I/O decomposition. This is the same as the + * global size of the variable that is written out using this I/O decomposition + * Note: This can be different from the global decomp map size since the map may + * not represent all elements of a variable/array + */ + PIO_Offset gdecomp_sz_; + + int elem_pio_type_; + int elem_mpi_type_; + int elem_mpi_type_sz_; + + /* Gather scatter info for data aggregation */ + MPI_Comm agg_comm_; + bool is_agg_root_; + int agg_comm_sz_; + std::vector agg_compmap_sorter_; + /* The byte displacements for each process, that is part of agg_comm_, in the aggregated data */ + std::vector agg_data_byte_displs_; + GatherScatter_info agg_gs_info_; + + /* All to all info for data rearrangement */ + MPI_Comm rearr_comm_; + int rearr_comm_rank_; + int rearr_comm_sz_; + PIO_Offset rearr_comm_iochunk_sz_; + Alltoall_info rearr_alltoall_info_; + + int create_agg_comm(void ); + int aggregate_compmap(const PIO_Offset *lcompmap, std::size_t lcompmap_sz, + std::vector &gcompmap, + std::vector &gcompmap_counts, + std::vector &gcompmap_displs); + int setup_data_agg_info(const PIO_Offset *lcompmap, std::size_t lcompmap_sz, + const std::vector &gcompmap, + const std::vector &gcompmap_counts, + const std::vector &gcompmap_displs, + const std::vector &to_proc); + int init_agg_recv_types(const std::vector &gcompmap_counts, + const std::vector &compmap_sorter); + int aggregate_data(const void *sbuf, std::size_t sbuf_sz, + void *abuf, std::size_t abuf_sz, int nvars); + int disperse_data(const void *abuf, std::size_t abuf_sz, + void *rbuf, std::size_t rbuf_sz, int nvars); + + int create_rearr_comm(void ); + std::pair get_rearr_decomp_map_range(int iorank) + { + assert(gdecomp_sz_ > 0); + assert(rearr_comm_iochunk_sz_ > 0); + + PIO_Offset iochunk = rearr_comm_iochunk_sz_; + PIO_Offset start = iorank * iochunk; + PIO_Offset end = start + iochunk; + if(iorank == (rearr_comm_sz_ - 1)){ + end = gdecomp_sz_; + } + return std::make_pair(start, end); + } + + int get_rearr_toproc_map(const std::vector &gcompmap, + std::vector &to_proc); + int setup_data_rearr_info(std::vector &gcompmap, std::vector &to_proc, + const int *gdimlen, int ndims); + int init_rearr_send_types(const std::vector &nregion_infos_sent, + const std::vector &displs_counts_sent); + int init_rearr_recvd_types(const std::vector &nregion_infos_recvd, + const std::vector &displs_counts_recvd); + int rearrange_data(const void *sbuf, std::size_t sbuf_sz, + void *rbuf, std::size_t rbuf_sz, int nvars, bool agg2rearr); + + }; + } // namespace DataRearr + +} // namespace SPIO +#endif // __PIO_REARR_CONTIG_HPP__ From b05a68eeecdb9883e884245a72c41d588732bc92 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 18 Nov 2024 11:28:24 -0600 Subject: [PATCH 011/194] Build/export PIO_REARR_CONTIG rearranger Including PIO_REARR_CONTIG rearranger in the C and Fortran libraries --- src/clib/CMakeLists.txt | 3 ++- src/clib/pio.h | 5 ++++- src/flib/pio.F90 | 3 ++- src/flib/pio_types.F90 | 1 + 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/clib/CMakeLists.txt b/src/clib/CMakeLists.txt index 39e38330b6..38d4100b5d 100644 --- a/src/clib/CMakeLists.txt +++ b/src/clib/CMakeLists.txt @@ -38,7 +38,8 @@ set (pio_api_src set (pio_lib_src topology.cpp pio_mpi_timer.cpp pio_timer.cpp pio_file.cpp pioc_support.cpp pio_lists.cpp pio_print.cpp - pioc.cpp pioc_sc.cpp pio_spmd.cpp pio_rearrange.cpp pio_nc4.cpp bget.cpp + pioc.cpp pioc_sc.cpp pio_spmd.cpp pio_rearrange.cpp pio_rearr_utils.cpp pio_rearr_contig.cpp + pio_nc4.cpp bget.cpp pio_nc.cpp pio_put_nc.cpp pio_get_nc.cpp pio_getput_int.cpp pio_msg.cpp pio_varm.cpp pio_darray.cpp pio_darray_int.cpp spio_hash.cpp pio_sdecomps_regex.cpp spio_io_summary.cpp spio_ltimer.cpp spio_serializer.cpp spio_file_mvcache.cpp diff --git a/src/clib/pio.h b/src/clib/pio.h index dcf68adf3a..44f97b68cf 100644 --- a/src/clib/pio.h +++ b/src/clib/pio.h @@ -449,7 +449,10 @@ enum PIO_REARRANGERS PIO_REARR_SUBSET = 2, /** Let the library choose the rearranger. */ - PIO_REARR_ANY = 3 + PIO_REARR_ANY = 3, + + /** Contig rearranger (data aggregation + contiguous data) */ + PIO_REARR_CONTIG = 4, }; /** diff --git a/src/flib/pio.F90 b/src/flib/pio.F90 index 85d2b3a8a1..a05ab50297 100644 --- a/src/flib/pio.F90 +++ b/src/flib/pio.F90 @@ -31,7 +31,8 @@ module pio pio_iotype_pnetcdf, pio_iotype_netcdf, pio_iotype_adios, pio_iotype_adiosc, & pio_iotype_hdf5, pio_iotype_hdf5c, & pio_global, pio_char, pio_write, pio_nowrite, pio_clobber, pio_noclobber, & - pio_max_name, pio_max_var_dims, pio_rearr_subset, pio_rearr_box, pio_rearr_any,& + pio_max_name, pio_max_var_dims,& + pio_rearr_subset, pio_rearr_box, pio_rearr_any, pio_rearr_contig,& #if defined(_NETCDF) || defined(_PNETCDF) pio_fill, pio_nofill, pio_unlimited, pio_fill_char, pio_fill_int, pio_fill_double, pio_fill_float, & #endif diff --git a/src/flib/pio_types.F90 b/src/flib/pio_types.F90 index 499f453eb6..c8bfe05b04 100644 --- a/src/flib/pio_types.F90 +++ b/src/flib/pio_types.F90 @@ -155,6 +155,7 @@ module pio_types integer(i4), public, parameter :: PIO_rearr_box = 1 integer(i4), public, parameter :: PIO_rearr_subset = 2 integer(i4), public, parameter :: PIO_rearr_any = 3 + integer(i4), public, parameter :: PIO_rearr_contig = 4 !> !! @public From a0c92f0ca4ee485b41db0dfe3ab2a6102567e45b Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 18 Nov 2024 11:31:06 -0600 Subject: [PATCH 012/194] Adding tests for PIO_REARR_CONTIG and coll utils Adding unit tests for the new rearranger, PIO_REARR_CONTIG, and the new utils added for gather/scatter/alltoall --- tests/cunit/CMakeLists.txt | 42 +- tests/cunit/test_spio_rearr_contig.cpp | 679 ++++++++++++++++++ tests/cunit/test_spio_rearr_contig_nvars.cpp | 671 +++++++++++++++++ .../cunit/test_spio_rearr_utils_alltoall.cpp | 453 ++++++++++++ tests/cunit/test_spio_rearr_utils_gather.cpp | 468 ++++++++++++ tests/cunit/test_spio_rearr_utils_scatter.cpp | 457 ++++++++++++ 6 files changed, 2769 insertions(+), 1 deletion(-) create mode 100644 tests/cunit/test_spio_rearr_contig.cpp create mode 100644 tests/cunit/test_spio_rearr_contig_nvars.cpp create mode 100644 tests/cunit/test_spio_rearr_utils_alltoall.cpp create mode 100644 tests/cunit/test_spio_rearr_utils_gather.cpp create mode 100644 tests/cunit/test_spio_rearr_utils_scatter.cpp diff --git a/tests/cunit/CMakeLists.txt b/tests/cunit/CMakeLists.txt index 80c370b1a2..79520522d1 100644 --- a/tests/cunit/CMakeLists.txt +++ b/tests/cunit/CMakeLists.txt @@ -104,10 +104,18 @@ add_spio_executable (test_spio_ltimer TRUE "" test_spio_ltimer.cpp) add_spio_executable (test_spio_serializer TRUE "" test_spio_serializer.cpp) add_spio_executable (test_spio_tree TRUE "" test_spio_tree.cpp) add_spio_executable (test_spio_file_mvcache TRUE "" test_spio_file_mvcache.cpp) +add_spio_executable (test_spio_rearr_utils_gather TRUE "" test_spio_rearr_utils_gather.cpp) +add_spio_executable (test_spio_rearr_utils_scatter TRUE "" test_spio_rearr_utils_scatter.cpp) +add_spio_executable (test_spio_rearr_utils_alltoall TRUE "" test_spio_rearr_utils_alltoall.cpp) +add_spio_executable (test_spio_rearr_contig TRUE "" test_spio_rearr_contig.cpp) +add_spio_executable (test_spio_rearr_contig_nvars TRUE "" test_spio_rearr_contig_nvars.cpp) add_spio_executable (test_sdecomp_regex TRUE "" test_sdecomp_regex.cpp test_common.cpp) add_spio_executable(test_req_block_wait TRUE "" test_req_block_wait.cpp test_common.cpp) add_dependencies (tests test_spmd test_spio_ltimer test_spio_serializer test_spio_tree - test_spio_file_mvcache test_sdecomp_regex test_req_block_wait) + test_spio_file_mvcache test_spio_rearr_utils_gather + test_spio_rearr_utils_scatter test_spio_rearr_utils_alltoall + test_spio_rearr_contig test_spio_rearr_contig_nvars + test_sdecomp_regex test_req_block_wait) if(PIO_USE_ASYNC_WR_THREAD) add_spio_executable (test_mtq TRUE "" test_async_mtq.cpp test_common.cpp) @@ -116,6 +124,8 @@ if(PIO_USE_ASYNC_WR_THREAD) add_dependencies(tests test_mtq test_mtq_signal test_mtq_pool) endif() +set (SPIO_TEST_MAX_NPROCS 4) + # Test Timeout in seconds. if (PIO_VALGRIND_CHECK) set (DEFAULT_TEST_TIMEOUT 480) @@ -162,6 +172,36 @@ else () EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/test_req_block_wait NUMPROCS 4 TIMEOUT ${DEFAULT_TEST_TIMEOUT}) + foreach(nproc RANGE 1 ${SPIO_TEST_MAX_NPROCS}) + add_mpi_test(test_spio_rearr_utils_gather${nproc} + EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/test_spio_rearr_utils_gather + NUMPROCS ${nproc} + TIMEOUT ${DEFAULT_TEST_TIMEOUT}) + endforeach() + foreach(nproc RANGE 1 ${SPIO_TEST_MAX_NPROCS}) + add_mpi_test(test_spio_rearr_utils_scatter${nproc} + EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/test_spio_rearr_utils_scatter + NUMPROCS ${nproc} + TIMEOUT ${DEFAULT_TEST_TIMEOUT}) + endforeach() + foreach(nproc RANGE 1 ${SPIO_TEST_MAX_NPROCS}) + add_mpi_test(test_spio_rearr_utils_alltoall${nproc} + EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/test_spio_rearr_utils_alltoall + NUMPROCS ${nproc} + TIMEOUT ${DEFAULT_TEST_TIMEOUT}) + endforeach() + foreach(nproc RANGE 1 ${SPIO_TEST_MAX_NPROCS}) + add_mpi_test(test_spio_rearr_contig${nproc} + EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/test_spio_rearr_contig + NUMPROCS ${nproc} + TIMEOUT ${DEFAULT_TEST_TIMEOUT}) + endforeach() + foreach(nproc RANGE 1 ${SPIO_TEST_MAX_NPROCS}) + add_mpi_test(test_spio_rearr_contig_nvars${nproc} + EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/test_spio_rearr_contig_nvars + NUMPROCS ${nproc} + TIMEOUT ${DEFAULT_TEST_TIMEOUT}) + endforeach() add_mpi_test(test_spmd EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/test_spmd NUMPROCS ${AT_LEAST_FOUR_TASKS} diff --git a/tests/cunit/test_spio_rearr_contig.cpp b/tests/cunit/test_spio_rearr_contig.cpp new file mode 100644 index 0000000000..8c914ebdd5 --- /dev/null +++ b/tests/cunit/test_spio_rearr_contig.cpp @@ -0,0 +1,679 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pio_config.h" +#include "pio.h" +#include "pio_tests.h" +#include "pio_rearr_contig.hpp" + +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL +#include "gptl.h" +#endif +#endif + +#define LOG_RANK0(rank, ...) \ + do{ \ + if(rank == 0){ \ + fprintf(stderr, __VA_ARGS__); \ + } \ + }while(0); + +static const int FAIL = -1; + +template +bool cmp_result(int wrank, const std::vector &res, const std::vector &exp) +{ + + if(res.size() != exp.size()){ + LOG_RANK0(wrank, "ERROR: The result and expected vectors are of different sizes\n"); + return false; + } + + for(std::size_t i = 0; i < res.size(); i++){ + if(res[i] != exp[i]){ + std::ostringstream oss; + oss << "ERROR: Invalid/Unexpected value, array[ " << i << "] = " << res[i] + << " (Expected array[" << i << "] = " << exp[i] << ")"; + LOG_RANK0(wrank, "ERROR: %s\n", oss.str().c_str()); + return false; + } + } + + return true; +} + +iosystem_desc_t *get_iosystem(MPI_Comm comm, int wrank, int wsz, int nio_procs) +{ + int ret = PIO_NOERR; + static int iosysid = 1; + iosystem_desc_t *ios = (iosystem_desc_t *) calloc(1, sizeof(iosystem_desc_t)); + if(!ios){ + LOG_RANK0(wrank, "Unable to allocate memory for I/O system"); + return NULL; + } + + ios->iosysid = iosysid++; + ios->union_comm = comm; + ios->num_uniontasks = wsz; + ios->union_rank = wrank; + /* Every proc is a compute proc */ + ios->comp_comm = comm; + ios->num_comptasks = wsz; + ios->comp_rank = wrank; + ios->compproc = true; + + assert(nio_procs <= wsz); + + /* Assign first nio_procs procs as I/O processes */ + int color = (wrank/nio_procs == 0) ? 0 : 1; + + ret = MPI_Comm_split(comm, color, 0, &(ios->io_comm)); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "Unable to split comm for creating I/O system"); + free(ios); + return NULL; + } + + ios->num_iotasks = nio_procs; + ios->ioproc = (color == 0) ? true : false; + if(ios->ioproc){ + ret = MPI_Comm_rank(ios->io_comm, &(ios->io_rank)); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "Unable to get rank of I/O process"); + free(ios); + return NULL; + } + } + else{ + ios->io_rank = -1; + } + + return ios; +} + +void free_iosystem(iosystem_desc_t *ios){ + if(!ios){ + return; + } + + MPI_Comm_free(&(ios->io_comm)); + free(ios); +} + +int test_create_block_rearr(MPI_Comm comm, int wrank, int wsz) +{ + int ret = PIO_NOERR; + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; + iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + if(!ios){ + LOG_RANK0(wrank, "Unable to get I/O system"); + return PIO_EINTERNAL; + } + + try{ + SPIO::DataRearr::Contig_rearr rearr(ios); + const int LOCAL_COMPMAP_SZ = 4; + int gdimlen = LOCAL_COMPMAP_SZ * wsz; + std::vector compmap(LOCAL_COMPMAP_SZ); + + std::iota(compmap.begin(), compmap.end(), wrank * LOCAL_COMPMAP_SZ); + ret = rearr.init(PIO_DOUBLE, compmap.data(), compmap.size(), &gdimlen, 1, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Initializing contig rearranger failed"); + return PIO_EINTERNAL; + } + + ret = rearr.finalize(); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Finalizing contig rearranger failed"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Creating contig rearranger failed"); + return PIO_EINTERNAL; + } + + free_iosystem(ios); + return PIO_NOERR; +} + +int test_c2i_block_data_rearr(MPI_Comm comm, int wrank, int wsz) +{ + int ret = PIO_NOERR; + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; + iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + if(!ios){ + LOG_RANK0(wrank, "Unable to get I/O system"); + return PIO_EINTERNAL; + } + + try{ + SPIO::DataRearr::Contig_rearr rearr(ios); + const int LOCAL_COMPMAP_SZ = 4; + int gdimlen = LOCAL_COMPMAP_SZ * wsz; + std::vector compmap(LOCAL_COMPMAP_SZ); + std::vector sdata(compmap.size()); + + std::vector rdata, exp_data; + + if(ios->ioproc){ + std::size_t rearr_iochunk_sz = gdimlen/nio_procs; + std::size_t rdata_sz = (ios->io_rank != (nio_procs - 1)) ? rearr_iochunk_sz : (gdimlen - (ios->io_rank * rearr_iochunk_sz)); + + rdata.resize(rdata_sz); + std::fill(rdata.begin(), rdata.end(), PIO_FILL_DOUBLE); + + exp_data.resize(rdata_sz); + std::iota(exp_data.begin(), exp_data.end(), ios->io_rank * rearr_iochunk_sz); + } + + std::iota(compmap.begin(), compmap.end(), wrank * LOCAL_COMPMAP_SZ); + std::transform(compmap.cbegin(), compmap.cend(), sdata.begin(), + [](const PIO_Offset i){ return static_cast(i); }); + ret = rearr.init(PIO_DOUBLE, compmap.data(), compmap.size(), &gdimlen, 1, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Initializing contig rearranger failed"); + return PIO_EINTERNAL; + } + ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), + rdata.data(), rdata.size() * sizeof(double), 1); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement\n"); + return PIO_EINTERNAL; + } + + ret = rearr.finalize(); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Finalizing contig rearranger failed"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + free_iosystem(ios); + return PIO_NOERR; +} + +int test_block_data_rearr(MPI_Comm comm, int wrank, int wsz) +{ + int ret = PIO_NOERR; + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; + iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + if(!ios){ + LOG_RANK0(wrank, "Unable to get I/O system"); + return PIO_EINTERNAL; + } + + try{ + SPIO::DataRearr::Contig_rearr rearr(ios); + const int LOCAL_COMPMAP_SZ = 4; + int gdimlen = LOCAL_COMPMAP_SZ * wsz; + std::vector compmap(LOCAL_COMPMAP_SZ); + std::vector sdata(compmap.size()); + + std::vector rdata, exp_data; + + if(ios->ioproc){ + std::size_t rearr_iochunk_sz = gdimlen/nio_procs; + std::size_t rdata_sz = (ios->io_rank != (nio_procs - 1)) ? rearr_iochunk_sz : (gdimlen - (ios->io_rank * rearr_iochunk_sz)); + + rdata.resize(rdata_sz); + std::fill(rdata.begin(), rdata.end(), PIO_FILL_DOUBLE); + + exp_data.resize(rdata_sz); + std::iota(exp_data.begin(), exp_data.end(), ios->io_rank * rearr_iochunk_sz); + } + + std::iota(compmap.begin(), compmap.end(), wrank * LOCAL_COMPMAP_SZ); + std::transform(compmap.cbegin(), compmap.cend(), sdata.begin(), + [](const PIO_Offset i){ return static_cast(i); }); + ret = rearr.init(PIO_DOUBLE, compmap.data(), compmap.size(), &gdimlen, 1, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Initializing contig rearranger failed"); + return PIO_EINTERNAL; + } + + /* Rearrange data from compute processes to I/O processes */ + ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), + rdata.data(), rdata.size() * sizeof(double), 1); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement (compute to I/O procs)\n"); + return PIO_EINTERNAL; + } + + /* Rearrange data from I/O processes to compute processes */ + exp_data.resize(LOCAL_COMPMAP_SZ); + assert(exp_data.size() == sdata.size()); + std::copy(sdata.begin(), sdata.end(), exp_data.begin()); + std::fill(sdata.begin(), sdata.end(), PIO_FILL_DOUBLE); + + ret = rearr.rearrange_io2comp(rdata.data(), rdata.size() * sizeof(double), + sdata.data(), sdata.size() * sizeof(double), 1); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, sdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement (I/O to compute procs)\n"); + return PIO_EINTERNAL; + } + + ret = rearr.finalize(); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Finalizing contig rearranger failed"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + free_iosystem(ios); + return PIO_NOERR; +} + +int test_rev_block_data_rearr(MPI_Comm comm, int wrank, int wsz) +{ + int ret = PIO_NOERR; + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; + iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + if(!ios){ + LOG_RANK0(wrank, "Unable to get I/O system"); + return PIO_EINTERNAL; + } + + try{ + SPIO::DataRearr::Contig_rearr rearr(ios); + const int LOCAL_COMPMAP_SZ = 4; + int gdimlen = LOCAL_COMPMAP_SZ * wsz; + std::vector compmap(LOCAL_COMPMAP_SZ); + std::vector sdata(compmap.size()); + + std::vector rdata, exp_data; + + if(ios->ioproc){ + std::size_t rearr_iochunk_sz = gdimlen/nio_procs; + std::size_t rdata_sz = (ios->io_rank != (nio_procs - 1)) ? rearr_iochunk_sz : (gdimlen - (ios->io_rank * rearr_iochunk_sz)); + + rdata.resize(rdata_sz); + std::fill(rdata.begin(), rdata.end(), PIO_FILL_DOUBLE); + + exp_data.resize(rdata_sz); + std::iota(exp_data.begin(), exp_data.end(), ios->io_rank * rearr_iochunk_sz); + } + + //std::iota(compmap.begin(), compmap.end(), wrank * LOCAL_COMPMAP_SZ); + PIO_Offset compmap_val = wrank * LOCAL_COMPMAP_SZ; + std::generate(compmap.begin(), compmap.end(), + [&compmap_val, gdimlen]() mutable { return gdimlen - 1 - compmap_val++; }); + std::transform(compmap.cbegin(), compmap.cend(), sdata.begin(), + [](const PIO_Offset i){ return static_cast(i); }); + ret = rearr.init(PIO_DOUBLE, compmap.data(), compmap.size(), &gdimlen, 1, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Initializing contig rearranger failed"); + return PIO_EINTERNAL; + } + ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), + rdata.data(), rdata.size() * sizeof(double), 1); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement\n"); + return PIO_EINTERNAL; + } + + /* Rearrange data from I/O processes to compute processes */ + exp_data.resize(LOCAL_COMPMAP_SZ); + assert(exp_data.size() == sdata.size()); + std::copy(sdata.begin(), sdata.end(), exp_data.begin()); + std::fill(sdata.begin(), sdata.end(), PIO_FILL_DOUBLE); + + ret = rearr.rearrange_io2comp(rdata.data(), rdata.size() * sizeof(double), + sdata.data(), sdata.size() * sizeof(double), 1); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed (I/O to compute procs)"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, sdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement (I/O to compute procs)\n"); + return PIO_EINTERNAL; + } + + ret = rearr.finalize(); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Finalizing contig rearranger failed"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + free_iosystem(ios); + return PIO_NOERR; +} + +int test_mrange_block_data_rearr(MPI_Comm comm, int wrank, int wsz) +{ + int ret = PIO_NOERR; + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; + iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + if(!ios){ + LOG_RANK0(wrank, "Unable to get I/O system"); + return PIO_EINTERNAL; + } + + try{ + SPIO::DataRearr::Contig_rearr rearr(ios); + const int FIRST_RANGE_SZ = 3; + const int SECOND_RANGE_SZ = 1; + const int THIRD_RANGE_SZ = 2; + const int LOCAL_COMPMAP_SZ = FIRST_RANGE_SZ + SECOND_RANGE_SZ + THIRD_RANGE_SZ; + int gdimlen = LOCAL_COMPMAP_SZ * wsz; + std::vector compmap(LOCAL_COMPMAP_SZ); + std::vector sdata(compmap.size()); + + std::vector rdata, exp_data; + + if(ios->ioproc){ + std::size_t rearr_iochunk_sz = gdimlen/nio_procs; + std::size_t rdata_sz = (ios->io_rank != (nio_procs - 1)) ? rearr_iochunk_sz : (gdimlen - (ios->io_rank * rearr_iochunk_sz)); + + rdata.resize(rdata_sz); + std::fill(rdata.begin(), rdata.end(), PIO_FILL_DOUBLE); + + exp_data.resize(rdata_sz); + std::iota(exp_data.begin(), exp_data.end(), ios->io_rank * rearr_iochunk_sz); + } + + std::iota(compmap.begin(), compmap.begin() + FIRST_RANGE_SZ, wrank * FIRST_RANGE_SZ); + std::iota(compmap.begin() + FIRST_RANGE_SZ, compmap.begin() + FIRST_RANGE_SZ + SECOND_RANGE_SZ, wsz * FIRST_RANGE_SZ + wrank * SECOND_RANGE_SZ); + std::iota(compmap.begin() + FIRST_RANGE_SZ + SECOND_RANGE_SZ, compmap.end(), wsz * (FIRST_RANGE_SZ + SECOND_RANGE_SZ) + wrank * THIRD_RANGE_SZ); + std::transform(compmap.cbegin(), compmap.cend(), sdata.begin(), + [](const PIO_Offset i){ return static_cast(i); }); + ret = rearr.init(PIO_DOUBLE, compmap.data(), compmap.size(), &gdimlen, 1, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Initializing contig rearranger failed"); + return PIO_EINTERNAL; + } + ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), + rdata.data(), rdata.size() * sizeof(double), 1); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement\n"); + return PIO_EINTERNAL; + } + + /* Rearrange data from I/O processes to compute processes */ + exp_data.resize(LOCAL_COMPMAP_SZ); + assert(exp_data.size() == sdata.size()); + std::copy(sdata.begin(), sdata.end(), exp_data.begin()); + std::fill(sdata.begin(), sdata.end(), PIO_FILL_DOUBLE); + + ret = rearr.rearrange_io2comp(rdata.data(), rdata.size() * sizeof(double), + sdata.data(), sdata.size() * sizeof(double), 1); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed (I/O to compute procs)"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, sdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement (I/O to compute procs)\n"); + return PIO_EINTERNAL; + } + + ret = rearr.finalize(); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Finalizing contig rearranger failed"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + free_iosystem(ios); + return PIO_NOERR; +} + +int test_mrange_oddz_data_rearr(MPI_Comm comm, int wrank, int wsz) +{ + bool is_odd_proc = ((wrank % 2) != 0) ? true : false; + int nodd_procs = wsz/2; + int neven_procs = wsz - nodd_procs; + int ret = PIO_NOERR; + + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; + iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + if(!ios){ + LOG_RANK0(wrank, "Unable to get I/O system"); + return PIO_EINTERNAL; + } + + try{ + SPIO::DataRearr::Contig_rearr rearr(ios); + const int FIRST_RANGE_SZ = 3; + const int SECOND_RANGE_SZ = 1; + const int THIRD_RANGE_SZ = 2; + const int LOCAL_COMPMAP_SZ = FIRST_RANGE_SZ + SECOND_RANGE_SZ + THIRD_RANGE_SZ; + /* Only even procs have data */ + int gdimlen = LOCAL_COMPMAP_SZ * neven_procs; + std::vector compmap; + std::vector sdata; + + std::vector rdata, exp_data; + + if(ios->ioproc){ + std::size_t rearr_iochunk_sz = gdimlen/nio_procs; + std::size_t rdata_sz = (ios->io_rank != (nio_procs - 1)) ? rearr_iochunk_sz : (gdimlen - (ios->io_rank * rearr_iochunk_sz)); + + rdata.resize(rdata_sz); + std::fill(rdata.begin(), rdata.end(), PIO_FILL_DOUBLE); + + exp_data.resize(rdata_sz); + std::iota(exp_data.begin(), exp_data.end(), ios->io_rank * rearr_iochunk_sz); + } + + if(!is_odd_proc){ + compmap.resize(LOCAL_COMPMAP_SZ); + sdata.resize(compmap.size()); + + int neven_procs_before_wrank = wrank - (wrank / 2); + std::iota(compmap.begin(), compmap.begin() + FIRST_RANGE_SZ, neven_procs_before_wrank * FIRST_RANGE_SZ); + std::iota(compmap.begin() + FIRST_RANGE_SZ, compmap.begin() + FIRST_RANGE_SZ + SECOND_RANGE_SZ, neven_procs * FIRST_RANGE_SZ + neven_procs_before_wrank * SECOND_RANGE_SZ); + std::iota(compmap.begin() + FIRST_RANGE_SZ + SECOND_RANGE_SZ, compmap.end(), neven_procs * (FIRST_RANGE_SZ + SECOND_RANGE_SZ) + neven_procs_before_wrank * THIRD_RANGE_SZ); + std::transform(compmap.cbegin(), compmap.cend(), sdata.begin(), + [](const PIO_Offset i){ return static_cast(i); }); + } + + ret = rearr.init(PIO_DOUBLE, compmap.data(), compmap.size(), &gdimlen, 1, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Initializing contig rearranger failed"); + return PIO_EINTERNAL; + } + ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), + rdata.data(), rdata.size() * sizeof(double), 1); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement\n"); + return PIO_EINTERNAL; + } + + /* Rearrange data from I/O processes to compute processes */ + if(!is_odd_proc){ + exp_data.resize(LOCAL_COMPMAP_SZ); + } + else{ + exp_data.clear(); + } + + assert(exp_data.size() == sdata.size()); + std::copy(sdata.begin(), sdata.end(), exp_data.begin()); + std::fill(sdata.begin(), sdata.end(), PIO_FILL_DOUBLE); + + ret = rearr.rearrange_io2comp(rdata.data(), rdata.size() * sizeof(double), + sdata.data(), sdata.size() * sizeof(double), 1); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed (I/O to compute procs)"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, sdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement (I/O to compute procs)\n"); + return PIO_EINTERNAL; + } + + ret = rearr.finalize(); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Finalizing contig rearranger failed"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + free_iosystem(ios); + return PIO_NOERR; +} + +int test_driver(MPI_Comm comm, int wrank, int wsz, int *num_errors) +{ + int nerrs = 0, ret = PIO_NOERR, mpierr = MPI_SUCCESS; + assert((comm != MPI_COMM_NULL) && (wrank >= 0) && (wsz > 0) && num_errors); + + std::vector > > test_funcs = { + {"test_create_block_rearr", test_create_block_rearr}, + {"test_c2i_block_data_rearr", test_c2i_block_data_rearr}, + {"test_block_data_rearr", test_block_data_rearr}, + {"test_rev_block_data_rearr", test_rev_block_data_rearr}, + {"test_mrange_block_data_rearr", test_mrange_block_data_rearr}, + {"test_mrange_oddz_data_rearr", test_mrange_oddz_data_rearr} + }; + + for(std::size_t tid = 0; tid < test_funcs.size(); tid++){ + try{ + ret = test_funcs[tid].second(comm, wrank, wsz); + } + catch(...){ + ret = PIO_EINTERNAL; + nerrs++; + } + int lfail = (ret == PIO_NOERR) ? 0 : 1; + mpierr = MPI_Reduce(&ret, &lfail, 1, MPI_INT, MPI_SUM, 0, comm); + if(mpierr != MPI_SUCCESS){ + LOG_RANK0(wrank, "Test Driver failed: Unable to calculate total num errors\n"); + } + if(ret != 0){ + std::string non_root_fail_msg = std::string(", failed on ") + std::to_string(ret) + std::string(" non-root processes"); + LOG_RANK0(wrank, "%s() FAILED (ret = %d%s)\n", test_funcs[tid].first.c_str(), ret, (lfail) ? "" : non_root_fail_msg.c_str()); + nerrs++; + } + else{ + LOG_RANK0(wrank, "%s() PASSED\n", test_funcs[tid].first.c_str()); + } + } + + *num_errors += nerrs; + return nerrs; +} + +int main(int argc, char *argv[]) +{ + int ret; + int wrank, wsz; + int num_errors; +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL + ret = GPTLinitialize(); + if(ret != 0){ + LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + + ret = MPI_Init(&argc, &argv); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Init() FAILED, ret = %d\n", ret); + return ret; + } + + ret = MPI_Comm_rank(MPI_COMM_WORLD, &wrank); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); + return ret; + } + ret = MPI_Comm_size(MPI_COMM_WORLD, &wsz); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); + return ret; + } + + num_errors = 0; + ret = test_driver(MPI_COMM_WORLD, wrank, wsz, &num_errors); + if(ret != 0){ + LOG_RANK0(wrank, "Test driver FAILED\n"); + return FAIL; + } + else{ + LOG_RANK0(wrank, "All tests PASSED\n"); + } + + MPI_Finalize(); + +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL + ret = GPTLfinalize(); + if(ret != 0){ + LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + + if(num_errors != 0){ + LOG_RANK0(wrank, "Total errors = %d\n", num_errors); + return FAIL; + } + return 0; +} diff --git a/tests/cunit/test_spio_rearr_contig_nvars.cpp b/tests/cunit/test_spio_rearr_contig_nvars.cpp new file mode 100644 index 0000000000..2002b78dfb --- /dev/null +++ b/tests/cunit/test_spio_rearr_contig_nvars.cpp @@ -0,0 +1,671 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pio_config.h" +#include "pio.h" +#include "pio_tests.h" +#include "pio_rearr_contig.hpp" + +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL +#include "gptl.h" +#endif +#endif + +#define LOG_RANK0(rank, ...) \ + do{ \ + if(rank == 0){ \ + fprintf(stderr, __VA_ARGS__); \ + } \ + }while(0); + +static const int FAIL = -1; + +template +bool cmp_result(int wrank, const std::vector &res, const std::vector &exp) +{ + + if(res.size() != exp.size()){ + LOG_RANK0(wrank, "ERROR: The result and expected vectors are of different sizes\n"); + return false; + } + + for(std::size_t i = 0; i < res.size(); i++){ + if(res[i] != exp[i]){ + std::ostringstream oss; + oss << "ERROR: Invalid/Unexpected value, array[ " << i << "] = " << res[i] + << " (Expected array[" << i << "] = " << exp[i] << ")"; + LOG_RANK0(wrank, "ERROR: %s\n", oss.str().c_str()); + return false; + } + } + + return true; +} + +iosystem_desc_t *get_iosystem(MPI_Comm comm, int wrank, int wsz, int nio_procs) +{ + int ret = PIO_NOERR; + static int iosysid = 1; + iosystem_desc_t *ios = (iosystem_desc_t *) calloc(1, sizeof(iosystem_desc_t)); + if(!ios){ + LOG_RANK0(wrank, "Unable to allocate memory for I/O system"); + return NULL; + } + + ios->iosysid = iosysid++; + ios->union_comm = comm; + ios->num_uniontasks = wsz; + ios->union_rank = wrank; + /* Every proc is a compute proc */ + ios->comp_comm = comm; + ios->num_comptasks = wsz; + ios->comp_rank = wrank; + ios->compproc = true; + + assert(nio_procs <= wsz); + + /* Assign first nio_procs procs as I/O processes */ + int color = (wrank/nio_procs == 0) ? 0 : 1; + + ret = MPI_Comm_split(comm, color, 0, &(ios->io_comm)); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "Unable to split comm for creating I/O system"); + free(ios); + return NULL; + } + + ios->num_iotasks = nio_procs; + ios->ioproc = (color == 0) ? true : false; + if(ios->ioproc){ + ret = MPI_Comm_rank(ios->io_comm, &(ios->io_rank)); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "Unable to get rank of I/O process"); + free(ios); + return NULL; + } + } + else{ + ios->io_rank = -1; + } + + return ios; +} + +void free_iosystem(iosystem_desc_t *ios){ + if(!ios){ + return; + } + + MPI_Comm_free(&(ios->io_comm)); + free(ios); +} + +int test_c2i_block_data_rearr_nvars(MPI_Comm comm, int wrank, int wsz, int nvars) +{ + int ret = PIO_NOERR; + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; + iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + if(!ios){ + LOG_RANK0(wrank, "Unable to get I/O system"); + return PIO_EINTERNAL; + } + + try{ + SPIO::DataRearr::Contig_rearr rearr(ios); + const int LOCAL_COMPMAP_SZ = 4; + int gdimlen = LOCAL_COMPMAP_SZ * wsz; + std::vector compmap(LOCAL_COMPMAP_SZ); + std::vector sdata(compmap.size() * nvars); + + std::vector rdata, exp_data; + + if(ios->ioproc){ + std::size_t rearr_iochunk_sz = gdimlen/nio_procs; + std::size_t one_var_rdata_sz = (ios->io_rank != (nio_procs - 1)) ? rearr_iochunk_sz : (gdimlen - (ios->io_rank * rearr_iochunk_sz)); + std::size_t rdata_sz = one_var_rdata_sz * nvars; + + rdata.resize(rdata_sz); + std::fill(rdata.begin(), rdata.end(), PIO_FILL_DOUBLE); + + exp_data.resize(rdata_sz); + for(int i = 0; i < nvars; i++){ + std::iota(exp_data.begin() + i * one_var_rdata_sz, exp_data.begin() + (i + 1) * one_var_rdata_sz, ios->io_rank * rearr_iochunk_sz); + } + } + + std::iota(compmap.begin(), compmap.end(), wrank * LOCAL_COMPMAP_SZ); + + for(int i = 0; i < nvars; i++){ + std::transform(compmap.cbegin(), compmap.cend(), sdata.begin() + i * LOCAL_COMPMAP_SZ, + [](const PIO_Offset i){ return static_cast(i); }); + } + ret = rearr.init(PIO_DOUBLE, compmap.data(), compmap.size(), &gdimlen, 1, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Initializing contig rearranger failed"); + return PIO_EINTERNAL; + } + ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), + rdata.data(), rdata.size() * sizeof(double), nvars); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement\n"); + return PIO_EINTERNAL; + } + + ret = rearr.finalize(); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Finalizing contig rearranger failed"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + free_iosystem(ios); + return PIO_NOERR; +} + +int test_block_data_rearr_nvars(MPI_Comm comm, int wrank, int wsz, int nvars) +{ + int ret = PIO_NOERR; + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; + iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + if(!ios){ + LOG_RANK0(wrank, "Unable to get I/O system"); + return PIO_EINTERNAL; + } + + try{ + SPIO::DataRearr::Contig_rearr rearr(ios); + const int LOCAL_COMPMAP_SZ = 4; + int gdimlen = LOCAL_COMPMAP_SZ * wsz; + std::vector compmap(LOCAL_COMPMAP_SZ); + std::vector sdata(compmap.size() * nvars); + + std::vector rdata, exp_data; + + if(ios->ioproc){ + std::size_t rearr_iochunk_sz = gdimlen/nio_procs; + std::size_t one_var_rdata_sz = (ios->io_rank != (nio_procs - 1)) ? rearr_iochunk_sz : (gdimlen - (ios->io_rank * rearr_iochunk_sz)); + std::size_t rdata_sz = one_var_rdata_sz * nvars; + + rdata.resize(rdata_sz); + std::fill(rdata.begin(), rdata.end(), PIO_FILL_DOUBLE); + + exp_data.resize(rdata_sz); + for(int i = 0; i < nvars; i++){ + std::iota(exp_data.begin() + i * one_var_rdata_sz, exp_data.begin() + (i + 1) * one_var_rdata_sz, ios->io_rank * rearr_iochunk_sz); + } + } + + std::iota(compmap.begin(), compmap.end(), wrank * LOCAL_COMPMAP_SZ); + + for(int i = 0; i < nvars; i++){ + std::transform(compmap.cbegin(), compmap.cend(), sdata.begin() + i * LOCAL_COMPMAP_SZ, + [](const PIO_Offset i){ return static_cast(i); }); + } + ret = rearr.init(PIO_DOUBLE, compmap.data(), compmap.size(), &gdimlen, 1, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Initializing contig rearranger failed"); + return PIO_EINTERNAL; + } + ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), + rdata.data(), rdata.size() * sizeof(double), nvars); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement\n"); + return PIO_EINTERNAL; + } + + /* Rearrange data from I/O processes to compute processes */ + exp_data.resize(LOCAL_COMPMAP_SZ * nvars); + assert(exp_data.size() == sdata.size()); + std::copy(sdata.begin(), sdata.end(), exp_data.begin()); + std::fill(sdata.begin(), sdata.end(), PIO_FILL_DOUBLE); + + ret = rearr.rearrange_io2comp(rdata.data(), rdata.size() * sizeof(double), + sdata.data(), sdata.size() * sizeof(double), nvars); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, sdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement (I/O to compute procs)\n"); + return PIO_EINTERNAL; + } + + ret = rearr.finalize(); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Finalizing contig rearranger failed"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + free_iosystem(ios); + return PIO_NOERR; +} + +int test_rev_block_data_rearr_nvars(MPI_Comm comm, int wrank, int wsz, int nvars) +{ + int ret = PIO_NOERR; + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; + iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + if(!ios){ + LOG_RANK0(wrank, "Unable to get I/O system"); + return PIO_EINTERNAL; + } + + try{ + SPIO::DataRearr::Contig_rearr rearr(ios); + const int LOCAL_COMPMAP_SZ = 4; + int gdimlen = LOCAL_COMPMAP_SZ * wsz; + std::vector compmap(LOCAL_COMPMAP_SZ); + std::vector sdata(compmap.size() * nvars); + + std::vector rdata, exp_data; + + if(ios->ioproc){ + std::size_t rearr_iochunk_sz = gdimlen/nio_procs; + std::size_t one_var_rdata_sz = (ios->io_rank != (nio_procs - 1)) ? rearr_iochunk_sz : (gdimlen - (ios->io_rank * rearr_iochunk_sz)); + std::size_t rdata_sz = one_var_rdata_sz * nvars; + + rdata.resize(rdata_sz); + std::fill(rdata.begin(), rdata.end(), PIO_FILL_DOUBLE); + + exp_data.resize(rdata_sz); + for(int i = 0; i < nvars; i++){ + std::iota(exp_data.begin() + i * one_var_rdata_sz, exp_data.begin() + (i + 1) * one_var_rdata_sz, ios->io_rank * rearr_iochunk_sz); + } + } + + //std::iota(compmap.begin(), compmap.end(), wrank * LOCAL_COMPMAP_SZ); + PIO_Offset compmap_val = wrank * LOCAL_COMPMAP_SZ; + std::generate(compmap.begin(), compmap.end(), + [&compmap_val, gdimlen]() mutable { return gdimlen - 1 - compmap_val++; }); + + for(int i = 0; i < nvars; i++){ + std::transform(compmap.cbegin(), compmap.cend(), sdata.begin() + i * LOCAL_COMPMAP_SZ, + [](const PIO_Offset i){ return static_cast(i); }); + } + ret = rearr.init(PIO_DOUBLE, compmap.data(), compmap.size(), &gdimlen, 1, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Initializing contig rearranger failed"); + return PIO_EINTERNAL; + } + ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), + rdata.data(), rdata.size() * sizeof(double), nvars); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement\n"); + return PIO_EINTERNAL; + } + + /* Rearrange data from I/O processes to compute processes */ + exp_data.resize(LOCAL_COMPMAP_SZ * nvars); + assert(exp_data.size() == sdata.size()); + std::copy(sdata.begin(), sdata.end(), exp_data.begin()); + std::fill(sdata.begin(), sdata.end(), PIO_FILL_DOUBLE); + + ret = rearr.rearrange_io2comp(rdata.data(), rdata.size() * sizeof(double), + sdata.data(), sdata.size() * sizeof(double), nvars); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed (I/O to compute procs)"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, sdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement (I/O to compute procs)\n"); + return PIO_EINTERNAL; + } + + ret = rearr.finalize(); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Finalizing contig rearranger failed"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + free_iosystem(ios); + return PIO_NOERR; +} + +int test_mrange_block_data_rearr_nvars(MPI_Comm comm, int wrank, int wsz, int nvars) +{ + int ret = PIO_NOERR; + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; + iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + if(!ios){ + LOG_RANK0(wrank, "Unable to get I/O system"); + return PIO_EINTERNAL; + } + + try{ + SPIO::DataRearr::Contig_rearr rearr(ios); + const int FIRST_RANGE_SZ = 3; + const int SECOND_RANGE_SZ = 1; + const int THIRD_RANGE_SZ = 2; + const int LOCAL_COMPMAP_SZ = FIRST_RANGE_SZ + SECOND_RANGE_SZ + THIRD_RANGE_SZ; + int gdimlen = LOCAL_COMPMAP_SZ * wsz; + std::vector compmap(LOCAL_COMPMAP_SZ); + std::vector sdata(compmap.size() * nvars); + + std::vector rdata, exp_data; + + if(ios->ioproc){ + std::size_t rearr_iochunk_sz = gdimlen/nio_procs; + std::size_t one_var_rdata_sz = (ios->io_rank != (nio_procs - 1)) ? rearr_iochunk_sz : (gdimlen - (ios->io_rank * rearr_iochunk_sz)); + std::size_t rdata_sz = one_var_rdata_sz * nvars; + + rdata.resize(rdata_sz); + std::fill(rdata.begin(), rdata.end(), PIO_FILL_DOUBLE); + + exp_data.resize(rdata_sz); + for(int i = 0; i < nvars; i++){ + std::iota(exp_data.begin() + i * one_var_rdata_sz, exp_data.begin() + (i + 1) * one_var_rdata_sz, ios->io_rank * rearr_iochunk_sz); + } + } + + std::iota(compmap.begin(), compmap.begin() + FIRST_RANGE_SZ, wrank * FIRST_RANGE_SZ); + std::iota(compmap.begin() + FIRST_RANGE_SZ, compmap.begin() + FIRST_RANGE_SZ + SECOND_RANGE_SZ, wsz * FIRST_RANGE_SZ + wrank * SECOND_RANGE_SZ); + std::iota(compmap.begin() + FIRST_RANGE_SZ + SECOND_RANGE_SZ, compmap.end(), wsz * (FIRST_RANGE_SZ + SECOND_RANGE_SZ) + wrank * THIRD_RANGE_SZ); + + for(int i = 0; i < nvars; i++){ + std::transform(compmap.cbegin(), compmap.cend(), sdata.begin() + i * LOCAL_COMPMAP_SZ, + [](const PIO_Offset i){ return static_cast(i); }); + } + ret = rearr.init(PIO_DOUBLE, compmap.data(), compmap.size(), &gdimlen, 1, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Initializing contig rearranger failed"); + return PIO_EINTERNAL; + } + ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), + rdata.data(), rdata.size() * sizeof(double), nvars); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement\n"); + return PIO_EINTERNAL; + } + + /* Rearrange data from I/O processes to compute processes */ + exp_data.resize(LOCAL_COMPMAP_SZ * nvars); + assert(exp_data.size() == sdata.size()); + std::copy(sdata.begin(), sdata.end(), exp_data.begin()); + std::fill(sdata.begin(), sdata.end(), PIO_FILL_DOUBLE); + + ret = rearr.rearrange_io2comp(rdata.data(), rdata.size() * sizeof(double), + sdata.data(), sdata.size() * sizeof(double), nvars); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed (I/O to compute procs)"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, sdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement (I/O to compute procs)\n"); + return PIO_EINTERNAL; + } + + ret = rearr.finalize(); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Finalizing contig rearranger failed"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + free_iosystem(ios); + return PIO_NOERR; +} + +int test_mrange_oddz_data_rearr_nvars(MPI_Comm comm, int wrank, int wsz, int nvars) +{ + bool is_odd_proc = ((wrank % 2) != 0) ? true : false; + int nodd_procs = wsz/2; + int neven_procs = wsz - nodd_procs; + int ret = PIO_NOERR; + + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; + iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + if(!ios){ + LOG_RANK0(wrank, "Unable to get I/O system"); + return PIO_EINTERNAL; + } + + try{ + SPIO::DataRearr::Contig_rearr rearr(ios); + const int FIRST_RANGE_SZ = 3; + const int SECOND_RANGE_SZ = 1; + const int THIRD_RANGE_SZ = 2; + const int LOCAL_COMPMAP_SZ = FIRST_RANGE_SZ + SECOND_RANGE_SZ + THIRD_RANGE_SZ; + /* Only even procs have data */ + int gdimlen = LOCAL_COMPMAP_SZ * neven_procs; + std::vector compmap; + std::vector sdata; + + std::vector rdata, exp_data; + + if(ios->ioproc){ + std::size_t rearr_iochunk_sz = gdimlen/nio_procs; + std::size_t one_var_rdata_sz = (ios->io_rank != (nio_procs - 1)) ? rearr_iochunk_sz : (gdimlen - (ios->io_rank * rearr_iochunk_sz)); + std::size_t rdata_sz = one_var_rdata_sz * nvars; + + rdata.resize(rdata_sz); + std::fill(rdata.begin(), rdata.end(), PIO_FILL_DOUBLE); + + exp_data.resize(rdata_sz); + for(int i = 0; i < nvars; i++){ + std::iota(exp_data.begin() + i * one_var_rdata_sz, exp_data.begin() + (i + 1) * one_var_rdata_sz, ios->io_rank * rearr_iochunk_sz); + } + } + + if(!is_odd_proc){ + compmap.resize(LOCAL_COMPMAP_SZ); + sdata.resize(compmap.size() * nvars); + + int neven_procs_before_wrank = wrank - (wrank / 2); + std::iota(compmap.begin(), compmap.begin() + FIRST_RANGE_SZ, neven_procs_before_wrank * FIRST_RANGE_SZ); + std::iota(compmap.begin() + FIRST_RANGE_SZ, compmap.begin() + FIRST_RANGE_SZ + SECOND_RANGE_SZ, neven_procs * FIRST_RANGE_SZ + neven_procs_before_wrank * SECOND_RANGE_SZ); + std::iota(compmap.begin() + FIRST_RANGE_SZ + SECOND_RANGE_SZ, compmap.end(), neven_procs * (FIRST_RANGE_SZ + SECOND_RANGE_SZ) + neven_procs_before_wrank * THIRD_RANGE_SZ); + + for(int i = 0; i < nvars; i++){ + std::transform(compmap.cbegin(), compmap.cend(), sdata.begin() + i * LOCAL_COMPMAP_SZ, + [](const PIO_Offset i){ return static_cast(i); }); + } + } + + ret = rearr.init(PIO_DOUBLE, compmap.data(), compmap.size(), &gdimlen, 1, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Initializing contig rearranger failed"); + return PIO_EINTERNAL; + } + ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), + rdata.data(), rdata.size() * sizeof(double), nvars); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement\n"); + return PIO_EINTERNAL; + } + + /* Rearrange data from I/O processes to compute processes */ + if(!is_odd_proc){ + exp_data.resize(LOCAL_COMPMAP_SZ * nvars); + } + else{ + exp_data.clear(); + } + + assert(exp_data.size() == sdata.size()); + std::copy(sdata.begin(), sdata.end(), exp_data.begin()); + std::fill(sdata.begin(), sdata.end(), PIO_FILL_DOUBLE); + + ret = rearr.rearrange_io2comp(rdata.data(), rdata.size() * sizeof(double), + sdata.data(), sdata.size() * sizeof(double), nvars); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed (I/O to compute procs)"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, sdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement (I/O to compute procs)\n"); + return PIO_EINTERNAL; + } + + ret = rearr.finalize(); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Finalizing contig rearranger failed"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + free_iosystem(ios); + return PIO_NOERR; +} + +int test_driver(MPI_Comm comm, int wrank, int wsz, int *num_errors) +{ + int nerrs = 0, ret = PIO_NOERR, mpierr = MPI_SUCCESS; + assert((comm != MPI_COMM_NULL) && (wrank >= 0) && (wsz > 0) && num_errors); + + std::vector > > test_funcs = { + {"test_c2i_block_data_rearr_nvars", test_c2i_block_data_rearr_nvars}, + {"test_block_data_rearr_nvars", test_block_data_rearr_nvars}, + {"test_rev_block_data_rearr_nvars", test_rev_block_data_rearr_nvars}, + {"test_mrange_block_data_rearr_nvars", test_mrange_block_data_rearr_nvars}, + {"test_mrange_oddz_data_rearr_nvars", test_mrange_oddz_data_rearr_nvars} + }; + + const int MAX_NVARS = 6; + for(std::size_t tid = 0; tid < test_funcs.size(); tid++){ + for(int i = 1; i < MAX_NVARS; i++){ + try{ + ret = test_funcs[tid].second(comm, wrank, wsz, i); + } + catch(...){ + ret = PIO_EINTERNAL; + nerrs++; + } + int lfail = (ret == PIO_NOERR) ? 0 : 1; + mpierr = MPI_Reduce(&ret, &lfail, 1, MPI_INT, MPI_SUM, 0, comm); + if(mpierr != MPI_SUCCESS){ + LOG_RANK0(wrank, "Test Driver failed: Unable to calculate total num errors\n"); + } + if(ret != 0){ + std::string non_root_fail_msg = std::string(", failed on ") + std::to_string(ret) + std::string(" non-root processes"); + LOG_RANK0(wrank, "%s(nvars=%d) FAILED (ret = %d%s)\n", test_funcs[tid].first.c_str(), i, ret, (lfail) ? "" : non_root_fail_msg.c_str()); + nerrs++; + } + else{ + LOG_RANK0(wrank, "%s(nvars=%d) PASSED\n", test_funcs[tid].first.c_str(), i); + } + } + } + + *num_errors += nerrs; + return nerrs; +} + +int main(int argc, char *argv[]) +{ + int ret; + int wrank, wsz; + int num_errors; +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL + ret = GPTLinitialize(); + if(ret != 0){ + LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + + ret = MPI_Init(&argc, &argv); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Init() FAILED, ret = %d\n", ret); + return ret; + } + + ret = MPI_Comm_rank(MPI_COMM_WORLD, &wrank); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); + return ret; + } + ret = MPI_Comm_size(MPI_COMM_WORLD, &wsz); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); + return ret; + } + + num_errors = 0; + ret = test_driver(MPI_COMM_WORLD, wrank, wsz, &num_errors); + if(ret != 0){ + LOG_RANK0(wrank, "Test driver FAILED\n"); + return FAIL; + } + else{ + LOG_RANK0(wrank, "All tests PASSED\n"); + } + + MPI_Finalize(); + +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL + ret = GPTLfinalize(); + if(ret != 0){ + LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + + if(num_errors != 0){ + LOG_RANK0(wrank, "Total errors = %d\n", num_errors); + return FAIL; + } + return 0; +} diff --git a/tests/cunit/test_spio_rearr_utils_alltoall.cpp b/tests/cunit/test_spio_rearr_utils_alltoall.cpp new file mode 100644 index 0000000000..a815e7492e --- /dev/null +++ b/tests/cunit/test_spio_rearr_utils_alltoall.cpp @@ -0,0 +1,453 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pio_config.h" +#include "pio.h" +#include "pio_tests.h" +#include "pio_rearr_utils.hpp" + +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL +#include "gptl.h" +#endif +#endif + +#define LOG_RANK0(rank, ...) \ + do{ \ + if(rank == 0){ \ + fprintf(stderr, __VA_ARGS__); \ + } \ + }while(0); + +static const int FAIL = -1; + +template +bool cmp_result(int wrank, const std::vector &res, const std::vector &exp) +{ + + if(res.size() != exp.size()){ + LOG_RANK0(wrank, "ERROR: The result and expected vectors are of different sizes\n"); + return false; + } + + for(std::size_t i = 0; i < res.size(); i++){ + if(res[i] != exp[i]){ + std::ostringstream oss; + oss << "ERROR: Invalid/Unexpected value, array[ " << i << "] = " << res[i] + << " (Expected array[" << i << "] = " << exp[i] << ")"; + LOG_RANK0(wrank, "ERROR: %s\n", oss.str().c_str()); + return false; + } + } + + return true; +} + +/* Test alltoall() with each process sending the same sized block of data */ +int test_alltoall_eq_sized_type_decomp(MPI_Comm comm, int wrank, int wsz) +{ + int ret = PIO_NOERR; + const int LOCAL_SZ = 4; + const double FILLVAL = -1.0; + std::vector sdata(LOCAL_SZ * wsz); + std::vector rdata(LOCAL_SZ * wsz, FILLVAL); + std::vector exp_data(LOCAL_SZ * wsz, FILLVAL); + rearr_comm_fc_opt_t ropts = {true, true, -1}; + + const double ldata_start = wrank * LOCAL_SZ; + double ldata = ldata_start; + int ldata_idx = 0; + std::generate(sdata.begin(), sdata.end(), + [&ldata, &ldata_idx, ldata_start] () mutable { + if(ldata_idx % LOCAL_SZ == 0){ + ldata = ldata_start; + } + ldata_idx++; + return ldata++; + } + ); + + std::iota(exp_data.begin(), exp_data.end(), 0); + + try{ + ret = SPIO_Util::Rearr_Util::alltoall(sdata.data(), LOCAL_SZ, MPI_DOUBLE, + rdata.data(), LOCAL_SZ, MPI_DOUBLE, comm, &ropts); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Alltoall failed\n"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/Invalid data received in alltoall()\n"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Alltoall failed\n"); + return PIO_EINTERNAL; + } + + return PIO_NOERR; +} + +/* Test alltoall() with each process sending a contig block of data */ +int test_alltoall_contig_to_type_decomp(MPI_Comm comm, int wrank, int wsz) +{ + int ret = PIO_NOERR; + const int LOCAL_SZ = 4; + const double FILLVAL = -1.0; + std::vector sdata(LOCAL_SZ * wsz); + std::vector rdata(LOCAL_SZ * wsz, FILLVAL); + std::vector exp_data(LOCAL_SZ * wsz, FILLVAL); + + MPI_Datatype stype = MPI_DATATYPE_NULL; + rearr_comm_fc_opt_t ropts = {true, true, -1}; + + const double ldata_start = wrank * LOCAL_SZ; + double ldata = ldata_start; + int ldata_idx = 0; + std::generate(sdata.begin(), sdata.end(), + [&ldata, &ldata_idx, ldata_start] () mutable { + if(ldata_idx % LOCAL_SZ == 0){ + ldata = ldata_start; + } + ldata_idx++; + return ldata++; + } + ); + + ret = MPI_Type_contiguous(LOCAL_SZ, MPI_DOUBLE, &stype); + if(ret == MPI_SUCCESS){ + ret = MPI_Type_commit(&stype); + } + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "Creating contig MPI type to send data failed\n"); + return PIO_EINTERNAL; + } + + std::iota(exp_data.begin(), exp_data.end(), 0); + + try{ + ret = SPIO_Util::Rearr_Util::alltoall(sdata.data(), 1, stype, + rdata.data(), LOCAL_SZ, MPI_DOUBLE, comm, &ropts); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Alltoall failed\n"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/Invalid data received in alltoall()\n"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Alltoall failed\n"); + return PIO_EINTERNAL; + } + + MPI_Type_free(&stype); + + return PIO_NOERR; +} + +/* Test alltoall() with each process receives a contig block of data */ +int test_alltoall_type_to_contig_decomp(MPI_Comm comm, int wrank, int wsz) +{ + int ret = PIO_NOERR; + const int LOCAL_SZ = 4; + const double FILLVAL = -1.0; + std::vector sdata(LOCAL_SZ * wsz); + std::vector rdata(LOCAL_SZ * wsz, FILLVAL); + std::vector exp_data(LOCAL_SZ * wsz, FILLVAL); + + MPI_Datatype rtype = MPI_DATATYPE_NULL; + rearr_comm_fc_opt_t ropts = {true, true, -1}; + + const double ldata_start = wrank * LOCAL_SZ; + double ldata = ldata_start; + int ldata_idx = 0; + std::generate(sdata.begin(), sdata.end(), + [&ldata, &ldata_idx, ldata_start] () mutable { + if(ldata_idx % LOCAL_SZ == 0){ + ldata = ldata_start; + } + ldata_idx++; + return ldata++; + } + ); + + ret = MPI_Type_contiguous(LOCAL_SZ, MPI_DOUBLE, &rtype); + if(ret == MPI_SUCCESS){ + ret = MPI_Type_commit(&rtype); + } + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "Creating contig MPI type to send data failed\n"); + return PIO_EINTERNAL; + } + + std::iota(exp_data.begin(), exp_data.end(), 0); + + try{ + ret = SPIO_Util::Rearr_Util::alltoall(sdata.data(), LOCAL_SZ, MPI_DOUBLE, + rdata.data(), 1, rtype, comm, &ropts); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Alltoall failed\n"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/Invalid data received in alltoall()\n"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Alltoall failed\n"); + return PIO_EINTERNAL; + } + + MPI_Type_free(&rtype); + + return PIO_NOERR; +} + +/* Test alltoallw() with each process sending the same sized block of data */ +int test_alltoallw_eq_sized_type_decomp(MPI_Comm comm, int wrank, int wsz) +{ + int ret = PIO_NOERR; + const int LOCAL_SZ = 4; + const double FILLVAL = -1.0; + std::vector sdata(LOCAL_SZ * wsz); + std::vector rdata(LOCAL_SZ * wsz, FILLVAL); + std::vector exp_data(LOCAL_SZ * wsz, FILLVAL); + rearr_comm_fc_opt_t ropts = {true, true, -1}; + + std::vector srcount(wsz, LOCAL_SZ); + std::vector srdispls(wsz, 0); + std::vector srtypes(wsz, MPI_DOUBLE); + int type_sz = 0; + + ret = MPI_Type_size(MPI_DOUBLE, &type_sz); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "ERROR: Unable to query size of MPI_DOUBLE\n"); + return PIO_EINTERNAL; + } + + const double ldata_start = wrank * LOCAL_SZ; + double ldata = ldata_start; + int ldata_idx = 0; + std::generate(sdata.begin(), sdata.end(), + [&ldata, &ldata_idx, ldata_start] () mutable { + if(ldata_idx % LOCAL_SZ == 0){ + ldata = ldata_start; + } + ldata_idx++; + return ldata++; + } + ); + + int displ = -LOCAL_SZ; + std::generate(srdispls.begin(), srdispls.end(), + [&displ, type_sz] () mutable { + displ += LOCAL_SZ; + return displ * type_sz; + } + ); + + std::iota(exp_data.begin(), exp_data.end(), 0); + + try{ + ret = SPIO_Util::Rearr_Util::alltoallw( + sdata.data(), srcount.data(), srdispls.data(), srtypes.data(), + rdata.data(), srcount.data(), srdispls.data(), srtypes.data(), + comm, &ropts); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Alltoallw failed\n"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/Invalid data received in alltoallw()\n"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Alltoallw failed\n"); + return PIO_EINTERNAL; + } + + return PIO_NOERR; +} + +/* Test alltoallw() with each process sending uneven sized block of data */ +int test_alltoallw_uneven_block_decomp(MPI_Comm comm, int wrank, int wsz) +{ + int ret = PIO_NOERR; + const double FILLVAL = -1.0; + const int LOCAL_SZ = wrank + 1; + std::vector sdata(LOCAL_SZ); + std::vector rdata((wsz * (wsz + 1))/2, FILLVAL); + std::vector exp_data((wsz * (wsz + 1))/2, FILLVAL); + + std::vector scounts(wsz), sdispls(wsz), rcounts(wsz), rdispls(wsz); + std::vector types(wsz, MPI_DOUBLE); + int type_sz = 0; + rearr_comm_fc_opt_t ropts = {true, true, -1}; + + ret = MPI_Type_size(MPI_DOUBLE, &type_sz); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "ERROR: Unable to query size of MPI_DOUBLE\n"); + return PIO_EINTERNAL; + } + + /* sdata[] in proc i contains i * wsz consecutive numbers, + * e.g.: wsz = 3 + * sdata[] at rank 0 is {0} => rank 0 sends {0} to all procs + * sdata[] at rank 1 is {1,2} => rank 1 sends {1,2} to all procs + * sdata[] at rank 2 is {3,4,5} => rank 2 sends {3,4,5} to all procs + * Number of elements in all procs <= wrank, = (wrank + 1) * (wrank + 2)/2 + * Number of elements in proc wrank = (wrank + 1) + * => Proc wrank starts at index (wrank * (wrank + 1)) / 2) + * sdata[] at rank wrank is {(wrank * (wrank + 1)) / 2), + * (wrank * (wrank + 1)) / 2) + 1, ..., + * (wrank * (wrank + 1)) / 2) + wrank - 1} + */ + std::iota(sdata.begin(), sdata.end(), (wrank * (wrank + 1)) / 2); + std::iota(exp_data.begin(), exp_data.end(), 0); + + for(int i = 0; i < wsz; i++){ + scounts[i] = wrank + 1; + sdispls[i] = 0; + + rcounts[i] = i + 1; + rdispls[i] = (i * (i + 1))/2 * type_sz; + } + + try{ + ret = SPIO_Util::Rearr_Util::alltoallw(sdata.data(), scounts.data(), sdispls.data(), types.data(), + rdata.data(), rcounts.data(), rdispls.data(), types.data(), comm, &ropts); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Alltoallw failed\n"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/Invalid data in alltoallw buffer\n"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Alltoallw failed\n"); + return PIO_EINTERNAL; + } + + return PIO_NOERR; +} + +int test_driver(MPI_Comm comm, int wrank, int wsz, int *num_errors) +{ + int nerrs = 0, ret = PIO_NOERR, mpierr = MPI_SUCCESS; + assert((comm != MPI_COMM_NULL) && (wrank >= 0) && (wsz > 0) && num_errors); + + std::vector > > test_funcs = { + {"test_alltoall_eq_sized_type_decomp", test_alltoall_eq_sized_type_decomp}, + {"test_alltoall_contig_to_type_decomp", test_alltoall_contig_to_type_decomp}, + {"test_alltoall_type_to_contig_decomp", test_alltoall_type_to_contig_decomp}, + {"test_alltoallw_eq_sized_type_decomp", test_alltoallw_eq_sized_type_decomp}, + {"test_alltoallw_uneven_block_decomp", test_alltoallw_uneven_block_decomp} + }; + + for(std::size_t tid = 0; tid < test_funcs.size(); tid++){ + try{ + ret = test_funcs[tid].second(comm, wrank, wsz); + } + catch(...){ + ret = PIO_EINTERNAL; + nerrs++; + } + int lfail = (ret == PIO_NOERR) ? 0 : 1; + mpierr = MPI_Reduce(&ret, &lfail, 1, MPI_INT, MPI_SUM, 0, comm); + if(mpierr != MPI_SUCCESS){ + LOG_RANK0(wrank, "Test Driver failed: Unable to calculate total num errors\n"); + } + if(ret != 0){ + std::string non_root_fail_msg = std::string(", failed on ") + std::to_string(ret) + std::string(" non-root processes"); + LOG_RANK0(wrank, "%s() FAILED (ret = %d%s)\n", test_funcs[tid].first.c_str(), ret, (lfail) ? "" : non_root_fail_msg.c_str()); + nerrs++; + } + else{ + LOG_RANK0(wrank, "%s() PASSED\n", test_funcs[tid].first.c_str()); + } + } + + *num_errors += nerrs; + return nerrs; +} + +int main(int argc, char *argv[]) +{ + int ret; + int wrank, wsz; + int num_errors; +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL + ret = GPTLinitialize(); + if(ret != 0){ + LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + + ret = MPI_Init(&argc, &argv); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Init() FAILED, ret = %d\n", ret); + return ret; + } + + ret = MPI_Comm_rank(MPI_COMM_WORLD, &wrank); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); + return ret; + } + ret = MPI_Comm_size(MPI_COMM_WORLD, &wsz); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); + return ret; + } + + num_errors = 0; + ret = test_driver(MPI_COMM_WORLD, wrank, wsz, &num_errors); + if(ret != 0){ + LOG_RANK0(wrank, "Test driver FAILED\n"); + } + else{ + LOG_RANK0(wrank, "All tests PASSED\n"); + } + + MPI_Finalize(); + +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL + ret = GPTLfinalize(); + if(ret != 0){ + LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + + if(num_errors != 0){ + LOG_RANK0(wrank, "Total errors = %d\n", num_errors); + return FAIL; + } + return 0; +} diff --git a/tests/cunit/test_spio_rearr_utils_gather.cpp b/tests/cunit/test_spio_rearr_utils_gather.cpp new file mode 100644 index 0000000000..13e5d20403 --- /dev/null +++ b/tests/cunit/test_spio_rearr_utils_gather.cpp @@ -0,0 +1,468 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pio_config.h" +#include "pio.h" +#include "pio_tests.h" +#include "pio_rearr_utils.hpp" + +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL +#include "gptl.h" +#endif +#endif + +#define LOG_RANK0(rank, ...) \ + do{ \ + if(rank == 0) \ + { \ + fprintf(stderr, __VA_ARGS__); \ + } \ + }while(0); + +static const int FAIL = -1; + +template +bool cmp_result(int wrank, const std::vector &res, const std::vector &exp) +{ + + if(res.size() != exp.size()){ + LOG_RANK0(wrank, "ERROR: The result and expected vectors are of different sizes\n"); + return false; + } + + for(std::size_t i = 0; i < res.size(); i++){ + if(res[i] != exp[i]){ + if(wrank == 0){ + std::cerr << "ERROR: Invalid/Unexpected value, array[ " << i << "] = " << res[i] + << " (Expected array[" << i << "] = " << exp[i] << ")\n"; + } + return false; + } + } + + return true; +} + +/* Test gatherw() with each process sending the same sized block of data */ +int test_gatherw_double_block_decomp(MPI_Comm comm, int wrank, int wsz) +{ + int ret = PIO_NOERR; + const int LOCAL_SZ = 4; + const double FILLVAL = -1.0; + const int ROOT_RANK = 0; + std::vector local_data(LOCAL_SZ); + std::vector gather_data; + + std::vector recvcounts, rdispls; + std::vector recvtypes; + + std::iota(local_data.begin(), local_data.end(), wrank * LOCAL_SZ); + + if(wrank == ROOT_RANK){ + gather_data.resize(wsz * LOCAL_SZ); + recvcounts.resize(wsz); + rdispls.resize(wsz); + recvtypes.resize(wsz); + for(std::size_t i = 0; i < gather_data.size(); i++){ + gather_data[i] = FILLVAL; + } + for(int i = 0; i < wsz; i++){ + recvcounts[i] = LOCAL_SZ; + rdispls[i] = i * LOCAL_SZ * sizeof(double); + recvtypes[i] = MPI_DOUBLE; + } + } + + try{ + ret = SPIO_Util::Rearr_Util::gatherw(local_data.data(), LOCAL_SZ, MPI_DOUBLE, + gather_data.data(), recvcounts, rdispls, recvtypes, + ROOT_RANK, comm, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Gathering data failed\n"); + return PIO_EINTERNAL; + } + + if(wrank == ROOT_RANK){ + std::vector expected_gather_data(wsz * LOCAL_SZ); + std::iota(expected_gather_data.begin(), expected_gather_data.end(), 0); + if(!cmp_result(wrank, gather_data, expected_gather_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/Invalid data in gather buffer\n"); + return PIO_EINTERNAL; + } + } + } + catch(...){ + LOG_RANK0(wrank, "Gathering data failed\n"); + return PIO_EINTERNAL; + } + + return PIO_NOERR; +} + +/* Test gatherw() with each process sending uneven sized block of data */ +int test_gatherw_double_uneven_block_decomp(MPI_Comm comm, int wrank, int wsz) +{ + int ret = PIO_NOERR; + const double FILLVAL = -1.0; + const int ROOT_RANK = 0; + const int LOCAL_SZ = wrank; + std::vector local_data(LOCAL_SZ); + std::vector gather_data; + + std::vector recvcounts, rdispls; + std::vector recvtypes; + + /* local_data[] in proc i contains i consecutive numbers, + * e.g.: wsz = 5 + * local_data[] at rank 0 is empty + * local_data[] at rank 1 is {0} + * local_data[] at rank 2 is {1,2} + * local_data[] at rank 3 is {3,4,5} + * local_data[] at rank 4 is {6,7,8,9} + * local_data[] at rank 5 is {10,11,12,13,14} + * Number of elements in all procs <= wrank, = wrank * (wrank + 1)/2 + * Number of elements in proc wrank = wrank + * => Proc wrank starts at index (wrank * (wrank + 1)) / 2 - wrank) + * local_data[] at rank wrank is {(wrank * (wrank + 1)) / 2 - wrank), + * (wrank * (wrank + 1)) / 2 - wrank) + 1, ..., + * (wrank * (wrank + 1)) / 2 - wrank) + wrank - 1} + */ + std::iota(local_data.begin(), local_data.end(), (wrank * (wrank + 1)) / 2 - wrank); + + if(wrank == ROOT_RANK){ + gather_data.resize((wsz * (wsz - 1))/2); + recvcounts.resize(wsz); + rdispls.resize(wsz); + recvtypes.resize(wsz); + for(std::size_t i = 0; i < gather_data.size(); i++){ + gather_data[i] = FILLVAL; + } + for(int i = 0; i < wsz; i++){ + recvcounts[i] = i; + /* Number of elements in all procs <= i, = i * (i + 1)/2 + * Number of elements in proc i = i + * => Proc i starts at index (i * (i + 1)) / 2 - i) + */ + rdispls[i] = ((i * (i + 1)) / 2 - i) * sizeof(double); + recvtypes[i] = MPI_DOUBLE; + } + } + + try{ + ret = SPIO_Util::Rearr_Util::gatherw(local_data.data(), LOCAL_SZ, MPI_DOUBLE, + gather_data.data(), recvcounts, rdispls, recvtypes, + ROOT_RANK, comm, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Gathering data failed\n"); + return PIO_EINTERNAL; + } + + if(wrank == ROOT_RANK){ + std::vector expected_gather_data((wsz * (wsz - 1))/2); + std::iota(expected_gather_data.begin(), expected_gather_data.end(), 0); + if(!cmp_result(wrank, gather_data, expected_gather_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/Invalid data in gather buffer\n"); + return PIO_EINTERNAL; + } + } + } + catch(...){ + LOG_RANK0(wrank, "Gathering data failed\n"); + return PIO_EINTERNAL; + } + + return PIO_NOERR; +} + +/* Test gatherw() with each process sending the same sized block of data using contig type */ +int test_gatherw_contig_block_decomp(MPI_Comm comm, int wrank, int wsz) +{ + int ret = PIO_NOERR; + const int LOCAL_SZ = 4; + const double FILLVAL = -1.0; + const int ROOT_RANK = 0; + std::vector local_data(LOCAL_SZ); + std::vector gather_data; + + std::vector recvcounts, rdispls; + MPI_Datatype sendtype = MPI_DATATYPE_NULL; + std::vector recvtypes; + + std::iota(local_data.begin(), local_data.end(), wrank * LOCAL_SZ); + + ret = MPI_Type_contiguous(LOCAL_SZ, MPI_DOUBLE, &sendtype); + if(ret == MPI_SUCCESS){ + ret = MPI_Type_commit(&sendtype); + } + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "ERROR: Unable to create MPI contig type to send double data (sz = %d)\n", LOCAL_SZ); + return PIO_EINTERNAL; + } + + if(wrank == ROOT_RANK){ + gather_data.resize(wsz * LOCAL_SZ); + recvcounts.resize(wsz); + rdispls.resize(wsz); + recvtypes.resize(wsz); + for(std::size_t i = 0; i < gather_data.size(); i++){ + gather_data[i] = FILLVAL; + } + for(int i = 0; i < wsz; i++){ + recvcounts[i] = 1; + rdispls[i] = i * LOCAL_SZ * sizeof(double); + + ret = MPI_Type_dup(sendtype, &(recvtypes[i])); + if(ret == MPI_SUCCESS){ + ret = MPI_Type_commit(&(recvtypes[i])); + } + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "ERROR: Unable to create MPI dup of send type to recv doubles\n"); + return PIO_EINTERNAL; + } + } + } + + try{ + ret = SPIO_Util::Rearr_Util::gatherw(local_data.data(), 1, sendtype, + gather_data.data(), recvcounts, rdispls, recvtypes, + ROOT_RANK, comm, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Gathering data failed\n"); + return PIO_EINTERNAL; + } + + if(wrank == ROOT_RANK){ + std::vector expected_gather_data(wsz * LOCAL_SZ); + std::iota(expected_gather_data.begin(), expected_gather_data.end(), 0); + if(!cmp_result(wrank, gather_data, expected_gather_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/Invalid data in gather buffer\n"); + return PIO_EINTERNAL; + } + } + } + catch(...){ + LOG_RANK0(wrank, "Gathering data failed\n"); + return PIO_EINTERNAL; + } + + if(sendtype != MPI_DATATYPE_NULL){ + MPI_Type_free(&sendtype); + } + for(std::size_t i = 0; i < recvtypes.size(); i++){ + if(recvtypes[i] != MPI_DATATYPE_NULL){ + MPI_Type_free(&(recvtypes[i])); + } + } + + return PIO_NOERR; +} + +/* Test gatherw() with each process sending contig block of data and gathered using an indexed type */ +int test_gatherw_contig_indexed(MPI_Comm comm, int wrank, int wsz) +{ + int ret = PIO_NOERR; + const int LOCAL_SZ = 4; + const double FILLVAL = -1.0; + const int ROOT_RANK = 0; + std::vector local_data(LOCAL_SZ); + std::vector gather_data; + + std::vector recvcounts, rdispls; + MPI_Datatype sendtype = MPI_DATATYPE_NULL; + std::vector recvtypes; + + /* Each process contains LOCAL_SZ doubles. + * rank0 contains {0, 0+wsz, 0+2*wsz,...} + * rank1 contains {1, 1+wsz, 1+2*wsz,...} + * ... + * ranki contains {i, i+wsz, i+2*wsz,...} + */ + int i = 0; + std::generate(local_data.begin(), local_data.end(), + [wrank, wsz, &i](){ return static_cast(i++ * wsz + wrank); } ); + + ret = MPI_Type_contiguous(LOCAL_SZ, MPI_DOUBLE, &sendtype); + if(ret == MPI_SUCCESS){ + ret = MPI_Type_commit(&sendtype); + } + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "ERROR: Unable to create MPI contig type to send double data (sz = %d)\n", LOCAL_SZ); + return PIO_EINTERNAL; + } + + if(wrank == ROOT_RANK){ + gather_data.resize(wsz * LOCAL_SZ); + recvcounts.resize(wsz); + rdispls.resize(wsz); + recvtypes.resize(wsz); + for(std::size_t i = 0; i < gather_data.size(); i++){ + gather_data[i] = FILLVAL; + } + for(int i = 0; i < wsz; i++){ + recvcounts[i] = 1; + rdispls[i] = i * sizeof(double); + + /* Receive the data such that the elements are in a sorted order - ascending */ + /* Receive data in rank0 {0, 0+wsz, 0+2*wz,...} at indices 0, 0+wsz, 0+2*wsz,... */ + std::vector elem_counts(LOCAL_SZ, 1); + std::vector elem_rdispls(LOCAL_SZ); + + int j = 0; + std::generate(elem_rdispls.begin(), elem_rdispls.end(), + [&j, wsz](){ return static_cast(j++ * wsz); } ); + + ret = MPI_Type_indexed(LOCAL_SZ, elem_counts.data(), elem_rdispls.data(), + MPI_DOUBLE, &(recvtypes[i])); + if(ret == MPI_SUCCESS){ + ret = MPI_Type_commit(&(recvtypes[i])); + } + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "ERROR: Unable to create MPI dup of send type to recv doubles\n"); + return PIO_EINTERNAL; + } + } + } + + try{ + ret = SPIO_Util::Rearr_Util::gatherw(local_data.data(), 1, sendtype, + gather_data.data(), recvcounts, rdispls, recvtypes, + ROOT_RANK, comm, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Gathering data failed\n"); + return PIO_EINTERNAL; + } + + if(wrank == ROOT_RANK){ + std::vector expected_gather_data(wsz * LOCAL_SZ); + std::iota(expected_gather_data.begin(), expected_gather_data.end(), 0); + if(!cmp_result(wrank, gather_data, expected_gather_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/Invalid data in gather buffer\n"); + return PIO_EINTERNAL; + } + } + } + catch(...){ + LOG_RANK0(wrank, "Gathering data failed\n"); + return PIO_EINTERNAL; + } + + if(sendtype != MPI_DATATYPE_NULL){ + MPI_Type_free(&sendtype); + } + for(std::size_t i = 0; i < recvtypes.size(); i++){ + if(recvtypes[i] != MPI_DATATYPE_NULL){ + MPI_Type_free(&(recvtypes[i])); + } + } + + return PIO_NOERR; +} + +int test_driver(MPI_Comm comm, int wrank, int wsz, int *num_errors) +{ + int nerrs = 0, ret = PIO_NOERR, mpierr = MPI_SUCCESS; + assert((comm != MPI_COMM_NULL) && (wrank >= 0) && (wsz > 0) && num_errors); + + std::vector > > test_funcs = { + {"test_gatherw_double_block_decomp", test_gatherw_double_block_decomp}, + {"test_gatherw_double_uneven_block_decomp", test_gatherw_double_uneven_block_decomp}, + {"test_gatherw_contig_block_decomp", test_gatherw_contig_block_decomp}, + {"test_gatherw_contig_indexed", test_gatherw_contig_indexed} + }; + + for(std::size_t tid = 0; tid < test_funcs.size(); tid++){ + try{ + ret = test_funcs[tid].second(comm, wrank, wsz); + } + catch(...){ + ret = PIO_EINTERNAL; + nerrs++; + } + int lfail = (ret == PIO_NOERR) ? 0 : 1; + mpierr = MPI_Reduce(&ret, &lfail, 1, MPI_INT, MPI_SUM, 0, comm); + if(mpierr != MPI_SUCCESS){ + LOG_RANK0(wrank, "Test Driver failed: Unable to calculate total num errors\n"); + } + if(ret != 0){ + std::string non_root_fail_msg = std::string(", failed on ") + std::to_string(ret) + std::string(" non-root processes"); + LOG_RANK0(wrank, "%s() FAILED (ret = %d%s)\n", test_funcs[tid].first.c_str(), ret, (lfail) ? "" : non_root_fail_msg.c_str()); + nerrs++; + } + else{ + LOG_RANK0(wrank, "%s() PASSED\n", test_funcs[tid].first.c_str()); + } + } + + *num_errors += nerrs; + return nerrs; +} + +int main(int argc, char *argv[]) +{ + int ret; + int wrank, wsz; + int num_errors; +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL + ret = GPTLinitialize(); + if(ret != 0){ + LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + + ret = MPI_Init(&argc, &argv); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Init() FAILED, ret = %d\n", ret); + return ret; + } + + ret = MPI_Comm_rank(MPI_COMM_WORLD, &wrank); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); + return ret; + } + ret = MPI_Comm_size(MPI_COMM_WORLD, &wsz); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); + return ret; + } + + num_errors = 0; + ret = test_driver(MPI_COMM_WORLD, wrank, wsz, &num_errors); + if(ret != 0){ + LOG_RANK0(wrank, "Test driver FAILED\n"); + } + else{ + LOG_RANK0(wrank, "All tests PASSED\n"); + } + + MPI_Finalize(); + +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL + ret = GPTLfinalize(); + if(ret != 0){ + LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + + if(num_errors != 0){ + LOG_RANK0(wrank, "Total errors = %d\n", num_errors); + return FAIL; + } + return 0; +} diff --git a/tests/cunit/test_spio_rearr_utils_scatter.cpp b/tests/cunit/test_spio_rearr_utils_scatter.cpp new file mode 100644 index 0000000000..fad5ce875b --- /dev/null +++ b/tests/cunit/test_spio_rearr_utils_scatter.cpp @@ -0,0 +1,457 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pio_config.h" +#include "pio.h" +#include "pio_tests.h" +#include "pio_rearr_utils.hpp" + +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL +#include "gptl.h" +#endif +#endif + +#define LOG_RANK0(rank, ...) \ + do{ \ + if(rank == 0) \ + { \ + fprintf(stderr, __VA_ARGS__); \ + } \ + }while(0); + +static const int FAIL = -1; + +template +bool cmp_result(int wrank, const std::vector &res, const std::vector &exp) +{ + + if(res.size() != exp.size()){ + LOG_RANK0(wrank, "ERROR: The result and expected vectors are of different sizes\n"); + return false; + } + + for(std::size_t i = 0; i < res.size(); i++){ + if(res[i] != exp[i]){ + if(wrank == 0){ + std::cerr << "ERROR: Invalid/Unexpected value, array[ " << i << "] = " << res[i] + << " (Expected array[" << i << "] = " << exp[i] << ")\n"; + } + return false; + } + } + + return true; +} + +/* Test scatterw() with each process receiving the same sized block of data */ +int test_scatterw_double_block_decomp(MPI_Comm comm, int wrank, int wsz) +{ + int ret = PIO_NOERR; + const int LOCAL_SZ = 4; + const double FILLVAL = -1.0; + const int ROOT_RANK = 0; + std::vector local_data(LOCAL_SZ); + std::vector scatter_data; + std::vector exp_data(LOCAL_SZ); + + int recvcount = LOCAL_SZ; + MPI_Datatype recvtype = MPI_DOUBLE; + + std::vector sendcounts, sdispls; + std::vector sendtypes; + + std::fill(local_data.begin(), local_data.end(), FILLVAL); + std::iota(exp_data.begin(), exp_data.end(), wrank * LOCAL_SZ); + + if(wrank == ROOT_RANK){ + scatter_data.resize(wsz * LOCAL_SZ); + std::iota(scatter_data.begin(), scatter_data.end(), 0); + + sendcounts.resize(wsz); + sdispls.resize(wsz); + sendtypes.resize(wsz); + + for(int i = 0; i < wsz; i++){ + sendcounts[i] = LOCAL_SZ; + sdispls[i] = i * LOCAL_SZ * sizeof(double); + sendtypes[i] = MPI_DOUBLE; + } + } + + try{ + ret = SPIO_Util::Rearr_Util::scatterw(scatter_data.data(), sendcounts, + sdispls, sendtypes, + local_data.data(), recvcount, recvtype, + ROOT_RANK, comm, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Scattering data failed\n"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, local_data, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/Invalid data in scatter buffer\n"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Scattering data failed\n"); + return PIO_EINTERNAL; + } + + return PIO_NOERR; +} + +/* Test scatterw() with each process sending uneven sized block of data */ +int test_scatterw_double_uneven_block_decomp(MPI_Comm comm, int wrank, int wsz) +{ + int ret = PIO_NOERR; + const double FILLVAL = -1.0; + const int ROOT_RANK = 0; + const int LOCAL_SZ = wrank; + std::vector local_data(LOCAL_SZ); + std::vector scatter_data; + std::vector exp_data(LOCAL_SZ); + + int recvcount = LOCAL_SZ; + MPI_Datatype recvtype = MPI_DOUBLE; + + std::vector sendcounts, sdispls; + std::vector sendtypes; + + /* local_data[] in proc i contains i consecutive numbers, + * e.g.: wsz = 5, after scatter, + * local_data[] at rank 0 is empty + * local_data[] at rank 1 is {0} + * local_data[] at rank 2 is {1,2} + * local_data[] at rank 3 is {3,4,5} + * local_data[] at rank 4 is {6,7,8,9} + * local_data[] at rank 5 is {10,11,12,13,14} + * Number of elements in all procs <= wrank, = wrank * (wrank + 1)/2 + * Number of elements in proc wrank = wrank + * => Proc wrank starts at index (wrank * (wrank + 1)) / 2 - wrank) + * local_data[] at rank wrank is {(wrank * (wrank + 1)) / 2 - wrank), + * (wrank * (wrank + 1)) / 2 - wrank) + 1, ..., + * (wrank * (wrank + 1)) / 2 - wrank) + wrank - 1} + */ + std::fill(local_data.begin(), local_data.end(), FILLVAL); + std::iota(exp_data.begin(), exp_data.end(), (wrank * (wrank + 1)) / 2 - wrank); + + if(wrank == ROOT_RANK){ + scatter_data.resize((wsz * (wsz - 1))/2); + std::iota(scatter_data.begin(), scatter_data.end(), 0); + + sendcounts.resize(wsz); + sdispls.resize(wsz); + sendtypes.resize(wsz); + + for(int i = 0; i < wsz; i++){ + sendcounts[i] = i; + /* Number of elements in all procs <= i, = i * (i + 1)/2 + * Number of elements in proc i = i + * => Proc i starts at index (i * (i + 1)) / 2 - i) + */ + sdispls[i] = ((i * (i + 1)) / 2 - i) * sizeof(double); + sendtypes[i] = MPI_DOUBLE; + } + } + + try{ + ret = SPIO_Util::Rearr_Util::scatterw(scatter_data.data(), sendcounts, + sdispls, sendtypes, + local_data.data(), recvcount, recvtype, + ROOT_RANK, comm, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Scattering data failed\n"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, local_data, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/Invalid data in scatter buffer\n"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Scattering data failed\n"); + return PIO_EINTERNAL; + } + + return PIO_NOERR; +} + +/* Test scatterw() with each process receiving the same sized block of data using contig type */ +int test_scatterw_contig_block_decomp(MPI_Comm comm, int wrank, int wsz) +{ + int ret = PIO_NOERR; + const int LOCAL_SZ = 4; + const double FILLVAL = -1.0; + const int ROOT_RANK = 0; + std::vector local_data(LOCAL_SZ); + std::vector scatter_data; + std::vector exp_data(LOCAL_SZ); + + int recvcount = 1; + MPI_Datatype srtype = MPI_DATATYPE_NULL; + + std::vector sendcounts, sdispls; + std::vector sendtypes; + + std::fill(local_data.begin(), local_data.end(), FILLVAL); + std::iota(exp_data.begin(), exp_data.end(), wrank * LOCAL_SZ); + + ret = MPI_Type_contiguous(LOCAL_SZ, MPI_DOUBLE, &srtype); + if(ret == MPI_SUCCESS){ + ret = MPI_Type_commit(&srtype); + } + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "ERROR: Unable to create MPI contig type to receive double data (sz = %d)\n", LOCAL_SZ); + return PIO_EINTERNAL; + } + + if(wrank == ROOT_RANK){ + scatter_data.resize(wsz * LOCAL_SZ); + std::iota(scatter_data.begin(), scatter_data.end(), 0); + + sendcounts.resize(wsz); + sdispls.resize(wsz); + sendtypes.resize(wsz); + + for(int i = 0; i < wsz; i++){ + sendcounts[i] = 1; + sdispls[i] = i * LOCAL_SZ * sizeof(double); + sendtypes[i] = srtype; + } + } + + try{ + ret = SPIO_Util::Rearr_Util::scatterw(scatter_data.data(), sendcounts, + sdispls, sendtypes, + local_data.data(), recvcount, srtype, + ROOT_RANK, comm, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Scattering data failed\n"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, local_data, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/Invalid data in scatter buffer\n"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Scattering data failed\n"); + return PIO_EINTERNAL; + } + + MPI_Type_free(&srtype); + + return PIO_NOERR; +} + +/* Test scatterw() with each process sending contig block of data and scattered using an indexed type */ +int test_scatterw_contig_indexed(MPI_Comm comm, int wrank, int wsz) +{ + int ret = PIO_NOERR; + const int LOCAL_SZ = 4; + const double FILLVAL = -1.0; + const int ROOT_RANK = 0; + std::vector local_data(LOCAL_SZ); + std::vector scatter_data; + std::vector exp_data(LOCAL_SZ); + + int recvcount = 1; + MPI_Datatype recvtype = MPI_DATATYPE_NULL; + + std::vector sendcounts, sdispls; + MPI_Datatype sendtype = MPI_DATATYPE_NULL; + std::vector sendtypes; + + /* Each process contains LOCAL_SZ doubles. After scatter, + * rank0 contains {0, 0+wsz, 0+2*wsz,...} + * rank1 contains {1, 1+wsz, 1+2*wsz,...} + * ... + * ranki contains {i, i+wsz, i+2*wsz,...} + */ + std::fill(local_data.begin(), local_data.end(), FILLVAL); + int i = 0; + std::generate(exp_data.begin(), exp_data.end(), + [wrank, wsz, &i](){ return static_cast(i++ * wsz + wrank); } ); + + ret = MPI_Type_contiguous(LOCAL_SZ, MPI_DOUBLE, &recvtype); + if(ret == MPI_SUCCESS){ + ret = MPI_Type_commit(&recvtype); + } + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "ERROR: Unable to create MPI contig type to recv double data (sz = %d)\n", LOCAL_SZ); + return PIO_EINTERNAL; + } + + if(wrank == ROOT_RANK){ + scatter_data.resize(wsz * LOCAL_SZ); + std::iota(scatter_data.begin(), scatter_data.end(), 0); + + sendcounts.resize(wsz); + sdispls.resize(wsz); + sendtypes.resize(wsz); + + /* Receive the data such that the elements are in a sorted order - ascending */ + /* Receive data in rank0 {0, 0+wsz, 0+2*wz,...} at indices 0, 0+wsz, 0+2*wsz,... */ + std::vector elem_counts(LOCAL_SZ, 1); + std::vector elem_rdispls(LOCAL_SZ); + + int j = 0; + std::generate(elem_rdispls.begin(), elem_rdispls.end(), + [&j, wsz](){ return static_cast(j++ * wsz); } ); + + ret = MPI_Type_indexed(LOCAL_SZ, elem_counts.data(), elem_rdispls.data(), + MPI_DOUBLE, &(sendtype)); + if(ret == MPI_SUCCESS){ + ret = MPI_Type_commit(&(sendtype)); + } + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "ERROR: Unable to create MPI indexed type to send doubles\n"); + return PIO_EINTERNAL; + } + + for(int i = 0; i < wsz; i++){ + sendcounts[i] = 1; + sdispls[i] = i * sizeof(double); + sendtypes[i] = sendtype; + } + } + + try{ + ret = SPIO_Util::Rearr_Util::scatterw(scatter_data.data(), sendcounts, + sdispls, sendtypes, + local_data.data(), recvcount, recvtype, + ROOT_RANK, comm, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Scattering data failed\n"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, local_data, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/Invalid data in scatter buffer\n"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Scattering data failed\n"); + return PIO_EINTERNAL; + } + + MPI_Type_free(&recvtype); + if(sendtype != MPI_DATATYPE_NULL){ + MPI_Type_free(&(sendtype)); + } + + return PIO_NOERR; +} + +int test_driver(MPI_Comm comm, int wrank, int wsz, int *num_errors) +{ + int nerrs = 0, ret = PIO_NOERR, mpierr = MPI_SUCCESS; + assert((comm != MPI_COMM_NULL) && (wrank >= 0) && (wsz > 0) && num_errors); + + std::vector > > test_funcs = { + {"test_scatterw_double_block_decomp", test_scatterw_double_block_decomp}, + {"test_scatterw_double_uneven_block_decomp", test_scatterw_double_uneven_block_decomp}, + {"test_scatterw_contig_block_decomp", test_scatterw_contig_block_decomp}, + {"test_scatterw_contig_indexed", test_scatterw_contig_indexed} + }; + + for(std::size_t tid = 0; tid < test_funcs.size(); tid++){ + try{ + ret = test_funcs[tid].second(comm, wrank, wsz); + } + catch(...){ + ret = PIO_EINTERNAL; + nerrs++; + } + int lfail = (ret == PIO_NOERR) ? 0 : 1; + mpierr = MPI_Reduce(&ret, &lfail, 1, MPI_INT, MPI_SUM, 0, comm); + if(mpierr != MPI_SUCCESS){ + LOG_RANK0(wrank, "Test Driver failed: Unable to calculate total num errors\n"); + } + if(ret != 0){ + std::string non_root_fail_msg = std::string(", failed on ") + std::to_string(ret) + std::string(" non-root processes"); + LOG_RANK0(wrank, "%s() FAILED (ret = %d%s)\n", test_funcs[tid].first.c_str(), ret, (lfail) ? "" : non_root_fail_msg.c_str()); + nerrs++; + } + else{ + LOG_RANK0(wrank, "%s() PASSED\n", test_funcs[tid].first.c_str()); + } + } + + *num_errors += nerrs; + return nerrs; +} + +int main(int argc, char *argv[]) +{ + int ret; + int wrank, wsz; + int num_errors; +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL + ret = GPTLinitialize(); + if(ret != 0){ + LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + + ret = MPI_Init(&argc, &argv); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Init() FAILED, ret = %d\n", ret); + return ret; + } + + ret = MPI_Comm_rank(MPI_COMM_WORLD, &wrank); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); + return ret; + } + ret = MPI_Comm_size(MPI_COMM_WORLD, &wsz); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); + return ret; + } + + num_errors = 0; + ret = test_driver(MPI_COMM_WORLD, wrank, wsz, &num_errors); + if(ret != 0){ + LOG_RANK0(wrank, "Test driver FAILED\n"); + } + else{ + LOG_RANK0(wrank, "All tests PASSED\n"); + } + + MPI_Finalize(); + +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL + ret = GPTLfinalize(); + if(ret != 0){ + LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + + if(num_errors != 0){ + LOG_RANK0(wrank, "Total errors = %d\n", num_errors); + return FAIL; + } + return 0; +} From e016e7fe501a3df177451ee9d5d07dbd05789160 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 19 Nov 2024 17:31:17 -0600 Subject: [PATCH 013/194] Adding a simple wrapper for ltimers Adding a simple wrapper class for SPIO timers to start and stop timers --- src/clib/spio_ltimer_utils.hpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/clib/spio_ltimer_utils.hpp diff --git a/src/clib/spio_ltimer_utils.hpp b/src/clib/spio_ltimer_utils.hpp new file mode 100644 index 0000000000..586e2cc6fd --- /dev/null +++ b/src/clib/spio_ltimer_utils.hpp @@ -0,0 +1,27 @@ +#ifndef __SPIO_LTIMER_UTILS_HPP__ +#define __SPIO_LTIMER_UTILS_HPP__ + +#include "pio_config.h" +#include "pio.h" +#include "pio_internal.h" + +#include "spio_ltimer.h" + +#include + +namespace SPIO_Util{ + namespace SPIO_Ltimer_Utils{ + class SPIO_ltimer_wrapper{ + public: + SPIO_ltimer_wrapper(const char *timer_name):timer_name_(timer_name){ + spio_ltimer_start(timer_name_.c_str()); + } + ~SPIO_ltimer_wrapper(){ + spio_ltimer_stop(timer_name_.c_str()); + } + private: + const std::string timer_name_; + }; + } // namespace SPIO_Ltimer_Utils +} // namespace SPIO_Util +#endif // __SPIO_LTIMER_UTILS_HPP__ From 3653d92ead886f5f4f1770702899147f447684b5 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 19 Nov 2024 17:32:30 -0600 Subject: [PATCH 014/194] Using GPTL and timer wrappers in pioc.cpp Using GPTL and SPIO timer wrapper classes to simplify stopping of timers (on function exits). This change simplifies the code by removing a lot of explicit stops of timers --- src/clib/pioc.cpp | 145 ++++------------------------------------------ 1 file changed, 10 insertions(+), 135 deletions(-) diff --git a/src/clib/pioc.cpp b/src/clib/pioc.cpp index 62431c2629..022fce1a97 100644 --- a/src/clib/pioc.cpp +++ b/src/clib/pioc.cpp @@ -17,6 +17,9 @@ #include "pio_sdecomps_regex.h" #include "spio_io_summary.h" #include "spio_rearrange_any.h" +#include "spio_ltimer.h" +#include "spio_ltimer_utils.hpp" +#include "spio_gptl_utils.hpp" /* Include headers for HDF5 compression filters */ #if PIO_USE_HDF5 @@ -690,25 +693,22 @@ int PIOc_InitDecomp_impl(int iosysid, int pio_type, int ndims, const int *gdimle int mpierr = MPI_SUCCESS; /* Return code from MPI function calls. */ int ierr; /* Return code. */ - GPTLstart("PIO:PIOc_initdecomp"); + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("PIO:PIOc_initdecomp"); LOG((1, "PIOc_InitDecomp iosysid = %d pio_type = %d ndims = %d maplen = %d", iosysid, pio_type, ndims, maplen)); /* Get IO system info. */ if (!(ios = pio_get_iosystem_from_id(iosysid))) { - GPTLstop("PIO:PIOc_initdecomp"); return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, "Initializing the PIO decomposition failed. Invalid io system id (%d) provided. Could not find an iosystem associated with the id", iosysid); } assert(ios); - spio_ltimer_start(ios->io_fstats->tot_timer_name); + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper ios_fstats_tot_timer(ios->io_fstats->tot_timer_name); /* Caller must provide these. */ if (!gdimlen || !compmap || !ioidp) { - GPTLstop("PIO:PIOc_initdecomp"); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); return pio_err(ios, NULL, PIO_EINVAL, __FILE__, __LINE__, "Initializing the PIO decomposition failed. Invalid pointers (NULL) to gdimlen(%s) or compmap(%s) or ioidp (%s) provided", (gdimlen) ? "not NULL" : "NULL", (compmap) ? "not NULL" : "NULL", (ioidp) ? "not NULL" : "NULL"); } @@ -717,8 +717,6 @@ int PIOc_InitDecomp_impl(int iosysid, int pio_type, int ndims, const int *gdimle for (int i = 0; i < ndims; i++) if (gdimlen[i] <= 0) { - GPTLstop("PIO:PIOc_initdecomp"); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); return pio_err(ios, NULL, PIO_EINVAL, __FILE__, __LINE__, "Initializing the PIO decomposition failed. Invalid value for global dimension lengths provided. The global length of dimension %d is provided as %d (expected > 0)", i, gdimlen[i]); } @@ -743,8 +741,6 @@ int PIOc_InitDecomp_impl(int iosysid, int pio_type, int ndims, const int *gdimle } if(!amsg_iostart || !amsg_iocount) { - GPTLstop("PIO:PIOc_initdecomp"); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, "Initializing the PIO decomposition failed. Out of memory allocating %lld bytes for start array and %lld bytes for count array for sending asynchronous message, PIO_MSG_INITDECOMP_DOF, on iosystem (iosysid=%d)", (unsigned long long) (ndims * sizeof(PIO_Offset)), (unsigned long long) (ndims * sizeof(PIO_Offset)), ios->iosysid); } @@ -771,8 +767,6 @@ int PIOc_InitDecomp_impl(int iosysid, int pio_type, int ndims, const int *gdimle * iodesc. */ if ((ierr = malloc_iodesc(ios, pio_type, ndims, &iodesc))) { - GPTLstop("PIO:PIOc_initdecomp"); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); return pio_err(ios, NULL, ierr, __FILE__, __LINE__, "Initializing the PIO decomposition failed. Out of memory allocating memory for I/O descriptor"); } @@ -783,8 +777,6 @@ int PIOc_InitDecomp_impl(int iosysid, int pio_type, int ndims, const int *gdimle /* Remember the map. */ if (!(iodesc->map = (PIO_Offset *) malloc(sizeof(PIO_Offset) * maplen))) { - GPTLstop("PIO:PIOc_initdecomp"); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, "Initializing the PIO decomposition failed. Out of memory allocating %lld bytes to store I/O decomposition map", (unsigned long long) (sizeof(PIO_Offset) * maplen)); } @@ -794,8 +786,6 @@ int PIOc_InitDecomp_impl(int iosysid, int pio_type, int ndims, const int *gdimle /* Remember the dim sizes. */ if (!(iodesc->dimlen = (int *)malloc(sizeof(int) * ndims))) { - GPTLstop("PIO:PIOc_initdecomp"); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, "Initializing the PIO decomposition failed. Out of memory allocating %lld bytes for dimension sizes in the I/O decomposition map", (unsigned long long) (sizeof(int) * ndims)); } @@ -840,8 +830,6 @@ int PIOc_InitDecomp_impl(int iosysid, int pio_type, int ndims, const int *gdimle if ((ierr = subset_rearrange_create(ios, maplen, (PIO_Offset *)compmap, gdimlen, ndims, iodesc))) { - GPTLstop("PIO:PIOc_initdecomp"); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); return pio_err(ios, NULL, ierr, __FILE__, __LINE__, "Initializing the PIO decomposition failed. Error creating the SUBSET rearranger"); } @@ -870,8 +858,6 @@ int PIOc_InitDecomp_impl(int iosysid, int pio_type, int ndims, const int *gdimle ios->io_rank, iodesc->firstregion->start, iodesc->firstregion->count, &iodesc->num_aiotasks))) { - GPTLstop("PIO:PIOc_initdecomp"); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); return pio_err(ios, NULL, ierr, __FILE__, __LINE__, "Initializing the PIO decomposition failed. Internal error calculating start/count for the decomposition"); } @@ -880,8 +866,6 @@ int PIOc_InitDecomp_impl(int iosysid, int pio_type, int ndims, const int *gdimle /* Compute the max io buffer size needed for an iodesc. */ if ((ierr = compute_maxIObuffersize(ios->io_comm, iodesc))) { - GPTLstop("PIO:PIOc_initdecomp"); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); return pio_err(ios, NULL, ierr, __FILE__, __LINE__, "Initializing the PIO decomposition failed. Internal error computing max io buffer size needed for the decomposition"); } @@ -894,8 +878,6 @@ int PIOc_InitDecomp_impl(int iosysid, int pio_type, int ndims, const int *gdimle if ((mpierr = MPI_Bcast(&(iodesc->num_aiotasks), 1, MPI_INT, ios->ioroot, ios->my_comm))) { - GPTLstop("PIO:PIOc_initdecomp"); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); return check_mpi(ios, NULL, mpierr, __FILE__, __LINE__); } LOG((3, "iodesc->num_aiotasks = %d", iodesc->num_aiotasks)); @@ -904,8 +886,6 @@ int PIOc_InitDecomp_impl(int iosysid, int pio_type, int ndims, const int *gdimle if (iodesc->rearranger == PIO_REARR_BOX) if ((ierr = box_rearrange_create(ios, maplen, compmap, gdimlen, ndims, iodesc))) { - GPTLstop("PIO:PIOc_initdecomp"); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); return pio_err(ios, NULL, ierr, __FILE__, __LINE__, "Error initializing the PIO decomposition. Error creating the BOX rearranger"); } @@ -932,8 +912,6 @@ int PIOc_InitDecomp_impl(int iosysid, int pio_type, int ndims, const int *gdimle ierr = pio_create_uniq_str(ios, iodesc, filename, PIO_MAX_NAME, "piodecomp", ".dat"); if(ierr != PIO_NOERR) { - GPTLstop("PIO:PIOc_initdecomp"); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); return pio_err(ios, NULL, ierr, __FILE__, __LINE__, "Initializing the PIO decomposition failed. Creating a unique file name for saving the decomposition failed"); } @@ -973,8 +951,6 @@ int PIOc_InitDecomp_impl(int iosysid, int pio_type, int ndims, const int *gdimle * PERFTUNE is set. */ performance_tune_rearranger(ios, iodesc); - GPTLstop("PIO:PIOc_initdecomp"); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); return PIO_NOERR; } @@ -1290,7 +1266,7 @@ int PIOc_Init_Intracomm_impl(MPI_Comm comp_comm, int num_iotasks, int stride, in pio_init_gptl(); #endif #endif - GPTLstart("PIO:PIOc_Init_Intracomm"); + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("PIO:PIOc_Init_Intracomm"); /* Turn on the logging system. */ pio_init_logging(); @@ -1302,7 +1278,6 @@ int PIOc_Init_Intracomm_impl(MPI_Comm comp_comm, int num_iotasks, int stride, in ret = mtimer_init(PIO_MICRO_MPI_WTIME_ROOT); if(ret != PIO_NOERR) { - GPTLstop("PIO:PIOc_Init_Intracomm"); return pio_err(NULL, NULL, PIO_EINTERNAL, __FILE__, __LINE__, "PIO Init failed, initializing PIO micro timers failed (ret=%d)", ret); } @@ -1311,7 +1286,6 @@ int PIOc_Init_Intracomm_impl(MPI_Comm comp_comm, int num_iotasks, int stride, in /* Find the number of computation tasks. */ if ((mpierr = MPI_Comm_size(comp_comm, &num_comptasks))) { - GPTLstop("PIO:PIOc_Init_Intracomm"); return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); } @@ -1322,7 +1296,6 @@ int PIOc_Init_Intracomm_impl(MPI_Comm comp_comm, int num_iotasks, int stride, in base < 0 || base >= num_comptasks || stride * (num_iotasks - 1) >= num_comptasks) { - GPTLstop("PIO:PIOc_Init_Intracomm"); return pio_err(NULL, NULL, PIO_EINVAL, __FILE__, __LINE__, "PIO Init failed. Invalid arguments provided. Pointer to iosysid is %s (expected not NULL), num_iotasks=%d (expected >= 1 && <= num_comptasks, %d), stride = %d (expected >= 1), base = %d (expected >= 0 && < num_comptasks, %d), stride * (num_iotasks - 1) = %d (expected < num_comptasks, %d)", (iosysidp) ? "not NULL" : "NULL", num_iotasks, num_comptasks, stride, base, num_comptasks, stride * (num_iotasks - 1), num_comptasks); } @@ -1333,7 +1306,6 @@ int PIOc_Init_Intracomm_impl(MPI_Comm comp_comm, int num_iotasks, int stride, in /* Allocate memory for the iosystem info. */ if (!(ios = (iosystem_desc_t *) calloc(1, sizeof(iosystem_desc_t)))) { - GPTLstop("PIO:PIOc_Init_Intracomm"); return pio_err(NULL, NULL, PIO_ENOMEM, __FILE__, __LINE__, "PIO Init failed. Out of memory allocating %lld bytes for I/O system descriptor", (unsigned long long) sizeof(iosystem_desc_t)); } @@ -1362,7 +1334,6 @@ int PIOc_Init_Intracomm_impl(MPI_Comm comp_comm, int num_iotasks, int stride, in /* Copy the computation communicator into union_comm. */ if ((mpierr = MPI_Comm_dup(comp_comm, &ios->union_comm))) { - GPTLstop("PIO:PIOc_Init_Intracomm"); return check_mpi(ios, NULL, mpierr, __FILE__, __LINE__); } @@ -1373,7 +1344,6 @@ int PIOc_Init_Intracomm_impl(MPI_Comm comp_comm, int num_iotasks, int stride, in ret = init_adios_comm(ios); if (ret != PIO_NOERR) { - GPTLstop("PIO:PIOc_Init_Intracomm"); return pio_err(ios, NULL, PIO_EADIOS2ERR, __FILE__, __LINE__, "Initializing ADIOS failed"); } @@ -1382,7 +1352,6 @@ int PIOc_Init_Intracomm_impl(MPI_Comm comp_comm, int num_iotasks, int stride, in ios->adiosH = adios2_init_mpi(ios->adios_comm); if (ios->adiosH == NULL) { - GPTLstop("PIO:PIOc_Init_Intracomm"); return pio_err(ios, NULL, PIO_EADIOS2ERR, __FILE__, __LINE__, "Initializing ADIOS failed"); } @@ -1451,7 +1420,6 @@ int PIOc_Init_Intracomm_impl(MPI_Comm comp_comm, int num_iotasks, int stride, in ios->adios_readerH = adios2_init_mpi(ios->union_comm); if (ios->adios_readerH == NULL) { - GPTLstop("PIO:PIOc_Init_Intracomm"); return pio_err(ios, NULL, PIO_EADIOS2ERR, __FILE__, __LINE__, "Initializing ADIOS (for read) failed"); } #endif @@ -1496,7 +1464,6 @@ int PIOc_Init_Intracomm_impl(MPI_Comm comp_comm, int num_iotasks, int stride, in /* Copy the computation communicator into comp_comm. */ if ((mpierr = MPI_Comm_dup(comp_comm, &ios->comp_comm))) { - GPTLstop("PIO:PIOc_Init_Intracomm"); return check_mpi(ios, NULL, mpierr, __FILE__, __LINE__); } LOG((2, "union_comm = %d comp_comm = %d", ios->union_comm, ios->comp_comm)); @@ -1507,7 +1474,6 @@ int PIOc_Init_Intracomm_impl(MPI_Comm comp_comm, int num_iotasks, int stride, in /* Find MPI rank in comp_comm communicator. */ if ((mpierr = MPI_Comm_rank(ios->comp_comm, &ios->comp_rank))) { - GPTLstop("PIO:PIOc_Init_Intracomm"); return check_mpi(ios, NULL, mpierr, __FILE__, __LINE__); } @@ -1518,7 +1484,6 @@ int PIOc_Init_Intracomm_impl(MPI_Comm comp_comm, int num_iotasks, int stride, in * for computation. */ if (!(ios->compranks = (int *)calloc(ios->num_comptasks, sizeof(int)))) { - GPTLstop("PIO:PIOc_Init_Intracomm"); return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, "PIO Init failed. Out of memory allocating %lld bytes for array of compute process ranks in the I/O descriptor", (unsigned long long) (ios->num_comptasks * sizeof(int))); } @@ -1534,7 +1499,6 @@ int PIOc_Init_Intracomm_impl(MPI_Comm comp_comm, int num_iotasks, int stride, in * for IO. */ if (!(ios->ioranks = (int *)calloc(ios->num_iotasks, sizeof(int)))) { - GPTLstop("PIO:PIOc_Init_Intracomm"); return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, "PIO Init failed. Out of memory allocating %lld bytes for array of I/O process ranks in the I/O descriptor", (unsigned long long) (ios->num_iotasks * sizeof(int))); } @@ -1557,7 +1521,6 @@ int PIOc_Init_Intracomm_impl(MPI_Comm comp_comm, int num_iotasks, int stride, in /* Create a group for the computation tasks. */ if ((mpierr = MPI_Comm_group(ios->comp_comm, &ios->compgroup))) { - GPTLstop("PIO:PIOc_Init_Intracomm"); return check_mpi(ios, NULL, mpierr, __FILE__, __LINE__); } @@ -1565,14 +1528,12 @@ int PIOc_Init_Intracomm_impl(MPI_Comm comp_comm, int num_iotasks, int stride, in if ((mpierr = MPI_Group_incl(ios->compgroup, ios->num_iotasks, ios->ioranks, &ios->iogroup))) { - GPTLstop("PIO:PIOc_Init_Intracomm"); return check_mpi(ios, NULL, mpierr, __FILE__, __LINE__); } /* Create an MPI communicator for the IO tasks. */ if ((mpierr = MPI_Comm_create(ios->comp_comm, ios->iogroup, &ios->io_comm))) { - GPTLstop("PIO:PIOc_Init_Intracomm"); return check_mpi(ios, NULL, mpierr, __FILE__, __LINE__); } @@ -1583,7 +1544,6 @@ int PIOc_Init_Intracomm_impl(MPI_Comm comp_comm, int num_iotasks, int stride, in { if ((mpierr = MPI_Comm_rank(ios->io_comm, &ios->io_rank))) { - GPTLstop("PIO:PIOc_Init_Intracomm"); return check_mpi(ios, NULL, mpierr, __FILE__, __LINE__); } } @@ -1604,7 +1564,6 @@ int PIOc_Init_Intracomm_impl(MPI_Comm comp_comm, int num_iotasks, int stride, in /* Allocate buffer space for compute nodes. */ if ((ret = compute_buffer_init(ios))) { - GPTLstop("PIO:PIOc_Init_Intracomm"); return pio_err(ios, NULL, ret, __FILE__, __LINE__, "PIO Init failed. Internal error allocating buffer space on compute processes to cache user data"); } @@ -1623,7 +1582,6 @@ int PIOc_Init_Intracomm_impl(MPI_Comm comp_comm, int num_iotasks, int stride, in LOG((2, "Init_Intracomm complete iosysid = %d", *iosysidp)); - GPTLstop("PIO:PIOc_Init_Intracomm"); return PIO_NOERR; } @@ -1697,12 +1655,11 @@ int PIOc_set_hint_impl(int iosysid, const char *hint, const char *hintval) "Setting PIO hints failed. Invalid io system id (%d) provided", iosysid); } assert(ios); - spio_ltimer_start(ios->io_fstats->tot_timer_name); + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper ios_fstats_tot_timer(ios->io_fstats->tot_timer_name); /* User must provide these. */ if (!hint || !hintval) { - spio_ltimer_stop(ios->io_fstats->tot_timer_name); return pio_err(ios, NULL, PIO_EINVAL, __FILE__, __LINE__, "Setting PIO hints failed. Invalid pointers (NULL) to hint (%s) or hintval (%s) provided", (hint) ? "not NULL" : "NULL", (hintval) ? "not NULL" : "NULL"); } @@ -1714,7 +1671,6 @@ int PIOc_set_hint_impl(int iosysid, const char *hint, const char *hintval) if ((mpierr = MPI_Info_create(&ios->info))) { LOG((1, "ERROR: Setting PIO hints failed. Creating MPI Info object failed (mpierr = %d)", mpierr)); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); return check_mpi(ios, NULL, mpierr, __FILE__, __LINE__); } @@ -1723,11 +1679,9 @@ int PIOc_set_hint_impl(int iosysid, const char *hint, const char *hintval) if ((mpierr = MPI_Info_set(ios->info, hint, hintval))) { LOG((1, "ERROR: Setting PIO hints failed. Settnig MPI hints using info object failed (mpierr = %d)", mpierr)); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); return check_mpi(ios, NULL, mpierr, __FILE__, __LINE__); } - spio_ltimer_stop(ios->io_fstats->tot_timer_name); return PIO_NOERR; } @@ -1750,14 +1704,13 @@ int PIOc_finalize_impl(int iosysid) char gptl_log_fname[PIO_MAX_NAME]; #endif - GPTLstart("PIO:PIOc_finalize"); + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("PIO:PIOc_finalize"); LOG((1, "PIOc_finalize iosysid = %d MPI_COMM_NULL = %d", iosysid, MPI_COMM_NULL)); /* Find the IO system information. */ if (!(ios = pio_get_iosystem_from_id(iosysid))) { - GPTLstop("PIO:PIOc_finalize"); return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, "PIO Finalize failed. Invalid iosystem id (%d) provided", iosysid); } @@ -1777,8 +1730,6 @@ int PIOc_finalize_impl(int iosysid) PIO_SEND_ASYNC_MSG(ios, msg, &ierr, iosysid); if(ierr != PIO_NOERR) { - GPTLstop("PIO:PIOc_finalize"); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); return pio_err(ios, NULL, ierr, __FILE__, __LINE__, "PIO Finalize failed on iosytem (%d). Error sending async msg for PIO_MSG_FINALIZE", iosysid); } @@ -1815,7 +1766,6 @@ int PIOc_finalize_impl(int iosysid) /* Learn the number of open IO systems. */ if ((ierr = pio_num_iosystem(&niosysid))) { - GPTLstop("PIO:PIOc_finalize"); return pio_err(ios, NULL, ierr, __FILE__, __LINE__, "PIO Finalize failed on iosystem (%d). Unable to get the number of open I/O systems", iosysid); } @@ -1859,7 +1809,6 @@ int PIOc_finalize_impl(int iosysid) adios2_error adiosErr = adios2_finalize(ios->adiosH); if (adiosErr != adios2_error_none) { - GPTLstop("PIO:PIOc_finalize"); return pio_err(ios, NULL, PIO_EADIOS2ERR, __FILE__, __LINE__, "Finalizing ADIOS failed (adios2_error=%s) on iosystem (%d)", convert_adios2_error_to_string(adiosErr), iosysid); } @@ -1871,7 +1820,6 @@ int PIOc_finalize_impl(int iosysid) adios2_error adiosErr = adios2_finalize(ios->adios_readerH); if (adiosErr != adios2_error_none) { - GPTLstop("PIO:PIOc_finalize"); return pio_err(ios, NULL, PIO_EADIOS2ERR, __FILE__, __LINE__, "Finalizing ADIOS (for read) failed (adios2_error=%s) on iosystem (%d)", convert_adios2_error_to_string(adiosErr), iosysid); } @@ -1895,7 +1843,6 @@ int PIOc_finalize_impl(int iosysid) pio_finalize_logging(); LOG((2, "PIOc_finalize completed successfully")); - GPTLstop("PIO:PIOc_finalize"); #ifdef TIMING #ifdef TIMING_INTERNAL if(spio_gptl_was_init_in_lib()){ @@ -2113,13 +2060,12 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li pio_init_gptl(); #endif #endif - GPTLstart("PIO:PIOc_init_async"); + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("PIO:PIOc_init_async"); /* Check input parameters. */ if (num_io_procs < 1 || component_count < 1 || !num_procs_per_comp || !iosysidp || (rearranger != PIO_REARR_BOX && rearranger != PIO_REARR_SUBSET)) { - GPTLstop("PIO:PIOc_init_async"); return pio_err(NULL, NULL, PIO_EINVAL, __FILE__, __LINE__, "PIO Init (async) failed. Invalid arguments provided, num_io_procs=%d (expected >= 1), component_count=%d (expected >= 1), num_procs_per_comp is %s (expected not NULL), iosysidp is %s (expected not NULL), rearranger=%s (expected PIO_REARR_BOX or PIO_REARR_SUBSET)", num_io_procs, component_count, (num_procs_per_comp) ? "not NULL" : "NULL", (iosysidp) ? "not NULL" : "NULL", (rearranger == PIO_REARR_BOX) ? "PIO_REARR_BOX" : ((rearranger == PIO_REARR_SUBSET) ? "PIO_REARR_SUBSET" : "UNKNOWN REARRANGER")); } @@ -2127,7 +2073,6 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li /* Temporarily limit to one computational component. */ if (component_count > 1) { - GPTLstop("PIO:PIOc_init_async"); return pio_err(NULL, NULL, PIO_EINVAL, __FILE__, __LINE__, "PIO Init (async) failed. Currently only one computational component is supported, and %d computation components were specified", component_count); } @@ -2145,7 +2090,6 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li ret = mtimer_init(PIO_MICRO_MPI_WTIME_ROOT); if(ret != PIO_NOERR) { - GPTLstop("PIO:PIOc_init_async"); return pio_err(NULL, NULL, PIO_EINTERNAL, __FILE__, __LINE__, "PIO Init (async) failed. Initializing micro timers failed"); } @@ -2157,7 +2101,6 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li LOG((3, "calculating processors for IO component")); if (!(io_proc_list_buf = (int *) malloc(num_io_procs * sizeof(int)))) { - GPTLstop("PIO:PIOc_init_async"); return pio_err(NULL, NULL, PIO_ENOMEM, __FILE__, __LINE__, "PIO Init (async) failed. Out of memory."); } @@ -2180,7 +2123,6 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li /* Allocate space for array of arrays. */ if (!(proc_list_buf = (int **)malloc((component_count) * sizeof(int *)))) { - GPTLstop("PIO:PIOc_init_async"); return pio_err(NULL, NULL, PIO_ENOMEM, __FILE__, __LINE__, "PIO Init (async) failed. Out of memory"); } @@ -2193,7 +2135,6 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li /* Allocate space for each array. */ if (!(proc_list_buf[cmp] = (int *)malloc(num_procs_per_comp[cmp] * sizeof(int)))) { - GPTLstop("PIO:PIOc_init_async"); return pio_err(NULL, NULL, PIO_ENOMEM, __FILE__, __LINE__, "PIO Init (async) failed. Out of memory"); } @@ -2214,7 +2155,6 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li /* Get rank of this task in world. */ if ((ret = MPI_Comm_rank(world, &my_rank))) { - GPTLstop("PIO:PIOc_init_async"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } @@ -2232,7 +2172,6 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li { if (!(iosys[cmp1] = (iosystem_desc_t *)calloc(1, sizeof(iosystem_desc_t)))) { - GPTLstop("PIO:PIOc_init_async"); return pio_err(NULL, NULL, PIO_ENOMEM, __FILE__, __LINE__, "PIO Init (async) failed. Out of memory"); } @@ -2249,7 +2188,6 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li if ((ret = MPI_Comm_group(world, &world_group))) { LOG((1, "ERROR: PIO Init (async failed). Getting MPI group associated with world failed")); - GPTLstop("PIO:PIOc_init_async"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } LOG((3, "world group created\n")); @@ -2271,7 +2209,6 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li if ((ret = MPI_Group_incl(world_group, num_io_procs, my_io_proc_list, &io_group))) { LOG((1, "ERROR: PIO Init (async) failed. Creating MPI group for IO component failed")); - GPTLstop("PIO:PIOc_init_async"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } LOG((3, "created IO group - io_group = %d MPI_GROUP_EMPTY = %d", io_group, MPI_GROUP_EMPTY)); @@ -2280,7 +2217,6 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li if ((ret = MPI_Comm_create(world, io_group, &io_comm))) { LOG((1, "ERROR: PIO Init (async) failed. Creating shared MPI Comm for IO component failed")); - GPTLstop("PIO:PIOc_init_async"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } LOG((3, "created io comm io_comm = %d", io_comm)); @@ -2292,7 +2228,6 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li if (in_io) if ((mpierr = MPI_Comm_dup(io_comm, user_io_comm))) { - GPTLstop("PIO:PIOc_init_async"); return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); } } @@ -2304,7 +2239,6 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li LOG((3, "about to get io rank")); if ((ret = MPI_Comm_rank(io_comm, &io_rank))) { - GPTLstop("PIO:PIOc_init_async"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } iomaster = !io_rank ? MPI_ROOT : MPI_PROC_NULL; @@ -2357,7 +2291,6 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li if ((ret = MPI_Group_incl(world_group, num_procs_per_comp[cmp], my_proc_list[cmp], &group[cmp]))) { - GPTLstop("PIO:PIOc_init_async"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } LOG((3, "created component MPI group - group[%d] = %d", cmp, group[cmp])); @@ -2384,7 +2317,6 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li /* Allocate space for computation task ranks. */ if (!(my_iosys->compranks = (int *)calloc(my_iosys->num_comptasks, sizeof(int)))) { - GPTLstop("PIO:PIOc_init_async"); return pio_err(NULL, NULL, PIO_ENOMEM, __FILE__, __LINE__, "PIO Init (async) failed. Out of memory"); } @@ -2397,7 +2329,6 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li if ((ret = MPI_Group_incl(world_group, nprocs_union, proc_list_union, &union_group[cmp]))) { LOG((1, "ERROR: PIO Init (async) failed. Creating union group failed")); - GPTLstop("PIO:PIOc_init_async"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } LOG((3, "created union MPI_group - union_group[%d] = %d with %d procs", cmp, @@ -2425,7 +2356,6 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li LOG((3, "creating intracomm cmp = %d from group[%d] = %d", cmp, cmp, group[cmp])); if ((ret = MPI_Comm_create(world, group[cmp], &my_iosys->comp_comm))) { - GPTLstop("PIO:PIOc_init_async"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } @@ -2435,14 +2365,12 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li if (user_comp_comm) if ((mpierr = MPI_Comm_dup(my_iosys->comp_comm, &user_comp_comm[cmp]))) { - GPTLstop("PIO:PIOc_init_async"); return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); } /* Get the rank in this comp comm. */ if ((ret = MPI_Comm_rank(my_iosys->comp_comm, &my_iosys->comp_rank))) { - GPTLstop("PIO:PIOc_init_async"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } @@ -2463,7 +2391,6 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li LOG((3, "making a dup of io_comm = %d io_rank = %d", io_comm, io_rank)); if ((ret = MPI_Comm_dup(io_comm, &my_iosys->io_comm))) { - GPTLstop("PIO:PIOc_init_async"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } LOG((3, "dup of io_comm = %d io_rank = %d", my_iosys->io_comm, io_rank)); @@ -2477,7 +2404,6 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li * for IO. */ if (!(my_iosys->ioranks = (int *) calloc(my_iosys->num_iotasks, sizeof(int)))) { - GPTLstop("PIO:PIOc_init_async"); return pio_err(NULL, NULL, PIO_ENOMEM, __FILE__, __LINE__, "PIO Init (async) failed. Out of memory"); } @@ -2494,13 +2420,11 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li * and one of the computation components. */ if ((ret = MPI_Comm_create(world, union_group[cmp], &my_iosys->union_comm))) { - GPTLstop("PIO:PIOc_init_async"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } if ((ret = MPI_Comm_rank(my_iosys->union_comm, &my_iosys->union_rank))) { - GPTLstop("PIO:PIOc_init_async"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } @@ -2518,7 +2442,6 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li if ((ret = MPI_Intercomm_create(my_iosys->io_comm, 0, my_iosys->union_comm, my_proc_list[cmp][0], 0, &my_iosys->intercomm))) { - GPTLstop("PIO:PIOc_init_async"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } } @@ -2530,7 +2453,6 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li if ((ret = MPI_Intercomm_create(my_iosys->comp_comm, 0, my_iosys->union_comm, my_io_proc_list[0], 0, &my_iosys->intercomm))) { - GPTLstop("PIO:PIOc_init_async"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } } @@ -2561,7 +2483,6 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li ret = init_async_msgs_sign(); if(ret != PIO_NOERR) { - GPTLstop("PIO:PIOc_init_async"); return pio_err(NULL, NULL, ret, __FILE__, __LINE__, "PIO Init (async) failed. Initializing async message signatures failed"); } @@ -2575,7 +2496,6 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li io_rank, component_count)); if ((ret = pio_msg_handler2(io_rank, component_count, iosys, io_comm))) { - GPTLstop("PIO:PIOc_init_async"); return pio_err(NULL, NULL, ret, __FILE__, __LINE__, "Error processing I/O message"); } @@ -2589,7 +2509,6 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li if (in_io) if ((mpierr = MPI_Comm_free(&io_comm))) { - GPTLstop("PIO:PIOc_init_async"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } @@ -2603,7 +2522,6 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li /* Free MPI groups. */ if ((ret = MPI_Group_free(&io_group))) { - GPTLstop("PIO:PIOc_init_async"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } @@ -2611,24 +2529,20 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li { if ((ret = MPI_Group_free(&group[cmp]))) { - GPTLstop("PIO:PIOc_init_async"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } if ((ret = MPI_Group_free(&union_group[cmp]))) { - GPTLstop("PIO:PIOc_init_async"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } } if ((ret = MPI_Group_free(&world_group))) { - GPTLstop("PIO:PIOc_init_async"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } LOG((2, "successfully done with PIO_Init_Async")); - GPTLstop("PIO:PIOc_init_async"); return PIO_NOERR; } @@ -2687,13 +2601,12 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, pio_init_gptl(); #endif #endif - GPTLstart("PIO:PIOc_init_intercomm"); + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("PIO:PIOc_init_intercomm"); assert((component_count > 0) && ucomp_comms && iosysidps); if((component_count <= 0) || (ucomp_comms == NULL) || ((rearranger != PIO_REARR_BOX) && (rearranger != PIO_REARR_SUBSET)) || (iosysidps == NULL)) { - GPTLstop("PIO:PIOc_init_intercomm"); return pio_err(NULL, NULL, PIO_EINVAL, __FILE__, __LINE__, "PIO Init (async) failed. Invalid arguments provided, component_count=%d (expected > 0), ucomp_comms is %s (expected not NULL), rearranger=%s (expected PIO_REARR_BOX or PIO_REARR_SUBSET), iosysidps is %s (expected not NULL)", component_count, (ucomp_comms) ? "not NULL" : "NULL", (rearranger == PIO_REARR_BOX) ? "PIO_REARR_BOX" : ((rearranger == PIO_REARR_SUBSET) ? "PIO_REARR_SUBSET" : "UNKNOWN REARRANGER"), (iosysidps) ? "not NULL" : "NULL"); } @@ -2710,7 +2623,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, ret = mtimer_init(PIO_MICRO_MPI_WTIME_ROOT); if(ret != PIO_NOERR) { - GPTLstop("PIO:PIOc_init_intercomm"); return pio_err(NULL, NULL, PIO_EINTERNAL, __FILE__, __LINE__, "PIO Init (async) failed. Initializing micro timers failed"); } @@ -2729,7 +2641,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, ret = MPI_Comm_dup(ucomp_comms[i], &(comp_comms[i])); if(ret != MPI_SUCCESS) { - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } } @@ -2737,7 +2648,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, } else { - GPTLstop("PIO:PIOc_init_intercomm"); return pio_err(NULL, NULL, PIO_ENOMEM, __FILE__, __LINE__, "PIO Init (async) failed. Out of memory allocating %lld bytes for storing MPI communicators for the different asynchronous components", (unsigned long long) (component_count * sizeof(MPI_Comm))); } @@ -2751,7 +2661,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, iosys[i] = (iosystem_desc_t *) calloc(1, sizeof(iosystem_desc_t)); if(!iosys[i]) { - GPTLstop("PIO:PIOc_init_intercomm"); return pio_err(NULL, NULL, PIO_ENOMEM, __FILE__, __LINE__, "PIO init (async) failed. Out of memory allocating %lld bytes for storing I/O system descriptor for component %d", (unsigned long long) sizeof(iosystem_desc_t), i); } @@ -2823,7 +2732,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, if(ret != MPI_SUCCESS) { LOG((1, "PIO Init (async) failed. Duping user I/O comm failed")); - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } } @@ -2855,14 +2763,12 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, ret = MPI_Comm_rank(io_comm, &(iosys[i]->io_rank)); if(ret != MPI_SUCCESS) { - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } ret = MPI_Comm_size(io_comm, &(iosys[i]->num_iotasks)); if(ret != MPI_SUCCESS) { - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } @@ -2873,7 +2779,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, ret = MPI_Comm_rank(peer_comm, &io_grank); if(ret != MPI_SUCCESS) { - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } /* Find the io leader for intercomm */ @@ -2893,7 +2798,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, if(ret != MPI_SUCCESS) { LOG((1, "PIO Init (async) failed. Finding I/O leader failed")); - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } @@ -2903,7 +2807,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, if(ret != MPI_SUCCESS) { LOG((1, "PIO Init (async) failed. Finding Comp leader failed")); - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } @@ -2912,7 +2815,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, if(ret != MPI_SUCCESS) { LOG((1, "PIO Init (async) failed. Creating an intercomm between I/O comm and Comp comms failed")); - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } @@ -2926,14 +2828,12 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, if(ret != MPI_SUCCESS) { LOG((1, "PIO Init (async) failed. Merging intercomm between I/O comm and Comp comms failed")); - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } ret = MPI_Comm_size(iosys[i]->union_comm, &(iosys[i]->num_uniontasks)); if(ret != MPI_SUCCESS) { - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } @@ -2941,7 +2841,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, ret = MPI_Comm_rank(iosys[i]->union_comm, &(iosys[i]->union_rank)); if(ret != MPI_SUCCESS) { - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } @@ -2956,7 +2855,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, iosys[i]->ioranks = (int *)malloc(iosys[i]->num_iotasks * sizeof(int)); if(!(iosys[i]->ioranks)) { - GPTLstop("PIO:PIOc_init_intercomm"); return pio_err(NULL, NULL, PIO_ENOMEM, __FILE__, __LINE__, "PIO Init (async) failed. Out of memory allocating %lld bytes to store ranks of I/O processes for component %d", (unsigned long long) (iosys[i]->num_iotasks * sizeof(int)), i); } @@ -2968,7 +2866,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, iosys[i]->compranks = (int *)malloc(iosys[i]->num_comptasks * sizeof(int)); if(!(iosys[i]->compranks)) { - GPTLstop("PIO:PIOc_init_intercomm"); return pio_err(NULL, NULL, PIO_ENOMEM, __FILE__, __LINE__, "PIO Init (async) failed. Out of memory allocating %lld bytes to store ranks of compute processes for component %d", (unsigned long long) (iosys[i]->num_comptasks * sizeof(int)), i); } @@ -2982,7 +2879,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, if(ret != MPI_SUCCESS) { LOG((1, "PIO Init (async) failed. Unable to get process group for the union comm")); - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } @@ -2990,7 +2886,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, if(ret != MPI_SUCCESS) { LOG((1, "PIO Init (async) failed. Unable to find procs in comp group")); - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } @@ -2998,7 +2893,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, if(ret != MPI_SUCCESS) { LOG((1, "PIO Init (async) failed. Unable to find procs in I/O group")); - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } @@ -3025,20 +2919,17 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, ret = MPI_Comm_rank(comp_comms[i], &(iosys[i]->comp_rank)); if(ret != MPI_SUCCESS) { - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } ret = MPI_Comm_size(comp_comms[i], &(iosys[i]->num_comptasks)); if(ret != MPI_SUCCESS) { - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } ret = MPI_Comm_rank(peer_comm, &comp_grank); if(ret != MPI_SUCCESS) { - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } @@ -3059,7 +2950,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, if(ret != MPI_SUCCESS) { LOG((1, "PIO Init (async) failed. Finding I/O leader failed")); - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } @@ -3069,7 +2959,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, if(ret != MPI_SUCCESS) { LOG((1, "PIO Init (async) failed. Finding Comp leader failed")); - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } @@ -3080,7 +2969,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, if(ret != MPI_SUCCESS) { LOG((1, "PIO Init (async) failed. Creating intercomm between I/O comm and Comp comms failed")); - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } @@ -3094,21 +2982,18 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, if(ret != MPI_SUCCESS) { LOG((1, "PIO Init (async) failed. Merging intercomm between I/O comm and Comp comms failed")); - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } ret = MPI_Comm_size(iosys[i]->union_comm, &(iosys[i]->num_uniontasks)); if(ret != MPI_SUCCESS) { - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } ret = MPI_Comm_rank(iosys[i]->union_comm, &(iosys[i]->union_rank)); if(ret != MPI_SUCCESS) { - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } @@ -3123,7 +3008,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, iosys[i]->ioranks = (int *)malloc(iosys[i]->num_iotasks * sizeof(int)); if(!(iosys[i]->ioranks)) { - GPTLstop("PIO:PIOc_init_intercomm"); return pio_err(NULL, NULL, PIO_ENOMEM, __FILE__, __LINE__, "PIO Init (async) failed. Out of memory allocating %lld bytes to store ranks of I/O processes for component %d", (unsigned long long) (iosys[i]->num_iotasks * sizeof(int)), i); } @@ -3135,7 +3019,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, iosys[i]->compranks = (int *)malloc(iosys[i]->num_comptasks * sizeof(int)); if(!(iosys[i]->compranks)) { - GPTLstop("PIO:PIOc_init_intercomm"); return pio_err(NULL, NULL, PIO_ENOMEM, __FILE__, __LINE__, "PIO Init (async) failed. Out of memory allocating %lld bytes to store ranks of compute processes for component %d", (unsigned long long) (iosys[i]->num_comptasks * sizeof(int)), i); } @@ -3149,7 +3032,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, if(ret != MPI_SUCCESS) { LOG((1, "PIO Init (async) failed. Finding MPI process group for union comm failed")); - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } @@ -3157,7 +3039,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, if(ret != MPI_SUCCESS) { LOG((1, "PIO Init (async) failed. Finding MPI processes in comp group failed")); - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } @@ -3165,7 +3046,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, if(ret != MPI_SUCCESS) { LOG((1, "PIO Init (async) failed. Finding MPI processes in io group failed")); - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } @@ -3204,7 +3084,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, ret = init_async_msgs_sign(); if(ret != PIO_NOERR) { - GPTLstop("PIO:PIOc_init_intercomm"); return pio_err(NULL, NULL, ret, __FILE__, __LINE__, "PIO Init (async) failed. Initializing asynchronous message signatures failed"); } @@ -3228,7 +3107,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, ret = create_async_service_msg_comm(uio_comm, &msg_comm); if(ret != PIO_NOERR) { - GPTLstop("PIO:PIOc_init_intercomm"); return pio_err(NULL, NULL, ret, __FILE__, __LINE__, "PIO Init (async) failed. Creating an MPI comm for asynchronous messages failed"); } @@ -3236,7 +3114,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, ret = MPI_Comm_rank(msg_comm, &rank); if(ret != MPI_SUCCESS) { - GPTLstop("PIO:PIOc_init_intercomm"); return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } @@ -3245,7 +3122,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, ret = pio_msg_handler2(rank, component_count, iosys, msg_comm); if(ret != PIO_NOERR) { - GPTLstop("PIO:PIOc_init_intercomm"); return pio_err(NULL, NULL, ret, __FILE__, __LINE__, "PIO Init (async) failed. Error processing asynchronous messages"); LOG((2, "Returned from pio_msg_handler2(), Msg handler failed, ret = %d", ret)); @@ -3253,7 +3129,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, LOG((2, "Returned from pio_msg_handler2() ret = %d", ret)); } - GPTLstop("PIO:PIOc_init_intercomm"); return PIO_NOERR; } From 1560623b16d4712b06a066c2de5199bd4338e150 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 19 Nov 2024 17:48:17 -0600 Subject: [PATCH 015/194] Code reformatting initdecomp func Code reformatting (starting braces on same line, no spaces btw keyword and starting of braces, 2 space tab) the PIO_initdecomp_impl() function --- src/clib/pioc.cpp | 309 +++++++++++++++++++++------------------------- 1 file changed, 144 insertions(+), 165 deletions(-) diff --git a/src/clib/pioc.cpp b/src/clib/pioc.cpp index 022fce1a97..bdc9ac5a40 100644 --- a/src/clib/pioc.cpp +++ b/src/clib/pioc.cpp @@ -698,105 +698,99 @@ int PIOc_InitDecomp_impl(int iosysid, int pio_type, int ndims, const int *gdimle iosysid, pio_type, ndims, maplen)); /* Get IO system info. */ - if (!(ios = pio_get_iosystem_from_id(iosysid))) - { - return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, - "Initializing the PIO decomposition failed. Invalid io system id (%d) provided. Could not find an iosystem associated with the id", iosysid); + if(!(ios = pio_get_iosystem_from_id(iosysid))){ + return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, + "Initializing the PIO decomposition failed. Invalid io system id (%d) provided. Could not find an iosystem associated with the id", iosysid); } assert(ios); SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper ios_fstats_tot_timer(ios->io_fstats->tot_timer_name); /* Caller must provide these. */ - if (!gdimlen || !compmap || !ioidp) - { - return pio_err(ios, NULL, PIO_EINVAL, __FILE__, __LINE__, - "Initializing the PIO decomposition failed. Invalid pointers (NULL) to gdimlen(%s) or compmap(%s) or ioidp (%s) provided", (gdimlen) ? "not NULL" : "NULL", (compmap) ? "not NULL" : "NULL", (ioidp) ? "not NULL" : "NULL"); + if(!gdimlen || !compmap || !ioidp){ + return pio_err(ios, NULL, PIO_EINVAL, __FILE__, __LINE__, + "Initializing the PIO decomposition failed. Invalid pointers (NULL) to gdimlen(%s) or compmap(%s) or ioidp (%s) provided", (gdimlen) ? "not NULL" : "NULL", (compmap) ? "not NULL" : "NULL", (ioidp) ? "not NULL" : "NULL"); } /* Check the dim lengths. */ - for (int i = 0; i < ndims; i++) - if (gdimlen[i] <= 0) - { - return pio_err(ios, NULL, PIO_EINVAL, __FILE__, __LINE__, - "Initializing the PIO decomposition failed. Invalid value for global dimension lengths provided. The global length of dimension %d is provided as %d (expected > 0)", i, gdimlen[i]); - } + for(int i = 0; i < ndims; i++){ + if(gdimlen[i] <= 0){ + return pio_err(ios, NULL, PIO_EINVAL, __FILE__, __LINE__, + "Initializing the PIO decomposition failed. Invalid value for global dimension lengths provided. The global length of dimension %d is provided as %d (expected > 0)", i, gdimlen[i]); + } + } /* If async is in use, and this is not an IO task, bcast the parameters. */ - if (ios->async) - { - int msg = PIO_MSG_INITDECOMP_DOF; /* Message for async notification. */ - char rearranger_present = rearranger ? true : false; - int amsg_rearranger = (rearranger) ? (*rearranger) : 0; - char iostart_present = iostart ? true : false; - char iocount_present = iocount ? true : false; - PIO_Offset *amsg_iostart = NULL, *amsg_iocount = NULL; - - if(!iostart_present) - { - amsg_iostart = (PIO_Offset *) calloc(ndims, sizeof(PIO_Offset)); - } - if(!iocount_present) - { - amsg_iocount = (PIO_Offset *) calloc(ndims, sizeof(PIO_Offset)); - } - if(!amsg_iostart || !amsg_iocount) - { - return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, - "Initializing the PIO decomposition failed. Out of memory allocating %lld bytes for start array and %lld bytes for count array for sending asynchronous message, PIO_MSG_INITDECOMP_DOF, on iosystem (iosysid=%d)", (unsigned long long) (ndims * sizeof(PIO_Offset)), (unsigned long long) (ndims * sizeof(PIO_Offset)), ios->iosysid); - } + if(ios->async){ + int msg = PIO_MSG_INITDECOMP_DOF; /* Message for async notification. */ + char rearranger_present = rearranger ? true : false; + int amsg_rearranger = (rearranger) ? (*rearranger) : 0; + char iostart_present = iostart ? true : false; + char iocount_present = iocount ? true : false; + PIO_Offset *amsg_iostart = NULL, *amsg_iocount = NULL; + + if(!iostart_present){ + amsg_iostart = (PIO_Offset *) calloc(ndims, sizeof(PIO_Offset)); + } + if(!iocount_present){ + amsg_iocount = (PIO_Offset *) calloc(ndims, sizeof(PIO_Offset)); + } + if(!amsg_iostart || !amsg_iocount){ + return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, + "Initializing the PIO decomposition failed. Out of memory allocating %lld bytes for start array and %lld bytes for count array for sending asynchronous message, PIO_MSG_INITDECOMP_DOF, on iosystem (iosysid=%d)", (unsigned long long) (ndims * sizeof(PIO_Offset)), (unsigned long long) (ndims * sizeof(PIO_Offset)), ios->iosysid); + } - PIO_SEND_ASYNC_MSG(ios, msg, &ierr, iosysid, pio_type, ndims, - gdimlen, maplen, compmap, rearranger_present, amsg_rearranger, - iostart_present, ndims, - (iostart_present) ? iostart : amsg_iostart, - iocount_present, ndims, - (iocount_present) ? iocount : amsg_iocount); + PIO_SEND_ASYNC_MSG(ios, msg, &ierr, iosysid, pio_type, ndims, + gdimlen, maplen, compmap, rearranger_present, amsg_rearranger, + iostart_present, ndims, + (iostart_present) ? iostart : amsg_iostart, + iocount_present, ndims, + (iocount_present) ? iocount : amsg_iocount); - if(!iostart_present) - { - free(amsg_iostart); - } - if(!iocount_present) - { - free(amsg_iocount); - } + if(!iostart_present){ + free(amsg_iostart); + } + if(!iocount_present){ + free(amsg_iocount); + } } /* Allocate space for the iodesc info. This also allocates the * first region and copies the rearranger opts into this * iodesc. */ - if ((ierr = malloc_iodesc(ios, pio_type, ndims, &iodesc))) - { - return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Initializing the PIO decomposition failed. Out of memory allocating memory for I/O descriptor"); + if((ierr = malloc_iodesc(ios, pio_type, ndims, &iodesc))){ + return pio_err(ios, NULL, ierr, __FILE__, __LINE__, + "Initializing the PIO decomposition failed. Out of memory allocating memory for I/O descriptor"); } /* Remember the maplen. */ iodesc->maplen = maplen; /* Remember the map. */ - if (!(iodesc->map = (PIO_Offset *) malloc(sizeof(PIO_Offset) * maplen))) - { - return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, - "Initializing the PIO decomposition failed. Out of memory allocating %lld bytes to store I/O decomposition map", (unsigned long long) (sizeof(PIO_Offset) * maplen)); + if(!(iodesc->map = (PIO_Offset *) malloc(sizeof(PIO_Offset) * maplen))){ + return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, + "Initializing the PIO decomposition failed. Out of memory allocating %lld bytes to store I/O decomposition map", (unsigned long long) (sizeof(PIO_Offset) * maplen)); + } + for(int m = 0; m < maplen; m++){ + iodesc->map[m] = compmap[m]; } - for (int m = 0; m < maplen; m++) - iodesc->map[m] = compmap[m]; /* Remember the dim sizes. */ - if (!(iodesc->dimlen = (int *)malloc(sizeof(int) * ndims))) - { - return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, - "Initializing the PIO decomposition failed. Out of memory allocating %lld bytes for dimension sizes in the I/O decomposition map", (unsigned long long) (sizeof(int) * ndims)); + if(!(iodesc->dimlen = (int *)malloc(sizeof(int) * ndims))){ + return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, + "Initializing the PIO decomposition failed. Out of memory allocating %lld bytes for dimension sizes in the I/O decomposition map", (unsigned long long) (sizeof(int) * ndims)); + } + + for(int d = 0; d < ndims; d++){ + iodesc->dimlen[d] = gdimlen[d]; } - for (int d = 0; d < ndims; d++) - iodesc->dimlen[d] = gdimlen[d]; /* Set the rearranger. */ - if (!rearranger) - iodesc->rearranger = ios->default_rearranger; - else - iodesc->rearranger = *rearranger; + if(!rearranger){ + iodesc->rearranger = ios->default_rearranger; + } + else{ + iodesc->rearranger = *rearranger; + } LOG((2, "iodesc->rearranger = %d", iodesc->rearranger)); /* In scenarios involving ultra-high resolution E3SM/SCREAM cases, @@ -816,79 +810,67 @@ int PIOc_InitDecomp_impl(int iosysid, int pio_type, int ndims, const int *gdimle * potentially negating the benefits of reduced initialization time * associated with this approach. */ - if (iodesc->rearranger == PIO_REARR_ANY) - { - iodesc->rearranger = spio_get_opt_pio_rearr(ios, maplen); + if(iodesc->rearranger == PIO_REARR_ANY){ + iodesc->rearranger = spio_get_opt_pio_rearr(ios, maplen); } /* Is this the subset rearranger? */ - if (iodesc->rearranger == PIO_REARR_SUBSET) - { - iodesc->num_aiotasks = ios->num_iotasks; - LOG((2, "creating subset rearranger iodesc->num_aiotasks = %d", - iodesc->num_aiotasks)); - if ((ierr = subset_rearrange_create(ios, maplen, (PIO_Offset *)compmap, gdimlen, - ndims, iodesc))) - { + if(iodesc->rearranger == PIO_REARR_SUBSET){ + iodesc->num_aiotasks = ios->num_iotasks; + LOG((2, "creating subset rearranger iodesc->num_aiotasks = %d", + iodesc->num_aiotasks)); + if((ierr = subset_rearrange_create(ios, maplen, (PIO_Offset *)compmap, gdimlen, + ndims, iodesc))){ + return pio_err(ios, NULL, ierr, __FILE__, __LINE__, + "Initializing the PIO decomposition failed. Error creating the SUBSET rearranger"); + } + } + else{ /* box rearranger */ + if(ios->ioproc){ + /* Unless the user specifies the start and count for each + * IO task compute it. */ + if(iostart && iocount){ + LOG((3, "iostart and iocount provided")); + for(int i = 0; i < ndims; i++){ + iodesc->firstregion->start[i] = iostart[i]; + iodesc->firstregion->count[i] = iocount[i]; + } + iodesc->num_aiotasks = ios->num_iotasks; + } + else{ + /* Compute start and count values for each io task. */ + LOG((2, "about to call CalcStartandCount pio_type = %d ndims = %d", pio_type, ndims)); + if((ierr = CalcStartandCount(pio_type, ndims, gdimlen, ios->num_iotasks, + ios->io_rank, iodesc->firstregion->start, + iodesc->firstregion->count, &iodesc->num_aiotasks))){ return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Initializing the PIO decomposition failed. Error creating the SUBSET rearranger"); + "Initializing the PIO decomposition failed. Internal error calculating start/count for the decomposition"); + } } - } - else /* box rearranger */ - { - if (ios->ioproc) - { - /* Unless the user specifies the start and count for each - * IO task compute it. */ - if (iostart && iocount) - { - LOG((3, "iostart and iocount provided")); - for (int i = 0; i < ndims; i++) - { - iodesc->firstregion->start[i] = iostart[i]; - iodesc->firstregion->count[i] = iocount[i]; - } - iodesc->num_aiotasks = ios->num_iotasks; - } - else - { - /* Compute start and count values for each io task. */ - LOG((2, "about to call CalcStartandCount pio_type = %d ndims = %d", pio_type, ndims)); - if ((ierr = CalcStartandCount(pio_type, ndims, gdimlen, ios->num_iotasks, - ios->io_rank, iodesc->firstregion->start, - iodesc->firstregion->count, &iodesc->num_aiotasks))) - { - return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Initializing the PIO decomposition failed. Internal error calculating start/count for the decomposition"); - } - } - /* Compute the max io buffer size needed for an iodesc. */ - if ((ierr = compute_maxIObuffersize(ios->io_comm, iodesc))) - { - return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Initializing the PIO decomposition failed. Internal error computing max io buffer size needed for the decomposition"); - } - LOG((3, "compute_maxIObuffersize called iodesc->maxiobuflen = %d", - iodesc->maxiobuflen)); + /* Compute the max io buffer size needed for an iodesc. */ + if((ierr = compute_maxIObuffersize(ios->io_comm, iodesc))){ + return pio_err(ios, NULL, ierr, __FILE__, __LINE__, + "Initializing the PIO decomposition failed. Internal error computing max io buffer size needed for the decomposition"); } + LOG((3, "compute_maxIObuffersize called iodesc->maxiobuflen = %d", iodesc->maxiobuflen)); + } - /* Depending on array size and io-blocksize the actual number - * of io tasks used may vary. */ - if ((mpierr = MPI_Bcast(&(iodesc->num_aiotasks), 1, MPI_INT, ios->ioroot, - ios->my_comm))) - { - return check_mpi(ios, NULL, mpierr, __FILE__, __LINE__); - } - LOG((3, "iodesc->num_aiotasks = %d", iodesc->num_aiotasks)); + /* Depending on array size and io-blocksize the actual number + * of io tasks used may vary. */ + if((mpierr = MPI_Bcast(&(iodesc->num_aiotasks), 1, MPI_INT, ios->ioroot, + ios->my_comm))){ + return check_mpi(ios, NULL, mpierr, __FILE__, __LINE__); + } + LOG((3, "iodesc->num_aiotasks = %d", iodesc->num_aiotasks)); - /* Compute the communications pattern for this decomposition. */ - if (iodesc->rearranger == PIO_REARR_BOX) - if ((ierr = box_rearrange_create(ios, maplen, compmap, gdimlen, ndims, iodesc))) - { - return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Error initializing the PIO decomposition. Error creating the BOX rearranger"); - } + /* Compute the communications pattern for this decomposition. */ + if(iodesc->rearranger == PIO_REARR_BOX){ + if((ierr = box_rearrange_create(ios, maplen, compmap, gdimlen, ndims, iodesc))){ + return pio_err(ios, NULL, ierr, __FILE__, __LINE__, + "Error initializing the PIO decomposition. Error creating the BOX rearranger"); + } + } } /* Add this IO description to the list. */ @@ -896,28 +878,25 @@ int PIOc_InitDecomp_impl(int iosysid, int pio_type, int ndims, const int *gdimle #ifdef _ADIOS2 comm = ios->union_comm; #endif - if(ios->async) - { - /* For asynchronous I/O service, the iodescs (iodesc ids) need to - * be unique across the union_comm (union of I/O and compute comms) - */ - comm = ios->union_comm; + if(ios->async){ + /* For asynchronous I/O service, the iodescs (iodesc ids) need to + * be unique across the union_comm (union of I/O and compute comms) + */ + comm = ios->union_comm; } *ioidp = pio_add_to_iodesc_list(iodesc, comm); #if PIO_SAVE_DECOMPS - if(pio_save_decomps_regex_match(*ioidp, NULL, NULL)) - { - char filename[PIO_MAX_NAME]; - ierr = pio_create_uniq_str(ios, iodesc, filename, PIO_MAX_NAME, "piodecomp", ".dat"); - if(ierr != PIO_NOERR) - { - return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Initializing the PIO decomposition failed. Creating a unique file name for saving the decomposition failed"); - } - LOG((2, "Saving decomp map to %s", filename)); - PIOc_writemap_impl(filename, *ioidp, ndims, gdimlen, maplen, (PIO_Offset *)compmap, ios->my_comm); - iodesc->is_saved = true; + if(pio_save_decomps_regex_match(*ioidp, NULL, NULL)){ + char filename[PIO_MAX_NAME]; + ierr = pio_create_uniq_str(ios, iodesc, filename, PIO_MAX_NAME, "piodecomp", ".dat"); + if(ierr != PIO_NOERR){ + return pio_err(ios, NULL, ierr, __FILE__, __LINE__, + "Initializing the PIO decomposition failed. Creating a unique file name for saving the decomposition failed"); + } + LOG((2, "Saving decomp map to %s", filename)); + PIOc_writemap_impl(filename, *ioidp, ndims, gdimlen, maplen, (PIO_Offset *)compmap, ios->my_comm); + iodesc->is_saved = true; } #endif @@ -928,22 +907,22 @@ int PIOc_InitDecomp_impl(int iosysid, int pio_type, int ndims, const int *gdimle iodesc->ioid, iodesc->nrecvs, iodesc->ndof, iodesc->ndims, iodesc->num_aiotasks, iodesc->rearranger, iodesc->maxregions, iodesc->needsfill, iodesc->llen, iodesc->maxiobuflen)); - if (ios->ioproc) - { - if (iodesc->rearranger == PIO_REARR_SUBSET) - { - for (int j = 0; j < iodesc->llen; j++) - LOG((3, "rindex[%d] = %lld", j, iodesc->rindex[j])); + if(ios->ioproc){ + if(iodesc->rearranger == PIO_REARR_SUBSET){ + for(int j = 0; j < iodesc->llen; j++){ + LOG((3, "rindex[%d] = %lld", j, iodesc->rindex[j])); + } + } + else{ + int totalrecv = 0; + for(int j = 0; j < iodesc->nrecvs; j++){ + totalrecv += iodesc->rcount[j]; } - else - { - int totalrecv = 0; - for (int j = 0; j < iodesc->nrecvs; j++) - totalrecv += iodesc->rcount[j]; - for (int j = 0; j < totalrecv; j++) - LOG((3, "rindex[%d] = %lld", j, iodesc->rindex[j])); + for(int j = 0; j < totalrecv; j++){ + LOG((3, "rindex[%d] = %lld", j, iodesc->rindex[j])); } + } } #endif /* PIO_ENABLE_LOGGING */ From 3484f8ac58c10478eec43f70808d43791d0f47e8 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 19 Nov 2024 17:56:15 -0600 Subject: [PATCH 016/194] Code reformatting malloc_iodesc func Code reformatting (starting braces on same line, no spaces btw keyword and starting of braces, 2 space tab) the malloc_iodesc function --- src/clib/pioc_support.cpp | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/clib/pioc_support.cpp b/src/clib/pioc_support.cpp index f0cdd3e40d..53fbd8779b 100644 --- a/src/clib/pioc_support.cpp +++ b/src/clib/pioc_support.cpp @@ -1703,24 +1703,21 @@ int malloc_iodesc(iosystem_desc_t *ios, int piotype, int ndims, LOG((1, "malloc_iodesc piotype = %d ndims = %d", piotype, ndims)); /* Get the MPI type corresponding with the PIO type. */ - if ((ret = find_mpi_type(piotype, &mpi_type, NULL))) - { - return pio_err(ios, NULL, ret, __FILE__, __LINE__, - "Internal error while allocating memory for iodesc. Unable to find MPI type corresponding to PIO type (%d)", piotype); + if((ret = find_mpi_type(piotype, &mpi_type, NULL))){ + return pio_err(ios, NULL, ret, __FILE__, __LINE__, + "Internal error while allocating memory for iodesc. Unable to find MPI type corresponding to PIO type (%d)", piotype); } /* What is the size of the pio type? */ - if ((ret = spio_pnetcdf_inq_type(0, piotype, NULL, &type_size))) - { - return pio_err(ios, NULL, ret, __FILE__, __LINE__, - "Internal error while allocating memory for iodesc. Finding the size of PIO type (%d) failed", piotype); + if((ret = spio_pnetcdf_inq_type(0, piotype, NULL, &type_size))){ + return pio_err(ios, NULL, ret, __FILE__, __LINE__, + "Internal error while allocating memory for iodesc. Finding the size of PIO type (%d) failed", piotype); } /* Allocate space for the io_desc_t struct. */ - if (!(*iodesc = (io_desc_t *) calloc(1, sizeof(io_desc_t)))) - { - return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, - "Internal error while allocating memory for iodesc. Out of memory allocating %lld bytes for the I/O descriptor", (unsigned long long) sizeof(io_desc_t)); + if(!(*iodesc = (io_desc_t *) calloc(1, sizeof(io_desc_t)))){ + return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, + "Internal error while allocating memory for iodesc. Out of memory allocating %lld bytes for the I/O descriptor", (unsigned long long) sizeof(io_desc_t)); } /* Remember the pio type and its size. */ @@ -1731,8 +1728,9 @@ int malloc_iodesc(iosystem_desc_t *ios, int piotype, int ndims, (*iodesc)->mpitype = mpi_type; /* Get the size of the type. */ - if ((mpierr = MPI_Type_size((*iodesc)->mpitype, &(*iodesc)->mpitype_size))) - return check_mpi(ios, NULL, mpierr, __FILE__, __LINE__); + if((mpierr = MPI_Type_size((*iodesc)->mpitype, &(*iodesc)->mpitype_size))){ + return check_mpi(ios, NULL, mpierr, __FILE__, __LINE__); + } /* Initialize some values in the struct. */ (*iodesc)->maxregions = 1; @@ -1740,10 +1738,9 @@ int malloc_iodesc(iosystem_desc_t *ios, int piotype, int ndims, (*iodesc)->ndims = ndims; /* Allocate space for, and initialize, the first region. */ - if ((ret = alloc_region2(ios, ndims, &((*iodesc)->firstregion)))) - { - return pio_err(ios, NULL, ret, __FILE__, __LINE__, - "Internal error while allocating memory for iodesc. Allocating memory for 1st region failed. Out of memory allocating memory for I/O region in the I/O descriptor"); + if((ret = alloc_region2(ios, ndims, &((*iodesc)->firstregion)))){ + return pio_err(ios, NULL, ret, __FILE__, __LINE__, + "Internal error while allocating memory for iodesc. Allocating memory for 1st region failed. Out of memory allocating memory for I/O region in the I/O descriptor"); } /* Set the swap memory settings to defaults for this IO system. */ From f900ca33797309a0c84f6cd7eae952ab25f5964c Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 19 Nov 2024 18:05:04 -0600 Subject: [PATCH 017/194] Moving alloc of map/dimlens to malloc_iodesc Moving memory allocation of internal arrays (to store map/dimlens) in the I/O descriptor to the malloc_iodesc() function --- src/clib/pio_internal.h | 2 +- src/clib/pioc.cpp | 16 ++-------------- src/clib/pioc_support.cpp | 16 +++++++++++++++- tests/cunit/test_pioc.cpp | 2 +- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/clib/pio_internal.h b/src/clib/pio_internal.h index 3ea45ca70a..6b1f843cde 100644 --- a/src/clib/pio_internal.h +++ b/src/clib/pio_internal.h @@ -255,7 +255,7 @@ extern "C" { const void *sbuf, void *rbuf, int nvars); /* Allocate and initialize storage for decomposition information. */ - int malloc_iodesc(iosystem_desc_t *ios, int piotype, int ndims, io_desc_t **iodesc); + int malloc_iodesc(iosystem_desc_t *ios, int piotype, int ndims, int maplen, io_desc_t **iodesc); void performance_tune_rearranger(iosystem_desc_t *ios, io_desc_t *iodesc); /* Flush contents of multi-buffer to disk. */ diff --git a/src/clib/pioc.cpp b/src/clib/pioc.cpp index bdc9ac5a40..e366564ab5 100644 --- a/src/clib/pioc.cpp +++ b/src/clib/pioc.cpp @@ -757,29 +757,17 @@ int PIOc_InitDecomp_impl(int iosysid, int pio_type, int ndims, const int *gdimle /* Allocate space for the iodesc info. This also allocates the * first region and copies the rearranger opts into this * iodesc. */ - if((ierr = malloc_iodesc(ios, pio_type, ndims, &iodesc))){ + if((ierr = malloc_iodesc(ios, pio_type, ndims, maplen, &iodesc))){ return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Initializing the PIO decomposition failed. Out of memory allocating memory for I/O descriptor"); + "Initializing the PIO decomposition failed. Out of memory allocating memory for I/O descriptor (ndims = %d, maplen = %d)", ndims, maplen); } - /* Remember the maplen. */ - iodesc->maplen = maplen; - /* Remember the map. */ - if(!(iodesc->map = (PIO_Offset *) malloc(sizeof(PIO_Offset) * maplen))){ - return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, - "Initializing the PIO decomposition failed. Out of memory allocating %lld bytes to store I/O decomposition map", (unsigned long long) (sizeof(PIO_Offset) * maplen)); - } for(int m = 0; m < maplen; m++){ iodesc->map[m] = compmap[m]; } /* Remember the dim sizes. */ - if(!(iodesc->dimlen = (int *)malloc(sizeof(int) * ndims))){ - return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, - "Initializing the PIO decomposition failed. Out of memory allocating %lld bytes for dimension sizes in the I/O decomposition map", (unsigned long long) (sizeof(int) * ndims)); - } - for(int d = 0; d < ndims; d++){ iodesc->dimlen[d] = gdimlen[d]; } diff --git a/src/clib/pioc_support.cpp b/src/clib/pioc_support.cpp index 53fbd8779b..cc9d83bd8b 100644 --- a/src/clib/pioc_support.cpp +++ b/src/clib/pioc_support.cpp @@ -1685,10 +1685,11 @@ int find_mpi_type(int pio_type, MPI_Datatype *mpi_type, int *type_size) * handling. * @param piotype the PIO data type (ex. PIO_FLOAT, PIO_INT, etc.). * @param ndims the number of dimensions. + * @param maplen the length of the local decomposition map * @param iodesc pointer that gets the newly allocated io_desc_t. * @returns 0 for success, error code otherwise. */ -int malloc_iodesc(iosystem_desc_t *ios, int piotype, int ndims, +int malloc_iodesc(iosystem_desc_t *ios, int piotype, int ndims, int maplen, io_desc_t **iodesc) { MPI_Datatype mpi_type; @@ -1735,6 +1736,7 @@ int malloc_iodesc(iosystem_desc_t *ios, int piotype, int ndims, /* Initialize some values in the struct. */ (*iodesc)->maxregions = 1; (*iodesc)->ioid = -1; + (*iodesc)->maplen = maplen; (*iodesc)->ndims = ndims; /* Allocate space for, and initialize, the first region. */ @@ -1743,6 +1745,18 @@ int malloc_iodesc(iosystem_desc_t *ios, int piotype, int ndims, "Internal error while allocating memory for iodesc. Allocating memory for 1st region failed. Out of memory allocating memory for I/O region in the I/O descriptor"); } + /* Allocate memory for the local decomposition map */ + if(!((*iodesc)->map = (PIO_Offset *) malloc(sizeof(PIO_Offset) * maplen))){ + return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, + "Internal error while allocating memory (%lld bytes) to store I/O decomposition map", (unsigned long long) (sizeof(PIO_Offset) * maplen)); + } + + /* Allocate memory for storing the dimension lengths of variables that use this decomposition */ + if(!((*iodesc)->dimlen = (int *)malloc(sizeof(int) * ndims))){ + return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, + "Internal error while allocating memory (%lld bytes) for storing dimension sizes in the I/O decomposition map", (unsigned long long) (sizeof(int) * ndims)); + } + /* Set the swap memory settings to defaults for this IO system. */ (*iodesc)->rearr_opts = ios->rearr_opts; diff --git a/tests/cunit/test_pioc.cpp b/tests/cunit/test_pioc.cpp index 255cffc9e9..69656813f1 100644 --- a/tests/cunit/test_pioc.cpp +++ b/tests/cunit/test_pioc.cpp @@ -1639,7 +1639,7 @@ int test_malloc_iodesc2(int iosysid, int my_rank) for (int t = 0; t < num_types; t++) { - if ((ret = malloc_iodesc(ios, test_type[t], 1, &iodesc))) + if ((ret = malloc_iodesc(ios, test_type[t], 1, 1, &iodesc))) return ret; if (iodesc->mpitype != mpi_type[t]) return ERR_WRONG; From 782f094db988719e41d78fd12108ead65ae83478 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 19 Nov 2024 20:11:56 -0600 Subject: [PATCH 018/194] Refactor initdecomp func to support 0/1 based maps Adding the logic to initdecomp function to support 0/1 based decomposition maps. Separating the user interfaces (and simplifying them) to thin wrapper functions that eventually call the initdecomp() function to create I/O decompositions for 0 & 1 based decomps Also using C++ algos to copy the map (and transform it as needed to support 0/1 based maps for the different rearrangers) and dimension lengths. --- src/clib/pioc.cpp | 128 +++++++++++++++++++++++++++++----------------- 1 file changed, 82 insertions(+), 46 deletions(-) diff --git a/src/clib/pioc.cpp b/src/clib/pioc.cpp index e366564ab5..a122240527 100644 --- a/src/clib/pioc.cpp +++ b/src/clib/pioc.cpp @@ -32,6 +32,7 @@ #include "blosc2_filter.h" #endif #endif +#include bool fortran_order = false; @@ -682,11 +683,10 @@ int pio_create_uniq_str(iosystem_desc_t *ios, io_desc_t *iodesc, char *str, int * iostarts are generated. * @returns 0 on success, error code otherwise * @ingroup PIO_initdecomp - * @author Jim Edwards, Ed Hartnett */ -int PIOc_InitDecomp_impl(int iosysid, int pio_type, int ndims, const int *gdimlen, int maplen, - const PIO_Offset *compmap, int *ioidp, const int *rearranger, - const PIO_Offset *iostart, const PIO_Offset *iocount) +static int initdecomp(int iosysid, int pio_type, int ndims, const int *gdimlen, int maplen, + const PIO_Offset *compmap, int *ioidp, const int *rearranger, + const PIO_Offset *iostart, const PIO_Offset *iocount, bool map_zero_based=false) { iosystem_desc_t *ios; /* Pointer to io system information. */ io_desc_t *iodesc; /* The IO description. */ @@ -762,16 +762,6 @@ int PIOc_InitDecomp_impl(int iosysid, int pio_type, int ndims, const int *gdimle "Initializing the PIO decomposition failed. Out of memory allocating memory for I/O descriptor (ndims = %d, maplen = %d)", ndims, maplen); } - /* Remember the map. */ - for(int m = 0; m < maplen; m++){ - iodesc->map[m] = compmap[m]; - } - - /* Remember the dim sizes. */ - for(int d = 0; d < ndims; d++){ - iodesc->dimlen[d] = gdimlen[d]; - } - /* Set the rearranger. */ if(!rearranger){ iodesc->rearranger = ios->default_rearranger; @@ -802,6 +792,31 @@ int PIOc_InitDecomp_impl(int iosysid, int pio_type, int ndims, const int *gdimle iodesc->rearranger = spio_get_opt_pio_rearr(ios, maplen); } + /* Cache the local decomposition map */ + if(map_zero_based){ + /* BOX and SUBSET rearrangers expect map to the 1-based */ + if((iodesc->rearranger == PIO_REARR_BOX) || (iodesc->rearranger == PIO_REARR_SUBSET)){ + std::transform(compmap, compmap + maplen, iodesc->map, + [](PIO_Offset off) { return off + 1; }); + } + else{ + std::copy(compmap, compmap + maplen, iodesc->map); + } + } + else{ + /* CONTIG rearranger expects map to be 0-based */ + if(iodesc->rearranger == PIO_REARR_CONTIG){ + std::transform(compmap, compmap + maplen, iodesc->map, + [](PIO_Offset off) { return off - 1; }); + } + else{ + std::copy(compmap, compmap + maplen, iodesc->map); + } + } + + /* Cache the dimension lengths */ + std::copy(gdimlen, gdimlen + ndims, iodesc->dimlen); + /* Is this the subset rearranger? */ if(iodesc->rearranger == PIO_REARR_SUBSET){ iodesc->num_aiotasks = ios->num_iotasks; @@ -921,6 +936,56 @@ int PIOc_InitDecomp_impl(int iosysid, int pio_type, int ndims, const int *gdimle return PIO_NOERR; } +/** + * Initialize the decomposition used with distributed arrays. The + * decomposition describes how the data will be distributed between + * tasks. + * + * Internally, this function will: + *
    + *
  • Allocate and initialize an iodesc struct for this + * decomposition. (This also allocates an io_region struct for the + * first region.) + *
  • (Box rearranger only) If iostart or iocount are NULL, call + * CalcStartandCount() to determine starts/counts. Then call + * compute_maxIObuffersize() to compute the max IO buffer size needed. + *
  • Create the rearranger. + *
  • Assign an ioid and add this decomposition to the list of open + * decompositions. + *
+ * + * @param iosysid the IO system ID. + * @param pio_type the basic PIO data type used. + * @param ndims the number of dimensions in the variable, not + * including the unlimited dimension. + * @param gdimlen an array length ndims with the sizes of the global + * dimensions. + * @param maplen the local length of the compmap array. + * @param compmap a 1 based array of offsets into the array record on + * file. A 0 in this array indicates a value which should not be + * transfered. + * @param ioidp pointer that will get the io description ID. + * @param rearranger pointer to the rearranger to be used for this + * decomp or NULL to use the default. + * @param iostart An array of start values for block cyclic + * decompositions for the SUBSET rearranger. Ignored if block + * rearranger is used. If NULL and SUBSET rearranger is used, the + * iostarts are generated. + * @param iocount An array of count values for block cyclic + * decompositions for the SUBSET rearranger. Ignored if block + * rearranger is used. If NULL and SUBSET rearranger is used, the + * iostarts are generated. + * @returns 0 on success, error code otherwise + * @ingroup PIO_initdecomp + */ +int PIOc_InitDecomp_impl(int iosysid, int pio_type, int ndims, const int *gdimlen, int maplen, + const PIO_Offset *compmap, int *ioidp, const int *rearranger, + const PIO_Offset *iostart, const PIO_Offset *iocount) +{ + return initdecomp(iosysid, pio_type, ndims, gdimlen, maplen, + compmap, ioidp, rearranger, iostart, iocount); +} + /** * Initialize the decomposition used with distributed arrays. The * decomposition describes how the data will be distributed between @@ -946,43 +1011,14 @@ int PIOc_InitDecomp_impl(int iosysid, int pio_type, int ndims, const int *gdimle * decompositions. If NULL ??? * @returns 0 on success, error code otherwise * @ingroup PIO_initdecomp - * @author Jim Edwards, Ed Hartnett */ int PIOc_init_decomp_impl(int iosysid, int pio_type, int ndims, const int *gdimlen, int maplen, const PIO_Offset *compmap, int *ioidp, int rearranger, const PIO_Offset *iostart, const PIO_Offset *iocount) { - PIO_Offset* compmap_1_based = (PIO_Offset*)calloc(maplen, sizeof(PIO_Offset)); - if (compmap_1_based == NULL) - { - return pio_err(NULL, NULL, PIO_ENOMEM, __FILE__, __LINE__, - "Initializing the decomposition used with distributed arrays failed. " - "Out of memory allocating %lld bytes for one-based compmap", - (unsigned long long) (maplen * sizeof(PIO_Offset))); - } - - int *rearrangerp = NULL; - - LOG((1, "PIOc_init_decomp iosysid = %d pio_type = %d ndims = %d maplen = %d", - iosysid, pio_type, ndims, maplen)); - - /* If the user specified a non-default rearranger, use it. */ - if (rearranger) - rearrangerp = &rearranger; - - /* Add 1 to all elements in compmap. */ - for (int e = 0; e < maplen; e++) - { - LOG((3, "zero-based compmap[%d] = %d", e, compmap[e])); - compmap_1_based[e] = compmap[e] + 1; - } - - /* Call the legacy version of the function. */ - int ret = PIOc_InitDecomp_impl(iosysid, pio_type, ndims, gdimlen, maplen, compmap_1_based, - ioidp, rearrangerp, iostart, iocount); - - free(compmap_1_based); - return ret; + return initdecomp(iosysid, pio_type, ndims, gdimlen, maplen, + compmap, ioidp, (rearranger) ? &rearranger : NULL, + iostart, iocount, true); } /** From 77ba0181a7d911f098fa8b0de38f3565a9f0730a Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 20 Nov 2024 12:15:49 -0600 Subject: [PATCH 019/194] Using GPTL and Ltimer wrapper for write_darray Using the GPTL and SPIO Ltimer wrapper classes to simplify timers (stop on return from function) in the write darray functions --- src/clib/pio_darray.cpp | 243 +++------------------------------------- 1 file changed, 14 insertions(+), 229 deletions(-) diff --git a/src/clib/pio_darray.cpp b/src/clib/pio_darray.cpp index ef9e86bb89..25e18c0e36 100644 --- a/src/clib/pio_darray.cpp +++ b/src/clib/pio_darray.cpp @@ -18,6 +18,8 @@ #include "spio_io_summary.h" #include "spio_file_mvcache.h" #include "spio_hash.h" +#include "spio_gptl_utils.hpp" +#include "spio_ltimer_utils.hpp" /* uint64_t definition */ #ifdef _ADIOS2 @@ -122,41 +124,31 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar int mpierr = MPI_SUCCESS; /* Return code from MPI function calls. */ int ierr = PIO_NOERR; /* Return code. */ - GPTLstart("PIO:PIOc_write_darray_multi"); + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("PIO:PIOc_write_darray_multi"); /* Get the file info. */ if ((ierr = pio_get_file(ncid, &file))) { - GPTLstop("PIO:PIOc_write_darray_multi"); return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, "Writing multiple variables to file (ncid=%d) failed. Unable to query the internal file structure associated with the file. Invalid file id", ncid); } assert(file); ios = file->iosystem; assert(ios); - spio_ltimer_start(ios->io_fstats->wr_timer_name); - spio_ltimer_start(ios->io_fstats->tot_timer_name); - spio_ltimer_start(file->io_fstats->wr_timer_name); - spio_ltimer_start(file->io_fstats->tot_timer_name); + + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper ios_fstats_wr_timer(ios->io_fstats->wr_timer_name); + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper ios_fstats_tot_timer(ios->io_fstats->tot_timer_name); + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper file_fstats_wr_timer(file->io_fstats->wr_timer_name); + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper file_fstats_tot_timer(file->io_fstats->tot_timer_name); /* Check inputs. */ if (nvars <= 0 || !varids) { - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, PIO_EINVAL, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Internal error, invalid arguments, nvars = %d (expected > 0), varids is %s (expected not NULL)", pio_get_fname_from_file(file), ncid, nvars, PIO_IS_NULL(varids)); } for (int v = 0; v < nvars; v++) if (varids[v] < 0 || varids[v] > PIO_MAX_VARS) { - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, PIO_EINVAL, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Internal error, invalid arguments, nvars = %d, varids[%d] = %d (expected >= 0 && <= PIO_MAX_VARS=%d)", pio_get_fname_from_file(file), ncid, nvars, v, varids[v], PIO_MAX_VARS); } @@ -168,11 +160,6 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar /* Check that we can write to this file. */ if (!(file->mode & PIO_WRITE)) { - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, PIO_EPERM, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Trying to write to a read only file, try reopening the file in write mode (use the PIO_WRITE flag)", pio_get_fname_from_file(file), ncid); } @@ -180,11 +167,6 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar /* Get iodesc. */ if (!(iodesc = pio_get_iodesc_from_id(ioid))) { - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, PIO_EBADID, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Invalid arguments, invalid PIO decomposition id (%d) provided", pio_get_fname_from_file(file), ncid, ioid); } @@ -206,7 +188,6 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar spio_ltimer_stop(file->io_fstats->tot_timer_name); ierr = PIOc_inq_varndims_impl(file->pio_ncid, varids[0], &fndims); if(ierr != PIO_NOERR){ - GPTLstop("PIO:PIOc_write_darray_multi"); return pio_err(ios, file, ierr, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Inquiring number of dimensions in the first variable (%s, varid=%d) in the list failed", pio_get_fname_from_file(file), ncid, pio_get_vname_from_file(file, varids[0]), varids[0]); } @@ -256,11 +237,6 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar /* Share results known only on computation tasks with IO tasks. */ if ((mpierr = MPI_Bcast(&fndims, 1, MPI_INT, ios->comproot, ios->my_comm))) { - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); } LOG((3, "shared fndims = %d", fndims)); @@ -272,11 +248,6 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar ierr = flush_output_buffer(file, true, 0); if (ierr != PIO_NOERR) { - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, ierr, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Flushing data to disk (PIO_IOTYPE_PNETCDF) failed", pio_get_fname_from_file(file), ncid); } @@ -303,11 +274,6 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar ierr = mtimer_start(file->varlist[varids[0]].wr_rearr_mtimer); if(ierr != PIO_NOERR) { - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, ierr, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Starting a micro timer failed", pio_get_fname_from_file(file), ncid); } @@ -323,11 +289,6 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar &(var_mtimer_was_running[i])); if(ierr != PIO_NOERR) { - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, ierr, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Pausing a micro timer failed", pio_get_fname_from_file(file), ncid); } @@ -342,11 +303,6 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar mv_iobuf = spio_file_mvcache_alloc(file, ioid, iodesc->mpitype_size * rlen); if (!mv_iobuf) { - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Out of memory (Trying to allocate %lld bytes for rearranged data for multiple variables with the same decomposition)", pio_get_fname_from_file(file), ncid, (unsigned long long)(iodesc->mpitype_size * rlen)); } @@ -372,11 +328,6 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar mv_iobuf = spio_file_mvcache_alloc(file, ioid, 1); if (!mv_iobuf) { - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Out of memory (Trying to allocate 1 byte)", pio_get_fname_from_file(file), ncid); } @@ -386,11 +337,6 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar /* Move data from compute to IO tasks. */ if ((ierr = rearrange_comp2io(ios, iodesc, file, array, mv_iobuf, nvars))) { - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, ierr, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Error rearranging and moving data from compute tasks to I/O tasks", pio_get_fname_from_file(file), ncid); } @@ -403,11 +349,6 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar ierr = mtimer_pause(file->varlist[varids[0]].wr_rearr_mtimer, NULL); if(ierr != PIO_NOERR) { - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, ierr, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Pausing a micro timer (to measure rearrange time) failed", pio_get_fname_from_file(file), ncid); } @@ -416,11 +357,6 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar &rearr_time); if(ierr != PIO_NOERR) { - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, ierr, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Retrieving wallclock time from a micro timer (rearrange time) failed", pio_get_fname_from_file(file), ncid); } @@ -433,11 +369,6 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar ierr = mtimer_reset(file->varlist[varids[i]].wr_rearr_mtimer); if(ierr != PIO_NOERR) { - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, ierr, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Resetting micro timer (to measure rearrange time) for variable %d failed", pio_get_fname_from_file(file), ncid, i); } @@ -448,11 +379,6 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar if(ierr != PIO_NOERR) { LOG((1, "ERROR: Unable to update wr rearr timer")); - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, ierr, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Updating micro timer (to measure rearrange time) for variable %d failed", pio_get_fname_from_file(file), ncid, i); } @@ -461,11 +387,6 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar if(ierr != PIO_NOERR) { LOG((1, "ERROR: Unable to flush wr rearr timer")); - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, ierr, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Flushing micro timer (to measure rearrange time) for variable %d failed", pio_get_fname_from_file(file), ncid, i); } @@ -477,11 +398,6 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar if(ierr != PIO_NOERR) { LOG((1, "ERROR: Unable to update wr timer")); - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, ierr, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Updating micro timer (to measure write time) for variable %d failed", pio_get_fname_from_file(file), ncid, i); } @@ -493,11 +409,6 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar if(ierr != PIO_NOERR) { LOG((1, "ERROR: Unable to resume wr timer")); - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, ierr, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Updating micro timer (to measure write time) for variable %d failed", pio_get_fname_from_file(file), ncid, i); } @@ -516,11 +427,6 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar if ((ierr = write_darray_multi_par(file, nvars, fndims, varids, iodesc, DARRAY_DATA, frame))) { - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, ierr, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Internal error writing variable data in parallel (iotype = %s)", pio_get_fname_from_file(file), ncid, pio_iotype_to_string(file->iotype)); } @@ -530,22 +436,12 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar if ((ierr = write_darray_multi_serial(file, nvars, fndims, varids, iodesc, DARRAY_DATA, frame))) { - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, ierr, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Internal error writing variable data serially (iotype = %s)", pio_get_fname_from_file(file), ncid, pio_iotype_to_string(file->iotype)); } break; default: - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(NULL, NULL, PIO_EBADIOTYPE, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Invalid iotype (%d) provided", pio_get_fname_from_file(file), ncid, file->iotype); } @@ -601,11 +497,6 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar if ((ierr = write_darray_multi_par(file, nvars, fndims, varids, iodesc, DARRAY_FILL, frame))) { - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, ierr, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Internal error writing variable fillvalues in parallel (iotype = %s)", pio_get_fname_from_file(file), ncid, pio_iotype_to_string(file->iotype)); } @@ -615,21 +506,11 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar if ((ierr = write_darray_multi_serial(file, nvars, fndims, varids, iodesc, DARRAY_FILL, frame))) { - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, ierr, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Internal error writing variable fillvalues serially (iotype = %s)", pio_get_fname_from_file(file), ncid, pio_iotype_to_string(file->iotype)); } break; default: - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, PIO_EBADIOTYPE, __FILE__, __LINE__, "Writing fillvalues for multiple variables to file (%s, ncid=%d) failed. Unsupported iotype (%s) provided", pio_get_fname_from_file(file), ncid, pio_iotype_to_string(file->iotype)); } @@ -655,11 +536,6 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar /* Flush data to disk for pnetcdf. */ if ((ierr = flush_output_buffer(file, flushtodisk, 0))) { - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, ierr, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Flushing data to disk (PIO_IOTYPE_PNETCDF) failed", pio_get_fname_from_file(file), ncid); } @@ -678,11 +554,6 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar file->wb_pend = 0; } - GPTLstop("PIO:PIOc_write_darray_multi"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return PIO_NOERR; } @@ -2118,27 +1989,25 @@ int PIOc_write_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, c int mpierr = MPI_SUCCESS; /* Return code from MPI functions. */ int ierr = PIO_NOERR; /* Return code. */ - GPTLstart("PIO:PIOc_write_darray"); - GPTLstart("PIO:write_total"); + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer1("PIO:PIOc_write_darray"); + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer2("PIO:write_total"); LOG((1, "PIOc_write_darray ncid = %d varid = %d ioid = %d arraylen = %d", ncid, varid, ioid, arraylen)); /* Get the file info. */ if ((ierr = pio_get_file(ncid, &file))) { - GPTLstop("PIO:PIOc_write_darray"); - GPTLstop("PIO:write_total"); return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, "Writing variable (varid=%d) failed on file. Invalid file id (ncid=%d) provided", varid, ncid); } assert(file); - spio_ltimer_start(file->io_fstats->wr_timer_name); - spio_ltimer_start(file->io_fstats->tot_timer_name); ios = file->iosystem; assert(ios); - spio_ltimer_start(ios->io_fstats->wr_timer_name); - spio_ltimer_start(ios->io_fstats->tot_timer_name); + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper file_fstats_wr_timer(file->io_fstats->wr_timer_name); + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper file_fstats_tot_timer(file->io_fstats->tot_timer_name); + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper ios_fstats_wr_timer(ios->io_fstats->wr_timer_name); + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper ios_fstats_tot_timer(ios->io_fstats->tot_timer_name); if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { @@ -2155,12 +2024,6 @@ int PIOc_write_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, c /* Can we write to this file? */ if (!(file->mode & PIO_WRITE)) { - GPTLstop("PIO:PIOc_write_darray"); - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { GPTLstop("PIO:PIOc_write_darray_adios"); @@ -2196,12 +2059,6 @@ int PIOc_write_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, c /* Get decomposition information. */ if (!(iodesc = pio_get_iodesc_from_id(ioid))) { - GPTLstop("PIO:PIOc_write_darray"); - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { GPTLstop("PIO:PIOc_write_darray_adios"); @@ -2217,12 +2074,6 @@ int PIOc_write_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, c * if it is too big (the excess values will be ignored.) */ if (arraylen < iodesc->ndof) { - GPTLstop("PIO:PIOc_write_darray"); - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { GPTLstop("PIO:PIOc_write_darray_adios"); @@ -2249,12 +2100,6 @@ int PIOc_write_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, c ierr = pio_create_uniq_str(ios, iodesc, filename, PIO_MAX_NAME, "piodecomp", ".dat"); if(ierr != PIO_NOERR) { - GPTLstop("PIO:PIOc_write_darray"); - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { GPTLstop("PIO:PIOc_write_darray_adios"); @@ -2286,8 +2131,6 @@ int PIOc_write_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, c { if ((ierr = PIOc_inq_vartype_impl(ncid, varid, &vdesc->pio_type))) { - GPTLstop("PIO:PIOc_write_darray"); - GPTLstop("PIO:write_total"); return pio_err(ios, NULL, ierr, __FILE__, __LINE__, "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Inquiring variable data type failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); } @@ -2300,8 +2143,6 @@ int PIOc_write_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, c { if ((ierr = PIOc_inq_type_impl(ncid, vdesc->pio_type, NULL, &vdesc->type_size))) { - GPTLstop("PIO:PIOc_write_darray"); - GPTLstop("PIO:write_total"); return pio_err(ios, NULL, ierr, __FILE__, __LINE__, "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Inquiring variable data type length failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); } @@ -2330,8 +2171,6 @@ if ((file->iotype != PIO_IOTYPE_HDF5) && (file->iotype != PIO_IOTYPE_HDF5C)) spio_ltimer_stop(file->io_fstats->tot_timer_name); if ((ierr = find_var_fillvalue(file, varid, vdesc))) { - GPTLstop("PIO:PIOc_write_darray"); - GPTLstop("PIO:write_total"); if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { GPTLstop("PIO:PIOc_write_darray_adios"); @@ -2366,12 +2205,6 @@ if ((file->iotype != PIO_IOTYPE_HDF5) && (file->iotype != PIO_IOTYPE_HDF5C)) ierr = PIOc_write_darray_adios(file, varid, ioid, iodesc, arraylen, array, fillvalue); GPTLstop("PIO:PIOc_write_darray_adios"); GPTLstop("PIO:write_total_adios"); - GPTLstop("PIO:PIOc_write_darray"); - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return ierr; } #endif @@ -2383,12 +2216,6 @@ if ((file->iotype != PIO_IOTYPE_HDF5) && (file->iotype != PIO_IOTYPE_HDF5C)) LOG((3, "allocating multi-buffer")); if (!(wmb->next = (wmulti_buffer *) calloc(1, sizeof(wmulti_buffer)))) { - GPTLstop("PIO:PIOc_write_darray"); - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Out of memory allocating %lld bytes for a write multi buffer to cache user data", pio_get_fname_from_file(file), varid, pio_get_fname_from_file(file), file->pio_ncid, (unsigned long long) sizeof(wmulti_buffer)); } @@ -2439,12 +2266,6 @@ if ((file->iotype != PIO_IOTYPE_HDF5) && (file->iotype != PIO_IOTYPE_HDF5C)) if ((mpierr = MPI_Allreduce(MPI_IN_PLACE, &needsflush, 1, MPI_INT, MPI_MAX, ios->comp_comm))) { - GPTLstop("PIO:PIOc_write_darray"); - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); } LOG((2, "needsflush = %d", needsflush)); @@ -2521,12 +2342,6 @@ if ((file->iotype != PIO_IOTYPE_HDF5) && (file->iotype != PIO_IOTYPE_HDF5C)) { if (!(wmb->data = bgetr(wmb->data, (1 + wmb->num_arrays) * arraylen * iodesc->mpitype_size))) { - GPTLstop("PIO:PIOc_write_darray"); - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Out of memory allocating space (realloc %lld bytes) to cache user data", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, (long long int )((1 + wmb->num_arrays) * arraylen * iodesc->mpitype_size)); } @@ -2537,12 +2352,6 @@ if ((file->iotype != PIO_IOTYPE_HDF5) && (file->iotype != PIO_IOTYPE_HDF5C)) * and add the new entry. */ if (!(wmb->vid = (int *) realloc(wmb->vid, sizeof(int) * (1 + wmb->num_arrays)))) { - GPTLstop("PIO:PIOc_write_darray"); - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Out of memory allocating space (realloc %lld bytes) for array of variable ids in write multi buffer to cache user data", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, (unsigned long long)(sizeof(int) * (1 + wmb->num_arrays))); } @@ -2553,12 +2362,6 @@ if ((file->iotype != PIO_IOTYPE_HDF5) && (file->iotype != PIO_IOTYPE_HDF5C)) if (vdesc->record >= 0) if (!(wmb->frame = (int *) realloc(wmb->frame, sizeof(int) * (1 + wmb->num_arrays)))) { - GPTLstop("PIO:PIOc_write_darray"); - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Out of memory allocating space (realloc %lld bytes) for array of frame numbers in write multi buffer to cache user data", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, (unsigned long long)(sizeof(int) * (1 + wmb->num_arrays))); } @@ -2571,12 +2374,6 @@ if ((file->iotype != PIO_IOTYPE_HDF5) && (file->iotype != PIO_IOTYPE_HDF5C)) /* Get memory to hold fill value. */ if (!(wmb->fillvalue = bgetr(wmb->fillvalue, iodesc->mpitype_size * (1 + wmb->num_arrays)))) { - GPTLstop("PIO:PIOc_write_darray"); - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Out of memory allocating space (realloc %lld bytes) for variable fillvalues in write multi buffer to cache user data", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, (unsigned long long)(iodesc->mpitype_size * (1 + wmb->num_arrays))); } @@ -2638,12 +2435,6 @@ if ((file->iotype != PIO_IOTYPE_HDF5) && (file->iotype != PIO_IOTYPE_HDF5C)) #endif /* _NETCDF4 */ else { - GPTLstop("PIO:PIOc_write_darray"); - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, PIO_EBADTYPE, __FILE__, __LINE__, "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Unable to find a default fillvalue for variable, unsupported variable type", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); } @@ -2686,12 +2477,6 @@ if ((file->iotype != PIO_IOTYPE_HDF5) && (file->iotype != PIO_IOTYPE_HDF5C)) #ifdef PIO_MICRO_TIMING mtimer_stop(file->varlist[varid].wr_mtimer, get_var_desc_str(ncid, varid, NULL)); #endif - GPTLstop("PIO:PIOc_write_darray"); - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return PIO_NOERR; } From a28724823a6eaa6b5db33e9d12a9a67e15f7ee86 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 20 Nov 2024 13:01:51 -0600 Subject: [PATCH 020/194] Code reformatting write darray funcs Code reformatting (starting braces on same line, no spaces btw keyword and starting of braces, 2 space tab) the write darray functions --- src/clib/pio_darray.cpp | 1648 +++++++++++++++++++-------------------- 1 file changed, 802 insertions(+), 846 deletions(-) diff --git a/src/clib/pio_darray.cpp b/src/clib/pio_darray.cpp index 25e18c0e36..067bab1ff0 100644 --- a/src/clib/pio_darray.cpp +++ b/src/clib/pio_darray.cpp @@ -115,446 +115,405 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar PIO_Offset arraylen, const void *array, const int *frame, const void **fillvalue, bool flushtodisk) { - iosystem_desc_t *ios; /* Pointer to io system information. */ - file_desc_t *file; /* Pointer to file information. */ - io_desc_t *iodesc; /* Pointer to IO description information. */ - size_t rlen = 0; /* Total data buffer size. */ - var_desc_t *vdesc0; /* Array of var_desc structure for each var. */ - int fndims = 0; /* Number of dims in the var in the file. */ - int mpierr = MPI_SUCCESS; /* Return code from MPI function calls. */ - int ierr = PIO_NOERR; /* Return code. */ - - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("PIO:PIOc_write_darray_multi"); - /* Get the file info. */ - if ((ierr = pio_get_file(ncid, &file))) - { - return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, - "Writing multiple variables to file (ncid=%d) failed. Unable to query the internal file structure associated with the file. Invalid file id", ncid); + iosystem_desc_t *ios; /* Pointer to io system information. */ + file_desc_t *file; /* Pointer to file information. */ + io_desc_t *iodesc; /* Pointer to IO description information. */ + size_t rlen = 0; /* Total data buffer size. */ + var_desc_t *vdesc0; /* Array of var_desc structure for each var. */ + int fndims = 0; /* Number of dims in the var in the file. */ + int mpierr = MPI_SUCCESS; /* Return code from MPI function calls. */ + int ierr = PIO_NOERR; /* Return code. */ + + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("PIO:PIOc_write_darray_multi"); + /* Get the file info. */ + if((ierr = pio_get_file(ncid, &file))){ + return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, + "Writing multiple variables to file (ncid=%d) failed. Unable to query the internal file structure associated with the file. Invalid file id", ncid); + } + assert(file); + ios = file->iosystem; + assert(ios); + + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper ios_fstats_wr_timer(ios->io_fstats->wr_timer_name); + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper ios_fstats_tot_timer(ios->io_fstats->tot_timer_name); + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper file_fstats_wr_timer(file->io_fstats->wr_timer_name); + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper file_fstats_tot_timer(file->io_fstats->tot_timer_name); + + /* Check inputs. */ + if(nvars <= 0 || !varids){ + return pio_err(ios, file, PIO_EINVAL, __FILE__, __LINE__, + "Writing multiple variables to file (%s, ncid=%d) failed. Internal error, invalid arguments, nvars = %d (expected > 0), varids is %s (expected not NULL)", pio_get_fname_from_file(file), ncid, nvars, PIO_IS_NULL(varids)); + } + for(int v = 0; v < nvars; v++){ + if(varids[v] < 0 || varids[v] > PIO_MAX_VARS){ + return pio_err(ios, file, PIO_EINVAL, __FILE__, __LINE__, + "Writing multiple variables to file (%s, ncid=%d) failed. Internal error, invalid arguments, nvars = %d, varids[%d] = %d (expected >= 0 && <= PIO_MAX_VARS=%d)", pio_get_fname_from_file(file), ncid, nvars, v, varids[v], PIO_MAX_VARS); + } + } + + LOG((1, "PIOc_write_darray_multi ncid = %d ioid = %d nvars = %d arraylen = %ld " + "flushtodisk = %d", + ncid, ioid, nvars, arraylen, flushtodisk)); + + /* Check that we can write to this file. */ + if(!(file->mode & PIO_WRITE)){ + return pio_err(ios, file, PIO_EPERM, __FILE__, __LINE__, + "Writing multiple variables to file (%s, ncid=%d) failed. Trying to write to a read only file, try reopening the file in write mode (use the PIO_WRITE flag)", pio_get_fname_from_file(file), ncid); + } + + /* Get iodesc. */ + if(!(iodesc = pio_get_iodesc_from_id(ioid))){ + return pio_err(ios, file, PIO_EBADID, __FILE__, __LINE__, + "Writing multiple variables to file (%s, ncid=%d) failed. Invalid arguments, invalid PIO decomposition id (%d) provided", pio_get_fname_from_file(file), ncid, ioid); + } + pioassert(iodesc->rearranger == PIO_REARR_BOX || iodesc->rearranger == PIO_REARR_SUBSET, + "unknown rearranger", __FILE__, __LINE__); + + /* Get a pointer to the variable info for the first variable. */ + vdesc0 = &file->varlist[varids[0]]; + + /* Run these on all tasks if async is not in use, but only on + * non-IO tasks if async is in use. */ + if(!ios->async || !ios->ioproc){ + /* Get the number of dims for this var. */ + LOG((3, "about to call PIOc_inq_varndims varids[0] = %d", varids[0])); + spio_ltimer_stop(ios->io_fstats->wr_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->wr_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + ierr = PIOc_inq_varndims_impl(file->pio_ncid, varids[0], &fndims); + if(ierr != PIO_NOERR){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Writing multiple variables to file (%s, ncid=%d) failed. Inquiring number of dimensions in the first variable (%s, varid=%d) in the list failed", pio_get_fname_from_file(file), ncid, pio_get_vname_from_file(file, varids[0]), varids[0]); } - assert(file); - ios = file->iosystem; - assert(ios); - - SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper ios_fstats_wr_timer(ios->io_fstats->wr_timer_name); - SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper ios_fstats_tot_timer(ios->io_fstats->tot_timer_name); - SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper file_fstats_wr_timer(file->io_fstats->wr_timer_name); - SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper file_fstats_tot_timer(file->io_fstats->tot_timer_name); + spio_ltimer_start(ios->io_fstats->wr_timer_name); + spio_ltimer_start(ios->io_fstats->tot_timer_name); + spio_ltimer_start(file->io_fstats->wr_timer_name); + spio_ltimer_start(file->io_fstats->tot_timer_name); + LOG((3, "called PIOc_inq_varndims varids[0] = %d fndims = %d", varids[0], fndims)); + } - /* Check inputs. */ - if (nvars <= 0 || !varids) - { - return pio_err(ios, file, PIO_EINVAL, __FILE__, __LINE__, - "Writing multiple variables to file (%s, ncid=%d) failed. Internal error, invalid arguments, nvars = %d (expected > 0), varids is %s (expected not NULL)", pio_get_fname_from_file(file), ncid, nvars, PIO_IS_NULL(varids)); - } - for (int v = 0; v < nvars; v++) - if (varids[v] < 0 || varids[v] > PIO_MAX_VARS) - { - return pio_err(ios, file, PIO_EINVAL, __FILE__, __LINE__, - "Writing multiple variables to file (%s, ncid=%d) failed. Internal error, invalid arguments, nvars = %d, varids[%d] = %d (expected >= 0 && <= PIO_MAX_VARS=%d)", pio_get_fname_from_file(file), ncid, nvars, v, varids[v], PIO_MAX_VARS); - } + /* If async is in use, and this is not an IO task, bcast the parameters. */ + if(ios->async){ + int msg = PIO_MSG_WRITEDARRAYMULTI; + char frame_present = frame ? true : false; /* Is frame non-NULL? */ + char fillvalue_present = fillvalue ? true : false; /* Is fillvalue non-NULL? */ + int flushtodisk_int = flushtodisk; /* Need this to be int not boolean. */ - LOG((1, "PIOc_write_darray_multi ncid = %d ioid = %d nvars = %d arraylen = %ld " - "flushtodisk = %d", - ncid, ioid, nvars, arraylen, flushtodisk)); + int *amsg_frame = NULL; + void *amsg_fillvalue = fillvalue; - /* Check that we can write to this file. */ - if (!(file->mode & PIO_WRITE)) - { - return pio_err(ios, file, PIO_EPERM, __FILE__, __LINE__, - "Writing multiple variables to file (%s, ncid=%d) failed. Trying to write to a read only file, try reopening the file in write mode (use the PIO_WRITE flag)", pio_get_fname_from_file(file), ncid); + if(!frame_present){ + amsg_frame = (int *)calloc(nvars, sizeof(int)); } - - /* Get iodesc. */ - if (!(iodesc = pio_get_iodesc_from_id(ioid))) - { - return pio_err(ios, file, PIO_EBADID, __FILE__, __LINE__, - "Writing multiple variables to file (%s, ncid=%d) failed. Invalid arguments, invalid PIO decomposition id (%d) provided", pio_get_fname_from_file(file), ncid, ioid); + if(!fillvalue_present){ + amsg_fillvalue = (char *) calloc(nvars * iodesc->piotype_size, sizeof(char )); } - pioassert(iodesc->rearranger == PIO_REARR_BOX || iodesc->rearranger == PIO_REARR_SUBSET, - "unknown rearranger", __FILE__, __LINE__); - /* Get a pointer to the variable info for the first variable. */ - vdesc0 = &file->varlist[varids[0]]; + PIO_SEND_ASYNC_MSG(ios, msg, &ierr, + ncid, nvars, nvars, varids, ioid, arraylen, + arraylen * iodesc->piotype_size, array, frame_present, + nvars, + (frame_present) ? frame : amsg_frame, fillvalue_present, + nvars * iodesc->piotype_size, amsg_fillvalue, flushtodisk_int); - /* Run these on all tasks if async is not in use, but only on - * non-IO tasks if async is in use. */ - if (!ios->async || !ios->ioproc) - { - /* Get the number of dims for this var. */ - LOG((3, "about to call PIOc_inq_varndims varids[0] = %d", varids[0])); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - ierr = PIOc_inq_varndims_impl(file->pio_ncid, varids[0], &fndims); - if(ierr != PIO_NOERR){ - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Writing multiple variables to file (%s, ncid=%d) failed. Inquiring number of dimensions in the first variable (%s, varid=%d) in the list failed", pio_get_fname_from_file(file), ncid, pio_get_vname_from_file(file, varids[0]), varids[0]); - } - spio_ltimer_start(ios->io_fstats->wr_timer_name); - spio_ltimer_start(ios->io_fstats->tot_timer_name); - spio_ltimer_start(file->io_fstats->wr_timer_name); - spio_ltimer_start(file->io_fstats->tot_timer_name); - LOG((3, "called PIOc_inq_varndims varids[0] = %d fndims = %d", varids[0], fndims)); + if(!frame_present){ + free(amsg_frame); + } + if(!fillvalue_present){ + free(amsg_fillvalue); } - /* If async is in use, and this is not an IO task, bcast the parameters. */ - if (ios->async) - { - int msg = PIO_MSG_WRITEDARRAYMULTI; - char frame_present = frame ? true : false; /* Is frame non-NULL? */ - char fillvalue_present = fillvalue ? true : false; /* Is fillvalue non-NULL? */ - int flushtodisk_int = flushtodisk; /* Need this to be int not boolean. */ - - int *amsg_frame = NULL; - void *amsg_fillvalue = fillvalue; - - if(!frame_present) - { - amsg_frame = (int *)calloc(nvars, sizeof(int)); - } - if(!fillvalue_present) - { - amsg_fillvalue = (char *) calloc(nvars * iodesc->piotype_size, sizeof(char )); - } - - PIO_SEND_ASYNC_MSG(ios, msg, &ierr, - ncid, nvars, nvars, varids, ioid, arraylen, - arraylen * iodesc->piotype_size, array, frame_present, - nvars, - (frame_present) ? frame : amsg_frame, fillvalue_present, - nvars * iodesc->piotype_size, amsg_fillvalue, flushtodisk_int); - - if(!frame_present) - { - free(amsg_frame); - } - if(!fillvalue_present) - { - free(amsg_fillvalue); - } - - /* Share results known only on computation tasks with IO tasks. */ - if ((mpierr = MPI_Bcast(&fndims, 1, MPI_INT, ios->comproot, ios->my_comm))) - { - return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); - } - LOG((3, "shared fndims = %d", fndims)); + /* Share results known only on computation tasks with IO tasks. */ + if((mpierr = MPI_Bcast(&fndims, 1, MPI_INT, ios->comproot, ios->my_comm))){ + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); } + LOG((3, "shared fndims = %d", fndims)); + } - /* if the buffer is already in use in pnetcdf we need to flush first */ - if (file->iotype == PIO_IOTYPE_PNETCDF && spio_file_mvcache_get(file, ioid)) - { - ierr = flush_output_buffer(file, true, 0); - if (ierr != PIO_NOERR) - { - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Writing multiple variables to file (%s, ncid=%d) failed. Flushing data to disk (PIO_IOTYPE_PNETCDF) failed", pio_get_fname_from_file(file), ncid); - } + /* if the buffer is already in use in pnetcdf we need to flush first */ + if(file->iotype == PIO_IOTYPE_PNETCDF && spio_file_mvcache_get(file, ioid)){ + ierr = flush_output_buffer(file, true, 0); + if(ierr != PIO_NOERR){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Writing multiple variables to file (%s, ncid=%d) failed. Flushing data to disk (PIO_IOTYPE_PNETCDF) failed", pio_get_fname_from_file(file), ncid); } + } - pioassert(!spio_file_mvcache_get(file, ioid), "buffer overwrite",__FILE__, __LINE__); + pioassert(!spio_file_mvcache_get(file, ioid), "buffer overwrite",__FILE__, __LINE__); - /* Determine total size of aggregated data (all vars/records). - * For netcdf serial writes we collect the data on io nodes and - * then move that data one node at a time to the io master node - * and write. The buffer size on io task 0 must be as large as - * the largest used to accommodate this serial io method (use - * iodesc->maxiobuflen to calculate it). */ - if ((file->iotype == PIO_IOTYPE_NETCDF || file->iotype == PIO_IOTYPE_NETCDF4C) && ios->iomaster == MPI_ROOT) - rlen = iodesc->maxiobuflen * nvars; - else - rlen = iodesc->llen * nvars; + /* Determine total size of aggregated data (all vars/records). + * For netcdf serial writes we collect the data on io nodes and + * then move that data one node at a time to the io master node + * and write. The buffer size on io task 0 must be as large as + * the largest used to accommodate this serial io method (use + * iodesc->maxiobuflen to calculate it). */ + if((file->iotype == PIO_IOTYPE_NETCDF || file->iotype == PIO_IOTYPE_NETCDF4C) && ios->iomaster == MPI_ROOT){ + rlen = iodesc->maxiobuflen * nvars; + } + else{ + rlen = iodesc->llen * nvars; + } #ifdef PIO_MICRO_TIMING - bool var_mtimer_was_running[nvars]; - /* Use the timer on the first variable to capture the total - *time to rearrange data for all variables - */ - ierr = mtimer_start(file->varlist[varids[0]].wr_rearr_mtimer); - if(ierr != PIO_NOERR) - { - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Writing multiple variables to file (%s, ncid=%d) failed. Starting a micro timer failed", pio_get_fname_from_file(file), ncid); - } - /* Stop any write timers that are running, these timers will - *be updated later with the avg rearrange time - * (wr_rearr_mtimer) - */ - for(int i=0; ivarlist[varids[i]].wr_mtimer)); - ierr = mtimer_pause(file->varlist[varids[i]].wr_mtimer, - &(var_mtimer_was_running[i])); - if(ierr != PIO_NOERR) - { - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Writing multiple variables to file (%s, ncid=%d) failed. Pausing a micro timer failed", pio_get_fname_from_file(file), ncid); - } - } + bool var_mtimer_was_running[nvars]; + /* Use the timer on the first variable to capture the total + *time to rearrange data for all variables + */ + ierr = mtimer_start(file->varlist[varids[0]].wr_rearr_mtimer); + if(ierr != PIO_NOERR){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Writing multiple variables to file (%s, ncid=%d) failed. Starting a micro timer failed", pio_get_fname_from_file(file), ncid); + } + /* Stop any write timers that are running, these timers will + *be updated later with the avg rearrange time + * (wr_rearr_mtimer) + */ + for(int i=0; ivarlist[varids[i]].wr_mtimer)); + ierr = mtimer_pause(file->varlist[varids[i]].wr_mtimer, &(var_mtimer_was_running[i])); + if(ierr != PIO_NOERR){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Writing multiple variables to file (%s, ncid=%d) failed. Pausing a micro timer failed", pio_get_fname_from_file(file), ncid); + } + } #endif - /* Allocate iobuf. */ - void *mv_iobuf = NULL; - if (rlen > 0) - { - /* Allocate memory for the buffer for all vars/records. */ - mv_iobuf = spio_file_mvcache_alloc(file, ioid, iodesc->mpitype_size * rlen); - if (!mv_iobuf) - { - return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, - "Writing multiple variables to file (%s, ncid=%d) failed. Out of memory (Trying to allocate %lld bytes for rearranged data for multiple variables with the same decomposition)", pio_get_fname_from_file(file), ncid, (unsigned long long)(iodesc->mpitype_size * rlen)); - } - LOG((3, "allocated %lld bytes for variable buffer", rlen * iodesc->mpitype_size)); - - /* If fill values are desired, and we're using the BOX - * rearranger, insert fill values. */ - if (iodesc->needsfill && iodesc->rearranger == PIO_REARR_BOX) - { - PIO_Offset localiobuflen = rlen / nvars; - LOG((3, "inserting fill values iodesc->maxiobuflen = %lld, localiobuflen = %lld", iodesc->maxiobuflen, localiobuflen)); - for (int nv = 0; nv < nvars; nv++) - for (PIO_Offset i = 0; i < localiobuflen; i++) - memcpy(&((char *)mv_iobuf)[iodesc->mpitype_size * (i + nv * localiobuflen)], - &((char *)fillvalue)[nv * iodesc->mpitype_size], iodesc->mpitype_size); - } - } - else if (file->iotype == PIO_IOTYPE_PNETCDF && ios->ioproc) - { - /* this assures that iobuf is allocated on all iotasks thus - assuring that the flush_output_buffer call above is called - collectively (from all iotasks) */ - mv_iobuf = spio_file_mvcache_alloc(file, ioid, 1); - if (!mv_iobuf) - { - return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, - "Writing multiple variables to file (%s, ncid=%d) failed. Out of memory (Trying to allocate 1 byte)", pio_get_fname_from_file(file), ncid); + /* Allocate iobuf. */ + void *mv_iobuf = NULL; + if(rlen > 0){ + /* Allocate memory for the buffer for all vars/records. */ + mv_iobuf = spio_file_mvcache_alloc(file, ioid, iodesc->mpitype_size * rlen); + if(!mv_iobuf){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Writing multiple variables to file (%s, ncid=%d) failed. Out of memory (Trying to allocate %lld bytes for rearranged data for multiple variables with the same decomposition)", pio_get_fname_from_file(file), ncid, (unsigned long long)(iodesc->mpitype_size * rlen)); + } + LOG((3, "allocated %lld bytes for variable buffer", rlen * iodesc->mpitype_size)); + + /* If fill values are desired, and we're using the BOX + * rearranger, insert fill values. */ + if(iodesc->needsfill && iodesc->rearranger == PIO_REARR_BOX){ + PIO_Offset localiobuflen = rlen / nvars; + LOG((3, "inserting fill values iodesc->maxiobuflen = %lld, localiobuflen = %lld", iodesc->maxiobuflen, localiobuflen)); + for(int nv = 0; nv < nvars; nv++){ + for(PIO_Offset i = 0; i < localiobuflen; i++){ + memcpy(&((char *)mv_iobuf)[iodesc->mpitype_size * (i + nv * localiobuflen)], + &((char *)fillvalue)[nv * iodesc->mpitype_size], iodesc->mpitype_size); } - LOG((3, "allocated token for variable buffer")); - } - - /* Move data from compute to IO tasks. */ - if ((ierr = rearrange_comp2io(ios, iodesc, file, array, mv_iobuf, nvars))) - { - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Writing multiple variables to file (%s, ncid=%d) failed. Error rearranging and moving data from compute tasks to I/O tasks", pio_get_fname_from_file(file), ncid); + } } + } + else if(file->iotype == PIO_IOTYPE_PNETCDF && ios->ioproc){ + /* this assures that iobuf is allocated on all iotasks thus + assuring that the flush_output_buffer call above is called + collectively (from all iotasks) */ + mv_iobuf = spio_file_mvcache_alloc(file, ioid, 1); + if(!mv_iobuf){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Writing multiple variables to file (%s, ncid=%d) failed. Out of memory (Trying to allocate 1 byte)", pio_get_fname_from_file(file), ncid); + } + LOG((3, "allocated token for variable buffer")); + } + + /* Move data from compute to IO tasks. */ + if((ierr = rearrange_comp2io(ios, iodesc, file, array, mv_iobuf, nvars))){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Writing multiple variables to file (%s, ncid=%d) failed. Error rearranging and moving data from compute tasks to I/O tasks", pio_get_fname_from_file(file), ncid); + } #ifdef PIO_MICRO_TIMING - double rearr_time = 0; - /* Use the timer on the first variable to capture the total - *time to rearrange data for all variables - */ - ierr = mtimer_pause(file->varlist[varids[0]].wr_rearr_mtimer, NULL); - if(ierr != PIO_NOERR) - { - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Writing multiple variables to file (%s, ncid=%d) failed. Pausing a micro timer (to measure rearrange time) failed", pio_get_fname_from_file(file), ncid); - } - - ierr = mtimer_get_wtime(file->varlist[varids[0]].wr_rearr_mtimer, - &rearr_time); - if(ierr != PIO_NOERR) - { + double rearr_time = 0; + /* Use the timer on the first variable to capture the total + *time to rearrange data for all variables + */ + ierr = mtimer_pause(file->varlist[varids[0]].wr_rearr_mtimer, NULL); + if(ierr != PIO_NOERR){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Writing multiple variables to file (%s, ncid=%d) failed. Pausing a micro timer (to measure rearrange time) failed", pio_get_fname_from_file(file), ncid); + } + + ierr = mtimer_get_wtime(file->varlist[varids[0]].wr_rearr_mtimer, &rearr_time); + if(ierr != PIO_NOERR){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Writing multiple variables to file (%s, ncid=%d) failed. Retrieving wallclock time from a micro timer (rearrange time) failed", pio_get_fname_from_file(file), ncid); + } + + /* Calculate the average rearrange time for a variable */ + rearr_time /= nvars; + for(int i=0; ivarlist[varids[i]].wr_rearr_mtimer); + if(ierr != PIO_NOERR){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Writing multiple variables to file (%s, ncid=%d) failed. Resetting micro timer (to measure rearrange time) for variable %d failed", pio_get_fname_from_file(file), ncid, i); + } + + /* Update the rearrange timer with avg rearrange time for a var */ + ierr = mtimer_update(file->varlist[varids[i]].wr_rearr_mtimer, rearr_time); + if(ierr != PIO_NOERR){ + LOG((1, "ERROR: Unable to update wr rearr timer")); + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Writing multiple variables to file (%s, ncid=%d) failed. Updating micro timer (to measure rearrange time) for variable %d failed", pio_get_fname_from_file(file), ncid, i); + } + ierr = mtimer_flush(file->varlist[varids[i]].wr_rearr_mtimer, + get_var_desc_str(file->pio_ncid, varids[i], NULL)); + if(ierr != PIO_NOERR){ + LOG((1, "ERROR: Unable to flush wr rearr timer")); + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Writing multiple variables to file (%s, ncid=%d) failed. Flushing micro timer (to measure rearrange time) for variable %d failed", pio_get_fname_from_file(file), ncid, i); + } + /* Update the write timer with avg rearrange time for a var + * i.e, the write timer includes the rearrange time + */ + ierr = mtimer_update(file->varlist[varids[i]].wr_mtimer, rearr_time); + if(ierr != PIO_NOERR){ + LOG((1, "ERROR: Unable to update wr timer")); + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Writing multiple variables to file (%s, ncid=%d) failed. Updating micro timer (to measure write time) for variable %d failed", pio_get_fname_from_file(file), ncid, i); + } + + /* If the write timer was already running, resume it */ + if(var_mtimer_was_running[i]){ + ierr = mtimer_resume(file->varlist[varids[i]].wr_mtimer); + if(ierr != PIO_NOERR){ + LOG((1, "ERROR: Unable to resume wr timer")); return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Writing multiple variables to file (%s, ncid=%d) failed. Retrieving wallclock time from a micro timer (rearrange time) failed", pio_get_fname_from_file(file), ncid); - } - - /* Calculate the average rearrange time for a variable */ - rearr_time /= nvars; - for(int i=0; ivarlist[varids[i]].wr_rearr_mtimer); - if(ierr != PIO_NOERR) - { - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Writing multiple variables to file (%s, ncid=%d) failed. Resetting micro timer (to measure rearrange time) for variable %d failed", pio_get_fname_from_file(file), ncid, i); - } - - /* Update the rearrange timer with avg rearrange time for a var */ - ierr = mtimer_update(file->varlist[varids[i]].wr_rearr_mtimer, - rearr_time); - if(ierr != PIO_NOERR) - { - LOG((1, "ERROR: Unable to update wr rearr timer")); - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Writing multiple variables to file (%s, ncid=%d) failed. Updating micro timer (to measure rearrange time) for variable %d failed", pio_get_fname_from_file(file), ncid, i); - } - ierr = mtimer_flush(file->varlist[varids[i]].wr_rearr_mtimer, - get_var_desc_str(file->pio_ncid, varids[i], NULL)); - if(ierr != PIO_NOERR) - { - LOG((1, "ERROR: Unable to flush wr rearr timer")); - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Writing multiple variables to file (%s, ncid=%d) failed. Flushing micro timer (to measure rearrange time) for variable %d failed", pio_get_fname_from_file(file), ncid, i); - } - /* Update the write timer with avg rearrange time for a var - * i.e, the write timer includes the rearrange time - */ - ierr = mtimer_update(file->varlist[varids[i]].wr_mtimer, - rearr_time); - if(ierr != PIO_NOERR) - { - LOG((1, "ERROR: Unable to update wr timer")); - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Writing multiple variables to file (%s, ncid=%d) failed. Updating micro timer (to measure write time) for variable %d failed", pio_get_fname_from_file(file), ncid, i); - } - - /* If the write timer was already running, resume it */ - if(var_mtimer_was_running[i]) - { - ierr = mtimer_resume(file->varlist[varids[i]].wr_mtimer); - if(ierr != PIO_NOERR) - { - LOG((1, "ERROR: Unable to resume wr timer")); - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Writing multiple variables to file (%s, ncid=%d) failed. Updating micro timer (to measure write time) for variable %d failed", pio_get_fname_from_file(file), ncid, i); - } - } + "Writing multiple variables to file (%s, ncid=%d) failed. Updating micro timer (to measure write time) for variable %d failed", pio_get_fname_from_file(file), ncid, i); + } } + } #endif - /* Write the darray based on the iotype. */ - LOG((2, "about to write darray for iotype = %d", file->iotype)); - switch (file->iotype) - { + /* Write the darray based on the iotype. */ + LOG((2, "about to write darray for iotype = %d", file->iotype)); + switch(file->iotype){ case PIO_IOTYPE_NETCDF4P: case PIO_IOTYPE_NETCDF4P_NCZARR: case PIO_IOTYPE_PNETCDF: case PIO_IOTYPE_HDF5: case PIO_IOTYPE_HDF5C: - if ((ierr = write_darray_multi_par(file, nvars, fndims, varids, iodesc, - DARRAY_DATA, frame))) - { - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Writing multiple variables to file (%s, ncid=%d) failed. Internal error writing variable data in parallel (iotype = %s)", pio_get_fname_from_file(file), ncid, pio_iotype_to_string(file->iotype)); + if((ierr = write_darray_multi_par(file, nvars, fndims, varids, iodesc, + DARRAY_DATA, frame))){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Writing multiple variables to file (%s, ncid=%d) failed. Internal error writing variable data in parallel (iotype = %s)", pio_get_fname_from_file(file), ncid, pio_iotype_to_string(file->iotype)); } break; case PIO_IOTYPE_NETCDF4C: case PIO_IOTYPE_NETCDF: - if ((ierr = write_darray_multi_serial(file, nvars, fndims, varids, iodesc, - DARRAY_DATA, frame))) - { - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Writing multiple variables to file (%s, ncid=%d) failed. Internal error writing variable data serially (iotype = %s)", pio_get_fname_from_file(file), ncid, pio_iotype_to_string(file->iotype)); + if((ierr = write_darray_multi_serial(file, nvars, fndims, varids, iodesc, + DARRAY_DATA, frame))){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Writing multiple variables to file (%s, ncid=%d) failed. Internal error writing variable data serially (iotype = %s)", pio_get_fname_from_file(file), ncid, pio_iotype_to_string(file->iotype)); } break; default: return pio_err(NULL, NULL, PIO_EBADIOTYPE, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Invalid iotype (%d) provided", pio_get_fname_from_file(file), ncid, file->iotype); + } + + /* For PNETCDF the iobuf is freed in flush_output_buffer() */ + if(file->iotype != PIO_IOTYPE_PNETCDF){ + /* Release resources. */ + if(mv_iobuf){ + LOG((3,"freeing variable buffer in pio_darray")); + spio_file_mvcache_free(file, ioid); + } + } + + /* The box rearranger will always have data (it could be fill + * data) to fill the entire array - that is the aggregate start + * and count values will completely describe one unlimited + * dimension unit of the array. For the subset method this is not + * necessarily the case, areas of missing data may never be + * written. In order to make sure that these areas are given the + * missing value a 'holegrid' is used to describe the missing + * points. This is generally faster than the netcdf method of + * filling the entire array with missing values before overwriting + * those values later. */ + if(iodesc->rearranger == PIO_REARR_SUBSET && iodesc->needsfill){ + LOG((2, "nvars = %d holegridsize = %ld iodesc->needsfill = %d\n", nvars, + iodesc->holegridsize, iodesc->needsfill)); + + pioassert(!vdesc0->fillbuf, "buffer overwrite",__FILE__, __LINE__); + + /* Get a buffer. */ + if(ios->io_rank == 0){ + vdesc0->fillbuf = bget(iodesc->maxholegridsize * iodesc->mpitype_size * nvars); + } + else if(iodesc->holegridsize > 0){ + vdesc0->fillbuf = bget(iodesc->holegridsize * iodesc->mpitype_size * nvars); + } + + /* copying the fill value into the data buffer for the box + * rearranger. This will be overwritten with data where + * provided. */ + for(int nv = 0; nv < nvars; nv++){ + for(int i = 0; i < iodesc->holegridsize; i++){ + memcpy(&((char *)vdesc0->fillbuf)[iodesc->mpitype_size * (i + nv * iodesc->holegridsize)], + &((char *)fillvalue)[iodesc->mpitype_size * nv], iodesc->mpitype_size); + } } - /* For PNETCDF the iobuf is freed in flush_output_buffer() */ - if (file->iotype != PIO_IOTYPE_PNETCDF) - { - /* Release resources. */ - if (mv_iobuf) - { - LOG((3,"freeing variable buffer in pio_darray")); - spio_file_mvcache_free(file, ioid); - } - } - - /* The box rearranger will always have data (it could be fill - * data) to fill the entire array - that is the aggregate start - * and count values will completely describe one unlimited - * dimension unit of the array. For the subset method this is not - * necessarily the case, areas of missing data may never be - * written. In order to make sure that these areas are given the - * missing value a 'holegrid' is used to describe the missing - * points. This is generally faster than the netcdf method of - * filling the entire array with missing values before overwriting - * those values later. */ - if (iodesc->rearranger == PIO_REARR_SUBSET && iodesc->needsfill) - { - LOG((2, "nvars = %d holegridsize = %ld iodesc->needsfill = %d\n", nvars, - iodesc->holegridsize, iodesc->needsfill)); - - pioassert(!vdesc0->fillbuf, "buffer overwrite",__FILE__, __LINE__); - - /* Get a buffer. */ - if (ios->io_rank == 0) - vdesc0->fillbuf = bget(iodesc->maxholegridsize * iodesc->mpitype_size * nvars); - else if (iodesc->holegridsize > 0) - vdesc0->fillbuf = bget(iodesc->holegridsize * iodesc->mpitype_size * nvars); - - /* copying the fill value into the data buffer for the box - * rearranger. This will be overwritten with data where - * provided. */ - for (int nv = 0; nv < nvars; nv++) - for (int i = 0; i < iodesc->holegridsize; i++) - memcpy(&((char *)vdesc0->fillbuf)[iodesc->mpitype_size * (i + nv * iodesc->holegridsize)], - &((char *)fillvalue)[iodesc->mpitype_size * nv], iodesc->mpitype_size); - - /* Write the darray based on the iotype. */ - switch (file->iotype) - { - case PIO_IOTYPE_PNETCDF: - case PIO_IOTYPE_NETCDF4P: - case PIO_IOTYPE_NETCDF4P_NCZARR: - if ((ierr = write_darray_multi_par(file, nvars, fndims, varids, iodesc, - DARRAY_FILL, frame))) - { - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Writing multiple variables to file (%s, ncid=%d) failed. Internal error writing variable fillvalues in parallel (iotype = %s)", pio_get_fname_from_file(file), ncid, pio_iotype_to_string(file->iotype)); - } - break; - case PIO_IOTYPE_NETCDF4C: - case PIO_IOTYPE_NETCDF: - if ((ierr = write_darray_multi_serial(file, nvars, fndims, varids, iodesc, - DARRAY_FILL, frame))) - { - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Writing multiple variables to file (%s, ncid=%d) failed. Internal error writing variable fillvalues serially (iotype = %s)", pio_get_fname_from_file(file), ncid, pio_iotype_to_string(file->iotype)); - } - break; - default: - return pio_err(ios, file, PIO_EBADIOTYPE, __FILE__, __LINE__, - "Writing fillvalues for multiple variables to file (%s, ncid=%d) failed. Unsupported iotype (%s) provided", pio_get_fname_from_file(file), ncid, pio_iotype_to_string(file->iotype)); - } - - /* For PNETCDF fillbuf is freed in flush_output_buffer() */ - if (file->iotype != PIO_IOTYPE_PNETCDF) - { - /* Free resources. */ - if (vdesc0->fillbuf) - { - brel(vdesc0->fillbuf); - vdesc0->fillbuf = NULL; - } - } - } - - /* Only PNETCDF does non-blocking buffered writes, and hence - * needs an explicit flush/wait to make sure data is written - * to disk (if the buffer is full) - */ - if (ios->ioproc && file->iotype == PIO_IOTYPE_PNETCDF) - { - /* Flush data to disk for pnetcdf. */ - if ((ierr = flush_output_buffer(file, flushtodisk, 0))) - { + /* Write the darray based on the iotype. */ + switch (file->iotype){ + case PIO_IOTYPE_PNETCDF: + case PIO_IOTYPE_NETCDF4P: + case PIO_IOTYPE_NETCDF4P_NCZARR: + if((ierr = write_darray_multi_par(file, nvars, fndims, varids, iodesc, + DARRAY_FILL, frame))){ return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Writing multiple variables to file (%s, ncid=%d) failed. Flushing data to disk (PIO_IOTYPE_PNETCDF) failed", pio_get_fname_from_file(file), ncid); - } + "Writing multiple variables to file (%s, ncid=%d) failed. Internal error writing variable fillvalues in parallel (iotype = %s)", pio_get_fname_from_file(file), ncid, pio_iotype_to_string(file->iotype)); + } + break; + case PIO_IOTYPE_NETCDF4C: + case PIO_IOTYPE_NETCDF: + if((ierr = write_darray_multi_serial(file, nvars, fndims, varids, iodesc, + DARRAY_FILL, frame))){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Writing multiple variables to file (%s, ncid=%d) failed. Internal error writing variable fillvalues serially (iotype = %s)", pio_get_fname_from_file(file), ncid, pio_iotype_to_string(file->iotype)); + } + break; + default: + return pio_err(ios, file, PIO_EBADIOTYPE, __FILE__, __LINE__, + "Writing fillvalues for multiple variables to file (%s, ncid=%d) failed. Unsupported iotype (%s) provided", pio_get_fname_from_file(file), ncid, pio_iotype_to_string(file->iotype)); + } + + /* For PNETCDF fillbuf is freed in flush_output_buffer() */ + if(file->iotype != PIO_IOTYPE_PNETCDF){ + /* Free resources. */ + if(vdesc0->fillbuf){ + brel(vdesc0->fillbuf); + vdesc0->fillbuf = NULL; + } } - else - { - for(int i=0; ivarlist[varids[i]].wb_pend = 0; + } + + /* Only PNETCDF does non-blocking buffered writes, and hence + * needs an explicit flush/wait to make sure data is written + * to disk (if the buffer is full) + */ + if(ios->ioproc && file->iotype == PIO_IOTYPE_PNETCDF){ + /* Flush data to disk for pnetcdf. */ + if((ierr = flush_output_buffer(file, flushtodisk, 0))){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Writing multiple variables to file (%s, ncid=%d) failed. Flushing data to disk (PIO_IOTYPE_PNETCDF) failed", pio_get_fname_from_file(file), ncid); + } + } + else{ + for(int i=0; ivarlist[varids[i]].wb_pend = 0; #ifdef PIO_MICRO_TIMING - /* No more async events pending (all buffered data is written out) */ - mtimer_async_event_in_progress(file->varlist[varids[i]].wr_mtimer, false); - mtimer_flush(file->varlist[varids[i]].wr_mtimer, get_var_desc_str(file->pio_ncid, varids[i], NULL)); + /* No more async events pending (all buffered data is written out) */ + mtimer_async_event_in_progress(file->varlist[varids[i]].wr_mtimer, false); + mtimer_flush(file->varlist[varids[i]].wr_mtimer, get_var_desc_str(file->pio_ncid, varids[i], NULL)); #endif - } - file->wb_pend = 0; } + file->wb_pend = 0; + } - return PIO_NOERR; + return PIO_NOERR; } /** @@ -1973,511 +1932,508 @@ static int PIOc_write_darray_adios(file_desc_t *file, int varid, int ioid, int PIOc_write_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, const void *array, const void *fillvalue) { - iosystem_desc_t *ios; /* Pointer to io system information. */ - file_desc_t *file; /* Info about file we are writing to. */ - io_desc_t *iodesc; /* The IO description. */ - var_desc_t *vdesc; /* Info about the var being written. */ - void *bufptr; /* A data buffer. */ - MPI_Datatype vtype; /* The MPI type of the variable. */ - wmulti_buffer *wmb; /* The write multi buffer for one or more vars. */ - int recordvar; /* Non-zero if this is a record variable. */ - int needsflush = 0; /* True if we need to flush buffer. */ + iosystem_desc_t *ios; /* Pointer to io system information. */ + file_desc_t *file; /* Info about file we are writing to. */ + io_desc_t *iodesc; /* The IO description. */ + var_desc_t *vdesc; /* Info about the var being written. */ + void *bufptr; /* A data buffer. */ + MPI_Datatype vtype; /* The MPI type of the variable. */ + wmulti_buffer *wmb; /* The write multi buffer for one or more vars. */ + int recordvar; /* Non-zero if this is a record variable. */ + int needsflush = 0; /* True if we need to flush buffer. */ #if PIO_LIMIT_CACHED_IO_REGIONS - PIO_Offset decomp_max_regions; /* Max non-contiguous regions in the IO decomposition */ - PIO_Offset io_max_regions; /* Max non-contiguous regions cached in a single IO process */ + PIO_Offset decomp_max_regions; /* Max non-contiguous regions in the IO decomposition */ + PIO_Offset io_max_regions; /* Max non-contiguous regions cached in a single IO process */ #endif - int mpierr = MPI_SUCCESS; /* Return code from MPI functions. */ - int ierr = PIO_NOERR; /* Return code. */ - - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer1("PIO:PIOc_write_darray"); - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer2("PIO:write_total"); - LOG((1, "PIOc_write_darray ncid = %d varid = %d ioid = %d arraylen = %d", - ncid, varid, ioid, arraylen)); - - /* Get the file info. */ - if ((ierr = pio_get_file(ncid, &file))) - { - return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, - "Writing variable (varid=%d) failed on file. Invalid file id (ncid=%d) provided", varid, ncid); - } - assert(file); - ios = file->iosystem; - assert(ios); - - SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper file_fstats_wr_timer(file->io_fstats->wr_timer_name); - SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper file_fstats_tot_timer(file->io_fstats->tot_timer_name); - SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper ios_fstats_wr_timer(ios->io_fstats->wr_timer_name); - SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper ios_fstats_tot_timer(ios->io_fstats->tot_timer_name); - - if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) - { - GPTLstart("PIO:PIOc_write_darray_adios"); - GPTLstart("PIO:write_total_adios"); - } - - LOG((1, "PIOc_write_darray ncid=%d varid=%d wb_pend=%llu file_wb_pend=%llu", - ncid, varid, - (unsigned long long int) file->varlist[varid].wb_pend, - (unsigned long long int) file->wb_pend - )); - - /* Can we write to this file? */ - if (!(file->mode & PIO_WRITE)) - { - if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) - { - GPTLstop("PIO:PIOc_write_darray_adios"); - GPTLstop("PIO:write_total_adios"); - } - return pio_err(ios, file, PIO_EPERM, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. The file was not opened for writing, try reopening the file in write mode (use the PIO_WRITE flag)", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } + int mpierr = MPI_SUCCESS; /* Return code from MPI functions. */ + int ierr = PIO_NOERR; /* Return code. */ + + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer1("PIO:PIOc_write_darray"); + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer2("PIO:write_total"); + LOG((1, "PIOc_write_darray ncid = %d varid = %d ioid = %d arraylen = %d", + ncid, varid, ioid, arraylen)); + + /* Get the file info. */ + if((ierr = pio_get_file(ncid, &file))){ + return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, + "Writing variable (varid=%d) failed on file. Invalid file id (ncid=%d) provided", varid, ncid); + } + assert(file); + ios = file->iosystem; + assert(ios); + + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper file_fstats_wr_timer(file->io_fstats->wr_timer_name); + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper file_fstats_tot_timer(file->io_fstats->tot_timer_name); + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper ios_fstats_wr_timer(ios->io_fstats->wr_timer_name); + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper ios_fstats_tot_timer(ios->io_fstats->tot_timer_name); + + if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ + GPTLstart("PIO:PIOc_write_darray_adios"); + GPTLstart("PIO:write_total_adios"); + } + + LOG((1, "PIOc_write_darray ncid=%d varid=%d wb_pend=%llu file_wb_pend=%llu", + ncid, varid, + (unsigned long long int) file->varlist[varid].wb_pend, + (unsigned long long int) file->wb_pend + )); + + /* Can we write to this file? */ + if(!(file->mode & PIO_WRITE)){ + if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ + GPTLstop("PIO:PIOc_write_darray_adios"); + GPTLstop("PIO:write_total_adios"); + } + return pio_err(ios, file, PIO_EPERM, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. The file was not opened for writing, try reopening the file in write mode (use the PIO_WRITE flag)", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + /* Get decomposition information. */ + if(!(iodesc = pio_get_iodesc_from_id(ioid))){ + if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ + GPTLstop("PIO:PIOc_write_darray_adios"); + GPTLstop("PIO:write_total_adios"); + } + return pio_err(ios, file, PIO_EBADID, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Invalid I/O descriptor id (ioid=%d) provided", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, ioid); + } + + /* Check that the local size of the variable passed in matches the + * size expected by the io descriptor. Fail if arraylen is too + * small, just put a warning in the log and truncate arraylen + * if it is too big (the excess values will be ignored.) */ + if(arraylen < iodesc->ndof){ + if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ + GPTLstop("PIO:PIOc_write_darray_adios"); + GPTLstop("PIO:write_total_adios"); + } + return pio_err(ios, file, PIO_EINVAL, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. The local array size (arraylen=%lld) is smaller than expected, the I/O decomposition (ioid=%d) requires a local array of size = %lld", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, (long long int) arraylen, ioid, (long long int) iodesc->ndof); + } + LOG((2, "%s arraylen = %d iodesc->ndof = %d", + (arraylen > iodesc->ndof) ? "WARNING: arraylen > iodesc->ndof" : "", + arraylen, iodesc->ndof)); #ifdef _ADIOS2 - if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) - { - /* ADIOS type does not support open to append mode */ - if (file->is_reopened) - { - GPTLstop("PIO:PIOc_write_darray"); - GPTLstop("PIO:write_total"); - GPTLstop("PIO:PIOc_write_darray_adios"); - GPTLstop("PIO:write_total_adios"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using ADIOS iotype failed. " - "Open to append mode is not supported yet", - pio_get_vname_from_file(file, varid), varid, - pio_get_fname_from_file(file), ncid); - } - } + if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ + /* ADIOS type does not support open to append mode */ + if(file->is_reopened){ + GPTLstop("PIO:PIOc_write_darray"); + GPTLstop("PIO:write_total"); + GPTLstop("PIO:PIOc_write_darray_adios"); + GPTLstop("PIO:write_total_adios"); + return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using ADIOS iotype failed. " + "Open to append mode is not supported yet", + pio_get_vname_from_file(file, varid), varid, + pio_get_fname_from_file(file), ncid); + } + } #endif - /* Get decomposition information. */ - if (!(iodesc = pio_get_iodesc_from_id(ioid))) - { - if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) - { - GPTLstop("PIO:PIOc_write_darray_adios"); - GPTLstop("PIO:write_total_adios"); - } - return pio_err(ios, file, PIO_EBADID, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Invalid I/O descriptor id (ioid=%d) provided", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, ioid); - } - - /* Check that the local size of the variable passed in matches the - * size expected by the io descriptor. Fail if arraylen is too - * small, just put a warning in the log and truncate arraylen - * if it is too big (the excess values will be ignored.) */ - if (arraylen < iodesc->ndof) - { - if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) - { - GPTLstop("PIO:PIOc_write_darray_adios"); - GPTLstop("PIO:write_total_adios"); - } - return pio_err(ios, file, PIO_EINVAL, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. The local array size (arraylen=%lld) is smaller than expected, the I/O decomposition (ioid=%d) requires a local array of size = %lld", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, (long long int) arraylen, ioid, (long long int) iodesc->ndof); - } - LOG((2, "%s arraylen = %d iodesc->ndof = %d", - (arraylen > iodesc->ndof) ? "WARNING: arraylen > iodesc->ndof" : "", - arraylen, iodesc->ndof)); - if (arraylen > iodesc->ndof) - arraylen = iodesc->ndof; + /* Get decomposition information. */ + if(!(iodesc = pio_get_iodesc_from_id(ioid))){ + if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ + GPTLstop("PIO:PIOc_write_darray_adios"); + GPTLstop("PIO:write_total_adios"); + } + return pio_err(ios, file, PIO_EBADID, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Invalid I/O descriptor id (ioid=%d) provided", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, ioid); + } + + /* Check that the local size of the variable passed in matches the + * size expected by the io descriptor. Fail if arraylen is too + * small, just put a warning in the log and truncate arraylen + * if it is too big (the excess values will be ignored.) */ + if(arraylen < iodesc->ndof){ + if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ + GPTLstop("PIO:PIOc_write_darray_adios"); + GPTLstop("PIO:write_total_adios"); + } + return pio_err(ios, file, PIO_EINVAL, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. The local array size (arraylen=%lld) is smaller than expected, the I/O decomposition (ioid=%d) requires a local array of size = %lld", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, (long long int) arraylen, ioid, (long long int) iodesc->ndof); + } + LOG((2, "%s arraylen = %d iodesc->ndof = %d", + (arraylen > iodesc->ndof) ? "WARNING: arraylen > iodesc->ndof" : "", + arraylen, iodesc->ndof)); + if(arraylen > iodesc->ndof){ + arraylen = iodesc->ndof; + } #ifdef PIO_MICRO_TIMING - mtimer_start(file->varlist[varid].wr_mtimer); + mtimer_start(file->varlist[varid].wr_mtimer); #endif #if PIO_SAVE_DECOMPS - if(!(iodesc->is_saved) && - pio_save_decomps_regex_match(ioid, file->fname, file->varlist[varid].vname)) - { - char filename[PIO_MAX_NAME]; - ierr = pio_create_uniq_str(ios, iodesc, filename, PIO_MAX_NAME, "piodecomp", ".dat"); - if(ierr != PIO_NOERR) - { - if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) - { - GPTLstop("PIO:PIOc_write_darray_adios"); - GPTLstop("PIO:write_total_adios"); - } - return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Saving I/O decomposition (ioid=%d) failed. Unable to create a unique file name for saving the I/O decomposition", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, ioid); - } - LOG((2, "Saving decomp map (write) to %s", filename)); - PIOc_writemap_impl(filename, ioid, iodesc->ndims, iodesc->dimlen, iodesc->maplen, iodesc->map, ios->my_comm); - iodesc->is_saved = true; + if(!(iodesc->is_saved) && + pio_save_decomps_regex_match(ioid, file->fname, file->varlist[varid].vname)){ + char filename[PIO_MAX_NAME]; + ierr = pio_create_uniq_str(ios, iodesc, filename, PIO_MAX_NAME, "piodecomp", ".dat"); + if(ierr != PIO_NOERR){ + if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ + GPTLstop("PIO:PIOc_write_darray_adios"); + GPTLstop("PIO:write_total_adios"); + } + return pio_err(ios, NULL, ierr, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Saving I/O decomposition (ioid=%d) failed. Unable to create a unique file name for saving the I/O decomposition", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, ioid); } + LOG((2, "Saving decomp map (write) to %s", filename)); + PIOc_writemap_impl(filename, ioid, iodesc->ndims, iodesc->dimlen, iodesc->maplen, iodesc->map, ios->my_comm); + iodesc->is_saved = true; + } #endif - /* Get var description. */ - vdesc = &(file->varlist[varid]); - LOG((2, "vdesc record %d nreqs %d", vdesc->record, vdesc->nreqs)); - - /* Run these on all tasks if async is not in use, but only on - * non-IO tasks if async is in use. */ - if (!ios->async || !ios->ioproc) - { - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - - /* Find out PIO data type of var. */ - if (vdesc->pio_type == PIO_NAT) - { - if ((ierr = PIOc_inq_vartype_impl(ncid, varid, &vdesc->pio_type))) - { - return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Inquiring variable data type failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - } - - assert(vdesc->pio_type != PIO_NAT); + /* Get var description. */ + vdesc = &(file->varlist[varid]); + LOG((2, "vdesc record %d nreqs %d", vdesc->record, vdesc->nreqs)); + + /* Run these on all tasks if async is not in use, but only on + * non-IO tasks if async is in use. */ + if(!ios->async || !ios->ioproc){ + spio_ltimer_stop(ios->io_fstats->wr_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->wr_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); - /* Find out length of type. */ - if (vdesc->type_size == 0) - { - if ((ierr = PIOc_inq_type_impl(ncid, vdesc->pio_type, NULL, &vdesc->type_size))) - { - return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Inquiring variable data type length failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - } + /* Find out PIO data type of var. */ + if(vdesc->pio_type == PIO_NAT){ + if((ierr = PIOc_inq_vartype_impl(ncid, varid, &vdesc->pio_type))){ + return pio_err(ios, NULL, ierr, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Inquiring variable data type failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + } - assert(vdesc->type_size > 0); + assert(vdesc->pio_type != PIO_NAT); - spio_ltimer_start(ios->io_fstats->wr_timer_name); - spio_ltimer_start(ios->io_fstats->tot_timer_name); - spio_ltimer_start(file->io_fstats->wr_timer_name); - spio_ltimer_start(file->io_fstats->tot_timer_name); + /* Find out length of type. */ + if(vdesc->type_size == 0){ + if((ierr = PIOc_inq_type_impl(ncid, vdesc->pio_type, NULL, &vdesc->type_size))){ + return pio_err(ios, NULL, ierr, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Inquiring variable data type length failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } } - ios->io_fstats->wb += vdesc->type_size * iodesc->llen; - file->io_fstats->wb += vdesc->type_size * iodesc->llen; + assert(vdesc->type_size > 0); - /* If we don't know the fill value for this var, get it. */ -/* TODO handle fill values for HDF5 type later */ -if ((file->iotype != PIO_IOTYPE_HDF5) && (file->iotype != PIO_IOTYPE_HDF5C)) -{ - if (!vdesc->fillvalue) - { - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - if ((ierr = find_var_fillvalue(file, varid, vdesc))) - { - if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) - { - GPTLstop("PIO:PIOc_write_darray_adios"); - GPTLstop("PIO:write_total_adios"); - } - return pio_err(ios, file, PIO_EBADID, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Finding fillvalue associated with the variable failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + spio_ltimer_start(ios->io_fstats->wr_timer_name); + spio_ltimer_start(ios->io_fstats->tot_timer_name); + spio_ltimer_start(file->io_fstats->wr_timer_name); + spio_ltimer_start(file->io_fstats->tot_timer_name); + } + + ios->io_fstats->wb += vdesc->type_size * iodesc->llen; + file->io_fstats->wb += vdesc->type_size * iodesc->llen; + + /* If we don't know the fill value for this var, get it. */ + /* TODO handle fill values for HDF5 type later */ + if((file->iotype != PIO_IOTYPE_HDF5) && (file->iotype != PIO_IOTYPE_HDF5C)){ + if(!vdesc->fillvalue){ + spio_ltimer_stop(ios->io_fstats->wr_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->wr_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + if((ierr = find_var_fillvalue(file, varid, vdesc))){ + if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ + GPTLstop("PIO:PIOc_write_darray_adios"); + GPTLstop("PIO:write_total_adios"); } - spio_ltimer_start(ios->io_fstats->wr_timer_name); - spio_ltimer_start(ios->io_fstats->tot_timer_name); - spio_ltimer_start(file->io_fstats->wr_timer_name); - spio_ltimer_start(file->io_fstats->tot_timer_name); + return pio_err(ios, file, PIO_EBADID, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Finding fillvalue associated with the variable failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + spio_ltimer_start(ios->io_fstats->wr_timer_name); + spio_ltimer_start(ios->io_fstats->tot_timer_name); + spio_ltimer_start(file->io_fstats->wr_timer_name); + spio_ltimer_start(file->io_fstats->tot_timer_name); } -} + } - /* Is this a record variable? The user must set the vdesc->record - * value by calling PIOc_setframe() before calling this - * function. */ - recordvar = vdesc->record >= 0 ? 1 : 0; - LOG((3, "recordvar = %d looking for multibuffer", recordvar)); + /* Is this a record variable? The user must set the vdesc->record + * value by calling PIOc_setframe() before calling this + * function. */ + recordvar = vdesc->record >= 0 ? 1 : 0; + LOG((3, "recordvar = %d looking for multibuffer", recordvar)); - /* Move to end of list or the entry that matches this ioid. */ - for (wmb = &file->buffer; wmb->next; wmb = wmb->next) - if (wmb->ioid == ioid && wmb->recordvar == recordvar) - break; - LOG((3, "wmb->ioid = %d wmb->recordvar = %d", wmb->ioid, wmb->recordvar)); + /* Move to end of list or the entry that matches this ioid. */ + for(wmb = &file->buffer; wmb->next; wmb = wmb->next){ + if(wmb->ioid == ioid && wmb->recordvar == recordvar){ + break; + } + } + LOG((3, "wmb->ioid = %d wmb->recordvar = %d", wmb->ioid, wmb->recordvar)); #ifdef _ADIOS2 - if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) - { - ierr = PIO_NOERR; - ierr = PIOc_write_darray_adios(file, varid, ioid, iodesc, arraylen, array, fillvalue); - GPTLstop("PIO:PIOc_write_darray_adios"); - GPTLstop("PIO:write_total_adios"); - return ierr; - } + if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ + ierr = PIO_NOERR; + ierr = PIOc_write_darray_adios(file, varid, ioid, iodesc, arraylen, array, fillvalue); + GPTLstop("PIO:PIOc_write_darray_adios"); + GPTLstop("PIO:write_total_adios"); + return ierr; + } #endif - /* If we did not find an existing wmb entry, create a new wmb. */ - if (wmb->ioid != ioid || wmb->recordvar != recordvar) - { - /* Allocate a buffer. */ - LOG((3, "allocating multi-buffer")); - if (!(wmb->next = (wmulti_buffer *) calloc(1, sizeof(wmulti_buffer)))) - { - return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Out of memory allocating %lld bytes for a write multi buffer to cache user data", pio_get_fname_from_file(file), varid, pio_get_fname_from_file(file), file->pio_ncid, (unsigned long long) sizeof(wmulti_buffer)); - } - LOG((3, "allocated multi-buffer")); - - /* Set pointer to newly allocated buffer and initialize.*/ - wmb = wmb->next; - wmb->recordvar = recordvar; - wmb->next = NULL; - wmb->ioid = ioid; - wmb->num_arrays = 0; - wmb->arraylen = arraylen; - wmb->vid = NULL; - wmb->data = NULL; - wmb->frame = NULL; - wmb->fillvalue = NULL; - } - LOG((2, "wmb->num_arrays = %d arraylen = %d iodesc->mpitype_size = %d\n", - wmb->num_arrays, arraylen, iodesc->mpitype_size)); + /* If we did not find an existing wmb entry, create a new wmb. */ + if(wmb->ioid != ioid || wmb->recordvar != recordvar){ + /* Allocate a buffer. */ + LOG((3, "allocating multi-buffer")); + if(!(wmb->next = (wmulti_buffer *) calloc(1, sizeof(wmulti_buffer)))){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Out of memory allocating %lld bytes for a write multi buffer to cache user data", pio_get_fname_from_file(file), varid, pio_get_fname_from_file(file), file->pio_ncid, (unsigned long long) sizeof(wmulti_buffer)); + } + LOG((3, "allocated multi-buffer")); + + /* Set pointer to newly allocated buffer and initialize.*/ + wmb = wmb->next; + wmb->recordvar = recordvar; + wmb->next = NULL; + wmb->ioid = ioid; + wmb->num_arrays = 0; + wmb->arraylen = arraylen; + wmb->vid = NULL; + wmb->data = NULL; + wmb->frame = NULL; + wmb->fillvalue = NULL; + } + LOG((2, "wmb->num_arrays = %d arraylen = %d iodesc->mpitype_size = %d\n", + wmb->num_arrays, arraylen, iodesc->mpitype_size)); - needsflush = PIO_wmb_needs_flush(wmb, arraylen, iodesc); - assert(needsflush >= 0); + needsflush = PIO_wmb_needs_flush(wmb, arraylen, iodesc); + assert(needsflush >= 0); #if PIO_LIMIT_CACHED_IO_REGIONS - /* When using PIO with PnetCDF + SUBSET rearranger the number - of non-contiguous regions cached in a single IO process can - grow to a large number. PnetCDF is not efficient at handling - very large number of regions (sub-array requests) in the - data written out. We typically run out of memory or the - write is very slow. - - We need to set a limit on the potential (after rearrangement) - maximum number of non-contiguous regions in an IO process and - forcefully flush out user data cached by a compute process - when that limit has been reached. - - Latest PnetCDF (version 1.11.0 and later) is more efficient at - handling very large number of regions, so we have turned off - PIO_LIMIT_CACHED_IO_REGIONS option by default. */ - decomp_max_regions = (iodesc->maxregions >= iodesc->maxfillregions)? iodesc->maxregions : iodesc->maxfillregions; - io_max_regions = (1 + wmb->num_arrays) * decomp_max_regions; - if (io_max_regions > PIO_MAX_CACHED_IO_REGIONS) - needsflush = 2; + /* When using PIO with PnetCDF + SUBSET rearranger the number + of non-contiguous regions cached in a single IO process can + grow to a large number. PnetCDF is not efficient at handling + very large number of regions (sub-array requests) in the + data written out. We typically run out of memory or the + write is very slow. + + We need to set a limit on the potential (after rearrangement) + maximum number of non-contiguous regions in an IO process and + forcefully flush out user data cached by a compute process + when that limit has been reached. + + Latest PnetCDF (version 1.11.0 and later) is more efficient at + handling very large number of regions, so we have turned off + PIO_LIMIT_CACHED_IO_REGIONS option by default. */ + decomp_max_regions = (iodesc->maxregions >= iodesc->maxfillregions)? iodesc->maxregions : iodesc->maxfillregions; + io_max_regions = (1 + wmb->num_arrays) * decomp_max_regions; + if(io_max_regions > PIO_MAX_CACHED_IO_REGIONS){ + needsflush = 2; + } #endif - /* Tell all tasks on the computation communicator whether we need - * to flush data. */ - if ((mpierr = MPI_Allreduce(MPI_IN_PLACE, &needsflush, 1, MPI_INT, MPI_MAX, - ios->comp_comm))) - { - return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + /* Tell all tasks on the computation communicator whether we need + * to flush data. */ + if((mpierr = MPI_Allreduce(MPI_IN_PLACE, &needsflush, 1, MPI_INT, MPI_MAX, ios->comp_comm))){ + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + } + LOG((2, "needsflush = %d", needsflush)); + + if(!ios->async || !ios->ioproc){ + if(file->varlist[varid].vrsize == 0){ + spio_ltimer_stop(ios->io_fstats->wr_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->wr_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + ierr = calc_var_rec_sz(ncid, varid); + if(ierr != PIO_NOERR){ + LOG((1, "Unable to calculate the variable record size")); + } + spio_ltimer_start(ios->io_fstats->wr_timer_name); + spio_ltimer_start(ios->io_fstats->tot_timer_name); + spio_ltimer_start(file->io_fstats->wr_timer_name); + spio_ltimer_start(file->io_fstats->tot_timer_name); } - LOG((2, "needsflush = %d", needsflush)); + } - if(!ios->async || !ios->ioproc) - { - if(file->varlist[varid].vrsize == 0) - { - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - ierr = calc_var_rec_sz(ncid, varid); - if(ierr != PIO_NOERR) - { - LOG((1, "Unable to calculate the variable record size")); - } - spio_ltimer_start(ios->io_fstats->wr_timer_name); - spio_ltimer_start(ios->io_fstats->tot_timer_name); - spio_ltimer_start(file->io_fstats->wr_timer_name); - spio_ltimer_start(file->io_fstats->tot_timer_name); - } - } - /* Flush data if needed. */ - if (needsflush > 0) - { + /* Flush data if needed. */ + if(needsflush > 0){ #if !PIO_USE_MALLOC #ifdef PIO_ENABLE_LOGGING - /* Collect a debug report about buffer. */ - cn_buffer_report(ios, true); + /* Collect a debug report about buffer. */ + cn_buffer_report(ios, true); #endif /* PIO_ENABLE_LOGGING */ #endif /* !PIO_USE_MALLOC */ - /* Flush buffer to I/O processes - rearrange data and - * start writing data from the I/O processes - * Note : Setting the last flag in flush_buffer to - * true will force flush the buffer to disk for all - * iotypes (wait for write to complete for PnetCDF) - */ - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - if ((ierr = flush_buffer(ncid, wmb, (needsflush == 2)))) - { - GPTLstop("PIO:PIOc_write_darray"); - GPTLstop("PIO:write_total"); - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Flushing data (multiple cached variables with the same decomposition) from compute processes to I/O processes %s failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, (needsflush == 2) ? "and to disk" : ""); - } - spio_ltimer_start(ios->io_fstats->wr_timer_name); - spio_ltimer_start(ios->io_fstats->tot_timer_name); - spio_ltimer_start(file->io_fstats->wr_timer_name); - spio_ltimer_start(file->io_fstats->tot_timer_name); + /* Flush buffer to I/O processes - rearrange data and + * start writing data from the I/O processes + * Note : Setting the last flag in flush_buffer to + * true will force flush the buffer to disk for all + * iotypes (wait for write to complete for PnetCDF) + */ + spio_ltimer_stop(ios->io_fstats->wr_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->wr_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + if((ierr = flush_buffer(ncid, wmb, (needsflush == 2)))){ + GPTLstop("PIO:PIOc_write_darray"); + GPTLstop("PIO:write_total"); + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Flushing data (multiple cached variables with the same decomposition) from compute processes to I/O processes %s failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, (needsflush == 2) ? "and to disk" : ""); } - - /* One record size (sum across all procs) of data is buffered */ - file->varlist[varid].wb_pend += file->varlist[varid].vrsize; - file->wb_pend += file->varlist[varid].vrsize; - LOG((1, "Current pending bytes for ncid=%d, varid=%d var_wb_pend= %llu, file_wb_pend=%llu", - ncid, varid, - (unsigned long long int) file->varlist[varid].wb_pend, - (unsigned long long int) file->wb_pend - )); - /* Buffering data is considered an async event (to indicate - *that the event is not yet complete) - */ + spio_ltimer_start(ios->io_fstats->wr_timer_name); + spio_ltimer_start(ios->io_fstats->tot_timer_name); + spio_ltimer_start(file->io_fstats->wr_timer_name); + spio_ltimer_start(file->io_fstats->tot_timer_name); + } + + /* One record size (sum across all procs) of data is buffered */ + file->varlist[varid].wb_pend += file->varlist[varid].vrsize; + file->wb_pend += file->varlist[varid].vrsize; + LOG((1, "Current pending bytes for ncid=%d, varid=%d var_wb_pend= %llu, file_wb_pend=%llu", + ncid, varid, + (unsigned long long int) file->varlist[varid].wb_pend, + (unsigned long long int) file->wb_pend + )); + /* Buffering data is considered an async event (to indicate + *that the event is not yet complete) + */ #ifdef PIO_MICRO_TIMING - mtimer_async_event_in_progress(file->varlist[varid].wr_mtimer, true); + mtimer_async_event_in_progress(file->varlist[varid].wr_mtimer, true); #endif - /* Get memory for data. */ - if (arraylen > 0) - { - if (!(wmb->data = bgetr(wmb->data, (1 + wmb->num_arrays) * arraylen * iodesc->mpitype_size))) - { - return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Out of memory allocating space (realloc %lld bytes) to cache user data", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, (long long int )((1 + wmb->num_arrays) * arraylen * iodesc->mpitype_size)); - } - LOG((2, "got %ld bytes for data", (1 + wmb->num_arrays) * arraylen * iodesc->mpitype_size)); - } - - /* vid is an array of variable ids in the wmb list, grow the list - * and add the new entry. */ - if (!(wmb->vid = (int *) realloc(wmb->vid, sizeof(int) * (1 + wmb->num_arrays)))) - { - return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Out of memory allocating space (realloc %lld bytes) for array of variable ids in write multi buffer to cache user data", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, (unsigned long long)(sizeof(int) * (1 + wmb->num_arrays))); - } - - /* wmb->frame is the record number, we assume that the variables - * in the wmb list may not all have the same unlimited dimension - * value although they usually do. */ - if (vdesc->record >= 0) - if (!(wmb->frame = (int *) realloc(wmb->frame, sizeof(int) * (1 + wmb->num_arrays)))) - { - return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Out of memory allocating space (realloc %lld bytes) for array of frame numbers in write multi buffer to cache user data", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, (unsigned long long)(sizeof(int) * (1 + wmb->num_arrays))); - } - - /* If we need a fill value, get it. If we are using the subset - * rearranger and not using the netcdf fill mode then we need to - * do an extra write to fill in the holes with the fill value. */ - if (iodesc->needsfill) - { - /* Get memory to hold fill value. */ - if (!(wmb->fillvalue = bgetr(wmb->fillvalue, iodesc->mpitype_size * (1 + wmb->num_arrays)))) - { - return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Out of memory allocating space (realloc %lld bytes) for variable fillvalues in write multi buffer to cache user data", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, (unsigned long long)(iodesc->mpitype_size * (1 + wmb->num_arrays))); - } - - /* If the user passed a fill value, use that, otherwise use - * the default fill value of the netCDF type. Copy the fill - * value to the buffer. */ - if (fillvalue) - { - memcpy((char *)wmb->fillvalue + iodesc->mpitype_size * wmb->num_arrays, - fillvalue, iodesc->mpitype_size); - LOG((3, "copied user-provided fill value iodesc->mpitype_size = %d", - iodesc->mpitype_size)); - } - else - { - void *fill; - signed char byte_fill = PIO_FILL_BYTE; - char char_fill = PIO_FILL_CHAR; - short short_fill = PIO_FILL_SHORT; - int int_fill = PIO_FILL_INT; - float float_fill = PIO_FILL_FLOAT; - double double_fill = PIO_FILL_DOUBLE; + /* Get memory for data. */ + if(arraylen > 0){ + if(!(wmb->data = bgetr(wmb->data, (1 + wmb->num_arrays) * arraylen * iodesc->mpitype_size))){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Out of memory allocating space (realloc %lld bytes) to cache user data", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, (long long int )((1 + wmb->num_arrays) * arraylen * iodesc->mpitype_size)); + } + LOG((2, "got %ld bytes for data", (1 + wmb->num_arrays) * arraylen * iodesc->mpitype_size)); + } + + /* vid is an array of variable ids in the wmb list, grow the list + * and add the new entry. */ + if(!(wmb->vid = (int *) realloc(wmb->vid, sizeof(int) * (1 + wmb->num_arrays)))){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Out of memory allocating space (realloc %lld bytes) for array of variable ids in write multi buffer to cache user data", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, (unsigned long long)(sizeof(int) * (1 + wmb->num_arrays))); + } + + /* wmb->frame is the record number, we assume that the variables + * in the wmb list may not all have the same unlimited dimension + * value although they usually do. */ + if(vdesc->record >= 0){ + if(!(wmb->frame = (int *) realloc(wmb->frame, sizeof(int) * (1 + wmb->num_arrays)))){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Out of memory allocating space (realloc %lld bytes) for array of frame numbers in write multi buffer to cache user data", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, (unsigned long long)(sizeof(int) * (1 + wmb->num_arrays))); + } + } + + /* If we need a fill value, get it. If we are using the subset + * rearranger and not using the netcdf fill mode then we need to + * do an extra write to fill in the holes with the fill value. */ + if(iodesc->needsfill){ + /* Get memory to hold fill value. */ + if(!(wmb->fillvalue = bgetr(wmb->fillvalue, iodesc->mpitype_size * (1 + wmb->num_arrays)))){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Out of memory allocating space (realloc %lld bytes) for variable fillvalues in write multi buffer to cache user data", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, (unsigned long long)(iodesc->mpitype_size * (1 + wmb->num_arrays))); + } + + /* If the user passed a fill value, use that, otherwise use + * the default fill value of the netCDF type. Copy the fill + * value to the buffer. */ + if(fillvalue){ + memcpy((char *)wmb->fillvalue + iodesc->mpitype_size * wmb->num_arrays, + fillvalue, iodesc->mpitype_size); + LOG((3, "copied user-provided fill value iodesc->mpitype_size = %d", iodesc->mpitype_size)); + } + else{ + void *fill; + signed char byte_fill = PIO_FILL_BYTE; + char char_fill = PIO_FILL_CHAR; + short short_fill = PIO_FILL_SHORT; + int int_fill = PIO_FILL_INT; + float float_fill = PIO_FILL_FLOAT; + double double_fill = PIO_FILL_DOUBLE; #ifdef _NETCDF4 - unsigned char ubyte_fill = PIO_FILL_UBYTE; - unsigned short ushort_fill = PIO_FILL_USHORT; - unsigned int uint_fill = PIO_FILL_UINT; - long long int64_fill = PIO_FILL_INT64; - long long uint64_fill = PIO_FILL_UINT64; + unsigned char ubyte_fill = PIO_FILL_UBYTE; + unsigned short ushort_fill = PIO_FILL_USHORT; + unsigned int uint_fill = PIO_FILL_UINT; + long long int64_fill = PIO_FILL_INT64; + long long uint64_fill = PIO_FILL_UINT64; #endif /* _NETCDF4 */ - vtype = (MPI_Datatype)iodesc->mpitype; - LOG((3, "caller did not provide fill value vtype = %d", vtype)); - - /* This must be done with an if statement, not a case, or - * openmpi will not build. */ - if (vtype == MPI_BYTE) - fill = &byte_fill; - else if (vtype == MPI_CHAR) - fill = &char_fill; - else if (vtype == MPI_SHORT) - fill = &short_fill; - else if (vtype == MPI_INT) - fill = &int_fill; - else if (vtype == MPI_FLOAT) - fill = &float_fill; - else if (vtype == MPI_DOUBLE) - fill = &double_fill; + vtype = (MPI_Datatype)iodesc->mpitype; + LOG((3, "caller did not provide fill value vtype = %d", vtype)); + + /* This must be done with an if statement, not a case, or + * openmpi will not build. */ + if(vtype == MPI_BYTE){ + fill = &byte_fill; + } + else if(vtype == MPI_CHAR){ + fill = &char_fill; + } + else if(vtype == MPI_SHORT){ + fill = &short_fill; + } + else if(vtype == MPI_INT){ + fill = &int_fill; + } + else if(vtype == MPI_FLOAT){ + fill = &float_fill; + } + else if(vtype == MPI_DOUBLE){ + fill = &double_fill; + } #ifdef _NETCDF4 - else if (vtype == MPI_UNSIGNED_CHAR) - fill = &ubyte_fill; - else if (vtype == MPI_UNSIGNED_SHORT) - fill = &ushort_fill; - else if (vtype == MPI_UNSIGNED) - fill = &uint_fill; - else if (vtype == MPI_LONG_LONG) - fill = &int64_fill; - else if (vtype == MPI_UNSIGNED_LONG_LONG) - fill = &uint64_fill; + else if(vtype == MPI_UNSIGNED_CHAR){ + fill = &ubyte_fill; + } + else if(vtype == MPI_UNSIGNED_SHORT){ + fill = &ushort_fill; + } + else if(vtype == MPI_UNSIGNED){ + fill = &uint_fill; + } + else if(vtype == MPI_LONG_LONG){ + fill = &int64_fill; + } + else if(vtype == MPI_UNSIGNED_LONG_LONG){ + fill = &uint64_fill; + } #endif /* _NETCDF4 */ - else - { - return pio_err(ios, file, PIO_EBADTYPE, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Unable to find a default fillvalue for variable, unsupported variable type", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - memcpy((char *)wmb->fillvalue + iodesc->mpitype_size * wmb->num_arrays, - fill, iodesc->mpitype_size); - LOG((3, "copied fill value")); - } - } - - /* Tell the buffer about the data it is getting. */ - wmb->arraylen = arraylen; - wmb->vid[wmb->num_arrays] = varid; - LOG((3, "wmb->num_arrays = %d wmb->vid[wmb->num_arrays] = %d", wmb->num_arrays, - wmb->vid[wmb->num_arrays])); - - /* Copy the user-provided data to the buffer. */ - bufptr = (void *)((char *)wmb->data + arraylen * iodesc->mpitype_size * wmb->num_arrays); - if (arraylen > 0) - { - memcpy(bufptr, array, arraylen * iodesc->mpitype_size); - LOG((3, "copied %ld bytes of user data", arraylen * iodesc->mpitype_size)); - } - - /* Add the unlimited dimension value of this variable to the frame - * array in wmb. */ - if (wmb->frame) - wmb->frame[wmb->num_arrays] = vdesc->record; - wmb->num_arrays++; - - LOG((2, "wmb->num_arrays = %d iodesc->maxbytes / iodesc->mpitype_size = %d " - "iodesc->ndof = %d iodesc->llen = %d", wmb->num_arrays, - iodesc->maxbytes / iodesc->mpitype_size, iodesc->ndof, iodesc->llen)); + else{ + return pio_err(ios, file, PIO_EBADTYPE, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Unable to find a default fillvalue for variable, unsupported variable type", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } - LOG((1, "Write darray end : pending bytes for ncid=%d, varid=%d var_wb_pend=%llu file_wb_pend=%llu", - ncid, varid, - (unsigned long long int) file->varlist[varid].wb_pend, - (unsigned long long int) file->wb_pend - )); + memcpy((char *)wmb->fillvalue + iodesc->mpitype_size * wmb->num_arrays, + fill, iodesc->mpitype_size); + LOG((3, "copied fill value")); + } + } + + /* Tell the buffer about the data it is getting. */ + wmb->arraylen = arraylen; + wmb->vid[wmb->num_arrays] = varid; + LOG((3, "wmb->num_arrays = %d wmb->vid[wmb->num_arrays] = %d", wmb->num_arrays, + wmb->vid[wmb->num_arrays])); + + /* Copy the user-provided data to the buffer. */ + bufptr = (void *)((char *)wmb->data + arraylen * iodesc->mpitype_size * wmb->num_arrays); + if(arraylen > 0){ + memcpy(bufptr, array, arraylen * iodesc->mpitype_size); + LOG((3, "copied %ld bytes of user data", arraylen * iodesc->mpitype_size)); + } + + /* Add the unlimited dimension value of this variable to the frame + * array in wmb. */ + if(wmb->frame){ + wmb->frame[wmb->num_arrays] = vdesc->record; + } + wmb->num_arrays++; + + LOG((2, "wmb->num_arrays = %d iodesc->maxbytes / iodesc->mpitype_size = %d " + "iodesc->ndof = %d iodesc->llen = %d", wmb->num_arrays, + iodesc->maxbytes / iodesc->mpitype_size, iodesc->ndof, iodesc->llen)); + + LOG((1, "Write darray end : pending bytes for ncid=%d, varid=%d var_wb_pend=%llu file_wb_pend=%llu", + ncid, varid, + (unsigned long long int) file->varlist[varid].wb_pend, + (unsigned long long int) file->wb_pend + )); #ifdef PIO_MICRO_TIMING - mtimer_stop(file->varlist[varid].wr_mtimer, get_var_desc_str(ncid, varid, NULL)); + mtimer_stop(file->varlist[varid].wr_mtimer, get_var_desc_str(ncid, varid, NULL)); #endif - return PIO_NOERR; + return PIO_NOERR; } #ifdef _ADIOS2 From 49e8c092eb752d14b0e011e8518d71ac0df9a354 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 28 Nov 2024 12:20:09 -0600 Subject: [PATCH 021/194] Expose decomp/rearranger info for contig rearr Adding functions to expose I/O decomposition and rearrangement information in the contig rearranger. * Check if rearranger is initialized * Get I/O decomposition map info * Get rearranger info (buffer size, range) --- src/clib/pio_rearr_contig.hpp | 68 +++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/src/clib/pio_rearr_contig.hpp b/src/clib/pio_rearr_contig.hpp index 2266f1fe07..efeb442ff5 100644 --- a/src/clib/pio_rearr_contig.hpp +++ b/src/clib/pio_rearr_contig.hpp @@ -61,12 +61,66 @@ namespace SPIO{ elem_mpi_type_sz_(0), agg_comm_(MPI_COMM_NULL), is_agg_root_(false), agg_comm_sz_(0), rearr_comm_(MPI_COMM_NULL), rearr_comm_sz_(0), rearr_comm_iochunk_sz_(0){} + /* Initialize the rearranger */ int init(int pio_type, const PIO_Offset *compmap, std::size_t compmap_sz, const int *gdimlen, int ndims, io_desc_t *iodesc); + + bool is_init(void ) const{ return is_init_; } + + /* Get decomp info */ + std::size_t get_decomp_map_lsz(void ) const{ + assert(is_init_); + return static_cast(lcompmap_sz_); + } + + std::size_t get_decomp_gsz(void ) const{ + assert(is_init_); + return static_cast(gdecomp_sz_); + } + + /* Get rearrange info */ + std::size_t get_rearrange_buf_sz(void ) const{ + assert(is_init_ && ios_); + if(!ios_->ioproc){ + return 0; + } + + /* FIXME: Should we return the buffer size in bytes ? */ + PIO_Offset iochunk = rearr_comm_iochunk_sz_; + if(rearr_comm_rank_ != (rearr_comm_sz_ - 1)){ + return iochunk; + } + else{ + /* The last I/O process gets the remaining data */ + return (gdecomp_sz_ - rearr_comm_rank_ * iochunk); + } + } + + std::pair get_rearr_decomp_map_range(int iorank) + { + assert(gdecomp_sz_ > 0); + assert(rearr_comm_iochunk_sz_ > 0); + + PIO_Offset iochunk = rearr_comm_iochunk_sz_; + PIO_Offset start = iorank * iochunk; + PIO_Offset end = start + iochunk; + if(iorank == (rearr_comm_sz_ - 1)){ + end = gdecomp_sz_; + } + return std::make_pair(start, end); + } + + std::pair get_rearr_decomp_map_range(void ) + { + return get_rearr_decomp_map_range(rearr_comm_rank_); + } + + /* Rearrange data */ int rearrange_comp2io(const void *sbuf, std::size_t sbuf_sz, void *rbuf, std::size_t rbuf_sz, int nvars); int rearrange_io2comp(const void *sbuf, std::size_t sbuf_sz, void *rbuf, std::size_t rbuf_sz, int nvars); + /* Finalize the rearranger */ int finalize(void ); private: bool is_init_; @@ -120,20 +174,6 @@ namespace SPIO{ void *rbuf, std::size_t rbuf_sz, int nvars); int create_rearr_comm(void ); - std::pair get_rearr_decomp_map_range(int iorank) - { - assert(gdecomp_sz_ > 0); - assert(rearr_comm_iochunk_sz_ > 0); - - PIO_Offset iochunk = rearr_comm_iochunk_sz_; - PIO_Offset start = iorank * iochunk; - PIO_Offset end = start + iochunk; - if(iorank == (rearr_comm_sz_ - 1)){ - end = gdecomp_sz_; - } - return std::make_pair(start, end); - } - int get_rearr_toproc_map(const std::vector &gcompmap, std::vector &to_proc); int setup_data_rearr_info(std::vector &gcompmap, std::vector &to_proc, From f433cee259a0427bc56a32136ca1ac22c9e8515f Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 28 Nov 2024 12:32:53 -0600 Subject: [PATCH 022/194] Using GPTL & Ltimer wrappers for read Using GPTL and SPIO ltimer wrappers, to simplify stopping the timer on function return, in the read darray function --- src/clib/pio_darray.cpp | 75 ++++------------------------------------- 1 file changed, 6 insertions(+), 69 deletions(-) diff --git a/src/clib/pio_darray.cpp b/src/clib/pio_darray.cpp index 067bab1ff0..3065b7940b 100644 --- a/src/clib/pio_darray.cpp +++ b/src/clib/pio_darray.cpp @@ -3426,33 +3426,28 @@ int PIOc_read_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, #ifdef _ADIOS2 adios_var_desc_t *vdesc_adios2; /* Info about the variable from the adios structure */ #endif - GPTLstart("PIO:PIOc_read_darray"); + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("PIO:PIOc_read_darray"); + /* Get the file info. */ if ((ierr = pio_get_file(ncid, &file))) { - GPTLstop("PIO:PIOc_read_darray"); return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, "Reading variable (varid=%d) failed. Invalid arguments provided, file id (ncid=%d) is invalid", varid, ncid); } assert(file); - spio_ltimer_start(file->io_fstats->rd_timer_name); - spio_ltimer_start(file->io_fstats->tot_timer_name); ios = file->iosystem; assert(ios); - spio_ltimer_start(ios->io_fstats->rd_timer_name); - spio_ltimer_start(ios->io_fstats->tot_timer_name); + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper ios_fstats_rd_timer(ios->io_fstats->rd_timer_name); + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper ios_fstats_tot_timer(ios->io_fstats->tot_timer_name); + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper file_fstats_rd_timer(file->io_fstats->rd_timer_name); + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper file_fstats_tot_timer(file->io_fstats->tot_timer_name); LOG((1, "PIOc_read_darray (ncid=%d (%s), varid=%d (%s)", ncid, pio_get_fname_from_file(file), varid, pio_get_vname_from_file(file, varid))); /* Get the iodesc. */ if (!(iodesc = pio_get_iodesc_from_id(ioid))) { - GPTLstop("PIO:PIOc_read_darray"); - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, PIO_EBADID, __FILE__, __LINE__, "Reading variable (%s, varid=%d) from file (%s, ncid=%d)failed. Invalid arguments provided, I/O descriptor id (ioid=%d) is invalid", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, ioid); } @@ -3493,7 +3488,6 @@ int PIOc_read_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, { if ((ierr = PIOc_inq_vartype_impl(ncid, varid, &vdesc->pio_type))) { - GPTLstop("PIO:PIOc_read_darray"); return pio_err(ios, NULL, ierr, __FILE__, __LINE__, "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed. Inquiring variable data type failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); } @@ -3516,7 +3510,6 @@ int PIOc_read_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, { if ((ierr = PIOc_inq_type_impl(ncid, vdesc->pio_type, NULL, &vdesc->type_size))) { - GPTLstop("PIO:PIOc_read_darray"); return pio_err(ios, NULL, ierr, __FILE__, __LINE__, "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed. Inquiring variable data type length failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); } @@ -3560,7 +3553,6 @@ int PIOc_read_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, spio_ltimer_stop(file->io_fstats->tot_timer_name); ierr = PIOc_inq_varndims_impl(file->pio_ncid, varid, &fndims); if(ierr != PIO_NOERR){ - GPTLstop("PIO:PIOc_read_darray"); return pio_err(ios, file, ierr, __FILE__, __LINE__, "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Inquiring number of variable dimensions failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); } @@ -3610,11 +3602,6 @@ int PIOc_read_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, if (ios->ioproc && rlen > 0) if (!(iobuf = bget(iodesc->mpitype_size * rlen))) { - GPTLstop("PIO:PIOc_read_darray"); - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Out of memory allocating space (%lld bytes) in I/O processes to read data from file (before rearrangement)", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, (long long int) (iodesc->mpitype_size * rlen)); } @@ -3627,11 +3614,6 @@ int PIOc_read_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, PIO_SEND_ASYNC_MSG(ios, msg, &ierr, ncid, varid, ioid); if(ierr != PIO_NOERR) { - GPTLstop("PIO:PIOc_read_darray"); - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, ierr, __FILE__, __LINE__, "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Sending async message, PIO_MSG_READDARRAY, failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); } @@ -3640,11 +3622,6 @@ int PIOc_read_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, mpierr = MPI_Bcast(&fndims, 1, MPI_INT, ios->comproot, ios->my_comm); if(mpierr != MPI_SUCCESS) { - GPTLstop("PIO:PIOc_read_darray"); - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); } LOG((3, "shared fndims = %d", fndims)); @@ -3658,11 +3635,6 @@ int PIOc_read_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, ierr = pio_create_uniq_str(ios, iodesc, filename, PIO_MAX_NAME, "piodecomp", ".dat"); if(ierr != PIO_NOERR) { - GPTLstop("PIO:PIOc_read_darray"); - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, NULL, ierr, __FILE__, __LINE__, "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Saving the I/O decomposition (ioid=%d) failed, unable to create a unique file name for saving the decomposition", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, ioid); } @@ -3680,11 +3652,6 @@ int PIOc_read_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, case PIO_IOTYPE_NETCDF4C: if ((ierr = pio_read_darray_nc_serial(file, fndims, iodesc, varid, iobuf))) { - GPTLstop("PIO:PIOc_read_darray"); - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, ierr, __FILE__, __LINE__, "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Reading variable in serial (iotype=%s) failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, pio_iotype_to_string(file->iotype)); } @@ -3694,11 +3661,6 @@ int PIOc_read_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, case PIO_IOTYPE_NETCDF4P_NCZARR: if ((ierr = pio_read_darray_nc(file, fndims, iodesc, varid, iobuf))) { - GPTLstop("PIO:PIOc_read_darray"); - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, ierr, __FILE__, __LINE__, "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Reading variable in parallel (iotype=%s) failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, pio_iotype_to_string(file->iotype)); } @@ -3710,11 +3672,6 @@ int PIOc_read_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, if ((ierr = PIOc_read_darray_adios(file, fndims, iodesc, varid, array))) { GPTLstop("PIO:PIOc_read_darray_adios"); - GPTLstop("PIO:PIOc_read_darray"); - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, ierr, __FILE__, __LINE__, "Reading variable (%s, varid=%d) from file (%s, ncid=%d) using ADIOS iotype failed. " "Reading variable in parallel failed", @@ -3722,20 +3679,10 @@ int PIOc_read_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, } GPTLstop("PIO:PIOc_read_darray_adios"); - GPTLstop("PIO:PIOc_read_darray"); - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return PIO_NOERR; #endif default: - GPTLstop("PIO:PIOc_read_darray"); - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(NULL, NULL, PIO_EBADIOTYPE, __FILE__, __LINE__, "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Invalid iotype (%d) provided", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, file->iotype); } @@ -3747,11 +3694,6 @@ int PIOc_read_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, /* Rearrange the data. */ if ((ierr = rearrange_io2comp(ios, iodesc, iobuf, array))) { - GPTLstop("PIO:PIOc_read_darray"); - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, ierr, __FILE__, __LINE__, "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Rearranging data read in the I/O processes to compute processes failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); } @@ -3770,10 +3712,5 @@ int PIOc_read_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, #ifdef PIO_MICRO_TIMING mtimer_stop(file->varlist[varid].rd_mtimer, get_var_desc_str(ncid, varid, NULL)); #endif - GPTLstop("PIO:PIOc_read_darray"); - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return PIO_NOERR; } From efc6c9f7ed6a0e70619c3f1e58e3e1e221c69dff Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 28 Nov 2024 12:43:32 -0600 Subject: [PATCH 023/194] Code reformatting read darray func Code reformatting (starting braces on same line, no spaces btw keyword and starting of braces, 2 space tab) the read darray function --- src/clib/pio_darray.cpp | 444 +++++++++++++++++++--------------------- 1 file changed, 210 insertions(+), 234 deletions(-) diff --git a/src/clib/pio_darray.cpp b/src/clib/pio_darray.cpp index 3065b7940b..70c102669c 100644 --- a/src/clib/pio_darray.cpp +++ b/src/clib/pio_darray.cpp @@ -3414,303 +3414,279 @@ static int PIOc_read_darray_adios(file_desc_t *file, int fndims, io_desc_t *iode int PIOc_read_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, void *array) { - iosystem_desc_t *ios; /* Pointer to io system information. */ - file_desc_t *file; /* Pointer to file information. */ - io_desc_t *iodesc; /* Pointer to IO description information. */ - var_desc_t *vdesc; /* Info about the var being read. */ - void *iobuf = NULL; /* holds the data as read on the io node. */ - size_t rlen = 0; /* the length of data in iobuf. */ - int ierr = PIO_NOERR, mpierr = MPI_SUCCESS; /* Return code. */ - int fndims = 0; + iosystem_desc_t *ios; /* Pointer to io system information. */ + file_desc_t *file; /* Pointer to file information. */ + io_desc_t *iodesc; /* Pointer to IO description information. */ + var_desc_t *vdesc; /* Info about the var being read. */ + void *iobuf = NULL; /* holds the data as read on the io node. */ + size_t rlen = 0; /* the length of data in iobuf. */ + int ierr = PIO_NOERR, mpierr = MPI_SUCCESS; /* Return code. */ + int fndims = 0; #ifdef _ADIOS2 - adios_var_desc_t *vdesc_adios2; /* Info about the variable from the adios structure */ + adios_var_desc_t *vdesc_adios2; /* Info about the variable from the adios structure */ #endif - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("PIO:PIOc_read_darray"); + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("PIO:PIOc_read_darray"); - /* Get the file info. */ - if ((ierr = pio_get_file(ncid, &file))) - { - return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, - "Reading variable (varid=%d) failed. Invalid arguments provided, file id (ncid=%d) is invalid", varid, ncid); - } - assert(file); - ios = file->iosystem; - assert(ios); + /* Get the file info. */ + if((ierr = pio_get_file(ncid, &file))){ + return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, + "Reading variable (varid=%d) failed. Invalid arguments provided, file id (ncid=%d) is invalid", varid, ncid); + } + assert(file); + ios = file->iosystem; + assert(ios); - SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper ios_fstats_rd_timer(ios->io_fstats->rd_timer_name); - SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper ios_fstats_tot_timer(ios->io_fstats->tot_timer_name); - SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper file_fstats_rd_timer(file->io_fstats->rd_timer_name); - SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper file_fstats_tot_timer(file->io_fstats->tot_timer_name); + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper ios_fstats_rd_timer(ios->io_fstats->rd_timer_name); + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper ios_fstats_tot_timer(ios->io_fstats->tot_timer_name); + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper file_fstats_rd_timer(file->io_fstats->rd_timer_name); + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper file_fstats_tot_timer(file->io_fstats->tot_timer_name); - LOG((1, "PIOc_read_darray (ncid=%d (%s), varid=%d (%s)", ncid, pio_get_fname_from_file(file), varid, pio_get_vname_from_file(file, varid))); + LOG((1, "PIOc_read_darray (ncid=%d (%s), varid=%d (%s)", ncid, pio_get_fname_from_file(file), varid, pio_get_vname_from_file(file, varid))); - /* Get the iodesc. */ - if (!(iodesc = pio_get_iodesc_from_id(ioid))) - { - return pio_err(ios, file, PIO_EBADID, __FILE__, __LINE__, - "Reading variable (%s, varid=%d) from file (%s, ncid=%d)failed. Invalid arguments provided, I/O descriptor id (ioid=%d) is invalid", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, ioid); - } - pioassert(iodesc->rearranger == PIO_REARR_BOX || iodesc->rearranger == PIO_REARR_SUBSET, - "unknown rearranger", __FILE__, __LINE__); + /* Get the iodesc. */ + if(!(iodesc = pio_get_iodesc_from_id(ioid))){ + return pio_err(ios, file, PIO_EBADID, __FILE__, __LINE__, + "Reading variable (%s, varid=%d) from file (%s, ncid=%d)failed. Invalid arguments provided, I/O descriptor id (ioid=%d) is invalid", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, ioid); + } + pioassert(iodesc->rearranger == PIO_REARR_BOX || iodesc->rearranger == PIO_REARR_SUBSET, + "unknown rearranger", __FILE__, __LINE__); - /* Get var description. */ - if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) - { + /* Get var description. */ + if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ #ifdef _ADIOS2 - vdesc_adios2 = &(file->adios_vars[varid]); + vdesc_adios2 = &(file->adios_vars[varid]); #endif - } - else - vdesc = &(file->varlist[varid]); + } + else{ + vdesc = &(file->varlist[varid]); + } - /* Run these on all tasks if async is not in use, but only on - * non-IO tasks if async is in use. */ - if (!ios->async || !ios->ioproc) - { - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); + /* Run these on all tasks if async is not in use, but only on + * non-IO tasks if async is in use. */ + if(!ios->async || !ios->ioproc){ + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->rd_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); - /* Find out PIO data type of var. */ - if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) - { + /* Find out PIO data type of var. */ + if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ #ifdef _ADIOS2 - assert(vdesc_adios2->nc_type != PIO_NAT); - vdesc_adios2->adios_type = spio_get_adios_type(vdesc_adios2->nc_type); - assert(vdesc_adios2->adios_type != adios2_type_unknown); + assert(vdesc_adios2->nc_type != PIO_NAT); + vdesc_adios2->adios_type = spio_get_adios_type(vdesc_adios2->nc_type); + assert(vdesc_adios2->adios_type != adios2_type_unknown); #endif + } + else{ + if(vdesc->pio_type == PIO_NAT){ + if((ierr = PIOc_inq_vartype_impl(ncid, varid, &vdesc->pio_type))){ + return pio_err(ios, NULL, ierr, __FILE__, __LINE__, + "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed. Inquiring variable data type failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); } - else - { - if (vdesc->pio_type == PIO_NAT) - { - if ((ierr = PIOc_inq_vartype_impl(ncid, varid, &vdesc->pio_type))) - { - return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed. Inquiring variable data type failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - } - assert(vdesc->pio_type != PIO_NAT); - } + } + assert(vdesc->pio_type != PIO_NAT); + } - /* Find out length of type. */ - if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) - { + /* Find out length of type. */ + if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ #ifdef _ADIOS2 - if (vdesc_adios2->adios_type_size == 0) - vdesc_adios2->adios_type_size = get_adios2_type_size(vdesc_adios2->adios_type, NULL); - assert(vdesc_adios2->adios_type_size > 0); + if(vdesc_adios2->adios_type_size == 0){ + vdesc_adios2->adios_type_size = get_adios2_type_size(vdesc_adios2->adios_type, NULL); + } + assert(vdesc_adios2->adios_type_size > 0); #endif + } + else{ + if(vdesc->type_size == 0){ + if((ierr = PIOc_inq_type_impl(ncid, vdesc->pio_type, NULL, &vdesc->type_size))){ + return pio_err(ios, NULL, ierr, __FILE__, __LINE__, + "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed. Inquiring variable data type length failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); } - else - { - if (vdesc->type_size == 0) - { - if ((ierr = PIOc_inq_type_impl(ncid, vdesc->pio_type, NULL, &vdesc->type_size))) - { - return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed. Inquiring variable data type length failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - } - - assert(vdesc->type_size > 0); - } - - spio_ltimer_start(ios->io_fstats->rd_timer_name); - spio_ltimer_start(ios->io_fstats->tot_timer_name); - spio_ltimer_start(file->io_fstats->rd_timer_name); - spio_ltimer_start(file->io_fstats->tot_timer_name); + } + assert(vdesc->type_size > 0); } - if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) - { + spio_ltimer_start(ios->io_fstats->rd_timer_name); + spio_ltimer_start(ios->io_fstats->tot_timer_name); + spio_ltimer_start(file->io_fstats->rd_timer_name); + spio_ltimer_start(file->io_fstats->tot_timer_name); + } + + if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ #ifdef _ADIOS2 - ios->io_fstats->rb += vdesc_adios2->adios_type_size * iodesc->llen; - file->io_fstats->rb += vdesc_adios2->adios_type_size * iodesc->llen; + ios->io_fstats->rb += vdesc_adios2->adios_type_size * iodesc->llen; + file->io_fstats->rb += vdesc_adios2->adios_type_size * iodesc->llen; #endif - } - else - { - ios->io_fstats->rb += vdesc->type_size * iodesc->llen; - file->io_fstats->rb += vdesc->type_size * iodesc->llen; - } + } + else{ + ios->io_fstats->rb += vdesc->type_size * iodesc->llen; + file->io_fstats->rb += vdesc->type_size * iodesc->llen; + } #ifdef PIO_MICRO_TIMING - mtimer_start(file->varlist[varid].rd_mtimer); + mtimer_start(file->varlist[varid].rd_mtimer); #endif - /* Run these on all tasks if async is not in use, but only on - * non-IO tasks if async is in use. */ - if (!ios->async || !ios->ioproc) - { - /* Get the number of dims for this var. */ - LOG((3, "about to call PIOc_inq_varndims varid = %d", varid)); - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - ierr = PIOc_inq_varndims_impl(file->pio_ncid, varid, &fndims); - if(ierr != PIO_NOERR){ - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Inquiring number of variable dimensions failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - spio_ltimer_start(ios->io_fstats->rd_timer_name); - spio_ltimer_start(ios->io_fstats->tot_timer_name); - spio_ltimer_start(file->io_fstats->rd_timer_name); - spio_ltimer_start(file->io_fstats->tot_timer_name); - LOG((3, "called PIOc_inq_varndims varid = %d fndims = %d", varid, fndims)); - } - /* For netcdf serial reads we read some data to the io master - * node then send that data to a corresponding io node. The - * buffer size on io task 0 must be as large as the largest - * used to accommodate this serial io method (use iodesc-> - * maxiobuflen to set it). */ - if ((file->iotype == PIO_IOTYPE_NETCDF || file->iotype == PIO_IOTYPE_NETCDF4C) && ios->iomaster == MPI_ROOT) - rlen = iodesc->maxiobuflen; - else - rlen = iodesc->llen; - - if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) - rlen = 0; - - if(!ios->async || !ios->ioproc) - { - if(file->varlist[varid].vrsize == 0) - { - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - ierr = calc_var_rec_sz(ncid, varid); - if(ierr != PIO_NOERR) - { - LOG((1, "Unable to calculate the variable record size")); - } - spio_ltimer_start(ios->io_fstats->rd_timer_name); - spio_ltimer_start(ios->io_fstats->tot_timer_name); - spio_ltimer_start(file->io_fstats->rd_timer_name); - spio_ltimer_start(file->io_fstats->tot_timer_name); - } + /* Run these on all tasks if async is not in use, but only on + * non-IO tasks if async is in use. */ + if(!ios->async || !ios->ioproc){ + /* Get the number of dims for this var. */ + LOG((3, "about to call PIOc_inq_varndims varid = %d", varid)); + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->rd_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + ierr = PIOc_inq_varndims_impl(file->pio_ncid, varid, &fndims); + if(ierr != PIO_NOERR){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Inquiring number of variable dimensions failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); } + spio_ltimer_start(ios->io_fstats->rd_timer_name); + spio_ltimer_start(ios->io_fstats->tot_timer_name); + spio_ltimer_start(file->io_fstats->rd_timer_name); + spio_ltimer_start(file->io_fstats->tot_timer_name); + LOG((3, "called PIOc_inq_varndims varid = %d fndims = %d", varid, fndims)); + } - file->varlist[varid].rb_pend += file->varlist[varid].vrsize; - file->rb_pend += file->varlist[varid].vrsize; + /* For netcdf serial reads we read some data to the io master + * node then send that data to a corresponding io node. The + * buffer size on io task 0 must be as large as the largest + * used to accommodate this serial io method (use iodesc-> + * maxiobuflen to set it). */ + if((file->iotype == PIO_IOTYPE_NETCDF || file->iotype == PIO_IOTYPE_NETCDF4C) && ios->iomaster == MPI_ROOT){ + rlen = iodesc->maxiobuflen; + } + else{ + rlen = iodesc->llen; + } - /* Allocate a buffer for one record. */ - if (ios->ioproc && rlen > 0) - if (!(iobuf = bget(iodesc->mpitype_size * rlen))) - { - return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, - "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Out of memory allocating space (%lld bytes) in I/O processes to read data from file (before rearrangement)", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, (long long int) (iodesc->mpitype_size * rlen)); - } + if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ + rlen = 0; + } - if(ios->async) - { - /* Send relevant args from compute procs to I/O procs */ - int msg = PIO_MSG_READDARRAY; - - PIO_SEND_ASYNC_MSG(ios, msg, &ierr, ncid, varid, ioid); - if(ierr != PIO_NOERR) - { - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Sending async message, PIO_MSG_READDARRAY, failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } + if(!ios->async || !ios->ioproc){ + if(file->varlist[varid].vrsize == 0){ + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->rd_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + ierr = calc_var_rec_sz(ncid, varid); + if(ierr != PIO_NOERR){ + LOG((1, "Unable to calculate the variable record size")); + } + spio_ltimer_start(ios->io_fstats->rd_timer_name); + spio_ltimer_start(ios->io_fstats->tot_timer_name); + spio_ltimer_start(file->io_fstats->rd_timer_name); + spio_ltimer_start(file->io_fstats->tot_timer_name); + } + } - /* Share results known only on computation tasks with IO tasks. */ - mpierr = MPI_Bcast(&fndims, 1, MPI_INT, ios->comproot, ios->my_comm); - if(mpierr != MPI_SUCCESS) - { - return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); - } - LOG((3, "shared fndims = %d", fndims)); + file->varlist[varid].rb_pend += file->varlist[varid].vrsize; + file->rb_pend += file->varlist[varid].vrsize; + + /* Allocate a buffer for one record. */ + if(ios->ioproc && rlen > 0){ + if(!(iobuf = bget(iodesc->mpitype_size * rlen))){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Out of memory allocating space (%lld bytes) in I/O processes to read data from file (before rearrangement)", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, (long long int) (iodesc->mpitype_size * rlen)); } + } + + if(ios->async){ + /* Send relevant args from compute procs to I/O procs */ + int msg = PIO_MSG_READDARRAY; + + PIO_SEND_ASYNC_MSG(ios, msg, &ierr, ncid, varid, ioid); + if(ierr != PIO_NOERR){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Sending async message, PIO_MSG_READDARRAY, failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + /* Share results known only on computation tasks with IO tasks. */ + mpierr = MPI_Bcast(&fndims, 1, MPI_INT, ios->comproot, ios->my_comm); + if(mpierr != MPI_SUCCESS){ + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + } + LOG((3, "shared fndims = %d", fndims)); + } #if PIO_SAVE_DECOMPS - if(!(iodesc->is_saved) && - pio_save_decomps_regex_match(ioid, file->fname, file->varlist[varid].vname)) - { - char filename[PIO_MAX_NAME]; - ierr = pio_create_uniq_str(ios, iodesc, filename, PIO_MAX_NAME, "piodecomp", ".dat"); - if(ierr != PIO_NOERR) - { - return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Saving the I/O decomposition (ioid=%d) failed, unable to create a unique file name for saving the decomposition", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, ioid); - } - LOG((2, "Saving decomp map (read) to %s", filename)); - PIOc_writemap_impl(filename, ioid, iodesc->ndims, iodesc->dimlen, iodesc->maplen, iodesc->map, ios->my_comm); - iodesc->is_saved = true; + if(!(iodesc->is_saved) && + pio_save_decomps_regex_match(ioid, file->fname, file->varlist[varid].vname)){ + char filename[PIO_MAX_NAME]; + ierr = pio_create_uniq_str(ios, iodesc, filename, PIO_MAX_NAME, "piodecomp", ".dat"); + if(ierr != PIO_NOERR){ + return pio_err(ios, NULL, ierr, __FILE__, __LINE__, + "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Saving the I/O decomposition (ioid=%d) failed, unable to create a unique file name for saving the decomposition", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, ioid); } + LOG((2, "Saving decomp map (read) to %s", filename)); + PIOc_writemap_impl(filename, ioid, iodesc->ndims, iodesc->dimlen, iodesc->maplen, iodesc->map, ios->my_comm); + iodesc->is_saved = true; + } #endif - /* Call the correct darray read function based on iotype. */ - if(!ios->async || ios->ioproc) - { - switch (file->iotype) - { + + /* Call the correct darray read function based on iotype. */ + if(!ios->async || ios->ioproc){ + switch (file->iotype){ case PIO_IOTYPE_NETCDF: case PIO_IOTYPE_NETCDF4C: - if ((ierr = pio_read_darray_nc_serial(file, fndims, iodesc, varid, iobuf))) - { - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Reading variable in serial (iotype=%s) failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, pio_iotype_to_string(file->iotype)); + if((ierr = pio_read_darray_nc_serial(file, fndims, iodesc, varid, iobuf))){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Reading variable in serial (iotype=%s) failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, pio_iotype_to_string(file->iotype)); } break; case PIO_IOTYPE_PNETCDF: case PIO_IOTYPE_NETCDF4P: case PIO_IOTYPE_NETCDF4P_NCZARR: - if ((ierr = pio_read_darray_nc(file, fndims, iodesc, varid, iobuf))) - { - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Reading variable in parallel (iotype=%s) failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, pio_iotype_to_string(file->iotype)); + if((ierr = pio_read_darray_nc(file, fndims, iodesc, varid, iobuf))){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Reading variable in parallel (iotype=%s) failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, pio_iotype_to_string(file->iotype)); } break; -#ifdef _ADIOS2 + #ifdef _ADIOS2 case PIO_IOTYPE_ADIOS: case PIO_IOTYPE_ADIOSC: GPTLstart("PIO:PIOc_read_darray_adios"); - if ((ierr = PIOc_read_darray_adios(file, fndims, iodesc, varid, array))) - { - GPTLstop("PIO:PIOc_read_darray_adios"); - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Reading variable (%s, varid=%d) from file (%s, ncid=%d) using ADIOS iotype failed. " - "Reading variable in parallel failed", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), ncid); + if((ierr = PIOc_read_darray_adios(file, fndims, iodesc, varid, array))){ + GPTLstop("PIO:PIOc_read_darray_adios"); + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Reading variable (%s, varid=%d) from file (%s, ncid=%d) using ADIOS iotype failed. " + "Reading variable in parallel failed", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), ncid); } - GPTLstop("PIO:PIOc_read_darray_adios"); - return PIO_NOERR; -#endif - default: + #endif + default: return pio_err(NULL, NULL, PIO_EBADIOTYPE, __FILE__, __LINE__, "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Invalid iotype (%d) provided", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, file->iotype); - } } + } #ifdef PIO_MICRO_TIMING - mtimer_start(file->varlist[varid].rd_rearr_mtimer); + mtimer_start(file->varlist[varid].rd_rearr_mtimer); #endif - /* Rearrange the data. */ - if ((ierr = rearrange_io2comp(ios, iodesc, iobuf, array))) - { - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Rearranging data read in the I/O processes to compute processes failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } + /* Rearrange the data. */ + if((ierr = rearrange_io2comp(ios, iodesc, iobuf, array))){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Rearranging data read in the I/O processes to compute processes failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } #ifdef PIO_MICRO_TIMING - mtimer_stop(file->varlist[varid].rd_rearr_mtimer, get_var_desc_str(ncid, varid, NULL)); + mtimer_stop(file->varlist[varid].rd_rearr_mtimer, get_var_desc_str(ncid, varid, NULL)); #endif - /* We don't use non-blocking reads */ - file->varlist[varid].rb_pend = 0; - file->rb_pend = 0; + /* We don't use non-blocking reads */ + file->varlist[varid].rb_pend = 0; + file->rb_pend = 0; - /* Free the buffer. */ - if (rlen > 0) - brel(iobuf); + /* Free the buffer. */ + if(rlen > 0){ + brel(iobuf); + } #ifdef PIO_MICRO_TIMING - mtimer_stop(file->varlist[varid].rd_mtimer, get_var_desc_str(ncid, varid, NULL)); + mtimer_stop(file->varlist[varid].rd_mtimer, get_var_desc_str(ncid, varid, NULL)); #endif - return PIO_NOERR; + return PIO_NOERR; } From 3a686d70a0a7019941887bd25995ac8a53bd062b Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 28 Nov 2024 12:54:15 -0600 Subject: [PATCH 024/194] Adding support for PIO_REARR_CONTIG for rd/wr Adding support for writing data and reading it back using the PIO_REARR_CONTIG rearranger. --- src/clib/pio_darray.cpp | 28 +- src/clib/pio_types.hpp | 10 + src/clib/pioc.cpp | 539 +++++++++++++++++----------- src/clib/pioc_support.cpp | 6 + tests/general/util/pio_tf_f90gen.pl | 6 +- 5 files changed, 364 insertions(+), 225 deletions(-) diff --git a/src/clib/pio_darray.cpp b/src/clib/pio_darray.cpp index 70c102669c..614793e59b 100644 --- a/src/clib/pio_darray.cpp +++ b/src/clib/pio_darray.cpp @@ -20,6 +20,7 @@ #include "spio_hash.h" #include "spio_gptl_utils.hpp" #include "spio_ltimer_utils.hpp" +#include "pio_rearr_contig.hpp" /* uint64_t definition */ #ifdef _ADIOS2 @@ -166,7 +167,7 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar return pio_err(ios, file, PIO_EBADID, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Invalid arguments, invalid PIO decomposition id (%d) provided", pio_get_fname_from_file(file), ncid, ioid); } - pioassert(iodesc->rearranger == PIO_REARR_BOX || iodesc->rearranger == PIO_REARR_SUBSET, + pioassert(iodesc->rearranger == PIO_REARR_BOX || iodesc->rearranger == PIO_REARR_SUBSET || iodesc->rearranger == PIO_REARR_CONTIG, "unknown rearranger", __FILE__, __LINE__); /* Get a pointer to the variable info for the first variable. */ @@ -293,7 +294,7 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar /* If fill values are desired, and we're using the BOX * rearranger, insert fill values. */ - if(iodesc->needsfill && iodesc->rearranger == PIO_REARR_BOX){ + if(iodesc->needsfill && ((iodesc->rearranger == PIO_REARR_BOX) || (iodesc->rearranger == PIO_REARR_CONTIG))){ PIO_Offset localiobuflen = rlen / nvars; LOG((3, "inserting fill values iodesc->maxiobuflen = %lld, localiobuflen = %lld", iodesc->maxiobuflen, localiobuflen)); for(int nv = 0; nv < nvars; nv++){ @@ -317,9 +318,16 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar } /* Move data from compute to IO tasks. */ - if((ierr = rearrange_comp2io(ios, iodesc, file, array, mv_iobuf, nvars))){ + if(iodesc->rearranger == PIO_REARR_CONTIG){ + ierr = iodesc->rearr->rearrange_comp2io(array, arraylen, mv_iobuf, rlen * iodesc->mpitype_size, nvars); + } + else{ + ierr = rearrange_comp2io(ios, iodesc, file, array, mv_iobuf, nvars); + } + if(ierr != PIO_NOERR){ return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Writing multiple variables to file (%s, ncid=%d) failed. Error rearranging and moving data from compute tasks to I/O tasks", pio_get_fname_from_file(file), ncid); + "Writing multiple variables to file (%s, ncid=%d) failed. Error rearranging and moving data from compute tasks to I/O tasks(rearranger = %d)", + pio_get_fname_from_file(file), ncid, iodesc->rearranger); } #ifdef PIO_MICRO_TIMING @@ -3449,7 +3457,7 @@ int PIOc_read_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, return pio_err(ios, file, PIO_EBADID, __FILE__, __LINE__, "Reading variable (%s, varid=%d) from file (%s, ncid=%d)failed. Invalid arguments provided, I/O descriptor id (ioid=%d) is invalid", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, ioid); } - pioassert(iodesc->rearranger == PIO_REARR_BOX || iodesc->rearranger == PIO_REARR_SUBSET, + pioassert(iodesc->rearranger == PIO_REARR_BOX || iodesc->rearranger == PIO_REARR_SUBSET || iodesc->rearranger == PIO_REARR_CONTIG, "unknown rearranger", __FILE__, __LINE__); /* Get var description. */ @@ -3668,9 +3676,15 @@ int PIOc_read_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, mtimer_start(file->varlist[varid].rd_rearr_mtimer); #endif /* Rearrange the data. */ - if((ierr = rearrange_io2comp(ios, iodesc, iobuf, array))){ + if(iodesc->rearranger == PIO_REARR_CONTIG){ + ierr = iodesc->rearr->rearrange_io2comp(iobuf, rlen, array, iodesc->ndof * iodesc->mpitype_size, 1); + } + else{ + ierr = rearrange_io2comp(ios, iodesc, iobuf, array); + } + if(ierr != PIO_NOERR){ return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Rearranging data read in the I/O processes to compute processes failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Rearranging data read in the I/O processes to compute processes failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); } #ifdef PIO_MICRO_TIMING diff --git a/src/clib/pio_types.hpp b/src/clib/pio_types.hpp index bbbb76ed40..50d37c8ea8 100644 --- a/src/clib/pio_types.hpp +++ b/src/clib/pio_types.hpp @@ -194,6 +194,13 @@ typedef struct io_region struct io_region *next; } io_region; + +namespace SPIO{ + namespace DataRearr{ + class Contig_rearr; + } +} + /** * IO descriptor structure. * @@ -323,6 +330,9 @@ typedef struct io_desc_t bool is_saved; #endif + /* FIXME: Once we have classes for subset/box this ptr should be to a base rearr class */ + SPIO::DataRearr::Contig_rearr *rearr; + /** Pointer to the next io_desc_t in the list. */ struct io_desc_t *next; } io_desc_t; diff --git a/src/clib/pioc.cpp b/src/clib/pioc.cpp index a122240527..b5f148cbfd 100644 --- a/src/clib/pioc.cpp +++ b/src/clib/pioc.cpp @@ -20,6 +20,7 @@ #include "spio_ltimer.h" #include "spio_ltimer_utils.hpp" #include "spio_gptl_utils.hpp" +#include "pio_rearr_contig.hpp" /* Include headers for HDF5 compression filters */ #if PIO_USE_HDF5 @@ -642,6 +643,178 @@ int pio_create_uniq_str(iosystem_desc_t *ios, io_desc_t *iodesc, char *str, int return PIO_NOERR; } +static int subset_rearranger_init(iosystem_desc_t *ios, io_desc_t *iodesc, const PIO_Offset *iostart, const PIO_Offset *iocount) +{ + int ret = PIO_NOERR; + + assert(ios && iodesc); + assert(iodesc->map && iodesc->dimlen); + + iodesc->num_aiotasks = ios->num_iotasks; + LOG((2, "creating subset rearranger iodesc->num_aiotasks = %d", iodesc->num_aiotasks)); + if((ret = subset_rearrange_create(ios, iodesc->maplen, (PIO_Offset *)(iodesc->map), + iodesc->dimlen, iodesc->ndims, iodesc))){ + return pio_err(ios, NULL, ret, __FILE__, __LINE__, + "Initializing the PIO decomposition failed. Error creating the SUBSET rearranger"); + } + + return PIO_NOERR; +} + +static int box_rearranger_init(iosystem_desc_t *ios, io_desc_t *iodesc, const PIO_Offset *iostart, const PIO_Offset *iocount) +{ + int ret = PIO_NOERR; + assert(ios && iodesc); + assert(iodesc->map && iodesc->dimlen && iodesc->firstregion); + + if(ios->ioproc){ + /* Unless the user specifies the start and count for each + * IO task compute it. */ + if(iostart && iocount){ + LOG((3, "iostart and iocount provided")); + for(int i = 0; i < iodesc->ndims; i++){ + iodesc->firstregion->start[i] = iostart[i]; + iodesc->firstregion->count[i] = iocount[i]; + } + iodesc->num_aiotasks = ios->num_iotasks; + } + else{ + /* Compute start and count values for each io task. */ + LOG((2, "about to call CalcStartandCount piotype = %d ndims = %d", iodesc->piotype, iodesc->ndims)); + if((ret = CalcStartandCount(iodesc->piotype, iodesc->ndims, iodesc->dimlen, ios->num_iotasks, + ios->io_rank, iodesc->firstregion->start, + iodesc->firstregion->count, &iodesc->num_aiotasks))){ + return pio_err(ios, NULL, ret, __FILE__, __LINE__, + "Initializing the PIO decomposition failed. Internal error calculating start/count for the decomposition"); + } + } + + /* Compute the max io buffer size needed for an iodesc. */ + if((ret = compute_maxIObuffersize(ios->io_comm, iodesc))){ + return pio_err(ios, NULL, ret, __FILE__, __LINE__, + "Initializing the PIO decomposition failed. Internal error computing max io buffer size needed for the decomposition"); + } + LOG((3, "compute_maxIObuffersize called iodesc->maxiobuflen = %d", iodesc->maxiobuflen)); + } + + /* Depending on array size and io-blocksize the actual number + * of io tasks used may vary. */ + if((ret = MPI_Bcast(&(iodesc->num_aiotasks), 1, MPI_INT, ios->ioroot, ios->my_comm))){ + return check_mpi(ios, NULL, ret, __FILE__, __LINE__); + } + LOG((3, "iodesc->num_aiotasks = %d", iodesc->num_aiotasks)); + + /* Compute the communications pattern for this decomposition. */ + if((ret = box_rearrange_create(ios, iodesc->maplen, iodesc->map, iodesc->dimlen, iodesc->ndims, iodesc))){ + return pio_err(ios, NULL, ret, __FILE__, __LINE__, + "Error initializing the PIO decomposition. Error creating the BOX rearranger"); + } + + return PIO_NOERR; +} + +static inline void off_range_to_dim_range(PIO_Offset off_start, PIO_Offset off_end, + int ndims, const int *dimlen, PIO_Offset *dim_start, PIO_Offset *dim_count) +{ + assert(off_start >= 0); + assert((ndims > 0) && dimlen && dim_start && dim_count); + + std::vector dim_chunk_sz(ndims, 1); + for(int i = ndims - 2; i >= 0; i--){ + dim_chunk_sz[i] = dimlen [i + 1] * dim_chunk_sz[i + 1]; + } + + PIO_Offset off_count = off_end - off_start; + for(int i = 0; i < ndims; i++){ + dim_start[i] = off_start / dim_chunk_sz[i]; + dim_count[i] = off_count / dim_chunk_sz[i]; + + off_start -= dim_start[i] * dim_chunk_sz[i]; + off_count -= dim_count[i] * dim_chunk_sz[i]; + } + + assert((off_start == 0) && (off_count == 0)); +} + +static void init_iodesc_contig_rearr_fields(iosystem_desc_t *ios, io_desc_t *iodesc) +{ + assert(ios && iodesc && iodesc->rearr && iodesc->rearr->is_init()); + + iodesc->ndof = iodesc->rearr->get_decomp_map_lsz(); + if(ios->ioproc){ + iodesc->num_aiotasks = ios->num_iotasks; + } + iodesc->maxregions = 1; + /* FIXME: We only need fillvalues when the total decomp map size is less than var size */ + iodesc->needsfill = true; + /* FIXME: Remove the field since we no longer use maxbytes */ + iodesc->maxbytes = 0; + iodesc->llen = iodesc->rearr->get_rearrange_buf_sz(); + iodesc->maxiobuflen = iodesc->rearr->get_decomp_gsz(); + + if(ios->ioproc){ + assert(iodesc->firstregion && iodesc->firstregion->start && iodesc->firstregion->count); + iodesc->firstregion->loffset = 0; + /* Fill the start/count arrays for the first/only region */ + std::pair off_range = iodesc->rearr->get_rearr_decomp_map_range(); + off_range_to_dim_range(off_range.first, off_range.second, + iodesc->ndims, iodesc->dimlen, + iodesc->firstregion->start, iodesc->firstregion->count); + } +} + +static int contig_rearranger_init(iosystem_desc_t *ios, io_desc_t *iodesc, const PIO_Offset *iostart, const PIO_Offset *iocount) +{ + int ret = PIO_NOERR; + + assert(ios && iodesc); + assert(iodesc->map && iodesc->dimlen); + + if(iostart && iocount){ + /* FIXME: We should at least convert iostart/iocount arrays to decomp maps */ + } + + iodesc->rearr = new SPIO::DataRearr::Contig_rearr(ios); + ret = iodesc->rearr->init(iodesc->piotype, iodesc->map, iodesc->maplen, iodesc->dimlen, iodesc->ndims, iodesc); + if(ret != PIO_NOERR){ + return pio_err(ios, NULL, ret, __FILE__, __LINE__, + "Error initializing the I/O decomposition. Error initializing PIO_REARR_CONTIG rearranger"); + } + + init_iodesc_contig_rearr_fields(ios, iodesc); + + return PIO_NOERR; +} + +static inline void dbg_log_iodesc(iosystem_desc_t *ios, io_desc_t *iodesc) +{ + assert(ios && iodesc); + + /* Log results. */ + LOG((2, "iodesc ioid = %d nrecvs = %d ndof = %d ndims = %d num_aiotasks = %d " + "rearranger = %d maxregions = %d needsfill = %d llen = %d maxiobuflen = %d", + iodesc->ioid, iodesc->nrecvs, iodesc->ndof, iodesc->ndims, iodesc->num_aiotasks, + iodesc->rearranger, iodesc->maxregions, iodesc->needsfill, iodesc->llen, + iodesc->maxiobuflen)); + if(ios->ioproc){ + if(iodesc->rearranger == PIO_REARR_SUBSET){ + for(int j = 0; j < iodesc->llen; j++){ + LOG((3, "rindex[%d] = %lld", j, iodesc->rindex[j])); + } + } + else{ + int totalrecv = 0; + for(int j = 0; j < iodesc->nrecvs; j++){ + totalrecv += iodesc->rcount[j]; + } + + for(int j = 0; j < totalrecv; j++){ + LOG((3, "rindex[%d] = %lld", j, iodesc->rindex[j])); + } + } + } +} + /** * Initialize the decomposition used with distributed arrays. The * decomposition describes how the data will be distributed between @@ -688,252 +861,188 @@ static int initdecomp(int iosysid, int pio_type, int ndims, const int *gdimlen, const PIO_Offset *compmap, int *ioidp, const int *rearranger, const PIO_Offset *iostart, const PIO_Offset *iocount, bool map_zero_based=false) { - iosystem_desc_t *ios; /* Pointer to io system information. */ - io_desc_t *iodesc; /* The IO description. */ - int mpierr = MPI_SUCCESS; /* Return code from MPI function calls. */ - int ierr; /* Return code. */ - - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("PIO:PIOc_initdecomp"); - LOG((1, "PIOc_InitDecomp iosysid = %d pio_type = %d ndims = %d maplen = %d", - iosysid, pio_type, ndims, maplen)); + iosystem_desc_t *ios; /* Pointer to io system information. */ + io_desc_t *iodesc; /* The IO description. */ + int mpierr = MPI_SUCCESS; /* Return code from MPI function calls. */ + int ierr; /* Return code. */ + + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("PIO:PIOc_initdecomp"); + LOG((1, "PIOc_InitDecomp iosysid = %d pio_type = %d ndims = %d maplen = %d", + iosysid, pio_type, ndims, maplen)); + + /* Get IO system info. */ + if(!(ios = pio_get_iosystem_from_id(iosysid))){ + return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, + "Initializing the PIO decomposition failed. Invalid io system id (%d) provided. Could not find an iosystem associated with the id", iosysid); + } + assert(ios); + SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper ios_fstats_tot_timer(ios->io_fstats->tot_timer_name); - /* Get IO system info. */ - if(!(ios = pio_get_iosystem_from_id(iosysid))){ - return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, - "Initializing the PIO decomposition failed. Invalid io system id (%d) provided. Could not find an iosystem associated with the id", iosysid); - } - assert(ios); - SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper ios_fstats_tot_timer(ios->io_fstats->tot_timer_name); + /* Caller must provide these. */ + if(!gdimlen || !compmap || !ioidp){ + return pio_err(ios, NULL, PIO_EINVAL, __FILE__, __LINE__, + "Initializing the PIO decomposition failed. Invalid pointers (NULL) to gdimlen(%s) or compmap(%s) or ioidp (%s) provided", (gdimlen) ? "not NULL" : "NULL", (compmap) ? "not NULL" : "NULL", (ioidp) ? "not NULL" : "NULL"); + } - /* Caller must provide these. */ - if(!gdimlen || !compmap || !ioidp){ + /* Check the dim lengths. */ + for(int i = 0; i < ndims; i++){ + if(gdimlen[i] <= 0){ return pio_err(ios, NULL, PIO_EINVAL, __FILE__, __LINE__, - "Initializing the PIO decomposition failed. Invalid pointers (NULL) to gdimlen(%s) or compmap(%s) or ioidp (%s) provided", (gdimlen) ? "not NULL" : "NULL", (compmap) ? "not NULL" : "NULL", (ioidp) ? "not NULL" : "NULL"); + "Initializing the PIO decomposition failed. Invalid value for global dimension lengths provided. The global length of dimension %d is provided as %d (expected > 0)", i, gdimlen[i]); } + } - /* Check the dim lengths. */ - for(int i = 0; i < ndims; i++){ - if(gdimlen[i] <= 0){ - return pio_err(ios, NULL, PIO_EINVAL, __FILE__, __LINE__, - "Initializing the PIO decomposition failed. Invalid value for global dimension lengths provided. The global length of dimension %d is provided as %d (expected > 0)", i, gdimlen[i]); - } - } - - /* If async is in use, and this is not an IO task, bcast the parameters. */ - if(ios->async){ - int msg = PIO_MSG_INITDECOMP_DOF; /* Message for async notification. */ - char rearranger_present = rearranger ? true : false; - int amsg_rearranger = (rearranger) ? (*rearranger) : 0; - char iostart_present = iostart ? true : false; - char iocount_present = iocount ? true : false; - PIO_Offset *amsg_iostart = NULL, *amsg_iocount = NULL; - - if(!iostart_present){ - amsg_iostart = (PIO_Offset *) calloc(ndims, sizeof(PIO_Offset)); - } - if(!iocount_present){ - amsg_iocount = (PIO_Offset *) calloc(ndims, sizeof(PIO_Offset)); - } - if(!amsg_iostart || !amsg_iocount){ - return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, - "Initializing the PIO decomposition failed. Out of memory allocating %lld bytes for start array and %lld bytes for count array for sending asynchronous message, PIO_MSG_INITDECOMP_DOF, on iosystem (iosysid=%d)", (unsigned long long) (ndims * sizeof(PIO_Offset)), (unsigned long long) (ndims * sizeof(PIO_Offset)), ios->iosysid); - } - - PIO_SEND_ASYNC_MSG(ios, msg, &ierr, iosysid, pio_type, ndims, - gdimlen, maplen, compmap, rearranger_present, amsg_rearranger, - iostart_present, ndims, - (iostart_present) ? iostart : amsg_iostart, - iocount_present, ndims, - (iocount_present) ? iocount : amsg_iocount); + /* If async is in use, and this is not an IO task, bcast the parameters. */ + if(ios->async){ + int msg = PIO_MSG_INITDECOMP_DOF; /* Message for async notification. */ + char rearranger_present = rearranger ? true : false; + int amsg_rearranger = (rearranger) ? (*rearranger) : 0; + char iostart_present = iostart ? true : false; + char iocount_present = iocount ? true : false; + PIO_Offset *amsg_iostart = NULL, *amsg_iocount = NULL; - if(!iostart_present){ - free(amsg_iostart); - } - if(!iocount_present){ - free(amsg_iocount); - } + if(!iostart_present){ + amsg_iostart = (PIO_Offset *) calloc(ndims, sizeof(PIO_Offset)); } - - /* Allocate space for the iodesc info. This also allocates the - * first region and copies the rearranger opts into this - * iodesc. */ - if((ierr = malloc_iodesc(ios, pio_type, ndims, maplen, &iodesc))){ - return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Initializing the PIO decomposition failed. Out of memory allocating memory for I/O descriptor (ndims = %d, maplen = %d)", ndims, maplen); + if(!iocount_present){ + amsg_iocount = (PIO_Offset *) calloc(ndims, sizeof(PIO_Offset)); + } + if(!amsg_iostart || !amsg_iocount){ + return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, + "Initializing the PIO decomposition failed. Out of memory allocating %lld bytes for start array and %lld bytes for count array for sending asynchronous message, PIO_MSG_INITDECOMP_DOF, on iosystem (iosysid=%d)", (unsigned long long) (ndims * sizeof(PIO_Offset)), (unsigned long long) (ndims * sizeof(PIO_Offset)), ios->iosysid); } - /* Set the rearranger. */ - if(!rearranger){ - iodesc->rearranger = ios->default_rearranger; + PIO_SEND_ASYNC_MSG(ios, msg, &ierr, iosysid, pio_type, ndims, + gdimlen, maplen, compmap, rearranger_present, amsg_rearranger, + iostart_present, ndims, + (iostart_present) ? iostart : amsg_iostart, + iocount_present, ndims, + (iocount_present) ? iocount : amsg_iocount); + + if(!iostart_present){ + free(amsg_iostart); } - else{ - iodesc->rearranger = *rearranger; - } - LOG((2, "iodesc->rearranger = %d", iodesc->rearranger)); - - /* In scenarios involving ultra-high resolution E3SM/SCREAM cases, - * the default BOX rearranger may encounter significant performance - * bottlenecks due to excessively large local decomposition maps. - * This elongated map length can dramatically extend the execution - * time of the box_rearrange_create() function, thereby increasing - * the overall runtime of the case. - * - * To mitigate this issue and ensure efficient runtime, Impose a - * maximum limit on the local map length for BOX rearranger. Once - * this limit is surpassed, switch to SUBSET rearranger. - * - * CAUTION: This transition is most effective for ADIOS type, as it - * does not involve data rearrangement. However, for PnetCDF type, - * utilizing SUBSET rearranger may significantly increase write time, - * potentially negating the benefits of reduced initialization time - * associated with this approach. - */ - if(iodesc->rearranger == PIO_REARR_ANY){ - iodesc->rearranger = spio_get_opt_pio_rearr(ios, maplen); + if(!iocount_present){ + free(amsg_iocount); } + } - /* Cache the local decomposition map */ - if(map_zero_based){ - /* BOX and SUBSET rearrangers expect map to the 1-based */ - if((iodesc->rearranger == PIO_REARR_BOX) || (iodesc->rearranger == PIO_REARR_SUBSET)){ - std::transform(compmap, compmap + maplen, iodesc->map, - [](PIO_Offset off) { return off + 1; }); - } - else{ - std::copy(compmap, compmap + maplen, iodesc->map); - } + /* Allocate space for the iodesc info. This also allocates the + * first region and copies the rearranger opts into this + * iodesc. */ + if((ierr = malloc_iodesc(ios, pio_type, ndims, maplen, &iodesc))){ + return pio_err(ios, NULL, ierr, __FILE__, __LINE__, + "Initializing the PIO decomposition failed. Out of memory allocating memory for I/O descriptor (ndims = %d, maplen = %d)", ndims, maplen); + } + + /* Set the rearranger. */ + if(!rearranger){ + iodesc->rearranger = ios->default_rearranger; + } + else{ + iodesc->rearranger = *rearranger; + } + LOG((2, "iodesc->rearranger = %d", iodesc->rearranger)); + + /* In scenarios involving ultra-high resolution E3SM/SCREAM cases, + * the default BOX rearranger may encounter significant performance + * bottlenecks due to excessively large local decomposition maps. + * This elongated map length can dramatically extend the execution + * time of the box_rearrange_create() function, thereby increasing + * the overall runtime of the case. + * + * To mitigate this issue and ensure efficient runtime, Impose a + * maximum limit on the local map length for BOX rearranger. Once + * this limit is surpassed, switch to SUBSET rearranger. + * + * CAUTION: This transition is most effective for ADIOS type, as it + * does not involve data rearrangement. However, for PnetCDF type, + * utilizing SUBSET rearranger may significantly increase write time, + * potentially negating the benefits of reduced initialization time + * associated with this approach. + */ + if(iodesc->rearranger == PIO_REARR_ANY){ + iodesc->rearranger = spio_get_opt_pio_rearr(ios, maplen); + } + + /* Cache the local decomposition map */ + if(map_zero_based){ + /* BOX and SUBSET rearrangers expect map to the 1-based */ + if((iodesc->rearranger == PIO_REARR_BOX) || (iodesc->rearranger == PIO_REARR_SUBSET)){ + std::transform(compmap, compmap + maplen, iodesc->map, + [](PIO_Offset off) { return off + 1; }); } else{ + std::copy(compmap, compmap + maplen, iodesc->map); + } + } + else{ + /* The decomposition map is 1-based */ + if(iodesc->rearranger == PIO_REARR_CONTIG){ /* CONTIG rearranger expects map to be 0-based */ - if(iodesc->rearranger == PIO_REARR_CONTIG){ - std::transform(compmap, compmap + maplen, iodesc->map, - [](PIO_Offset off) { return off - 1; }); - } - else{ - std::copy(compmap, compmap + maplen, iodesc->map); - } + std::transform(compmap, compmap + maplen, iodesc->map, + [](PIO_Offset off) { return off - 1; }); } - - /* Cache the dimension lengths */ - std::copy(gdimlen, gdimlen + ndims, iodesc->dimlen); - - /* Is this the subset rearranger? */ - if(iodesc->rearranger == PIO_REARR_SUBSET){ - iodesc->num_aiotasks = ios->num_iotasks; - LOG((2, "creating subset rearranger iodesc->num_aiotasks = %d", - iodesc->num_aiotasks)); - if((ierr = subset_rearrange_create(ios, maplen, (PIO_Offset *)compmap, gdimlen, - ndims, iodesc))){ - return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Initializing the PIO decomposition failed. Error creating the SUBSET rearranger"); - } + else{ + std::copy(compmap, compmap + maplen, iodesc->map); } - else{ /* box rearranger */ - if(ios->ioproc){ - /* Unless the user specifies the start and count for each - * IO task compute it. */ - if(iostart && iocount){ - LOG((3, "iostart and iocount provided")); - for(int i = 0; i < ndims; i++){ - iodesc->firstregion->start[i] = iostart[i]; - iodesc->firstregion->count[i] = iocount[i]; - } - iodesc->num_aiotasks = ios->num_iotasks; - } - else{ - /* Compute start and count values for each io task. */ - LOG((2, "about to call CalcStartandCount pio_type = %d ndims = %d", pio_type, ndims)); - if((ierr = CalcStartandCount(pio_type, ndims, gdimlen, ios->num_iotasks, - ios->io_rank, iodesc->firstregion->start, - iodesc->firstregion->count, &iodesc->num_aiotasks))){ - return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Initializing the PIO decomposition failed. Internal error calculating start/count for the decomposition"); - } - } + } - /* Compute the max io buffer size needed for an iodesc. */ - if((ierr = compute_maxIObuffersize(ios->io_comm, iodesc))){ - return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Initializing the PIO decomposition failed. Internal error computing max io buffer size needed for the decomposition"); - } - LOG((3, "compute_maxIObuffersize called iodesc->maxiobuflen = %d", iodesc->maxiobuflen)); - } + /* Cache the dimension lengths */ + std::copy(gdimlen, gdimlen + ndims, iodesc->dimlen); - /* Depending on array size and io-blocksize the actual number - * of io tasks used may vary. */ - if((mpierr = MPI_Bcast(&(iodesc->num_aiotasks), 1, MPI_INT, ios->ioroot, - ios->my_comm))){ - return check_mpi(ios, NULL, mpierr, __FILE__, __LINE__); - } - LOG((3, "iodesc->num_aiotasks = %d", iodesc->num_aiotasks)); + /* Initialize the rearranger */ + if(iodesc->rearranger == PIO_REARR_SUBSET){ + ierr = subset_rearranger_init(ios, iodesc, iostart, iocount); + } + else if(iodesc->rearranger == PIO_REARR_BOX){ + ierr = box_rearranger_init(ios, iodesc, iostart, iocount); + } + else if(iodesc->rearranger == PIO_REARR_CONTIG){ + ierr = contig_rearranger_init(ios, iodesc, iostart, iocount); + } + else{ + return pio_err(ios, NULL, ierr, __FILE__, __LINE__, + "Initializing the PIO decomposition failed. Error initializing rearranger, invalid rearranger (ndims = %d, maplen = %d, rearranger=%d)", ndims, maplen, iodesc->rearranger); + } - /* Compute the communications pattern for this decomposition. */ - if(iodesc->rearranger == PIO_REARR_BOX){ - if((ierr = box_rearrange_create(ios, maplen, compmap, gdimlen, ndims, iodesc))){ - return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Error initializing the PIO decomposition. Error creating the BOX rearranger"); - } - } - } + if(ierr != PIO_NOERR){ + return pio_err(ios, NULL, ierr, __FILE__, __LINE__, + "Initializing the PIO decomposition failed. Error initializing rearranger (ndims = %d, maplen = %d, rearranger=%d)", ndims, maplen, iodesc->rearranger); + } - /* Add this IO description to the list. */ - MPI_Comm comm = MPI_COMM_NULL; + /* Add this IO description to the list. */ + MPI_Comm comm = MPI_COMM_NULL; #ifdef _ADIOS2 - comm = ios->union_comm; + comm = ios->union_comm; #endif - if(ios->async){ - /* For asynchronous I/O service, the iodescs (iodesc ids) need to - * be unique across the union_comm (union of I/O and compute comms) - */ - comm = ios->union_comm; - } - *ioidp = pio_add_to_iodesc_list(iodesc, comm); + if(ios->async){ + /* For asynchronous I/O service, the iodescs (iodesc ids) need to + * be unique across the union_comm (union of I/O and compute comms) + */ + comm = ios->union_comm; + } + *ioidp = pio_add_to_iodesc_list(iodesc, comm); #if PIO_SAVE_DECOMPS - if(pio_save_decomps_regex_match(*ioidp, NULL, NULL)){ - char filename[PIO_MAX_NAME]; - ierr = pio_create_uniq_str(ios, iodesc, filename, PIO_MAX_NAME, "piodecomp", ".dat"); - if(ierr != PIO_NOERR){ - return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Initializing the PIO decomposition failed. Creating a unique file name for saving the decomposition failed"); - } - LOG((2, "Saving decomp map to %s", filename)); - PIOc_writemap_impl(filename, *ioidp, ndims, gdimlen, maplen, (PIO_Offset *)compmap, ios->my_comm); - iodesc->is_saved = true; + if(pio_save_decomps_regex_match(*ioidp, NULL, NULL)){ + char filename[PIO_MAX_NAME]; + ierr = pio_create_uniq_str(ios, iodesc, filename, PIO_MAX_NAME, "piodecomp", ".dat"); + if(ierr != PIO_NOERR){ + return pio_err(ios, NULL, ierr, __FILE__, __LINE__, + "Initializing the PIO decomposition failed. Creating a unique file name for saving the decomposition failed"); } + LOG((2, "Saving decomp map to %s", filename)); + PIOc_writemap_impl(filename, *ioidp, ndims, gdimlen, maplen, (PIO_Offset *)compmap, ios->my_comm); + iodesc->is_saved = true; + } #endif #if PIO_ENABLE_LOGGING - /* Log results. */ - LOG((2, "iodesc ioid = %d nrecvs = %d ndof = %d ndims = %d num_aiotasks = %d " - "rearranger = %d maxregions = %d needsfill = %d llen = %d maxiobuflen = %d", - iodesc->ioid, iodesc->nrecvs, iodesc->ndof, iodesc->ndims, iodesc->num_aiotasks, - iodesc->rearranger, iodesc->maxregions, iodesc->needsfill, iodesc->llen, - iodesc->maxiobuflen)); - if(ios->ioproc){ - if(iodesc->rearranger == PIO_REARR_SUBSET){ - for(int j = 0; j < iodesc->llen; j++){ - LOG((3, "rindex[%d] = %lld", j, iodesc->rindex[j])); - } - } - else{ - int totalrecv = 0; - for(int j = 0; j < iodesc->nrecvs; j++){ - totalrecv += iodesc->rcount[j]; - } - - for(int j = 0; j < totalrecv; j++){ - LOG((3, "rindex[%d] = %lld", j, iodesc->rindex[j])); - } - } - } + dbg_log_iodesc(ios, iodesc); #endif /* PIO_ENABLE_LOGGING */ - /* This function only does something if pre-processor macro - * PERFTUNE is set. */ - performance_tune_rearranger(ios, iodesc); - - return PIO_NOERR; + return PIO_NOERR; } /** diff --git a/src/clib/pioc_support.cpp b/src/clib/pioc_support.cpp index cc9d83bd8b..ffb89c06f7 100644 --- a/src/clib/pioc_support.cpp +++ b/src/clib/pioc_support.cpp @@ -24,6 +24,7 @@ #include "spio_io_summary.h" #include "spio_file_mvcache.h" #include "spio_hash.h" +#include "pio_rearr_contig.hpp" /* Include headers for HDF5 compression filters */ #if PIO_USE_HDF5 @@ -1901,6 +1902,11 @@ int PIOc_freedecomp_impl(int iosysid, int ioid) return check_mpi(ios, NULL, mpierr, __FILE__, __LINE__); } + if(iodesc->rearr){ + iodesc->rearr->finalize(); + delete iodesc->rearr; + } + ret = pio_delete_iodesc_from_list(ioid); if (ret != PIO_NOERR) { diff --git a/tests/general/util/pio_tf_f90gen.pl b/tests/general/util/pio_tf_f90gen.pl index d6f3cb0d9e..d275421c0d 100755 --- a/tests/general/util/pio_tf_f90gen.pl +++ b/tests/general/util/pio_tf_f90gen.pl @@ -607,9 +607,9 @@ sub get_default_test_main $out_line = $out_line . " PROGRAM PIO_TF_Test_main_\n"; $out_line = $out_line . " USE pio_tutil\n"; $out_line = $out_line . " IMPLICIT NONE\n"; - $out_line = $out_line . " INTEGER, PARAMETER :: NREARRS = 2\n"; - $out_line = $out_line . " INTEGER :: rearrs(NREARRS) = (/pio_rearr_subset,pio_rearr_box/)\n"; - $out_line = $out_line . " CHARACTER(LEN=PIO_TF_MAX_STR_LEN) :: rearrs_info(NREARRS) = (/\"PIO_REARR_SUBSET\",\"PIO_REARR_BOX \"/)\n"; + $out_line = $out_line . " INTEGER, PARAMETER :: NREARRS = 3\n"; + $out_line = $out_line . " INTEGER :: rearrs(NREARRS) = (/pio_rearr_subset,pio_rearr_box,pio_rearr_contig/)\n"; + $out_line = $out_line . " CHARACTER(LEN=PIO_TF_MAX_STR_LEN) :: rearrs_info(NREARRS) = (/\"PIO_REARR_SUBSET\",\"PIO_REARR_BOX \",\"PIO_REARR_CONTIG\"/)\n"; $out_line = $out_line . " INTEGER i, ierr\n"; $out_line = $out_line . "\n"; $out_line = $out_line . " pio_tf_nerrs_total_=0\n"; From 3f260e5878bbeb216937787a6900b46b7aea93cb Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 9 Jan 2025 23:42:22 -0600 Subject: [PATCH 025/194] Adding support for fillvalues in contig rearr Adding support for fillvalues in the new contig rearranger. This commit includes debug statements and needs more fixes to support all fillvalue tests. --- src/clib/pio_rearr_contig.cpp | 228 ++++- src/clib/pio_rearr_contig.hpp | 14 + tests/cunit/CMakeLists.txt | 9 +- .../cunit/test_spio_rearr_contig_fillval.cpp | 839 ++++++++++++++++++ 4 files changed, 1067 insertions(+), 23 deletions(-) create mode 100644 tests/cunit/test_spio_rearr_contig_fillval.cpp diff --git a/src/clib/pio_rearr_contig.cpp b/src/clib/pio_rearr_contig.cpp index a92d29e67b..455e63695d 100644 --- a/src/clib/pio_rearr_contig.cpp +++ b/src/clib/pio_rearr_contig.cpp @@ -56,7 +56,7 @@ int SPIO::DataRearr::Contig_rearr::init(int pio_type, assert(ios_); lcompmap_sz_ = compmap_sz; - gdecomp_sz_ = std::accumulate(gdimlen, gdimlen + ndims, 0); + gdecomp_sz_ = std::accumulate(gdimlen, gdimlen + ndims, 1, std::multiplies()); elem_pio_type_ = pio_type; ret = find_mpi_type(elem_pio_type_, &elem_mpi_type_, &elem_mpi_type_sz_); @@ -82,9 +82,12 @@ int SPIO::DataRearr::Contig_rearr::init(int pio_type, } /* Aggregate compmaps into the aggregating procs */ + std::size_t non_fval_compmap_sz = 0; std::vector aggcompmap; + std::vector non_fval_compmap_counts, non_fval_compmap_displs; std::vector aggcompmap_counts, aggcompmap_displs; - ret = aggregate_compmap(compmap, compmap_sz, aggcompmap, aggcompmap_counts, aggcompmap_displs); + ret = aggregate_compmap(compmap, compmap_sz, non_fval_compmap_sz, non_fval_compmap_counts, non_fval_compmap_displs, + aggcompmap, aggcompmap_counts, aggcompmap_displs); if(ret != PIO_NOERR){ return pio_err(ios_, NULL, ret, __FILE__, __LINE__, "Internal error while initializing PIO_REARR_CONTIG. Unable to aggregate local compmaps (iosysid = %d)", ios_->iosysid); @@ -99,7 +102,8 @@ int SPIO::DataRearr::Contig_rearr::init(int pio_type, } /* Set up the types and info required to aggregate data */ - ret = setup_data_agg_info(compmap, compmap_sz, aggcompmap, aggcompmap_counts, aggcompmap_displs, to_proc); + ret = setup_data_agg_info(compmap, compmap_sz, non_fval_compmap_sz, non_fval_compmap_counts, non_fval_compmap_displs, + aggcompmap, aggcompmap_counts, aggcompmap_displs, to_proc); if(ret != PIO_NOERR){ return pio_err(ios_, NULL, ret, __FILE__, __LINE__, "Internal error while initializing PIO_REARR_CONTIG. Unable to setup data aggregation (iosysid = %d)", ios_->iosysid); @@ -166,13 +170,17 @@ int SPIO::DataRearr::Contig_rearr::aggregate_data(const void *sbuf, std::size_t assert(is_init_); /* Gather data from compute processes in this aggregating comm to the aggregating/IO process */ - MPI_Datatype agg_stype = agg_gs_info_.stype; + MPI_Datatype agg_stype_nvars = MPI_DATATYPE_NULL; std::vector agg_rtypes_nvars; /* FIXME: We need a better way to find this info out */ std::size_t agg_data_nelems = agg_compmap_sorter_.size(); assert(abuf_sz == nvars * agg_data_nelems * elem_mpi_type_sz_); +// std::cout << "DBG: sbuf[], abuf[] before gather :" << abuf_sz << "," << nvars << "," << elem_mpi_type_sz_ << ":" << std::flush; +// SPIO_Util::Dbg_Util::print_1dvec((int *)sbuf, (int *)((char *)sbuf + sbuf_sz * nvars)); +// SPIO_Util::Dbg_Util::print_1dvec((int *)abuf, (int *)((char *)abuf + abuf_sz)); + if(nvars > 1){ /* We are aggregating a block of variables */ /* The stride between each block - each variable - is the total size of the data aggregated from @@ -196,11 +204,23 @@ int SPIO::DataRearr::Contig_rearr::aggregate_data(const void *sbuf, std::size_t agg_rtypes_nvars.push_back(agg_rtype); } } + if(agg_gs_info_.stype != MPI_DATATYPE_NULL){ + MPI_Aint stride_between_vars = static_cast(sbuf_sz * elem_mpi_type_sz_); + ret = MPI_Type_hvector(nvars, 1, stride_between_vars, agg_gs_info_.stype, &agg_stype_nvars); + if(ret == MPI_SUCCESS){ + ret = MPI_Type_commit(&agg_stype_nvars); + } + if(ret != MPI_SUCCESS){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while aggregating data from compute processes to aggregating processes (PIO_REARR_CONTIG). Unable to create vector types to send data for data aggregation (iosysid = %d)", ios_->iosysid); + } + } } - int scount = (agg_stype != MPI_DATATYPE_NULL) ? nvars : 0; + int scount = (agg_gs_info_.stype != MPI_DATATYPE_NULL) ? 1 : 0; - ret = SPIO_Util::Rearr_Util::gatherw(sbuf, scount, agg_stype, + ret = SPIO_Util::Rearr_Util::gatherw(sbuf, scount, + (nvars > 1) ? agg_stype_nvars : agg_gs_info_.stype, abuf, agg_gs_info_.rcounts, agg_data_byte_displs_, (nvars > 1) ? agg_rtypes_nvars : agg_gs_info_.rtypes, 0, agg_comm_, NULL); @@ -209,6 +229,16 @@ int SPIO::DataRearr::Contig_rearr::aggregate_data(const void *sbuf, std::size_t "Internal error while aggregating data from compute processes to aggregating processes (PIO_REARR_CONTIG). Unable to gather data during data aggregation (iosysid = %d)", ios_->iosysid); } +// if(is_agg_root_){ +// std::cout << "DBG: sbuf[], abuf[] after gather :\n" << std::flush; +// SPIO_Util::Dbg_Util::print_1dvec((int *)sbuf, (int *)((char *)sbuf + sbuf_sz * nvars)); +// SPIO_Util::Dbg_Util::print_1dvec((int *)abuf, (int *)((char *)abuf + abuf_sz)); +// } + + if(agg_stype_nvars != MPI_DATATYPE_NULL){ + MPI_Type_free(&agg_stype_nvars); + } + for(std::size_t i = 0; i < agg_rtypes_nvars.size(); i++){ if(agg_rtypes_nvars[i] != MPI_DATATYPE_NULL){ MPI_Type_free(&(agg_rtypes_nvars[i])); @@ -231,6 +261,7 @@ int SPIO::DataRearr::Contig_rearr::disperse_data(const void *abuf, std::size_t a * process from the compute processes, is now the type use to send/disperse data */ MPI_Datatype dis_rtype = agg_gs_info_.stype; + MPI_Datatype dis_rtype_nvars = MPI_DATATYPE_NULL; std::vector dis_stypes_nvars; /* FIXME: We need a better way to find this info out */ @@ -260,20 +291,41 @@ int SPIO::DataRearr::Contig_rearr::disperse_data(const void *abuf, std::size_t a dis_stypes_nvars.push_back(dis_stype); } } + if(agg_gs_info_.stype != MPI_DATATYPE_NULL){ + MPI_Aint stride_between_vars = static_cast(abuf_sz * elem_mpi_type_sz_); + ret = MPI_Type_hvector(nvars, 1, stride_between_vars, agg_gs_info_.stype, &dis_rtype_nvars); + if(ret == MPI_SUCCESS){ + ret = MPI_Type_commit(&dis_rtype_nvars); + } + if(ret != MPI_SUCCESS){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while dispersing data from aggregating processes to compute processes (PIO_REARR_CONTIG). Unable to create vector types to recv data for data dispersion (iosysid = %d)", ios_->iosysid); + } + } } - int rcount = (dis_rtype != MPI_DATATYPE_NULL) ? nvars : 0; + int rcount = (dis_rtype != MPI_DATATYPE_NULL) ? 1 : 0; + //std::cout << "DBG: abuf[], rbuf[] before final scatter:\n" << std::flush; + //SPIO_Util::Dbg_Util::print_1dvec((double *)abuf, (double *)((char *)abuf + abuf_sz)); + //SPIO_Util::Dbg_Util::print_1dvec((double *)rbuf, (double *)((char *)rbuf + rbuf_sz)); ret = SPIO_Util::Rearr_Util::scatterw(abuf, agg_gs_info_.rcounts, agg_data_byte_displs_, (nvars > 1) ? dis_stypes_nvars : agg_gs_info_.rtypes, - rbuf, rcount, dis_rtype, + rbuf, rcount, + (nvars > 1) ? dis_rtype_nvars : dis_rtype, 0, agg_comm_, NULL); if(ret != MPI_SUCCESS){ return pio_err(ios_, NULL, ret, __FILE__, __LINE__, "Internal error while dispersing data from aggregating processes to compute processes (PIO_REARR_CONTIG). Unable to disperse/scatter data during data dispersion (iosysid = %d)", ios_->iosysid); } + //std::cout << "DBG: rbuf[] after final scatter:\n" << std::flush; + //SPIO_Util::Dbg_Util::print_1dvec((double *)rbuf, (double *)((char *)rbuf + rbuf_sz)); + if(dis_rtype_nvars != MPI_DATATYPE_NULL){ + MPI_Type_free(&dis_rtype_nvars); + } + for(std::size_t i = 0; i < dis_stypes_nvars.size(); i++){ if(dis_stypes_nvars[i] != MPI_DATATYPE_NULL){ MPI_Type_free(&(dis_stypes_nvars[i])); @@ -391,6 +443,9 @@ inline int SPIO::DataRearr::Contig_rearr::create_agg_comm(void ) } int SPIO::DataRearr::Contig_rearr::aggregate_compmap(const PIO_Offset *lcompmap, std::size_t lcompmap_sz, + std::size_t &non_fval_lcompmap_sz, + std::vector &non_fval_lcompmap_counts, + std::vector &non_fval_lcompmap_displs, std::vector &gcompmap, std::vector &gcompmap_counts, std::vector &gcompmap_displs) @@ -404,8 +459,13 @@ int SPIO::DataRearr::Contig_rearr::aggregate_compmap(const PIO_Offset *lcompmap, gcompmap_displs.resize(agg_comm_sz_); } - int send_sz = static_cast(lcompmap_sz); - ret = MPI_Gather(&send_sz, 1, MPI_INT, gcompmap_counts.data(), 1, MPI_INT, 0, agg_comm_); + // We only send/recv non-fillval elements & map values + get_non_fval_lcompmap_counts_displs(lcompmap, lcompmap_sz, + non_fval_lcompmap_sz, non_fval_lcompmap_counts, non_fval_lcompmap_displs); + + //std::cout << "DBG: non_fval_lcompmap_sz = " << non_fval_lcompmap_sz << "\n" << std::flush; + int non_fval_lcompmap_sz_int = static_cast(non_fval_lcompmap_sz); + ret = MPI_Gather(&non_fval_lcompmap_sz_int, 1, MPI_INT, gcompmap_counts.data(), 1, MPI_INT, 0, agg_comm_); if(ret != MPI_SUCCESS){ return pio_err(ios_, NULL, ret, __FILE__, __LINE__, "Internal error while initializing PIO_REARR_CONTIG. Unable to gather local compmap sizes (iosysid=%d)", ios_->iosysid); @@ -424,7 +484,26 @@ int SPIO::DataRearr::Contig_rearr::aggregate_compmap(const PIO_Offset *lcompmap, } /* Gather local compmaps */ - ret = MPI_Gatherv(lcompmap, lcompmap_sz, PIO_OFFSET, + MPI_Datatype non_fval_lcompmap_stype = MPI_DATATYPE_NULL; + int non_fval_lcompmap_scount = 0; + if(non_fval_lcompmap_sz > 0){ + ret = MPI_Type_indexed(static_cast(non_fval_lcompmap_counts.size()), + non_fval_lcompmap_counts.data(), non_fval_lcompmap_displs.data(), + PIO_OFFSET, &non_fval_lcompmap_stype); + if(ret == MPI_SUCCESS){ + ret = MPI_Type_commit(&non_fval_lcompmap_stype); + } + + if(ret != MPI_SUCCESS){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while initializing PIO_REARR_CONTIG. Unable to create/commit indexed type to send local compmaps (iosysid=%d)", ios_->iosysid); + } + non_fval_lcompmap_scount = 1; + } + + // Some MPI implementations do not like MPI_DATATYPE_NULL even when count is 0 + MPI_Datatype stype = (non_fval_lcompmap_stype != MPI_DATATYPE_NULL) ? non_fval_lcompmap_stype : MPI_CHAR; + ret = MPI_Gatherv(lcompmap, non_fval_lcompmap_scount, stype, gcompmap.data(), gcompmap_counts.data(), gcompmap_displs.data(), PIO_OFFSET, 0, agg_comm_); if(ret != MPI_SUCCESS){ @@ -432,11 +511,60 @@ int SPIO::DataRearr::Contig_rearr::aggregate_compmap(const PIO_Offset *lcompmap, "Internal error while initializing PIO_REARR_CONTIG. Unable to gather local compmaps (iosysid=%d)", ios_->iosysid); } + if(non_fval_lcompmap_stype != MPI_DATATYPE_NULL){ + MPI_Type_free(&non_fval_lcompmap_stype); + } + +// std::cout << "DBG: Sent/Gathered lcompmap/gcompmap : " << std::flush; +// SPIO_Util::Dbg_Util::print_1dvec(lcompmap, lcompmap + lcompmap_sz); +// SPIO_Util::Dbg_Util::print_1dvec(gcompmap); + return ret; } +void SPIO::DataRearr::Contig_rearr::get_non_fval_lcompmap_counts_displs(const PIO_Offset *lcompmap, + std::size_t lcompmap_sz, + std::size_t &non_fval_lcompmap_sz, + std::vector &non_fval_lcompmap_counts, + std::vector &non_fval_lcompmap_displs) +{ + non_fval_lcompmap_sz = 0; + if((lcompmap_sz == 0) || (lcompmap == NULL)){ + return; + } + + /* Compmap values that are -1 indicate fillvalues, we do not aggregate/disperse these values */ + const PIO_Offset FILLVAL = -1; + const int INVALID_DISP = -1; + /* The count and disp in lcompmap for the current range of non-fillvalues */ + std::pair non_fval_lcompmap_cur_range = {0, INVALID_DISP}; + for(std::size_t i = 0; i < lcompmap_sz; i++){ + if(lcompmap[i] != FILLVAL){ + non_fval_lcompmap_sz++; + non_fval_lcompmap_cur_range.first++; + if(non_fval_lcompmap_cur_range.second == INVALID_DISP){ + non_fval_lcompmap_cur_range.second = static_cast(i); + } + } + else{ + if(non_fval_lcompmap_cur_range.first > 0){ + non_fval_lcompmap_counts.push_back(non_fval_lcompmap_cur_range.first); + non_fval_lcompmap_displs.push_back(non_fval_lcompmap_cur_range.second); + } + non_fval_lcompmap_cur_range = {0, INVALID_DISP}; + } + } + if(non_fval_lcompmap_cur_range.first > 0){ + non_fval_lcompmap_counts.push_back(non_fval_lcompmap_cur_range.first); + non_fval_lcompmap_displs.push_back(non_fval_lcompmap_cur_range.second); + } +} + int SPIO::DataRearr::Contig_rearr::setup_data_agg_info(const PIO_Offset *lcompmap, std::size_t lcompmap_sz, + std::size_t non_fval_lcompmap_sz, + const std::vector &non_fval_lcompmap_counts, + const std::vector &non_fval_lcompmap_displs, const std::vector &gcompmap, const std::vector &gcompmap_counts, const std::vector &gcompmap_displs, @@ -449,17 +577,10 @@ int SPIO::DataRearr::Contig_rearr::setup_data_agg_info(const PIO_Offset *lcompma * aggregate/IO procs * Sending/receiving 1 contiguous array of lcompmap_sz length */ - agg_gs_info_.stype = MPI_DATATYPE_NULL; - if(lcompmap_sz > 0){ - ret = MPI_Type_contiguous(static_cast(lcompmap_sz), elem_mpi_type_, &(agg_gs_info_.stype)); - if(ret == MPI_SUCCESS){ - ret = MPI_Type_commit(&(agg_gs_info_.stype)); - } - - if(ret != MPI_SUCCESS){ - return pio_err(ios_, NULL, ret, __FILE__, __LINE__, - "Internal error while initializing PIO_REARR_CONTIG. Unable to create/commit contiguous type (size=%d) on compute process for data aggregation (iosysid=%d)", static_cast(lcompmap_sz), ios_->iosysid); - } + ret = init_agg_send_type(lcompmap, non_fval_lcompmap_sz, non_fval_lcompmap_counts, non_fval_lcompmap_displs); + if(ret != MPI_SUCCESS){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while initializing PIO_REARR_CONTIG. Unable to create/commit indexed type (local compmap size=%d, num of non-fillvals=%d) on compute process for data aggregation (iosysid=%d)", static_cast(lcompmap_sz), static_cast(non_fval_lcompmap_sz), ios_->iosysid); } if(!is_agg_root_){ @@ -502,11 +623,54 @@ int SPIO::DataRearr::Contig_rearr::setup_data_agg_info(const PIO_Offset *lcompma for(std::size_t i = 0; i < gcompmap_idx.size(); i++){ agg_compmap_sorter_[gcompmap_idx[i]] = i; } + /* + for(std::size_t i = 0; i < gcompmap_idx.size(); i++){ + if(gcompmap[gcompmap_idx[i]] == -1){ + agg_compmap_sorter_skip_idx_end_ = i + 1; + } + else{ + break; + } + } + + std::cout << "DBG: agg_compmap_sorter_skip_idx_ : " << agg_compmap_sorter_skip_idx_end_ << "\n" << std::flush; + */ +// std::cout << "DBG: agg_compmap_sorter_ : " << std::flush; +// SPIO_Util::Dbg_Util::print_1dvec(agg_compmap_sorter_); ret = init_agg_recv_types(gcompmap_counts, agg_compmap_sorter_); return ret; } +int SPIO::DataRearr::Contig_rearr::init_agg_send_type(const PIO_Offset *lcompmap, + std::size_t lcompmap_sz, + const std::vector &lcompmap_counts, + const std::vector &lcompmap_displs) +{ + int ret = PIO_NOERR; + + assert(ios_); + /* Setup gather scatter info for sending/receiving data from compute procs to + * aggregate/IO procs + * Sending/receiving only non-fillval elements (hence using indexed type instead of a contiguous type) + */ + agg_gs_info_.stype = MPI_DATATYPE_NULL; + if(lcompmap_sz > 0){ + ret = MPI_Type_indexed(static_cast(lcompmap_counts.size()), lcompmap_counts.data(), lcompmap_displs.data(), + elem_mpi_type_, &(agg_gs_info_.stype)); + if(ret == MPI_SUCCESS){ + ret = MPI_Type_commit(&(agg_gs_info_.stype)); + } + + if(ret != MPI_SUCCESS){ + return pio_err(ios_, NULL, ret, __FILE__, __LINE__, + "Internal error while initializing PIO_REARR_CONTIG. Unable to create/commit indexed type on compute process for data aggregation (iosysid=%d)", ios_->iosysid); + } + } + + return ret; +} + int SPIO::DataRearr::Contig_rearr::init_agg_recv_types(const std::vector &gcompmap_counts, const std::vector &compmap_sorter) { @@ -614,9 +778,21 @@ int SPIO::DataRearr::Contig_rearr::get_rearr_toproc_map(const std::vector= 0); to_proc[i] = std::min(static_cast(gcompmap[i]/rearr_comm_iochunk_sz_), rearr_comm_sz_ - 1); + /* + if(gcompmap[i] >= 0){ + to_proc[i] = std::min(static_cast(gcompmap[i]/rearr_comm_iochunk_sz_), rearr_comm_sz_ - 1); + } + else{ + to_proc[i] = -1; + } + */ } + //std::cout << "DBG: gcompmap/to_proc : \n" << std::flush; + //SPIO_Util::Dbg_Util::print_1dvec(gcompmap); + //SPIO_Util::Dbg_Util::print_1dvec(to_proc); return ret; } @@ -900,6 +1076,10 @@ int SPIO::DataRearr::Contig_rearr::rearrange_data(const void *sbuf, std::size_t std::size_t agg_data_nelems = agg_compmap_sorter_.size(); //assert(abuf_sz == nvars * agg_data_nelems * elem_mpi_type_sz_); + //std::cout << "DBG: sbuf[], rbuf[] before rearrange :\n" << std::flush; + //SPIO_Util::Dbg_Util::print_1dvec((int *)sbuf, (int *)((char *)sbuf + sbuf_sz)); + //SPIO_Util::Dbg_Util::print_1dvec((int *)rbuf, (int *)((char *)rbuf + rbuf_sz)); + if(nvars > 1){ /* We are rearranging a block of variables */ /* The stride between each block - data for each variable @@ -980,6 +1160,10 @@ int SPIO::DataRearr::Contig_rearr::rearrange_data(const void *sbuf, std::size_t "Internal error while aggregating data from compute processes to aggregating processes (PIO_REARR_CONTIG). Unable to gather data during data aggregation (iosysid = %d)", ios_->iosysid); } + //std::cout << "DBG: sbuf[], rbuf[] after rearrange :\n" << std::flush; + //SPIO_Util::Dbg_Util::print_1dvec((int *)sbuf, (int *)((char *)sbuf + sbuf_sz)); + //SPIO_Util::Dbg_Util::print_1dvec((int *)rbuf, (int *)((char *)rbuf + rbuf_sz)); + for(std::size_t i = 0; i < rearr_stypes_nvars.size(); i++){ if(rearr_stypes_nvars[i] != MPI_DATATYPE_NULL){ MPI_Type_free(&(rearr_stypes_nvars[i])); diff --git a/src/clib/pio_rearr_contig.hpp b/src/clib/pio_rearr_contig.hpp index efeb442ff5..a6757f8be7 100644 --- a/src/clib/pio_rearr_contig.hpp +++ b/src/clib/pio_rearr_contig.hpp @@ -157,15 +157,29 @@ namespace SPIO{ Alltoall_info rearr_alltoall_info_; int create_agg_comm(void ); + static void get_non_fval_lcompmap_counts_displs(const PIO_Offset *lcompmap, + std::size_t lcompmap_sz, + std::size_t &non_fval_lcompmap_sz, + std::vector &non_fval_lcompmap_counts, + std::vector &non_fval_lcompmap_displs); int aggregate_compmap(const PIO_Offset *lcompmap, std::size_t lcompmap_sz, + std::size_t &non_fval_lcompmap_sz, + std::vector &non_fval_lcompmap_counts, + std::vector &non_fval_lcompmap_displs, std::vector &gcompmap, std::vector &gcompmap_counts, std::vector &gcompmap_displs); int setup_data_agg_info(const PIO_Offset *lcompmap, std::size_t lcompmap_sz, + std::size_t non_fval_lcompmap_sz, + const std::vector &non_fval_lcompmap_counts, + const std::vector &non_fval_lcompmap_displs, const std::vector &gcompmap, const std::vector &gcompmap_counts, const std::vector &gcompmap_displs, const std::vector &to_proc); + int init_agg_send_type(const PIO_Offset *lcompmap, std::size_t lcompmap_sz, + const std::vector &lcompmap_counts, + const std::vector &lcompmap_displs); int init_agg_recv_types(const std::vector &gcompmap_counts, const std::vector &compmap_sorter); int aggregate_data(const void *sbuf, std::size_t sbuf_sz, diff --git a/tests/cunit/CMakeLists.txt b/tests/cunit/CMakeLists.txt index 79520522d1..f951049e73 100644 --- a/tests/cunit/CMakeLists.txt +++ b/tests/cunit/CMakeLists.txt @@ -109,12 +109,13 @@ add_spio_executable (test_spio_rearr_utils_scatter TRUE "" test_spio_rearr_utils add_spio_executable (test_spio_rearr_utils_alltoall TRUE "" test_spio_rearr_utils_alltoall.cpp) add_spio_executable (test_spio_rearr_contig TRUE "" test_spio_rearr_contig.cpp) add_spio_executable (test_spio_rearr_contig_nvars TRUE "" test_spio_rearr_contig_nvars.cpp) +add_spio_executable (test_spio_rearr_contig_fillval TRUE "" test_spio_rearr_contig_fillval.cpp) add_spio_executable (test_sdecomp_regex TRUE "" test_sdecomp_regex.cpp test_common.cpp) add_spio_executable(test_req_block_wait TRUE "" test_req_block_wait.cpp test_common.cpp) add_dependencies (tests test_spmd test_spio_ltimer test_spio_serializer test_spio_tree test_spio_file_mvcache test_spio_rearr_utils_gather test_spio_rearr_utils_scatter test_spio_rearr_utils_alltoall - test_spio_rearr_contig test_spio_rearr_contig_nvars + test_spio_rearr_contig test_spio_rearr_contig_nvars test_spio_rearr_contig_fillval test_sdecomp_regex test_req_block_wait) if(PIO_USE_ASYNC_WR_THREAD) @@ -202,6 +203,12 @@ else () NUMPROCS ${nproc} TIMEOUT ${DEFAULT_TEST_TIMEOUT}) endforeach() + foreach(nproc RANGE 1 ${SPIO_TEST_MAX_NPROCS}) + add_mpi_test(test_spio_rearr_contig_fillval${nproc} + EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/test_spio_rearr_contig_fillval + NUMPROCS ${nproc} + TIMEOUT ${DEFAULT_TEST_TIMEOUT}) + endforeach() add_mpi_test(test_spmd EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/test_spmd NUMPROCS ${AT_LEAST_FOUR_TASKS} diff --git a/tests/cunit/test_spio_rearr_contig_fillval.cpp b/tests/cunit/test_spio_rearr_contig_fillval.cpp new file mode 100644 index 0000000000..2c631c3f64 --- /dev/null +++ b/tests/cunit/test_spio_rearr_contig_fillval.cpp @@ -0,0 +1,839 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pio_config.h" +#include "pio.h" +#include "pio_tests.h" +#include "pio_rearr_contig.hpp" + +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL +#include "gptl.h" +#endif +#endif + +#define LOG_RANK0(rank, ...) \ + do{ \ + if(rank == 0){ \ + fprintf(stderr, __VA_ARGS__); \ + } \ + }while(0); + +static const int FAIL = -1; + +template +bool cmp_result(int wrank, const std::vector &res, const std::vector &exp) +{ + + if(res.size() != exp.size()){ + LOG_RANK0(wrank, "ERROR: The result and expected vectors are of different sizes\n"); + return false; + } + + for(std::size_t i = 0; i < res.size(); i++){ + if(res[i] != exp[i]){ + std::ostringstream oss; + oss << "ERROR: Invalid/Unexpected value, array[ " << i << "] = " << res[i] + << " (Expected array[" << i << "] = " << exp[i] << ")"; + LOG_RANK0(wrank, "ERROR: %s\n", oss.str().c_str()); + return false; + } + } + + return true; +} + +iosystem_desc_t *get_iosystem(MPI_Comm comm, int wrank, int wsz, int nio_procs) +{ + int ret = PIO_NOERR; + static int iosysid = 1; + iosystem_desc_t *ios = (iosystem_desc_t *) calloc(1, sizeof(iosystem_desc_t)); + if(!ios){ + LOG_RANK0(wrank, "Unable to allocate memory for I/O system"); + return NULL; + } + + ios->iosysid = iosysid++; + ios->union_comm = comm; + ios->num_uniontasks = wsz; + ios->union_rank = wrank; + /* Every proc is a compute proc */ + ios->comp_comm = comm; + ios->num_comptasks = wsz; + ios->comp_rank = wrank; + ios->compproc = true; + + assert(nio_procs <= wsz); + + /* Assign first nio_procs procs as I/O processes */ + int color = (wrank/nio_procs == 0) ? 0 : 1; + + ret = MPI_Comm_split(comm, color, 0, &(ios->io_comm)); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "Unable to split comm for creating I/O system"); + free(ios); + return NULL; + } + + ios->num_iotasks = nio_procs; + ios->ioproc = (color == 0) ? true : false; + if(ios->ioproc){ + ret = MPI_Comm_rank(ios->io_comm, &(ios->io_rank)); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "Unable to get rank of I/O process"); + free(ios); + return NULL; + } + } + else{ + ios->io_rank = -1; + } + + return ios; +} + +void free_iosystem(iosystem_desc_t *ios){ + if(!ios){ + return; + } + + MPI_Comm_free(&(ios->io_comm)); + free(ios); +} + +int test_c2i_block_data_exp_fillval(MPI_Comm comm, int wrank, int wsz) +{ + int ret = PIO_NOERR; + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; + iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + if(!ios){ + LOG_RANK0(wrank, "Unable to get I/O system"); + return PIO_EINTERNAL; + } + + try{ + SPIO::DataRearr::Contig_rearr rearr(ios); + const int LOCAL_COMPMAP_SZ = 10; + int gdimlen = LOCAL_COMPMAP_SZ * wsz; + std::vector compmap(LOCAL_COMPMAP_SZ); + std::vector sdata(compmap.size()); + + std::vector rdata, exp_data; + const std::size_t FILLVAL_MASK_OFFSET = 3; + const double FILLVAL = 123.456; + const PIO_Offset PIO_COMPMAP_FILLVAL = -1; + + if(ios->ioproc){ + std::size_t rearr_iochunk_sz = gdimlen/nio_procs; + std::size_t rdata_sz = (ios->io_rank != (nio_procs - 1)) ? rearr_iochunk_sz : (gdimlen - (ios->io_rank * rearr_iochunk_sz)); + + rdata.resize(rdata_sz); + std::fill(rdata.begin(), rdata.end(), FILLVAL); + + exp_data.resize(rdata_sz); + std::iota(exp_data.begin(), exp_data.end(), ios->io_rank * rearr_iochunk_sz); + + for(std::size_t i = 0, gstart = ios->io_rank * rearr_iochunk_sz; i < exp_data.size(); i++){ + if((gstart + i) % FILLVAL_MASK_OFFSET == 0){ + exp_data[i] = FILLVAL; + } + } + } + + std::iota(compmap.begin(), compmap.end(), wrank * LOCAL_COMPMAP_SZ); + std::transform(compmap.cbegin(), compmap.cend(), compmap.begin(), + [FILLVAL_MASK_OFFSET](const PIO_Offset i){ return (i % FILLVAL_MASK_OFFSET == 0) ? PIO_COMPMAP_FILLVAL : i; }); + std::transform(compmap.cbegin(), compmap.cend(), sdata.begin(), + [PIO_COMPMAP_FILLVAL, FILLVAL](const PIO_Offset i){ return static_cast((i != PIO_COMPMAP_FILLVAL) ? i : FILLVAL); }); + ret = rearr.init(PIO_DOUBLE, compmap.data(), compmap.size(), &gdimlen, 1, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Initializing contig rearranger failed"); + return PIO_EINTERNAL; + } + ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), + rdata.data(), rdata.size() * sizeof(double), 1); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement\n"); + return PIO_EINTERNAL; + } + + ret = rearr.finalize(); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Finalizing contig rearranger failed"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + free_iosystem(ios); + return PIO_NOERR; +} + +int test_c2i_block_data_imp_fillval(MPI_Comm comm, int wrank, int wsz) +{ + int ret = PIO_NOERR; + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; + iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + if(!ios){ + LOG_RANK0(wrank, "Unable to get I/O system"); + return PIO_EINTERNAL; + } + + try{ + SPIO::DataRearr::Contig_rearr rearr(ios); + const int LOCAL_COMPMAP_SZ = 10; + int gdimlen = LOCAL_COMPMAP_SZ * wsz; + std::vector compmap; + std::vector sdata; + + std::vector rdata, exp_data; + const std::size_t FILLVAL_MASK_OFFSET = 3; + const double FILLVAL = 123.456; + + if(ios->ioproc){ + std::size_t rearr_iochunk_sz = gdimlen/nio_procs; + std::size_t rdata_sz = (ios->io_rank != (nio_procs - 1)) ? rearr_iochunk_sz : (gdimlen - (ios->io_rank * rearr_iochunk_sz)); + + rdata.resize(rdata_sz); + std::fill(rdata.begin(), rdata.end(), FILLVAL); + + exp_data.resize(rdata_sz); + std::iota(exp_data.begin(), exp_data.end(), ios->io_rank * rearr_iochunk_sz); + + for(std::size_t i = 0, gstart = ios->io_rank * rearr_iochunk_sz; i < exp_data.size(); i++){ + if((gstart + i) % FILLVAL_MASK_OFFSET == 0){ + exp_data[i] = FILLVAL; + } + } + } + + const std::size_t wrank_compmap_end_idx = static_cast(wrank * LOCAL_COMPMAP_SZ + LOCAL_COMPMAP_SZ); + for(std::size_t i = wrank * LOCAL_COMPMAP_SZ; i < wrank_compmap_end_idx; i++){ + if(i % FILLVAL_MASK_OFFSET != 0){ + compmap.push_back(i); + sdata.push_back(static_cast(i)); + } + } + + ret = rearr.init(PIO_DOUBLE, compmap.data(), compmap.size(), &gdimlen, 1, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Initializing contig rearranger failed"); + return PIO_EINTERNAL; + } + ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), + rdata.data(), rdata.size() * sizeof(double), 1); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement\n"); + return PIO_EINTERNAL; + } + + ret = rearr.finalize(); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Finalizing contig rearranger failed"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + free_iosystem(ios); + return PIO_NOERR; +} + +int test_block_data_exp_fillval(MPI_Comm comm, int wrank, int wsz) +{ + int ret = PIO_NOERR; + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; + iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + if(!ios){ + LOG_RANK0(wrank, "Unable to get I/O system"); + return PIO_EINTERNAL; + } + + try{ + SPIO::DataRearr::Contig_rearr rearr(ios); + const int LOCAL_COMPMAP_SZ = 10; + int gdimlen = LOCAL_COMPMAP_SZ * wsz; + std::vector compmap(LOCAL_COMPMAP_SZ); + std::vector sdata(compmap.size()); + + std::vector rdata, exp_data; + const std::size_t FILLVAL_MASK_OFFSET = 3; + const double FILLVAL = 123.456; + const PIO_Offset PIO_COMPMAP_FILLVAL = -1; + + if(ios->ioproc){ + std::size_t rearr_iochunk_sz = gdimlen/nio_procs; + std::size_t rdata_sz = (ios->io_rank != (nio_procs - 1)) ? rearr_iochunk_sz : (gdimlen - (ios->io_rank * rearr_iochunk_sz)); + + rdata.resize(rdata_sz); + std::fill(rdata.begin(), rdata.end(), FILLVAL); + + exp_data.resize(rdata_sz); + std::iota(exp_data.begin(), exp_data.end(), ios->io_rank * rearr_iochunk_sz); + + for(std::size_t i = 0, gstart = ios->io_rank * rearr_iochunk_sz; i < exp_data.size(); i++){ + if((gstart + i) % FILLVAL_MASK_OFFSET == 0){ + exp_data[i] = FILLVAL; + } + } + } + + std::iota(compmap.begin(), compmap.end(), wrank * LOCAL_COMPMAP_SZ); + std::transform(compmap.cbegin(), compmap.cend(), compmap.begin(), + [FILLVAL_MASK_OFFSET](const PIO_Offset i){ return (i % FILLVAL_MASK_OFFSET == 0) ? PIO_COMPMAP_FILLVAL : i; }); + std::transform(compmap.cbegin(), compmap.cend(), sdata.begin(), + [PIO_COMPMAP_FILLVAL, FILLVAL](const PIO_Offset i){ return static_cast((i != PIO_COMPMAP_FILLVAL) ? i : FILLVAL); }); + ret = rearr.init(PIO_DOUBLE, compmap.data(), compmap.size(), &gdimlen, 1, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Initializing contig rearranger failed"); + return PIO_EINTERNAL; + } + + /* Rearrange data from compute processes to I/O processes */ + ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), + rdata.data(), rdata.size() * sizeof(double), 1); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement (compute to I/O procs)\n"); + return PIO_EINTERNAL; + } + + /* Rearrange data from I/O processes to compute processes */ + exp_data.resize(LOCAL_COMPMAP_SZ); + assert(exp_data.size() == sdata.size()); + std::copy(sdata.begin(), sdata.end(), exp_data.begin()); + std::fill(sdata.begin(), sdata.end(), FILLVAL); + + ret = rearr.rearrange_io2comp(rdata.data(), rdata.size() * sizeof(double), + sdata.data(), sdata.size() * sizeof(double), 1); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, sdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement (I/O to compute procs)\n"); + return PIO_EINTERNAL; + } + + ret = rearr.finalize(); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Finalizing contig rearranger failed"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + free_iosystem(ios); + return PIO_NOERR; +} + +int test_block_data_imp_fillval(MPI_Comm comm, int wrank, int wsz) +{ + int ret = PIO_NOERR; + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; + iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + if(!ios){ + LOG_RANK0(wrank, "Unable to get I/O system"); + return PIO_EINTERNAL; + } + + try{ + SPIO::DataRearr::Contig_rearr rearr(ios); + const int LOCAL_COMPMAP_SZ = 10; + int gdimlen = LOCAL_COMPMAP_SZ * wsz; + std::vector compmap; + std::vector sdata; + + std::vector rdata, exp_data; + const std::size_t FILLVAL_MASK_OFFSET = 3; + const double FILLVAL = 123.456; + + if(ios->ioproc){ + std::size_t rearr_iochunk_sz = gdimlen/nio_procs; + std::size_t rdata_sz = (ios->io_rank != (nio_procs - 1)) ? rearr_iochunk_sz : (gdimlen - (ios->io_rank * rearr_iochunk_sz)); + + rdata.resize(rdata_sz); + std::fill(rdata.begin(), rdata.end(), FILLVAL); + + exp_data.resize(rdata_sz); + std::iota(exp_data.begin(), exp_data.end(), ios->io_rank * rearr_iochunk_sz); + + for(std::size_t i = 0, gstart = ios->io_rank * rearr_iochunk_sz; i < exp_data.size(); i++){ + if((gstart + i) % FILLVAL_MASK_OFFSET == 0){ + exp_data[i] = FILLVAL; + } + } + } + + const std::size_t wrank_compmap_end_idx = static_cast(wrank * LOCAL_COMPMAP_SZ + LOCAL_COMPMAP_SZ); + for(std::size_t i = wrank * LOCAL_COMPMAP_SZ; i < wrank_compmap_end_idx; i++){ + if(i % FILLVAL_MASK_OFFSET != 0){ + compmap.push_back(i); + sdata.push_back(static_cast(i)); + } + } + + ret = rearr.init(PIO_DOUBLE, compmap.data(), compmap.size(), &gdimlen, 1, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Initializing contig rearranger failed"); + return PIO_EINTERNAL; + } + + /* Rearrange data from compute processes to I/O processes */ + ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), + rdata.data(), rdata.size() * sizeof(double), 1); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement (compute to I/O procs)\n"); + return PIO_EINTERNAL; + } + + /* Rearrange data from I/O processes to compute processes */ + exp_data.resize(sdata.size()); + std::copy(sdata.begin(), sdata.end(), exp_data.begin()); + std::fill(sdata.begin(), sdata.end(), PIO_FILL_DOUBLE); + + ret = rearr.rearrange_io2comp(rdata.data(), rdata.size() * sizeof(double), + sdata.data(), sdata.size() * sizeof(double), 1); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, sdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement (I/O to compute procs)\n"); + return PIO_EINTERNAL; + } + + ret = rearr.finalize(); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Finalizing contig rearranger failed"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + free_iosystem(ios); + return PIO_NOERR; +} + +int test_rev_block_data_rearr(MPI_Comm comm, int wrank, int wsz) +{ + int ret = PIO_NOERR; + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; + iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + if(!ios){ + LOG_RANK0(wrank, "Unable to get I/O system"); + return PIO_EINTERNAL; + } + + try{ + SPIO::DataRearr::Contig_rearr rearr(ios); + const int LOCAL_COMPMAP_SZ = 4; + int gdimlen = LOCAL_COMPMAP_SZ * wsz; + std::vector compmap(LOCAL_COMPMAP_SZ); + std::vector sdata(compmap.size()); + + std::vector rdata, exp_data; + + if(ios->ioproc){ + std::size_t rearr_iochunk_sz = gdimlen/nio_procs; + std::size_t rdata_sz = (ios->io_rank != (nio_procs - 1)) ? rearr_iochunk_sz : (gdimlen - (ios->io_rank * rearr_iochunk_sz)); + + rdata.resize(rdata_sz); + std::fill(rdata.begin(), rdata.end(), PIO_FILL_DOUBLE); + + exp_data.resize(rdata_sz); + std::iota(exp_data.begin(), exp_data.end(), ios->io_rank * rearr_iochunk_sz); + } + + //std::iota(compmap.begin(), compmap.end(), wrank * LOCAL_COMPMAP_SZ); + PIO_Offset compmap_val = wrank * LOCAL_COMPMAP_SZ; + std::generate(compmap.begin(), compmap.end(), + [&compmap_val, gdimlen]() mutable { return gdimlen - 1 - compmap_val++; }); + std::transform(compmap.cbegin(), compmap.cend(), sdata.begin(), + [](const PIO_Offset i){ return static_cast(i); }); + ret = rearr.init(PIO_DOUBLE, compmap.data(), compmap.size(), &gdimlen, 1, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Initializing contig rearranger failed"); + return PIO_EINTERNAL; + } + ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), + rdata.data(), rdata.size() * sizeof(double), 1); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement\n"); + return PIO_EINTERNAL; + } + + /* Rearrange data from I/O processes to compute processes */ + exp_data.resize(LOCAL_COMPMAP_SZ); + assert(exp_data.size() == sdata.size()); + std::copy(sdata.begin(), sdata.end(), exp_data.begin()); + std::fill(sdata.begin(), sdata.end(), PIO_FILL_DOUBLE); + + ret = rearr.rearrange_io2comp(rdata.data(), rdata.size() * sizeof(double), + sdata.data(), sdata.size() * sizeof(double), 1); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed (I/O to compute procs)"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, sdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement (I/O to compute procs)\n"); + return PIO_EINTERNAL; + } + + ret = rearr.finalize(); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Finalizing contig rearranger failed"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + free_iosystem(ios); + return PIO_NOERR; +} + +int test_mrange_block_data_rearr(MPI_Comm comm, int wrank, int wsz) +{ + int ret = PIO_NOERR; + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; + iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + if(!ios){ + LOG_RANK0(wrank, "Unable to get I/O system"); + return PIO_EINTERNAL; + } + + try{ + SPIO::DataRearr::Contig_rearr rearr(ios); + const int FIRST_RANGE_SZ = 3; + const int SECOND_RANGE_SZ = 1; + const int THIRD_RANGE_SZ = 2; + const int LOCAL_COMPMAP_SZ = FIRST_RANGE_SZ + SECOND_RANGE_SZ + THIRD_RANGE_SZ; + int gdimlen = LOCAL_COMPMAP_SZ * wsz; + std::vector compmap(LOCAL_COMPMAP_SZ); + std::vector sdata(compmap.size()); + + std::vector rdata, exp_data; + + if(ios->ioproc){ + std::size_t rearr_iochunk_sz = gdimlen/nio_procs; + std::size_t rdata_sz = (ios->io_rank != (nio_procs - 1)) ? rearr_iochunk_sz : (gdimlen - (ios->io_rank * rearr_iochunk_sz)); + + rdata.resize(rdata_sz); + std::fill(rdata.begin(), rdata.end(), PIO_FILL_DOUBLE); + + exp_data.resize(rdata_sz); + std::iota(exp_data.begin(), exp_data.end(), ios->io_rank * rearr_iochunk_sz); + } + + std::iota(compmap.begin(), compmap.begin() + FIRST_RANGE_SZ, wrank * FIRST_RANGE_SZ); + std::iota(compmap.begin() + FIRST_RANGE_SZ, compmap.begin() + FIRST_RANGE_SZ + SECOND_RANGE_SZ, wsz * FIRST_RANGE_SZ + wrank * SECOND_RANGE_SZ); + std::iota(compmap.begin() + FIRST_RANGE_SZ + SECOND_RANGE_SZ, compmap.end(), wsz * (FIRST_RANGE_SZ + SECOND_RANGE_SZ) + wrank * THIRD_RANGE_SZ); + std::transform(compmap.cbegin(), compmap.cend(), sdata.begin(), + [](const PIO_Offset i){ return static_cast(i); }); + ret = rearr.init(PIO_DOUBLE, compmap.data(), compmap.size(), &gdimlen, 1, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Initializing contig rearranger failed"); + return PIO_EINTERNAL; + } + ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), + rdata.data(), rdata.size() * sizeof(double), 1); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement\n"); + return PIO_EINTERNAL; + } + + /* Rearrange data from I/O processes to compute processes */ + exp_data.resize(LOCAL_COMPMAP_SZ); + assert(exp_data.size() == sdata.size()); + std::copy(sdata.begin(), sdata.end(), exp_data.begin()); + std::fill(sdata.begin(), sdata.end(), PIO_FILL_DOUBLE); + + ret = rearr.rearrange_io2comp(rdata.data(), rdata.size() * sizeof(double), + sdata.data(), sdata.size() * sizeof(double), 1); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed (I/O to compute procs)"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, sdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement (I/O to compute procs)\n"); + return PIO_EINTERNAL; + } + + ret = rearr.finalize(); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Finalizing contig rearranger failed"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + free_iosystem(ios); + return PIO_NOERR; +} + +int test_mrange_oddz_data_rearr(MPI_Comm comm, int wrank, int wsz) +{ + bool is_odd_proc = ((wrank % 2) != 0) ? true : false; + int nodd_procs = wsz/2; + int neven_procs = wsz - nodd_procs; + int ret = PIO_NOERR; + + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; + iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + if(!ios){ + LOG_RANK0(wrank, "Unable to get I/O system"); + return PIO_EINTERNAL; + } + + try{ + SPIO::DataRearr::Contig_rearr rearr(ios); + const int FIRST_RANGE_SZ = 3; + const int SECOND_RANGE_SZ = 1; + const int THIRD_RANGE_SZ = 2; + const int LOCAL_COMPMAP_SZ = FIRST_RANGE_SZ + SECOND_RANGE_SZ + THIRD_RANGE_SZ; + /* Only even procs have data */ + int gdimlen = LOCAL_COMPMAP_SZ * neven_procs; + std::vector compmap; + std::vector sdata; + + std::vector rdata, exp_data; + + if(ios->ioproc){ + std::size_t rearr_iochunk_sz = gdimlen/nio_procs; + std::size_t rdata_sz = (ios->io_rank != (nio_procs - 1)) ? rearr_iochunk_sz : (gdimlen - (ios->io_rank * rearr_iochunk_sz)); + + rdata.resize(rdata_sz); + std::fill(rdata.begin(), rdata.end(), PIO_FILL_DOUBLE); + + exp_data.resize(rdata_sz); + std::iota(exp_data.begin(), exp_data.end(), ios->io_rank * rearr_iochunk_sz); + } + + if(!is_odd_proc){ + compmap.resize(LOCAL_COMPMAP_SZ); + sdata.resize(compmap.size()); + + int neven_procs_before_wrank = wrank - (wrank / 2); + std::iota(compmap.begin(), compmap.begin() + FIRST_RANGE_SZ, neven_procs_before_wrank * FIRST_RANGE_SZ); + std::iota(compmap.begin() + FIRST_RANGE_SZ, compmap.begin() + FIRST_RANGE_SZ + SECOND_RANGE_SZ, neven_procs * FIRST_RANGE_SZ + neven_procs_before_wrank * SECOND_RANGE_SZ); + std::iota(compmap.begin() + FIRST_RANGE_SZ + SECOND_RANGE_SZ, compmap.end(), neven_procs * (FIRST_RANGE_SZ + SECOND_RANGE_SZ) + neven_procs_before_wrank * THIRD_RANGE_SZ); + std::transform(compmap.cbegin(), compmap.cend(), sdata.begin(), + [](const PIO_Offset i){ return static_cast(i); }); + } + + ret = rearr.init(PIO_DOUBLE, compmap.data(), compmap.size(), &gdimlen, 1, NULL); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Initializing contig rearranger failed"); + return PIO_EINTERNAL; + } + ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), + rdata.data(), rdata.size() * sizeof(double), 1); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement\n"); + return PIO_EINTERNAL; + } + + /* Rearrange data from I/O processes to compute processes */ + if(!is_odd_proc){ + exp_data.resize(LOCAL_COMPMAP_SZ); + } + else{ + exp_data.clear(); + } + + assert(exp_data.size() == sdata.size()); + std::copy(sdata.begin(), sdata.end(), exp_data.begin()); + std::fill(sdata.begin(), sdata.end(), PIO_FILL_DOUBLE); + + ret = rearr.rearrange_io2comp(rdata.data(), rdata.size() * sizeof(double), + sdata.data(), sdata.size() * sizeof(double), 1); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed (I/O to compute procs)"); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, sdata, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement (I/O to compute procs)\n"); + return PIO_EINTERNAL; + } + + ret = rearr.finalize(); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Finalizing contig rearranger failed"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + return PIO_EINTERNAL; + } + + free_iosystem(ios); + return PIO_NOERR; +} + +int test_driver(MPI_Comm comm, int wrank, int wsz, int *num_errors) +{ + int nerrs = 0, ret = PIO_NOERR, mpierr = MPI_SUCCESS; + assert((comm != MPI_COMM_NULL) && (wrank >= 0) && (wsz > 0) && num_errors); + + std::vector > > test_funcs = { + {"test_c2i_block_data_exp_fillval", test_c2i_block_data_exp_fillval}, + {"test_c2i_block_data_imp_fillval", test_c2i_block_data_imp_fillval}, + {"test_block_data_exp_fillval", test_block_data_exp_fillval}, + {"test_block_data_imp_fillval", test_block_data_imp_fillval}, + {"test_rev_block_data_rearr", test_rev_block_data_rearr}, + {"test_mrange_block_data_rearr", test_mrange_block_data_rearr}, + {"test_mrange_oddz_data_rearr", test_mrange_oddz_data_rearr} + }; + + for(std::size_t tid = 0; tid < test_funcs.size(); tid++){ + try{ + ret = test_funcs[tid].second(comm, wrank, wsz); + } + catch(...){ + ret = PIO_EINTERNAL; + nerrs++; + } + int lfail = (ret == PIO_NOERR) ? 0 : 1; + mpierr = MPI_Reduce(&ret, &lfail, 1, MPI_INT, MPI_SUM, 0, comm); + if(mpierr != MPI_SUCCESS){ + LOG_RANK0(wrank, "Test Driver failed: Unable to calculate total num errors\n"); + } + if(ret != 0){ + std::string non_root_fail_msg = std::string(", failed on ") + std::to_string(ret) + std::string(" non-root processes"); + LOG_RANK0(wrank, "%s() FAILED (ret = %d%s)\n", test_funcs[tid].first.c_str(), ret, (lfail) ? "" : non_root_fail_msg.c_str()); + nerrs++; + } + else{ + LOG_RANK0(wrank, "%s() PASSED\n", test_funcs[tid].first.c_str()); + } + } + + *num_errors += nerrs; + return nerrs; +} + +int main(int argc, char *argv[]) +{ + int ret; + int wrank, wsz; + int num_errors; +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL + ret = GPTLinitialize(); + if(ret != 0){ + LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + + ret = MPI_Init(&argc, &argv); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Init() FAILED, ret = %d\n", ret); + return ret; + } + + ret = MPI_Comm_rank(MPI_COMM_WORLD, &wrank); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); + return ret; + } + ret = MPI_Comm_size(MPI_COMM_WORLD, &wsz); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); + return ret; + } + + num_errors = 0; + ret = test_driver(MPI_COMM_WORLD, wrank, wsz, &num_errors); + if(ret != 0){ + LOG_RANK0(wrank, "Test driver FAILED\n"); + return FAIL; + } + else{ + LOG_RANK0(wrank, "All tests PASSED\n"); + } + + MPI_Finalize(); + +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL + ret = GPTLfinalize(); + if(ret != 0){ + LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + + if(num_errors != 0){ + LOG_RANK0(wrank, "Total errors = %d\n", num_errors); + return FAIL; + } + return 0; +} From e06c830a759c09d3aa9c2df70508561902c1786d Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 10 Jan 2025 14:11:14 -0600 Subject: [PATCH 026/194] Ensure that hs buffer is valid in gatherw util Fixing issue with sending/recving local buffer in gatherw --- src/clib/pio_rearr_utils.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/clib/pio_rearr_utils.cpp b/src/clib/pio_rearr_utils.cpp index 269122875d..4466ee002c 100644 --- a/src/clib/pio_rearr_utils.cpp +++ b/src/clib/pio_rearr_utils.cpp @@ -1,25 +1,26 @@ #include "pio_rearr_utils.hpp" #include "spio_gptl_utils.hpp" #include +#include namespace SPIO_Util{ namespace Rearr_Util{ + char gsend_hs = 'h'; int isend_hs(int to_proc, MPI_Comm comm, int comm_rank, int comm_sz, MPI_Request &req) { /* Tag identifies who the data is from */ int tag = comm_sz + comm_rank; - char hs = 'h'; - return MPI_Isend(&hs, 1, MPI_CHAR, to_proc, tag, comm, &req); + return MPI_Isend(&gsend_hs, 1, MPI_CHAR, to_proc, tag, comm, &req); } + char grecv_hs; int irecv_hs(int from_proc, MPI_Comm comm, int comm_rank, int comm_sz, MPI_Request &req) { /* Tag identifies who the data is from */ int tag = comm_sz + from_proc; - char hs; - return MPI_Irecv(&hs, 1, MPI_CHAR, from_proc, tag, comm, &req); + return MPI_Irecv(&grecv_hs, 1, MPI_CHAR, from_proc, tag, comm, &req); } }// namespace Rearr_Util From 1d5de5b07f009fa0bdc6cbc5e801014df248d086 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 13 Jan 2025 11:02:16 -0600 Subject: [PATCH 027/194] Re-order tested rearr types to mv contig Reordering the order of the I/O rearranger types in the testing framework so that PIO_REARR_CONTIG is tested first --- tests/general/util/pio_tf_f90gen.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/general/util/pio_tf_f90gen.pl b/tests/general/util/pio_tf_f90gen.pl index d275421c0d..dc2c3c010c 100755 --- a/tests/general/util/pio_tf_f90gen.pl +++ b/tests/general/util/pio_tf_f90gen.pl @@ -608,8 +608,8 @@ sub get_default_test_main $out_line = $out_line . " USE pio_tutil\n"; $out_line = $out_line . " IMPLICIT NONE\n"; $out_line = $out_line . " INTEGER, PARAMETER :: NREARRS = 3\n"; - $out_line = $out_line . " INTEGER :: rearrs(NREARRS) = (/pio_rearr_subset,pio_rearr_box,pio_rearr_contig/)\n"; - $out_line = $out_line . " CHARACTER(LEN=PIO_TF_MAX_STR_LEN) :: rearrs_info(NREARRS) = (/\"PIO_REARR_SUBSET\",\"PIO_REARR_BOX \",\"PIO_REARR_CONTIG\"/)\n"; + $out_line = $out_line . " INTEGER :: rearrs(NREARRS) = (/pio_rearr_contig,pio_rearr_box,pio_rearr_subset/)\n"; + $out_line = $out_line . " CHARACTER(LEN=PIO_TF_MAX_STR_LEN) :: rearrs_info(NREARRS) = (/\"PIO_REARR_CONTIG\",\"PIO_REARR_BOX \",\"PIO_REARR_SUBSET\"/)\n"; $out_line = $out_line . " INTEGER i, ierr\n"; $out_line = $out_line . "\n"; $out_line = $out_line . " pio_tf_nerrs_total_=0\n"; From 37a01aa057b7fd489778d17456b86bd18c3b5657 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 15 Jan 2025 08:37:51 -0600 Subject: [PATCH 028/194] Adding some simple PnetCDF tests Adding some PnetCDF tests to write 1d, 2d, 3d vars --- tests/CMakeLists.txt | 4 + tests/pnetcdf/CMakeLists.txt | 106 ++++++ tests/pnetcdf/test_pnetcdf.c | 272 +++++++++++++ tests/pnetcdf/test_pnetcdf_4d.cpp | 611 ++++++++++++++++++++++++++++++ 4 files changed, 993 insertions(+) create mode 100644 tests/pnetcdf/CMakeLists.txt create mode 100644 tests/pnetcdf/test_pnetcdf.c create mode 100644 tests/pnetcdf/test_pnetcdf_4d.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3196ced72e..8288f9098b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -23,3 +23,7 @@ if (PIO_ENABLE_FORTRAN) endif() add_subdirectory (cunit) + +if (WITH_PNETCDF) + add_subdirectory (pnetcdf) +endif () diff --git a/tests/pnetcdf/CMakeLists.txt b/tests/pnetcdf/CMakeLists.txt new file mode 100644 index 0000000000..7bb8e03289 --- /dev/null +++ b/tests/pnetcdf/CMakeLists.txt @@ -0,0 +1,106 @@ +include (LibMPI) + +message(STATUS "===== Configuring SCORPIO PnetCDF tests... =====") +#============================================================================== +# HELPER MACROS +#============================================================================== +include(SPIOUtils) + +#============================================================================== +# SET THE COMPILER OPTIONS +#============================================================================== +include_directories("${SCORPIO_SOURCE_DIR}/tests/cunit" "${SCORPIO_SOURCE_DIR}/src/clib" "${SCORPIO_BINARY_DIR}/src/clib") + +# Compiler-specific compiler options +string (TOUPPER "${CMAKE_C_COMPILER_ID}" CMAKE_C_COMPILER_NAME) +if (CMAKE_C_COMPILER_NAME STREQUAL "CRAY") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -h std=c99") +elseif (CMAKE_C_COMPILER_NAME STREQUAL "PGI") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -c99") +elseif (CMAKE_C_COMPILER_NAME STREQUAL "NVHPC") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -c99") +else () + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") +endif () + +string (TOUPPER "${CMAKE_CXX_COMPILER_ID}" CMAKE_CXX_COMPILER_NAME) +if (CMAKE_CXX_COMPILER_NAME STREQUAL "CRAY") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -h std=c++11") +else () + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +endif () + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0") + +#============================================================================== +# FIND EXTERNAL LIBRARIES/DEPENDENCIES +#============================================================================== +#===== MPI ===== +if (PIO_USE_MPISERIAL) + find_package (MPISERIAL COMPONENTS C REQUIRED) + if (MPISERIAL_C_FOUND) + set (CMAKE_REQUIRED_INCLUDES ${MPISERIAL_C_INCLUDE_DIRS}) + endif () +else () + find_package (MPI REQUIRED) + set (CMAKE_REQUIRED_INCLUDES ${MPI_INCLUDE_PATH}) +endif () + +#===== GPTL ===== +if (PIO_ENABLE_TIMING) + find_package (GPTL COMPONENTS C QUIET) + if (GPTL_C_FOUND) + message (STATUS "Found GPTL C: ${GPTL_C_LIBRARIES}") + else () + include_directories(${PROJECT_SOURCE_DIR}/../src/gptl) + message (STATUS "Using internal GPTL C library for timing") + endif () +endif () + +#===== PnetCDF-C ===== +if (WITH_PNETCDF) + find_package (PnetCDF ${PNETCDF_MIN_VER_REQD} COMPONENTS C) + if (PnetCDF_FOUND) + message(STATUS "PnetCDF C library dependencies: ${PnetCDF_C_LIBRARY}") + include_directories (${PnetCDF_C_INCLUDE_DIRS}) + link_libraries (${PnetCDF_C_LIBRARIES}) + else () + message(STATUS "Could not find PnetCDF library, disable PnetCDF tests") + endif () +else () + message(STATUS "Disabling support for PnetCDF tests") +endif () + +#============================================================================== +# DEFINE THE TARGETS AND TESTS +#============================================================================== + +# Exclude tests that require more than 1 procs when using the MPI serial library +if (WITH_PNETCDF) + add_spio_executable (test_pnetcdf TRUE "" test_pnetcdf.c) + add_spio_executable (test_pnetcdf_4d TRUE "" test_pnetcdf_4d.cpp) +endif () +add_dependencies (tests test_pnetcdf test_pnetcdf_4d) + +set (SPIO_TEST_MAX_NPROCS 4) + +# Test Timeout in seconds. +if (PIO_VALGRIND_CHECK) + set (DEFAULT_TEST_TIMEOUT 480) +else () + set (DEFAULT_TEST_TIMEOUT 240) +endif () + +if (WITH_PNETCDF) + foreach(nproc RANGE 1 ${SPIO_TEST_MAX_NPROCS}) + add_mpi_test(test_pnetcdf${nproc} + EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/test_pnetcdf + NUMPROCS ${nproc} + TIMEOUT ${DEFAULT_TEST_TIMEOUT}) + add_mpi_test(test_pnetcdf_4d${nproc} + EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/test_pnetcdf_4d + NUMPROCS ${nproc} + TIMEOUT ${DEFAULT_TEST_TIMEOUT}) + endforeach() +endif () diff --git a/tests/pnetcdf/test_pnetcdf.c b/tests/pnetcdf/test_pnetcdf.c new file mode 100644 index 0000000000..a172c70e84 --- /dev/null +++ b/tests/pnetcdf/test_pnetcdf.c @@ -0,0 +1,272 @@ +/********************************************************************* + * + * Copyright (C) 2013, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + * + *********************************************************************/ +/* $Id$ */ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * This example shows how to use ncmpi_put_vara_int_all() to write a 2D 4-byte + * integer array in parallel. It first defines a netCDF variable of size + * global_ny * global_nx where + * global_ny == NY and + * global_nx == (NX * number of MPI processes). + * The data partitioning pattern is a column-wise partitioning across all + * processes. Each process writes a subarray of size ny * nx. + * + * To compile: + * mpicc -O2 put_vara.c -o put_vara -lpnetcdf + * + * Example commands for MPI run and outputs from running ncmpidump on the + * output netCDF file produced by this example program: + * + * % mpiexec -n 4 ./put_vara /pvfs2/wkliao/testfile.nc + * + * % ncmpidump /pvfs2/wkliao/testfile.nc + * netcdf testfile { + * // file format: CDF-5 (big variables) + * dimensions: + * y = 10 ; + * x = 16 ; + * variables: + * int var(y, x) ; + * var:str_att_name = "example attribute of type text." ; + * var:float_att_name = 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f ; + * var:short_att_name = 1000s ; + * // global attributes: + * :history = "Mon Aug 13 21:27:48 2018" ; + * "" ; + * data: + * + * var = + * 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + * 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + * 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + * 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + * 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + * 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + * 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + * 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + * 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + * 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3 ; + * } + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include +#include /* strcpy(), strncpy() */ +#include /* getopt() */ +#include /* time() localtime(), asctime() */ +#include +#include + +#define NZ 2 +#define NY 10 +#define NX 4 + +static int verbose; + +#define ERR {if(err!=NC_NOERR){printf("Error at %s:%d : %s\n", __FILE__,__LINE__, ncmpi_strerror(err));nerrs++;}} + +static void +usage(char *argv0) +{ + char *help = + "Usage: %s [-h] | [-q] [-k format] [file_name]\n" + " [-h] Print help\n" + " [-q] Quiet mode (reports when fail)\n" + " [-k format] file format: 1 for CDF-1, 2 for CDF-2, 3 for NetCDF4,\n" + " 4 for NetCDF4 classic model, 5 for CDF-5\n" + " [filename] output netCDF file name\n"; + fprintf(stderr, help, argv0); +} + +/*----< pnetcdf_check_mem_usage() >------------------------------------------*/ +/* check PnetCDF library internal memory usage */ +static int +pnetcdf_check_mem_usage(MPI_Comm comm) +{ + int err, nerrs=0, rank; + MPI_Offset malloc_size, sum_size; + + MPI_Comm_rank(comm, &rank); + + /* print info about PnetCDF internal malloc usage */ + err = ncmpi_inq_malloc_max_size(&malloc_size); + if (err == NC_NOERR) { + MPI_Reduce(&malloc_size, &sum_size, 1, MPI_OFFSET, MPI_SUM, 0, MPI_COMM_WORLD); + if (rank == 0 && verbose) + printf("maximum heap memory allocated by PnetCDF internally is %lld bytes\n", + sum_size); + + /* check if there is any PnetCDF internal malloc residue */ + err = ncmpi_inq_malloc_size(&malloc_size); + MPI_Reduce(&malloc_size, &sum_size, 1, MPI_OFFSET, MPI_SUM, 0, MPI_COMM_WORLD); + if (rank == 0 && sum_size > 0) + printf("heap memory allocated by PnetCDF internally has %lld bytes yet to be freed\n", + sum_size); + } + else if (err != NC_ENOTENABLED) { + printf("Error at %s:%d: %s\n", __FILE__,__LINE__,ncmpi_strerror(err)); + nerrs++; + } + return nerrs; +} + +/*----< pnetcdf_io() >-------------------------------------------------------*/ +static int +pnetcdf_io(MPI_Comm comm, char *filename, int cmode) +{ + int i, j, z, rank, nprocs, err, nerrs=0; + int ncid, var1did, var2did, var3did, dimid[3], buf1d[NX], buf2d[NY][NX], buf3d[NZ][NY][NX]; + char str_att[128]; + float float_att[100]; + MPI_Offset global_nz, global_ny, global_nx; + MPI_Offset start[3], count[3]; + + MPI_Comm_rank(comm, &rank); + MPI_Comm_size(comm, &nprocs); + + /* create a new file for writing ----------------------------------------*/ + cmode |= NC_CLOBBER; + err = ncmpi_create(comm, filename, cmode, MPI_INFO_NULL, &ncid); ERR + + for (i=0; i 0); +} + diff --git a/tests/pnetcdf/test_pnetcdf_4d.cpp b/tests/pnetcdf/test_pnetcdf_4d.cpp new file mode 100644 index 0000000000..8e23d90ffc --- /dev/null +++ b/tests/pnetcdf/test_pnetcdf_4d.cpp @@ -0,0 +1,611 @@ +/********************************************************************* + * + * Copyright (C) 2013, Northwestern University and Argonne National Laboratory + * See COPYRIGHT notice in top-level directory. + * + *********************************************************************/ +/* $Id$ */ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * This example shows how to use ncmpi_put_vara_int_all() to write a 2D 4-byte + * integer array in parallel. It first defines a netCDF variable of size + * global_ny * global_nx where + * global_ny == NY and + * global_nx == (NX * number of MPI processes). + * The data partitioning pattern is a column-wise partitioning across all + * processes. Each process writes a subarray of size ny * nx. + * + * To compile: + * mpicc -O2 put_vara.c -o put_vara -lpnetcdf + * + * Example commands for MPI run and outputs from running ncmpidump on the + * output netCDF file produced by this example program: + * + * % mpiexec -n 4 ./put_vara /pvfs2/wkliao/testfile.nc + * + * % ncmpidump /pvfs2/wkliao/testfile.nc + * netcdf testfile { + * // file format: CDF-5 (big variables) + * dimensions: + * y = 10 ; + * x = 16 ; + * variables: + * int var(y, x) ; + * var:str_att_name = "example attribute of type text." ; + * var:float_att_name = 0.f, 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f ; + * var:short_att_name = 1000s ; + * // global attributes: + * :history = "Mon Aug 13 21:27:48 2018" ; + * "" ; + * data: + * + * var = + * 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + * 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + * 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + * 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + * 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + * 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + * 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + * 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + * 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + * 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3 ; + * } + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include /* strcpy(), strncpy() */ +#include /* getopt() */ +#include /* time() localtime(), asctime() */ +#include +#include +#include +#include + +#define NZ 2 +#define NY 7 +#define NX 2 + +static int verbose; + +#define ERR {if(err!=NC_NOERR){printf("Error at %s:%d : %s\n", __FILE__,__LINE__, ncmpi_strerror(err));nerrs++;}} + +static void +usage(char *argv0) +{ + char *help = + "Usage: %s [-h] | [-q] [-k format] [file_name]\n" + " [-h] Print help\n" + " [-q] Quiet mode (reports when fail)\n" + " [-k format] file format: 1 for CDF-1, 2 for CDF-2, 3 for NetCDF4,\n" + " 4 for NetCDF4 classic model, 5 for CDF-5\n" + " [filename] output netCDF file name\n"; + fprintf(stderr, help, argv0); +} + +/*----< pnetcdf_check_mem_usage() >------------------------------------------*/ +/* check PnetCDF library internal memory usage */ +static int +pnetcdf_check_mem_usage(MPI_Comm comm) +{ + int err, nerrs=0, rank; + MPI_Offset malloc_size, sum_size; + + MPI_Comm_rank(comm, &rank); + + /* print info about PnetCDF internal malloc usage */ + err = ncmpi_inq_malloc_max_size(&malloc_size); + if (err == NC_NOERR) { + MPI_Reduce(&malloc_size, &sum_size, 1, MPI_OFFSET, MPI_SUM, 0, MPI_COMM_WORLD); + if (rank == 0 && verbose) + printf("maximum heap memory allocated by PnetCDF internally is %lld bytes\n", + sum_size); + + /* check if there is any PnetCDF internal malloc residue */ + err = ncmpi_inq_malloc_size(&malloc_size); + MPI_Reduce(&malloc_size, &sum_size, 1, MPI_OFFSET, MPI_SUM, 0, MPI_COMM_WORLD); + if (rank == 0 && sum_size > 0) + printf("heap memory allocated by PnetCDF internally has %lld bytes yet to be freed\n", + sum_size); + } + else if (err != NC_ENOTENABLED) { + printf("Error at %s:%d: %s\n", __FILE__,__LINE__,ncmpi_strerror(err)); + nerrs++; + } + return nerrs; +} + +void convert_gidx_to_dim_idx(int gidx, int ndims, const MPI_Offset *gdimlen, std::vector &dim_idx) +{ + int dim_chunk_sz[ndims]; + + assert(ndims > 0); + assert(gdimlen && (dim_idx.size() == ndims)); + + dim_chunk_sz[ndims - 1] = 1; + for(int i = ndims - 2; i >= 0; i--){ + dim_chunk_sz[i] = dim_chunk_sz[i + 1] * gdimlen[i + 1]; + } + + for(int i = 0; i < ndims; i++){ + dim_idx[i] = gidx / dim_chunk_sz[i]; + + gidx -= dim_idx[i] * dim_chunk_sz[i]; + } + + assert(gidx == 0); +} + +/* Debug print a vector */ +template +static void print_1dvec(const std::vector &v) +{ + std::ostringstream ostr; + ostr << "["; + std::copy(v.cbegin(), v.cend(), std::ostream_iterator(ostr, ",")); + ostr << "]"; + std::cout << ostr.str().c_str() << "\n" << std::flush; +} + + +void partition_range_to_contig_dim_ranges(int ndims, const MPI_Offset *gdimlen, + MPI_Offset start_off, MPI_Offset end_off, + std::vector &start, std::vector &count) +{ + assert(ndims > 0); + assert(gdimlen && (start_off >= 0) && (end_off >= start_off)); + + start.clear(); count.clear(); + + MPI_Offset cur_tot_count = end_off - start_off; + + if(cur_tot_count == 0) return; + + // First get start_off to a multiple of last dim len + // e.g. v[z][y][x], get range to get to multiple of x + MPI_Offset cur_range_start = start_off; + MPI_Offset cur_range_count = 0; + MPI_Offset off_from_last_dim_mult = cur_range_start % gdimlen[ndims - 1]; + if(off_from_last_dim_mult != 0){ + cur_range_count = gdimlen[ndims - 1] - off_from_last_dim_mult; + if(start_off + cur_range_count > end_off){ + cur_range_count = end_off - start_off; + } + start.push_back(cur_range_start); + count.push_back(cur_range_count); + + cur_range_start += cur_range_count; + cur_tot_count -= cur_range_count; + } + + if(cur_tot_count == 0) return; + + // Break/partition the cur_range_start to end_off to contiguous dim chunks + // e.g. v[z][y][x], break up remaining range to ranges of sizes y*x, x, 1 + std::vector dim_chunk_sz(ndims, 1); + for(int i = ndims - 2; i >= 0; i--){ + dim_chunk_sz[i] = dim_chunk_sz[i + 1] * gdimlen[i + 1]; + } + + MPI_Offset cur_range_end = cur_range_start; + for(int i = 0; i < ndims; i++){ + cur_range_end = dim_chunk_sz[i] * (end_off / dim_chunk_sz[i]); + if(cur_range_end != 0){ + cur_range_count = cur_range_end - cur_range_start; + start.push_back(cur_range_start); + count.push_back(cur_range_count); + + cur_range_start += cur_range_count; + cur_tot_count -= cur_range_count; + } + if(cur_tot_count == 0) break; + } + + assert(cur_tot_count == 0); +} + +int validate_starts_counts(MPI_Offset start_off, MPI_Offset end_off, + const std::vector > &starts, + const std::vector > &counts) +{ + const int FAIL = 1, SUCCESS = 0; + MPI_Offset cur_off; + + if(start_off > end_off){ + std::cerr << "ERROR: Start offset provided needs to be <= end offset\n"; + return FAIL; + } + + if(starts.size() != counts.size()){ + std::cerr << "ERROR: Mismatched starts/counts array sizes\n"; + return FAIL; + } + + if(starts.size() == 0) return SUCCESS; + + if(starts[0].size() == 0){ + std::cerr << "ERROR: No start arrays in the starts vector\n"; + return FAIL; + } + + if(starts[0][0] != start_off){ + std::cerr << "ERROR: Invalid start offset, starts[0][0] = " << starts[0][0] << ", expected = " << start_off << "\n" << std::flush; + return FAIL; + } + + MPI_Offset next_exp_off = start_off; + for(std::size_t i = 0; i < starts.size(); i++){ + if(starts[i].size() != counts[i].size()){ + std::cerr << "ERROR: Mismatch in start/count array sizes: starts[" << i << "].size() = " << starts[i].size() << ", counts[" << i << "].size() = " << counts[i].size() << "\n" << std::flush; + return FAIL; + } + for(std::size_t j = 0; j < starts[i].size(); j++){ + if(starts[i][j] != next_exp_off){ + std::cout << "ERROR : Mismatch in start offset, starts[" << i << "][" << j << "] = " << starts[i][j] << ", expected = " << next_exp_off << "\n" << std::flush; + return FAIL; + } + next_exp_off += counts[i][j]; + } + } + + return SUCCESS; +} + +void test_partition_ranges(void ) +{ + const MPI_Offset ZMAX = 10; + const MPI_Offset YMAX = 10; + const MPI_Offset XMAX = 10; + const int MAX_NPROCS = 6; + + for(MPI_Offset z = 1; z < ZMAX; z++){ + for(MPI_Offset y = 1; y < YMAX; y++){ + for(MPI_Offset x = 1; x < XMAX; x++){ + std::vector gdimlen = {z, y, x}; + MPI_Offset tot_gdimlen = 1; + std::vector start, count; + std::vector > starts, counts; + + for(std::size_t d = 0; d < gdimlen.size(); d++){ + tot_gdimlen *= gdimlen[d]; + } + std::cout << "Testing gdimlen[] : "; print_1dvec(gdimlen); + for(int nprocs = 1; nprocs < std::min(MAX_NPROCS, static_cast(tot_gdimlen)); nprocs++){ + + MPI_Offset proc_chunk_sz = tot_gdimlen / nprocs; + for(int rank = 0; rank < nprocs; rank++){ + MPI_Offset start_off = rank * proc_chunk_sz; + if(rank == nprocs - 1) proc_chunk_sz = tot_gdimlen - (nprocs - 1) * proc_chunk_sz; + MPI_Offset end_off = start_off + proc_chunk_sz; + + partition_range_to_contig_dim_ranges(gdimlen.size(), gdimlen.data(), start_off, end_off, start, count); + std::cout << "[" << rank << "/" << nprocs << "]: partition_range start/count [" << start_off << "," << end_off <<") : "; print_1dvec(start); print_1dvec(count); + starts.push_back(start); counts.push_back(count); + } + validate_starts_counts(0, tot_gdimlen, starts, counts); + starts.clear(); counts.clear(); + } + } + } + } +} + +static inline void convert_off_to_start_dim_idx(const std::vector &dim_chunk_sz, int start_off, std::vector &start_dim_idx) +{ + assert(dim_chunk_sz.size() == start_dim_idx.size()); + for(std::size_t i = 0; i < start_dim_idx.size(); i++){ + start_dim_idx[i] = 0; + } + for(std::size_t i = 0; i < dim_chunk_sz.size(); i++){ + start_dim_idx[i] = start_off / dim_chunk_sz[i]; + + start_off -= start_dim_idx[i] * dim_chunk_sz[i]; + if(start_off == 0) break; + } + assert(start_off == 0); +} + +static inline void convert_off_to_count_dim_idx(int ndims, const MPI_Offset *gdimlen, const std::vector &dim_chunk_sz, int count_off, std::vector &count_dim_idx) +{ + assert(dim_chunk_sz.size() == count_dim_idx.size()); + assert(count_dim_idx.size() == ndims); + + for(std::size_t i = 0; i < ndims; i++){ + count_dim_idx[i] = gdimlen[i]; + } + for(std::size_t i = 0; i < dim_chunk_sz.size(); i++){ + count_dim_idx[i] = count_off / dim_chunk_sz[i]; + + count_off -= count_dim_idx[i] * dim_chunk_sz[i]; + if(count_off == 0) break; + } + + assert(count_off == 0); + for(std::size_t i = 0; i < count_dim_idx.size(); i++){ + if(count_dim_idx[i] != 0){ + break; + } + else{ + count_dim_idx[i] = 1; + } + } +} + +void convert_start_count_off_to_dim_idx(int ndims, const MPI_Offset *gdimlen, + std::vector &start_off, std::vector &count_off, + std::vector > &starts, std::vector > &counts) +{ + assert((ndims > 0) && gdimlen); + assert(start_off.size() == count_off.size()); + + std::vector dim_chunk_sz(ndims, 1); + for(int i = ndims - 2; i >= 0; i--){ + dim_chunk_sz[i] = dim_chunk_sz[i + 1] * gdimlen[i + 1]; + } + std::vector start(ndims, 0), count(ndims, 1); + assert(start_off.size() == count_off.size()); + for(std::size_t i = 0; i < start_off.size(); i++){ + convert_off_to_start_dim_idx(dim_chunk_sz, start_off[i], start); + convert_off_to_count_dim_idx(ndims, gdimlen, dim_chunk_sz, count_off[i], count); + starts.push_back(start); counts.push_back(count); + } +} + +void partition_buf(int rank, int nprocs, int ndims, const MPI_Offset *gdimlen, + std::vector > &starts, std::vector > &counts) +{ + std::vector start_coff, count_coff; + + MPI_Offset tot_gdimlen = 1; + for(int i = 0; i < ndims; i++){ + tot_gdimlen *= gdimlen[i]; + } + + MPI_Offset iochunk_sz = tot_gdimlen / nprocs; + assert(iochunk_sz > 0); + + MPI_Offset start_off = rank * iochunk_sz; + if(rank == nprocs - 1){ + iochunk_sz = tot_gdimlen - (nprocs - 1) * iochunk_sz; + } + MPI_Offset end_off = start_off + iochunk_sz; + + //std::cout << "start/end off : " << start_off << ", " << end_off << "\n" << std::flush; + partition_range_to_contig_dim_ranges(ndims, gdimlen, start_off, end_off, start_coff, count_coff); + //usleep(rank * 1000000); + //std::cout << "start/end contig off : "; print_1dvec(start_coff); print_1dvec(count_coff); + convert_start_count_off_to_dim_idx(ndims, gdimlen, start_coff, count_coff, starts, counts); +} + +/* +// Hard-coded partition for var [2, 7, 2] with 3 procs +void hc_partition_buf(int rank, int nprocs, int ndims, const MPI_Offset *gdimlen, + std::vector > &starts, std::vector > &counts) +{ + std::vector hc_start(ndims, 0), hc_count(ndims, 1); + if(rank == 0){ + hc_start = {0, 0, 0}; + hc_count = {1, 4, 2}; + + starts.push_back(hc_start); + counts.push_back(hc_count); + } + else if(rank == 1){ + hc_start = {0, 4, 0}; + hc_count = {1, 3, 2}; + + starts.push_back(hc_start); + counts.push_back(hc_count); + + hc_start = {1, 0, 0}; + hc_count = {1, 1, 2}; + + starts.push_back(hc_start); + counts.push_back(hc_count); + } + else if(rank == 2){ + hc_start = {1, 1, 0}; + hc_count = {1, 6, 2}; + + starts.push_back(hc_start); + counts.push_back(hc_count); + } + else{ + assert(0); + } +} +*/ + +/*----< pnetcdf_io() >-------------------------------------------------------*/ +static int +pnetcdf_io(MPI_Comm comm, char *filename, int cmode) +{ + int i, j, z, rank, nprocs, err, nerrs=0; + int ncid, dimid[3]; + int dimid_x_1d2d; + int var1did, buf1d[NX]; + int var2did, buf2d[NY][NX]; + int var3did, buf3d[NZ][NY][NX], var3d_rankid, buf3d_rank[NZ][NY][NX]; + char str_att[128]; + float float_att[100]; + MPI_Offset global_nz, global_ny, global_nx, global_tot_sz, gdimlen[3]; + MPI_Offset global_nx_1d2d; + MPI_Offset start[3], count[3]; + std::vector > starts, counts; + + MPI_Comm_rank(comm, &rank); + MPI_Comm_size(comm, &nprocs); + + /* create a new file for writing ----------------------------------------*/ + cmode |= NC_CLOBBER; + err = ncmpi_create(comm, filename, cmode, MPI_INFO_NULL, &ncid); ERR + + for (i=0; i 0); +} + From c2db1076fd50ac341c72e31dd15fcf94c3775c95 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 15 Jan 2025 08:39:06 -0600 Subject: [PATCH 029/194] Chunking proc off range to contig dim range Making sure that we chunk/partition the contiguous offset range to contiguous dim ranges before writing out multi dim vars --- src/clib/pio_rearr_contig.cpp | 135 ++++++++++++++++++++++++++++++++++ src/clib/pio_rearr_contig.hpp | 80 ++++++++++++++++---- src/clib/pioc.cpp | 52 ++++++++++--- 3 files changed, 242 insertions(+), 25 deletions(-) diff --git a/src/clib/pio_rearr_contig.cpp b/src/clib/pio_rearr_contig.cpp index 455e63695d..ffb7144e58 100644 --- a/src/clib/pio_rearr_contig.cpp +++ b/src/clib/pio_rearr_contig.cpp @@ -54,9 +54,16 @@ int SPIO::DataRearr::Contig_rearr::init(int pio_type, { int ret = PIO_NOERR; assert(ios_); + assert(ndims > 0); lcompmap_sz_ = compmap_sz; gdecomp_sz_ = std::accumulate(gdimlen, gdimlen + ndims, 1, std::multiplies()); + std::copy(gdimlen, gdimlen + ndims, std::back_inserter(gdimlen_)); + dim_chunk_sz_.resize(ndims); + dim_chunk_sz_[ndims - 1] = 1; + for(int i = ndims - 2; i >= 0; i--){ + dim_chunk_sz_[i] = dim_chunk_sz_[i + 1] * gdimlen_[i + 1]; + } elem_pio_type_ = pio_type; ret = find_mpi_type(elem_pio_type_, &elem_mpi_type_, &elem_mpi_type_sz_); @@ -81,6 +88,8 @@ int SPIO::DataRearr::Contig_rearr::init(int pio_type, "Internal error while initializing PIO_REARR_CONTIG. Unable to create rearranger comm (iosysid = %d)", ios_->iosysid); } + set_rearr_comm_iochunk_sz(ndims, gdimlen); + /* Aggregate compmaps into the aggregating procs */ std::size_t non_fval_compmap_sz = 0; std::vector aggcompmap; @@ -121,6 +130,81 @@ int SPIO::DataRearr::Contig_rearr::init(int pio_type, return ret; } +std::vector > SPIO::DataRearr::Contig_rearr::get_rearr_decomp_map_contig_ranges(int iorank) const +{ + assert(gdecomp_sz_ > 0); + assert(rearr_comm_iochunk_sz_ > 0); + + PIO_Offset iochunk = rearr_comm_iochunk_sz_; + PIO_Offset start_off = iorank * iochunk; + PIO_Offset end_off = start_off + iochunk; + if(iorank == (rearr_comm_sz_ - 1)){ + end_off = gdecomp_sz_; + } + + assert((gdimlen_.size() > 0) && (dim_chunk_sz_.size() == gdimlen_.size()) && + (start_off >= 0) && (end_off >= start_off)); + + std::vector > contig_map_ranges; + int ndims = static_cast(gdimlen_.size()); + + PIO_Offset cur_tot_count = end_off - start_off; + + if(cur_tot_count == 0) return contig_map_ranges; + + // First get start_off to a multiple of last dim len + // e.g. v[z][y][x], get range to get to multiple of x + PIO_Offset cur_range_start = start_off; + PIO_Offset cur_range_count = 0; + PIO_Offset off_from_last_dim_mult = cur_range_start % gdimlen_[ndims - 1]; + if(off_from_last_dim_mult != 0){ + cur_range_count = gdimlen_[ndims - 1] - off_from_last_dim_mult; + if(start_off + cur_range_count > end_off){ + cur_range_count = end_off - start_off; + } + contig_map_ranges.push_back(std::make_pair(cur_range_start, cur_range_count)); + + cur_range_start += cur_range_count; + cur_tot_count -= cur_range_count; + } + + if(cur_tot_count == 0) return contig_map_ranges; + + // Break/partition the cur_range_start to end_off to contiguous dim chunks + // e.g. v[z][y][x], break up remaining range to ranges of sizes y*x, x, 1 + + PIO_Offset cur_range_end = cur_range_start; + for(int i = 0; i < ndims; i++){ + cur_range_end = dim_chunk_sz_[i] * (end_off / dim_chunk_sz_[i]); + if(cur_range_end != 0){ + cur_range_count = cur_range_end - cur_range_start; + if(cur_range_count > 0){ + contig_map_ranges.push_back(std::make_pair(cur_range_start, cur_range_count)); + + cur_range_start += cur_range_count; + cur_tot_count -= cur_range_count; + } + } + if(cur_tot_count == 0) break; + } + + assert(cur_tot_count == 0); + + return contig_map_ranges; +} + +// FIXME: Change start/count (on the caller side the list with C ptrs for start/count) to be +// vectors +void SPIO::DataRearr::Contig_rearr::off_range_to_dim_range(PIO_Offset start_off, PIO_Offset count_off, + PIO_Offset *start, PIO_Offset *count) const +{ + assert((start_off >= 0) && (count_off >= 0)); + assert(start && count); + + convert_off_to_start_dim_idx(start_off, start); + convert_off_to_count_dim_idx(count_off, count); +} + int SPIO::DataRearr::Contig_rearr::rearrange_comp2io(const void *sbuf, std::size_t sbuf_sz, void *rbuf, std::size_t rbuf_sz, int nvars) { @@ -757,13 +841,64 @@ inline int SPIO::DataRearr::Contig_rearr::create_rearr_comm(void ) } } + /* if(ret == MPI_SUCCESS){ rearr_comm_iochunk_sz_ = gdecomp_sz_ / rearr_comm_sz_; } + */ return ret; } +inline void SPIO::DataRearr::Contig_rearr::set_rearr_comm_iochunk_sz(int ndims, const int *gdimlen) +{ + assert((ndims > 0) && gdimlen); + assert(ios_); + assert(gdecomp_sz_ > 0); + + if(ios_->ioproc){ + assert((rearr_comm_ != MPI_COMM_NULL) && (rearr_comm_sz_ > 0)); + + rearr_comm_iochunk_sz_ = gdecomp_sz_ / rearr_comm_sz_; + } + else{ + rearr_comm_iochunk_sz_ = 0; + } + /* + // Get the largest contiguous chunk of data on an I/O process for data rearrangement + + // Number of contiguous regions in dim id + // gdimlen = {2, 5, 7} + // => dim id 0 has 2 contiguous regions of dims {5, 7} + // => dim id 1 has 10 contiguous regions of dims {7} + // => ncontig_dim_regions_in_idx = {2, 10, 70} respectively + PIO_Offset ncontig_dim_regions_in_idx = 1; + int idx_to_chunk = 0; + for(;idx_to_chunk < ndims; idx_to_chunk++){ + ncontig_dim_regions_in_idx *= gdimlen[idx_to_chunk]; + if(rearr_comm_sz_ < ncontig_dim_regions_in_idx){ + break; + } + } + assert(idx_to_chunk < ndims); + + // Size of a single contiguous dim region in chunk dim id + // e.g. gdimlen = {2, 5, 7}, + // 1) nprocs = 2 => idx_to_chunk = 0 + // sz_contig_dim_region_in_chunk_idx = size of contig region represented by {5, 7} => 5 * 7 + // 2) nprocs = 3 => idx_to_chunk = 1 + // sz_contig_dim_region_in_chunk_idx = size of contig region represented by {7} => 7 + PIO_Offset sz_contig_dim_region_in_chunk_idx = 1; + for(int i = idx_to_chunk + 1; i < ndims; i++){ + sz_contig_dim_region_in_chunk_idx *= static_cast(gdimlen[i]); + } + + // FIXME: Look at better way to partition data across procs. This method is ok when + // rearr_comm_sz_ << ncontig_dim_regions_in_idx + rearr_comm_iochunk_sz_ = ncontig_dim_regions_in_idx/rearr_comm_sz_ * sz_contig_dim_region_in_chunk_idx; + */ +} + int SPIO::DataRearr::Contig_rearr::get_rearr_toproc_map(const std::vector &gcompmap, std::vector &to_proc) { diff --git a/src/clib/pio_rearr_contig.hpp b/src/clib/pio_rearr_contig.hpp index a6757f8be7..5cff592f46 100644 --- a/src/clib/pio_rearr_contig.hpp +++ b/src/clib/pio_rearr_contig.hpp @@ -96,25 +96,16 @@ namespace SPIO{ } } - std::pair get_rearr_decomp_map_range(int iorank) - { - assert(gdecomp_sz_ > 0); - assert(rearr_comm_iochunk_sz_ > 0); - - PIO_Offset iochunk = rearr_comm_iochunk_sz_; - PIO_Offset start = iorank * iochunk; - PIO_Offset end = start + iochunk; - if(iorank == (rearr_comm_sz_ - 1)){ - end = gdecomp_sz_; - } - return std::make_pair(start, end); - } + std::vector > get_rearr_decomp_map_contig_ranges(int iorank) const; - std::pair get_rearr_decomp_map_range(void ) + std::vector > get_rearr_decomp_map_contig_ranges(void ) const { - return get_rearr_decomp_map_range(rearr_comm_rank_); + return get_rearr_decomp_map_contig_ranges(rearr_comm_rank_); } + void off_range_to_dim_range(PIO_Offset start_off, PIO_Offset end_off, + PIO_Offset *start, PIO_Offset *count) const; + /* Rearrange data */ int rearrange_comp2io(const void *sbuf, std::size_t sbuf_sz, void *rbuf, std::size_t rbuf_sz, int nvars); @@ -135,6 +126,8 @@ namespace SPIO{ * not represent all elements of a variable/array */ PIO_Offset gdecomp_sz_; + std::vector gdimlen_; + std::vector dim_chunk_sz_; int elem_pio_type_; int elem_mpi_type_; @@ -156,6 +149,62 @@ namespace SPIO{ PIO_Offset rearr_comm_iochunk_sz_; Alltoall_info rearr_alltoall_info_; + // FIXME: Change start_dim_idx ptr to a vector (requires changing the C array in ioregion list) + void convert_off_to_start_dim_idx(PIO_Offset start_off, PIO_Offset *start_dim_idx) const + { + std::size_t ndims = gdimlen_.size(); + for(std::size_t i = 0; i < ndims; i++){ + start_dim_idx[i] = 0; + } + for(std::size_t i = 0; i < ndims; i++){ + start_dim_idx[i] = start_off / dim_chunk_sz_[i]; + + start_off -= start_dim_idx[i] * dim_chunk_sz_[i]; + if(start_off == 0) break; + } + assert(start_off == 0); + } + + // FIXME: Change count_dim_idx ptr to a vector (requires changing the C array in ioregion list) + void convert_off_to_count_dim_idx(PIO_Offset count_off, PIO_Offset *count_dim_idx) const + { + std::size_t ndims = gdimlen_.size(); + for(std::size_t i = 0; i < ndims; i++){ + count_dim_idx[i] = gdimlen_[i]; + } + for(std::size_t i = 0; i < ndims; i++){ + count_dim_idx[i] = count_off / dim_chunk_sz_[i]; + + count_off -= count_dim_idx[i] * dim_chunk_sz_[i]; + if(count_off == 0) break; + } + + assert(count_off == 0); + for(std::size_t i = 0; i < ndims; i++){ + if(count_dim_idx[i] != 0){ + break; + } + else{ + count_dim_idx[i] = 1; + } + } + } + + std::pair get_rearr_decomp_map_range(int iorank) const + { + assert(gdecomp_sz_ > 0); + assert(rearr_comm_iochunk_sz_ > 0); + + PIO_Offset iochunk = rearr_comm_iochunk_sz_; + PIO_Offset start = iorank * iochunk; + PIO_Offset end = start + iochunk; + if(iorank == (rearr_comm_sz_ - 1)){ + end = gdecomp_sz_; + } + return std::make_pair(start, end); + } + + int create_agg_comm(void ); static void get_non_fval_lcompmap_counts_displs(const PIO_Offset *lcompmap, std::size_t lcompmap_sz, @@ -188,6 +237,7 @@ namespace SPIO{ void *rbuf, std::size_t rbuf_sz, int nvars); int create_rearr_comm(void ); + void set_rearr_comm_iochunk_sz(int ndims, const int *gdimlen); int get_rearr_toproc_map(const std::vector &gcompmap, std::vector &to_proc); int setup_data_rearr_info(std::vector &gcompmap, std::vector &to_proc, diff --git a/src/clib/pioc.cpp b/src/clib/pioc.cpp index b5f148cbfd..7af0c2a459 100644 --- a/src/clib/pioc.cpp +++ b/src/clib/pioc.cpp @@ -719,21 +719,35 @@ static inline void off_range_to_dim_range(PIO_Offset off_start, PIO_Offset off_e assert(off_start >= 0); assert((ndims > 0) && dimlen && dim_start && dim_count); + PIO_Offset off_count = off_end - off_start; + std::vector dim_chunk_sz(ndims, 1); for(int i = ndims - 2; i >= 0; i--){ dim_chunk_sz[i] = dimlen [i + 1] * dim_chunk_sz[i + 1]; } - PIO_Offset off_count = off_end - off_start; for(int i = 0; i < ndims; i++){ dim_start[i] = off_start / dim_chunk_sz[i]; + off_start -= dim_start[i] * dim_chunk_sz[i]; + } + + assert(off_start == 0); + + std::transform(dimlen, dimlen + ndims, dim_count, [](int len) { return static_cast(len); }); + + for(int i = 0; i < ndims; i++){ dim_count[i] = off_count / dim_chunk_sz[i]; - off_start -= dim_start[i] * dim_chunk_sz[i]; off_count -= dim_count[i] * dim_chunk_sz[i]; + + dim_count[i] = (dim_count[i] == 0) ? 1 : dim_count[i]; + + if(off_count == 0){ + break; + } } - assert((off_start == 0) && (off_count == 0)); + assert(off_count == 0); } static void init_iodesc_contig_rearr_fields(iosystem_desc_t *ios, io_desc_t *iodesc) @@ -744,7 +758,9 @@ static void init_iodesc_contig_rearr_fields(iosystem_desc_t *ios, io_desc_t *iod if(ios->ioproc){ iodesc->num_aiotasks = ios->num_iotasks; } - iodesc->maxregions = 1; + + /* The first region is pre-allocated when iodesc is allocated */ + iodesc->maxregions = 0; /* FIXME: We only need fillvalues when the total decomp map size is less than var size */ iodesc->needsfill = true; /* FIXME: Remove the field since we no longer use maxbytes */ @@ -754,12 +770,28 @@ static void init_iodesc_contig_rearr_fields(iosystem_desc_t *ios, io_desc_t *iod if(ios->ioproc){ assert(iodesc->firstregion && iodesc->firstregion->start && iodesc->firstregion->count); - iodesc->firstregion->loffset = 0; - /* Fill the start/count arrays for the first/only region */ - std::pair off_range = iodesc->rearr->get_rearr_decomp_map_range(); - off_range_to_dim_range(off_range.first, off_range.second, - iodesc->ndims, iodesc->dimlen, - iodesc->firstregion->start, iodesc->firstregion->count); + /* Get (start, count) pairs of contiguous decomp ranges for this I/O process */ + std::vector > off_ranges = iodesc->rearr->get_rearr_decomp_map_contig_ranges(); + io_region *cur_region = iodesc->firstregion; + io_region *prev_region = cur_region; + int loff = 0; + + // FIXME : Move to C++ lists for region list + for(int i = 0; i < off_ranges.size(); i++){ + if(cur_region == NULL){ + alloc_region2(ios, iodesc->ndims, &cur_region); + prev_region->next = cur_region; + } + cur_region->loffset = loff; + loff += static_cast(off_ranges[i].second); + /* Convert the range (start, count) offsets to dim indices & store in the region info */ + iodesc->rearr->off_range_to_dim_range(off_ranges[i].first, off_ranges[i].second, + cur_region->start, cur_region->count); + + prev_region = cur_region; + cur_region = cur_region->next; + } + iodesc->maxregions = off_ranges.size(); } } From 4b598fef54ccc4e3cb6b035c42b95a8aece85b67 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 17 Jan 2025 01:12:14 -0600 Subject: [PATCH 030/194] When dispersing n vars fix stride of type Since the aggregator buffer size is in bytes (not elements), fix the stride for MPI hvector accordingly while dispersing data read for multiple variables (nvars > 1, io2comp) --- src/clib/pio_rearr_contig.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clib/pio_rearr_contig.cpp b/src/clib/pio_rearr_contig.cpp index ffb7144e58..e0fd8d1a6a 100644 --- a/src/clib/pio_rearr_contig.cpp +++ b/src/clib/pio_rearr_contig.cpp @@ -376,7 +376,7 @@ int SPIO::DataRearr::Contig_rearr::disperse_data(const void *abuf, std::size_t a } } if(agg_gs_info_.stype != MPI_DATATYPE_NULL){ - MPI_Aint stride_between_vars = static_cast(abuf_sz * elem_mpi_type_sz_); + MPI_Aint stride_between_vars = static_cast(abuf_sz / nvars); ret = MPI_Type_hvector(nvars, 1, stride_between_vars, agg_gs_info_.stype, &dis_rtype_nvars); if(ret == MPI_SUCCESS){ ret = MPI_Type_commit(&dis_rtype_nvars); From 7ee92014afa4807ed80e2fb498b14fe193067d88 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 17 Jan 2025 01:14:16 -0600 Subject: [PATCH 031/194] Sync nvars unit test with the latest code The current code uses different metrics (number of elements vs size in bytes) for the send and recv buffer sizes. The contig rearranger was modified to reflect this requirement. Updating the unit tests accordingly --- tests/cunit/test_spio_rearr_contig_nvars.cpp | 26 ++++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/cunit/test_spio_rearr_contig_nvars.cpp b/tests/cunit/test_spio_rearr_contig_nvars.cpp index 2002b78dfb..b9b6e85e6f 100644 --- a/tests/cunit/test_spio_rearr_contig_nvars.cpp +++ b/tests/cunit/test_spio_rearr_contig_nvars.cpp @@ -152,7 +152,7 @@ int test_c2i_block_data_rearr_nvars(MPI_Comm comm, int wrank, int wsz, int nvars LOG_RANK0(wrank, "Initializing contig rearranger failed"); return PIO_EINTERNAL; } - ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), + ret = rearr.rearrange_comp2io(sdata.data(), compmap.size(), rdata.data(), rdata.size() * sizeof(double), nvars); if(ret != PIO_NOERR){ LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); @@ -223,7 +223,7 @@ int test_block_data_rearr_nvars(MPI_Comm comm, int wrank, int wsz, int nvars) LOG_RANK0(wrank, "Initializing contig rearranger failed"); return PIO_EINTERNAL; } - ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), + ret = rearr.rearrange_comp2io(sdata.data(), compmap.size(), rdata.data(), rdata.size() * sizeof(double), nvars); if(ret != PIO_NOERR){ LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); @@ -241,8 +241,8 @@ int test_block_data_rearr_nvars(MPI_Comm comm, int wrank, int wsz, int nvars) std::copy(sdata.begin(), sdata.end(), exp_data.begin()); std::fill(sdata.begin(), sdata.end(), PIO_FILL_DOUBLE); - ret = rearr.rearrange_io2comp(rdata.data(), rdata.size() * sizeof(double), - sdata.data(), sdata.size() * sizeof(double), nvars); + ret = rearr.rearrange_io2comp(rdata.data(), compmap.size(), + sdata.data(), compmap.size() * sizeof(double), nvars); if(ret != PIO_NOERR){ LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); return PIO_EINTERNAL; @@ -315,7 +315,7 @@ int test_rev_block_data_rearr_nvars(MPI_Comm comm, int wrank, int wsz, int nvars LOG_RANK0(wrank, "Initializing contig rearranger failed"); return PIO_EINTERNAL; } - ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), + ret = rearr.rearrange_comp2io(sdata.data(), compmap.size(), rdata.data(), rdata.size() * sizeof(double), nvars); if(ret != PIO_NOERR){ LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); @@ -333,8 +333,8 @@ int test_rev_block_data_rearr_nvars(MPI_Comm comm, int wrank, int wsz, int nvars std::copy(sdata.begin(), sdata.end(), exp_data.begin()); std::fill(sdata.begin(), sdata.end(), PIO_FILL_DOUBLE); - ret = rearr.rearrange_io2comp(rdata.data(), rdata.size() * sizeof(double), - sdata.data(), sdata.size() * sizeof(double), nvars); + ret = rearr.rearrange_io2comp(rdata.data(), compmap.size(), + sdata.data(), compmap.size() * sizeof(double), nvars); if(ret != PIO_NOERR){ LOG_RANK0(wrank, "Rearranging data using contig rearranger failed (I/O to compute procs)"); return PIO_EINTERNAL; @@ -409,7 +409,7 @@ int test_mrange_block_data_rearr_nvars(MPI_Comm comm, int wrank, int wsz, int nv LOG_RANK0(wrank, "Initializing contig rearranger failed"); return PIO_EINTERNAL; } - ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), + ret = rearr.rearrange_comp2io(sdata.data(), compmap.size(), rdata.data(), rdata.size() * sizeof(double), nvars); if(ret != PIO_NOERR){ LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); @@ -427,8 +427,8 @@ int test_mrange_block_data_rearr_nvars(MPI_Comm comm, int wrank, int wsz, int nv std::copy(sdata.begin(), sdata.end(), exp_data.begin()); std::fill(sdata.begin(), sdata.end(), PIO_FILL_DOUBLE); - ret = rearr.rearrange_io2comp(rdata.data(), rdata.size() * sizeof(double), - sdata.data(), sdata.size() * sizeof(double), nvars); + ret = rearr.rearrange_io2comp(rdata.data(), compmap.size(), + sdata.data(), compmap.size() * sizeof(double), nvars); if(ret != PIO_NOERR){ LOG_RANK0(wrank, "Rearranging data using contig rearranger failed (I/O to compute procs)"); return PIO_EINTERNAL; @@ -515,7 +515,7 @@ int test_mrange_oddz_data_rearr_nvars(MPI_Comm comm, int wrank, int wsz, int nva LOG_RANK0(wrank, "Initializing contig rearranger failed"); return PIO_EINTERNAL; } - ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), + ret = rearr.rearrange_comp2io(sdata.data(), compmap.size(), rdata.data(), rdata.size() * sizeof(double), nvars); if(ret != PIO_NOERR){ LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); @@ -539,8 +539,8 @@ int test_mrange_oddz_data_rearr_nvars(MPI_Comm comm, int wrank, int wsz, int nva std::copy(sdata.begin(), sdata.end(), exp_data.begin()); std::fill(sdata.begin(), sdata.end(), PIO_FILL_DOUBLE); - ret = rearr.rearrange_io2comp(rdata.data(), rdata.size() * sizeof(double), - sdata.data(), sdata.size() * sizeof(double), nvars); + ret = rearr.rearrange_io2comp(rdata.data(), compmap.size(), + sdata.data(), compmap.size() * sizeof(double), nvars); if(ret != PIO_NOERR){ LOG_RANK0(wrank, "Rearranging data using contig rearranger failed (I/O to compute procs)"); return PIO_EINTERNAL; From 1e5399a1a564a1328608f32e74abf13c6209814c Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 17 Jan 2025 13:21:43 -0600 Subject: [PATCH 032/194] Adding CONTIG/ANY rearr support in replay tool Adding support for ANY and CONTIG rearrangers in the replay tool Also adding some prints --- tests/performance/pioperformance_rearr.F90 | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/tests/performance/pioperformance_rearr.F90 b/tests/performance/pioperformance_rearr.F90 index 5b1d9b4494..7b247cc95b 100644 --- a/tests/performance/pioperformance_rearr.F90 +++ b/tests/performance/pioperformance_rearr.F90 @@ -7,7 +7,8 @@ program pioperformance_rearr use mpi #endif use pio, only : pio_iotype_netcdf, pio_iotype_pnetcdf, pio_iotype_netcdf4p, & - pio_iotype_netcdf4c, pio_iotype_adios, pio_iotype_hdf5, pio_rearr_subset, pio_rearr_box, PIO_MAX_NAME,& + pio_iotype_netcdf4c, pio_iotype_adios, pio_iotype_hdf5,& + pio_rearr_subset, pio_rearr_box, pio_rearr_any, pio_rearr_contig, PIO_MAX_NAME,& pio_rearr_opt_t, pio_rearr_comm_p2p, pio_rearr_comm_coll,& pio_rearr_comm_fc_2d_disable, pio_rearr_comm_fc_1d_comp2io,& pio_rearr_comm_fc_1d_io2comp, pio_rearr_comm_fc_2d_enable,& @@ -19,7 +20,7 @@ program pioperformance_rearr integer, parameter :: MAX_IO_TASK_ARRAY_SIZE=256, MAX_DECOMP_FILES=256 integer, parameter :: MAX_FNAME_LEN = 1024 integer, parameter :: MAX_PIO_TYPENAME_LEN = 8 - integer, parameter :: MAX_PIO_TYPES = 4, MAX_PIO_REARRS = 2 + integer, parameter :: MAX_PIO_TYPES = 4, MAX_PIO_REARRS = 4 integer, parameter :: MAX_NVARS = 12 character(len=*), parameter :: PIO_NML_FNAME = 'pioperf_rearr.nl' @@ -60,6 +61,10 @@ program pioperformance_rearr call CheckMPIreturn(__LINE__,ierr) if(mype==0) then Mastertask=.true. + if(mype == 0) then + print *, 'SCORPIO REPLAY TOOL' + print *, '=======================' + endif else Mastertask=.false. endif @@ -75,6 +80,9 @@ program pioperformance_rearr varsize = 0 varsize(1) = 1 unlimdimindof=.false. + if(mype == 0) then + print *, "Reading user input..." + endif call read_user_input(mype, decompfile, piotypes, rearrangers,& niotasks, nframes, unlimdimindof, nvars, varsize,& rearr_opts, ierr) @@ -92,6 +100,8 @@ program pioperformance_rearr if(rearrangers(1)==0) then rearrangers(1)=1 rearrangers(2)=2 + rearrangers(3)=3 + rearrangers(4)=4 endif do i=1,MAX_DECOMP_FILES @@ -622,7 +632,7 @@ subroutine pioperformance_rearrtest(filename, piotypes, mype, npe_base, & integer, parameter :: c0 = -1 double precision, parameter :: cd0 = 1.0e30 integer :: nvarmult - character(len=*), parameter :: rearr_name(MAX_PIO_REARRS) = (/' BOX','SUBSET'/) + character(len=*), parameter :: rearr_name(MAX_PIO_REARRS) = (/' BOX','SUBSET',' ANY','CONTIG'/) nullify(compmap) @@ -701,9 +711,9 @@ subroutine pioperformance_rearrtest(filename, piotypes, mype, npe_base, & else mode = 0 endif - do rearrtype=1,2 + do rearrtype=1,4 rearr = rearrangers(rearrtype) - if(rearr /= PIO_REARR_SUBSET .and. rearr /= PIO_REARR_BOX) exit + if(rearr /= PIO_REARR_SUBSET .and. rearr /= PIO_REARR_BOX .and. rearr /= PIO_REARR_ANY .and. rearr /= PIO_REARR_CONTIG) exit do n=niomin,niomax ntasks = niotasks(n) From 68a916750e1915154fae27c68e4829906a59e2b0 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 17 Jan 2025 14:04:57 -0600 Subject: [PATCH 033/194] Adding log level to replay tool args Adding support for setting log level (--pio-log-level=) in the replay tool via command line args --- tests/performance/pioperformance_rearr.F90 | 29 ++++++++++++++++------ 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/tests/performance/pioperformance_rearr.F90 b/tests/performance/pioperformance_rearr.F90 index 7b247cc95b..fa5674b6cc 100644 --- a/tests/performance/pioperformance_rearr.F90 +++ b/tests/performance/pioperformance_rearr.F90 @@ -35,6 +35,7 @@ program pioperformance_rearr integer :: vs, varsize(MAX_NVARS) ! Local size of array for idealized decomps logical :: unlimdimindof type(pio_rearr_opt_t) :: rearr_opts + integer :: log_level #ifdef BGQTRY external :: print_memusage #endif @@ -80,12 +81,13 @@ program pioperformance_rearr varsize = 0 varsize(1) = 1 unlimdimindof=.false. + log_level = 0 if(mype == 0) then print *, "Reading user input..." endif call read_user_input(mype, decompfile, piotypes, rearrangers,& niotasks, nframes, unlimdimindof, nvars, varsize,& - rearr_opts, ierr) + rearr_opts, log_level, ierr) #ifdef SPIO_ENABLE_GPTL_TIMING #ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL @@ -113,7 +115,7 @@ program pioperformance_rearr if(nvars(nv)>0) then call pioperformance_rearrtest(decompfile(i), piotypes(1:niotypes),& mype, npe, rearrangers, rearr_opts, niotasks, nframes,& - nvars(nv), varsize(vs),unlimdimindof) + nvars(nv), varsize(vs),unlimdimindof, log_level) endif enddo endif @@ -273,7 +275,7 @@ end subroutine pio_rearr_str2opt ! Parse a single command line arg subroutine parse_and_process_input(argv, decompfiles, piotypes,& rearrangers, niotasks, nframes, unlimdimindof, nvars, varsize,& - rearr_opts, ierr) + rearr_opts, log_level, ierr) character(len=*), intent(in) :: argv character(len=MAX_FNAME_LEN), intent(out) :: decompfiles(MAX_DECOMP_FILES) integer, intent(out) :: piotypes(MAX_PIO_TYPES) @@ -284,6 +286,7 @@ subroutine parse_and_process_input(argv, decompfiles, piotypes,& integer, intent(out) :: nvars(MAX_NVARS) integer, intent(out) :: varsize(MAX_NVARS) type(pio_rearr_opt_t), intent(out) :: rearr_opts + integer, intent(out) :: log_level integer, intent(out) :: ierr integer, parameter :: MAX_PIO_REARR_OPT_LEN = 128 @@ -361,6 +364,9 @@ subroutine parse_and_process_input(argv, decompfiles, piotypes,& else if (argv(:pos) == "--pio-varsize=") then call init_arr_from_list(argv(pos+1:), iarr=varsize, ierr=ierr) !print *, "Read varsize : ", varsize + else if (argv(:pos) == "--pio-log-level=") then + read(argv(pos+1:), *) log_level + !print *, "Read varsize : ", varsize end if end if @@ -369,7 +375,7 @@ end subroutine parse_and_process_input ! Parse command line user options subroutine read_cmd_line_input(decompfile, piotypes, rearrangers,& niotasks, nframes, unlimdimindof, nvars, varsize,& - rearr_opts, ierr) + rearr_opts, log_level, ierr) character(len=MAX_FNAME_LEN), intent(out) :: decompfile(MAX_DECOMP_FILES) integer, intent(out) :: piotypes(MAX_PIO_TYPES) integer, intent(out) :: rearrangers(MAX_PIO_REARRS) @@ -379,6 +385,7 @@ subroutine read_cmd_line_input(decompfile, piotypes, rearrangers,& integer, intent(out) :: nvars(MAX_NVARS) integer, intent(out) :: varsize(MAX_NVARS) type(pio_rearr_opt_t), intent(out) :: rearr_opts + integer, intent(out) :: log_level integer, intent(out) :: ierr integer, parameter :: MAX_STDIN_ARG_LEN = 8192 @@ -390,7 +397,7 @@ subroutine read_cmd_line_input(decompfile, piotypes, rearrangers,& call get_command_argument(i, argv) call parse_and_process_input(argv, decompfile, piotypes, rearrangers,& niotasks, nframes, unlimdimindof, nvars, varsize,& - rearr_opts, ierr) + rearr_opts, log_level, ierr) end do end subroutine read_cmd_line_input @@ -546,7 +553,7 @@ end subroutine bcast_rearr_opts ! read (and override) the command line options subroutine read_user_input(mype, decompfile, piotypes, rearrangers,& niotasks, nframes, unlimdimindof, nvars, varsize,& - rearr_opts, ierr) + rearr_opts, log_level, ierr) integer, intent(in) :: mype character(len=MAX_FNAME_LEN), intent(out) :: decompfile(MAX_DECOMP_FILES) integer, intent(out) :: piotypes(MAX_PIO_TYPES) @@ -557,11 +564,13 @@ subroutine read_user_input(mype, decompfile, piotypes, rearrangers,& integer, intent(out) :: nvars(MAX_NVARS) integer, intent(out) :: varsize(MAX_NVARS) type(pio_rearr_opt_t), intent(out) :: rearr_opts + integer, intent(out) :: log_level integer, intent(out) :: ierr character(len=MAX_PIO_TYPENAME_LEN) :: pio_typenames(MAX_PIO_TYPES) pio_typenames = ' ' + log_level = 0 if(mype == 0) then ! Read namelist file @@ -571,7 +580,7 @@ subroutine read_user_input(mype, decompfile, piotypes, rearrangers,& ! Allow user to override the values via command line call read_cmd_line_input(decompfile, piotypes, rearrangers,& niotasks, nframes, unlimdimindof, nvars, varsize,& - rearr_opts, ierr) + rearr_opts, log_level, ierr) end if call MPI_Bcast(decompfile,MAX_FNAME_LEN*MAX_DECOMP_FILES,MPI_CHARACTER,0, MPI_COMM_WORLD,ierr) @@ -582,6 +591,7 @@ subroutine read_user_input(mype, decompfile, piotypes, rearrangers,& call MPI_Bcast(unlimdimindof, 1, MPI_INTEGER, 0, MPI_COMM_WORLD,ierr) call MPI_Bcast(nvars, MAX_NVARS, MPI_INTEGER, 0, MPI_COMM_WORLD,ierr) call MPI_Bcast(varsize, MAX_NVARS, MPI_INTEGER, 0, MPI_COMM_WORLD,ierr) + call MPI_Bcast(log_level, 1, MPI_INTEGER, 0, MPI_COMM_WORLD,ierr) call bcast_rearr_opts(rearr_opts) @@ -589,7 +599,7 @@ end subroutine read_user_input subroutine pioperformance_rearrtest(filename, piotypes, mype, npe_base, & rearrangers, rearr_opts, niotasks,nframes, nvars, varsize,& - unlimdimindof) + unlimdimindof, log_level) use pio character(len=*), intent(in) :: filename integer, intent(in) :: mype, npe_base @@ -601,6 +611,7 @@ subroutine pioperformance_rearrtest(filename, piotypes, mype, npe_base, & integer, intent(in) :: nvars integer, intent(in) :: varsize logical, intent(in) :: unlimdimindof + integer, intent(in) :: log_level integer(kind=PIO_Offset_kind), pointer :: compmap(:) integer :: ntasks integer :: comm @@ -723,6 +734,8 @@ subroutine pioperformance_rearrtest(filename, piotypes, mype, npe_base, & call pio_init(mype, comm, ntasks, 0, stride, PIO_REARR_SUBSET,& iosystem, rearr_opts=rearr_opts) + + ierr = PIO_set_log_level(log_level) write(fname, '(a,i1,a,i5.5,a,i5.5,a,i5.5,a,i1,a,i5.5,a,i5.5,a)') 'pioperf-rearr-', rearr, & '-ncomptasks-', npe, '-niotasks-', ntasks, '-stride-', stride, '-iotype-', iotype, & From 74c8a5b725e99110c3a7b4c51616a521900b56a6 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 17 Jan 2025 16:11:52 -0600 Subject: [PATCH 034/194] Using C++ min in pio_darray_int.cpp Using C++ min instead of custom C99 min in pio_darray_int.cpp --- src/clib/pio_darray_int.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/clib/pio_darray_int.cpp b/src/clib/pio_darray_int.cpp index fd57f4be68..131d7d2f8c 100644 --- a/src/clib/pio_darray_int.cpp +++ b/src/clib/pio_darray_int.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #ifdef PIO_MICRO_TIMING #include "pio_timer.h" #endif @@ -2508,7 +2507,7 @@ int compute_maxaggregate_bytes(iosystem_desc_t *ios, io_desc_t *iodesc) maxbytesoncomputetask = pio_cnbuffer_limit / iodesc->ndof; /* Take the min of the max IO and max comp bytes. */ - maxbytes = min(maxbytesoniotask, maxbytesoncomputetask); + maxbytes = std::min(maxbytesoniotask, maxbytesoncomputetask); LOG((2, "compute_maxaggregate_bytes maxbytesoniotask = %d maxbytesoncomputetask = %d", maxbytesoniotask, maxbytesoncomputetask)); From b788ed34b0883661cad46b1aecd9cb0f7b4dcc0f Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 17 Jan 2025 16:20:42 -0600 Subject: [PATCH 035/194] Adding dbg info for I/O desc Adding a function to get string info about an I/O descriptor. This function can be used for debugging (or printing out error msgs) I/O descs --- src/clib/CMakeLists.txt | 2 +- src/clib/spio_dbg_ds.cpp | 52 +++++++++++++++++++++++++++++++++++++ src/clib/spio_dbg_utils.hpp | 3 +++ 3 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 src/clib/spio_dbg_ds.cpp diff --git a/src/clib/CMakeLists.txt b/src/clib/CMakeLists.txt index 38d4100b5d..ad3756d63d 100644 --- a/src/clib/CMakeLists.txt +++ b/src/clib/CMakeLists.txt @@ -37,7 +37,7 @@ set (pio_api_src # PIO lib source set (pio_lib_src topology.cpp pio_mpi_timer.cpp pio_timer.cpp pio_file.cpp - pioc_support.cpp pio_lists.cpp pio_print.cpp + pioc_support.cpp pio_lists.cpp pio_print.cpp spio_dbg_ds.cpp pioc.cpp pioc_sc.cpp pio_spmd.cpp pio_rearrange.cpp pio_rearr_utils.cpp pio_rearr_contig.cpp pio_nc4.cpp bget.cpp pio_nc.cpp pio_put_nc.cpp pio_get_nc.cpp pio_getput_int.cpp pio_msg.cpp pio_varm.cpp diff --git a/src/clib/spio_dbg_ds.cpp b/src/clib/spio_dbg_ds.cpp new file mode 100644 index 0000000000..b3ec9f8f85 --- /dev/null +++ b/src/clib/spio_dbg_ds.cpp @@ -0,0 +1,52 @@ +#include "pio_config.h" +#include "pio.h" +#include "pio_internal.h" +#include "pio_types.hpp" +#include "spio_dbg_utils.hpp" + +#include +#include +#include +#include +#include +#include + +std::string SPIO_Util::Dbg_Util::get_iodesc_info(io_desc_t *iodesc) +{ + std::ostringstream ostr; + if(iodesc){ + ostr << "iodesc{"; + ostr << "ioid = " << iodesc->ioid << ", maplen =" << iodesc->maplen; + ostr << ", map = ["; + std::copy(iodesc->map, iodesc->map + iodesc->maplen, std::ostream_iterator(ostr, ",")); + ostr << "], ndof = " << iodesc->ndof << ", ndims = " << iodesc->ndims; + ostr << ", dimlen = ["; + std::copy(iodesc->dimlen, iodesc->dimlen + iodesc->ndims, std::ostream_iterator(ostr, ",")); + ostr << "], rearranger = " << iodesc->rearranger; + ostr << ", maxregions =" << iodesc->maxregions; + ostr << ", llen = " << iodesc->llen; + io_region *cur_region = iodesc->firstregion; + for(int i = 0; i < iodesc->maxregions; i++){ + if(cur_region == NULL){ + ostr << ", region " << i << "{NULL}"; continue; + } + ostr << ", region " << i << "{"; + ostr << "loffset = " << cur_region->loffset; + ostr << "start = ["; + std::copy(cur_region->start, cur_region->start + iodesc->ndims, std::ostream_iterator(ostr, ",")); + ostr << "]"; + ostr << "count = ["; + std::copy(cur_region->count, cur_region->count + iodesc->ndims, std::ostream_iterator(ostr, ",")); + ostr << "]"; + ostr << "}"; + cur_region = cur_region->next; + } + ostr << "}"; + //std::copy(v.cbegin(), v.cend(), std::ostream_iterator(ostr, ",")); + } + else{ + ostr<< "iodesc{NULL}"; + } + + return ostr.str(); +} diff --git a/src/clib/spio_dbg_utils.hpp b/src/clib/spio_dbg_utils.hpp index 474474fba6..e64eaa8216 100644 --- a/src/clib/spio_dbg_utils.hpp +++ b/src/clib/spio_dbg_utils.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -50,6 +51,8 @@ namespace SPIO_Util{ ostr << "]"; std::cout << ostr.str().c_str() << "\n" << std::flush; } + + std::string get_iodesc_info(io_desc_t *ios); } // namespace Dbg_Util } // namespace SPIO_Util From c26c54512655bed05dd4d1c7dc0347c44cf5f3ab Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 16 Apr 2025 18:43:55 -0500 Subject: [PATCH 036/194] Rm limit on log msg size Using C++ ds to remove the limit on log message size. All log msgs are now logged into the log files --- src/clib/pioc_support.cpp | 84 +++++++++++---------------------------- 1 file changed, 24 insertions(+), 60 deletions(-) diff --git a/src/clib/pioc_support.cpp b/src/clib/pioc_support.cpp index ffb89c06f7..3a62af45d5 100644 --- a/src/clib/pioc_support.cpp +++ b/src/clib/pioc_support.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -61,7 +62,7 @@ extern int GPTLis_initialized (void); /* Some logging constants. */ #if PIO_ENABLE_LOGGING -#define MAX_LOG_MSG 1024 +#define MAX_LOG_MSG 8192 #define MAX_RANK_STR 12 #define ERROR_PREFIX "ERROR: " #define NC_LEVEL_DIFF 3 @@ -1044,70 +1045,33 @@ void pio_finalize_gptl(void) */ void pio_log(int severity, const char *fmt, ...) { - va_list argp; - int t; - int rem_len = MAX_LOG_MSG; - char msg[MAX_LOG_MSG]; - char *ptr = msg; - char rank_str[MAX_RANK_STR]; + va_list argp; + int log_msg_sz = 0; - /* If the severity is greater than the log level, we don't print - this message. */ - if (severity > pio_log_level) - return; + if(severity > pio_log_level) return; - /* If the severity is 0, only print on rank 0. */ - if (severity < 1 && my_rank != 0) - return; + // Find the size of the log msg + va_start(argp, fmt); + int log_msg_size = std::vsnprintf(NULL, 0, fmt, argp); + va_end(argp); - /* If the severity is zero, this is an error. Otherwise insert that - many tabs before the message. */ - if (!severity) - { - strncpy(ptr, ERROR_PREFIX, (rem_len > 0) ? rem_len : 0); - ptr += strlen(ERROR_PREFIX); - rem_len -= strlen(ERROR_PREFIX); - } - for (t = 0; t < severity; t++) - { - strncpy(ptr++, "\t", (rem_len > 0) ? rem_len : 0); - rem_len--; - } + if(log_msg_size == 0) return; - /* Show the rank. */ - snprintf(rank_str, MAX_RANK_STR, "%d ", my_rank); - strncpy(ptr, rank_str, (rem_len > 0) ? rem_len : 0); - ptr += strlen(rank_str); - rem_len -= strlen(rank_str); + // Get the log msg + std::string log_msg(log_msg_size + 1, '\0'); + va_start(argp, fmt); + vsnprintf(&log_msg[0], log_msg.size(), fmt, argp); + va_end(argp); - /* Print out the variable list of args with vprintf. */ - va_start(argp, fmt); - vsnprintf(ptr, ((rem_len > 0) ? rem_len : 0), fmt, argp); - va_end(argp); - - /* Put on a final linefeed. */ - ptr = msg + strlen(msg); - rem_len = MAX_LOG_MSG - strlen(msg); - strncpy(ptr, "\n\0", (rem_len > 0) ? rem_len : 0); - - /* Add string delimiter to handle the case where the buffer - * is completely filled up - */ - msg[MAX_LOG_MSG - 1] = '\0'; - - /* Send message to log file. */ - if (LOG_FILE) - { - fprintf(LOG_FILE, "%s", msg); - fflush(LOG_FILE); - } - else - { - /* Send message to stdout. */ - fprintf(stdout, "%s", msg); - /* Ensure an immediate flush of stdout. */ - fflush(stdout); - } + // Write log msg to file + if(LOG_FILE){ + fprintf(LOG_FILE, "%s\n", log_msg.c_str()); + fflush(LOG_FILE); + } + else{ + fprintf(stdout, "%s\n", log_msg.c_str()); + fflush(stdout); + } } #endif /* PIO_ENABLE_LOGGING */ From d98692eb5a4c6f91ad67c82670a5e07a0aef86eb Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Sun, 19 Jan 2025 20:11:56 -0600 Subject: [PATCH 037/194] Adding iodesc info in log when put fails When ncmpi_put_varn() fails log the iodesc info into the log files --- src/clib/pio_darray_int.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/clib/pio_darray_int.cpp b/src/clib/pio_darray_int.cpp index 131d7d2f8c..a81c5f4a9b 100644 --- a/src/clib/pio_darray_int.cpp +++ b/src/clib/pio_darray_int.cpp @@ -18,6 +18,7 @@ #endif #include "spio_io_summary.h" #include "spio_file_mvcache.h" +#include "spio_dbg_utils.hpp" /* 10MB default limit. */ extern PIO_Offset pio_buffer_size_limit; @@ -411,6 +412,7 @@ int write_darray_multi_par(file_desc_t *file, int nvars, int fndims, const int * bufptr, llen, iodesc->mpitype, vdesc->request + vdesc->nreqs); if (ierr != PIO_NOERR) { + LOG((3, "ERROR: ncmpi_iput_varn() FAILED: iodesc = %s", SPIO_Util::Dbg_Util::get_iodesc_info(iodesc).c_str())); ierr = pio_err(ios, file, ierr, __FILE__, __LINE__, "Writing variables (number of variables = %d) to file (%s, ncid=%d) using PIO_IOTYPE_PNETCDF iotype failed. Non blocking write for variable (%s, varid=%d) failed (Number of subarray requests/regions=%d, Size of data local to this process = %lld)", nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, varids[nv]), varids[nv], rrcnt, (long long int )llen); break; From f608b81f5ac0acfcfb1c609451f773bce42da63c Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 21 Jan 2025 17:42:26 -0600 Subject: [PATCH 038/194] Adding util to convert 1d vec to str Adding util function to convert 1d vectors to string for logging and debugging --- src/clib/spio_dbg_utils.hpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/clib/spio_dbg_utils.hpp b/src/clib/spio_dbg_utils.hpp index e64eaa8216..e19ac151f6 100644 --- a/src/clib/spio_dbg_utils.hpp +++ b/src/clib/spio_dbg_utils.hpp @@ -7,6 +7,7 @@ #include "pio_types.hpp" #include +#include #include #include #include @@ -52,6 +53,17 @@ namespace SPIO_Util{ std::cout << ostr.str().c_str() << "\n" << std::flush; } + /* Convert vector to string */ + template + std::string vec1d_to_string(const T *vbegin, const T *vend) + { + std::ostringstream ostr; + ostr << "["; + std::copy(vbegin, vend, std::ostream_iterator(ostr, ",")); + ostr << "]"; + return ostr.str(); + } + std::string get_iodesc_info(io_desc_t *ios); } // namespace Dbg_Util } // namespace SPIO_Util From 318c9ea1693516d659b6c20c027766e846bb0a26 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 21 Jan 2025 17:44:03 -0600 Subject: [PATCH 039/194] Avoid logging map when getting iodesc info Avoid logging/printing the map when getting io desc info for logging/debugging --- src/clib/spio_dbg_ds.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/clib/spio_dbg_ds.cpp b/src/clib/spio_dbg_ds.cpp index b3ec9f8f85..cac0d766da 100644 --- a/src/clib/spio_dbg_ds.cpp +++ b/src/clib/spio_dbg_ds.cpp @@ -18,7 +18,8 @@ std::string SPIO_Util::Dbg_Util::get_iodesc_info(io_desc_t *iodesc) ostr << "iodesc{"; ostr << "ioid = " << iodesc->ioid << ", maplen =" << iodesc->maplen; ostr << ", map = ["; - std::copy(iodesc->map, iodesc->map + iodesc->maplen, std::ostream_iterator(ostr, ",")); + // std::copy(iodesc->map, iodesc->map + iodesc->maplen, std::ostream_iterator(ostr, ",")); + ostr << "..."; ostr << "], ndof = " << iodesc->ndof << ", ndims = " << iodesc->ndims; ostr << ", dimlen = ["; std::copy(iodesc->dimlen, iodesc->dimlen + iodesc->ndims, std::ostream_iterator(ostr, ",")); @@ -30,19 +31,18 @@ std::string SPIO_Util::Dbg_Util::get_iodesc_info(io_desc_t *iodesc) if(cur_region == NULL){ ostr << ", region " << i << "{NULL}"; continue; } - ostr << ", region " << i << "{"; + ostr << ", region " << i << " {"; ostr << "loffset = " << cur_region->loffset; - ostr << "start = ["; + ostr << ", start = ["; std::copy(cur_region->start, cur_region->start + iodesc->ndims, std::ostream_iterator(ostr, ",")); - ostr << "]"; + ostr << "], "; ostr << "count = ["; std::copy(cur_region->count, cur_region->count + iodesc->ndims, std::ostream_iterator(ostr, ",")); ostr << "]"; - ostr << "}"; + ostr << " }"; cur_region = cur_region->next; } ostr << "}"; - //std::copy(v.cbegin(), v.cend(), std::ostream_iterator(ostr, ",")); } else{ ostr<< "iodesc{NULL}"; From 1855152264f1a701da3ca0799f50c7f91d606cbe Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 21 Jan 2025 17:45:54 -0600 Subject: [PATCH 040/194] Rm unused func and add some logs in contig init Removing an unused function and adding some logging in contig rearranger init function --- src/clib/pioc.cpp | 40 +++------------------------------------- 1 file changed, 3 insertions(+), 37 deletions(-) diff --git a/src/clib/pioc.cpp b/src/clib/pioc.cpp index 7af0c2a459..1ea22b3215 100644 --- a/src/clib/pioc.cpp +++ b/src/clib/pioc.cpp @@ -21,6 +21,7 @@ #include "spio_ltimer_utils.hpp" #include "spio_gptl_utils.hpp" #include "pio_rearr_contig.hpp" +#include "spio_dbg_utils.hpp" /* Include headers for HDF5 compression filters */ #if PIO_USE_HDF5 @@ -713,43 +714,6 @@ static int box_rearranger_init(iosystem_desc_t *ios, io_desc_t *iodesc, const PI return PIO_NOERR; } -static inline void off_range_to_dim_range(PIO_Offset off_start, PIO_Offset off_end, - int ndims, const int *dimlen, PIO_Offset *dim_start, PIO_Offset *dim_count) -{ - assert(off_start >= 0); - assert((ndims > 0) && dimlen && dim_start && dim_count); - - PIO_Offset off_count = off_end - off_start; - - std::vector dim_chunk_sz(ndims, 1); - for(int i = ndims - 2; i >= 0; i--){ - dim_chunk_sz[i] = dimlen [i + 1] * dim_chunk_sz[i + 1]; - } - - for(int i = 0; i < ndims; i++){ - dim_start[i] = off_start / dim_chunk_sz[i]; - off_start -= dim_start[i] * dim_chunk_sz[i]; - } - - assert(off_start == 0); - - std::transform(dimlen, dimlen + ndims, dim_count, [](int len) { return static_cast(len); }); - - for(int i = 0; i < ndims; i++){ - dim_count[i] = off_count / dim_chunk_sz[i]; - - off_count -= dim_count[i] * dim_chunk_sz[i]; - - dim_count[i] = (dim_count[i] == 0) ? 1 : dim_count[i]; - - if(off_count == 0){ - break; - } - } - - assert(off_count == 0); -} - static void init_iodesc_contig_rearr_fields(iosystem_desc_t *ios, io_desc_t *iodesc) { assert(ios && iodesc && iodesc->rearr && iodesc->rearr->is_init()); @@ -776,6 +740,7 @@ static void init_iodesc_contig_rearr_fields(iosystem_desc_t *ios, io_desc_t *iod io_region *prev_region = cur_region; int loff = 0; + LOG((1, "Contig rearranger : iodesc {ioid=%d, llen=%lld, maxiobuflen=%lld, ndims=%d, dimlen=%s, maxregions=%lld", iodesc->ioid, static_cast(iodesc->llen), static_cast(iodesc->maxiobuflen), iodesc->ndims, SPIO_Util::Dbg_Util::vec1d_to_string(iodesc->dimlen, iodesc->dimlen + iodesc->ndims).c_str(), static_cast(off_ranges.size()))); // FIXME : Move to C++ lists for region list for(int i = 0; i < off_ranges.size(); i++){ if(cur_region == NULL){ @@ -788,6 +753,7 @@ static void init_iodesc_contig_rearr_fields(iosystem_desc_t *ios, io_desc_t *iod iodesc->rearr->off_range_to_dim_range(off_ranges[i].first, off_ranges[i].second, cur_region->start, cur_region->count); + LOG((1, "Contig range = [%lld, %lld), start=%s, count=%s", static_cast(off_ranges[i].first), static_cast(off_ranges[i].second), SPIO_Util::Dbg_Util::vec1d_to_string(cur_region->start, cur_region->start + iodesc->ndims).c_str(), SPIO_Util::Dbg_Util::vec1d_to_string(cur_region->count, cur_region->count + iodesc->ndims).c_str())); prev_region = cur_region; cur_region = cur_region->next; } From e980e401009688dccc165729915803819cf32f5f Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 21 Jan 2025 17:46:51 -0600 Subject: [PATCH 041/194] Adding func to convert off range to cont range Adding a new util function to convert offset range to contig dim range --- src/clib/pio_rearr_contig.cpp | 75 ++++++++++++++++++++++++++++++++++- src/clib/pio_rearr_contig.hpp | 24 +++++++++-- 2 files changed, 95 insertions(+), 4 deletions(-) diff --git a/src/clib/pio_rearr_contig.cpp b/src/clib/pio_rearr_contig.cpp index e0fd8d1a6a..2a69d73e08 100644 --- a/src/clib/pio_rearr_contig.cpp +++ b/src/clib/pio_rearr_contig.cpp @@ -130,7 +130,76 @@ int SPIO::DataRearr::Contig_rearr::init(int pio_type, return ret; } -std::vector > SPIO::DataRearr::Contig_rearr::get_rearr_decomp_map_contig_ranges(int iorank) const +/* +void SPIO::DataRearr::Contig_rearr::get_contig_ranges_from_off_range(std::vector > &contig_map_ranges, PIO_Offset start_off, PIO_Offset count, std::size_t dim_idx) const +{ + assert((dim_idx >= 0) && (dim_idx < dim_chunk_sz_.size())); + if(count == 0) return; + + PIO_Offset end_off = start_off + count; + PIO_Offset cur_start_off = start_off; + for(std::size_t idx = dim_idx; idx < dim_chunk_sz_.size(); idx++){ + PIO_Offset off_from_last_dim_mult = cur_start_off % dim_chunk_sz_[idx]; + PIO_Offset start_off_dim_mult = cur_start_off; + if(off_from_last_dim_mult != 0){ + start_off_dim_mult = cur_start_off + (dim_chunk_sz_[idx] - off_from_last_dim_mult); + } + if(start_off_dim_mult < end_off){ + PIO_Offset ndim_idx = (end_off - start_off_dim_mult) / dim_chunk_sz_[idx]; + if(ndim_idx > 0){ + if(off_from_last_dim_mult > 0){ + get_contig_ranges_from_off_range(contig_map_ranges, cur_start_off, (dim_chunk_sz_[idx] - off_from_last_dim_mult), dim_idx + 1); + } + PIO_Offset cur_range_count = ndim_idx * dim_chunk_sz_[idx]; + contig_map_ranges.push_back(std::make_pair(start_off_dim_mult, cur_range_count)); + cur_start_off = start_off_dim_mult + cur_range_count; + assert(cur_start_off <= end_off); + count -= (cur_start_off - start_off); + assert(count >= 0); + if(count > 0){ + get_contig_ranges_from_off_range(contig_map_ranges, cur_start_off, count, dim_idx + 1); + } + break; + } + } + } +} +*/ +void SPIO::DataRearr::Contig_rearr::get_contig_ranges_from_off_range(std::vector > &contig_map_ranges, + PIO_Offset start_off, PIO_Offset count) +{ + std::size_t last_contig_dim = 0; + std::size_t ndims = gdimlen_.size(); + std::vector start_dim_idx(ndims, 0); + + while(count > 0){ + convert_off_to_start_dim_idx(start_off, start_dim_idx, last_contig_dim); + PIO_Offset last_contig_dim_nchunks = gdimlen_[last_contig_dim] - start_dim_idx[last_contig_dim]; + PIO_Offset dim_nchunks = count / dim_chunk_sz_[last_contig_dim]; + PIO_Offset range_sz = 0; + if(dim_nchunks > 0){ + dim_nchunks = std::min(dim_nchunks, last_contig_dim_nchunks); + range_sz = dim_nchunks * dim_chunk_sz_[last_contig_dim]; + } + else{ + for(std::size_t idx = last_contig_dim + 1; idx < ndims; idx++){ + dim_nchunks = count / dim_chunk_sz_[idx]; + if(dim_nchunks > 0){ + dim_nchunks = std::min(dim_nchunks, static_cast(gdimlen_[idx])); + range_sz = dim_nchunks * dim_chunk_sz_[idx]; + break; + } + } + } + contig_map_ranges.push_back(std::make_pair(start_off, range_sz)); + start_off += range_sz; + count -= range_sz; + } + + assert(count == 0); +} + +std::vector > SPIO::DataRearr::Contig_rearr::get_rearr_decomp_map_contig_ranges(int iorank) { assert(gdecomp_sz_ > 0); assert(rearr_comm_iochunk_sz_ > 0); @@ -146,6 +215,9 @@ std::vector > SPIO::DataRearr::Contig_rearr::g (start_off >= 0) && (end_off >= start_off)); std::vector > contig_map_ranges; + get_contig_ranges_from_off_range(contig_map_ranges, start_off, end_off - start_off); + + /* int ndims = static_cast(gdimlen_.size()); PIO_Offset cur_tot_count = end_off - start_off; @@ -189,6 +261,7 @@ std::vector > SPIO::DataRearr::Contig_rearr::g } assert(cur_tot_count == 0); + */ return contig_map_ranges; } diff --git a/src/clib/pio_rearr_contig.hpp b/src/clib/pio_rearr_contig.hpp index 5cff592f46..19d03c0c32 100644 --- a/src/clib/pio_rearr_contig.hpp +++ b/src/clib/pio_rearr_contig.hpp @@ -96,9 +96,9 @@ namespace SPIO{ } } - std::vector > get_rearr_decomp_map_contig_ranges(int iorank) const; + std::vector > get_rearr_decomp_map_contig_ranges(int iorank); - std::vector > get_rearr_decomp_map_contig_ranges(void ) const + std::vector > get_rearr_decomp_map_contig_ranges(void ) { return get_rearr_decomp_map_contig_ranges(rearr_comm_rank_); } @@ -190,6 +190,23 @@ namespace SPIO{ } } + void convert_off_to_start_dim_idx(PIO_Offset start_off, std::vector &start_dim_idx, + std::size_t &last_contig_dim) + { + last_contig_dim = 0; + for(std::size_t i = 0; i < start_dim_idx.size(); i++){ + if(start_off == 0){ + start_dim_idx[i] = 0; + } + else{ + start_dim_idx[i] = start_off / dim_chunk_sz_[i]; + start_off -= start_dim_idx[i] * dim_chunk_sz_[i]; + if(start_dim_idx[i] != 0) last_contig_dim = i; + } + } + assert(start_off == 0); + } + std::pair get_rearr_decomp_map_range(int iorank) const { assert(gdecomp_sz_ > 0); @@ -204,7 +221,8 @@ namespace SPIO{ return std::make_pair(start, end); } - + void get_contig_ranges_from_off_range(std::vector > &contig_map_ranges, + PIO_Offset start_off, PIO_Offset count); int create_agg_comm(void ); static void get_non_fval_lcompmap_counts_displs(const PIO_Offset *lcompmap, std::size_t lcompmap_sz, From 6abd9bdc03f21edb74c147462c3c67ad5fe9a95a Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 21 Jan 2025 23:38:03 -0600 Subject: [PATCH 042/194] Fix type of elem mpi type in contig rearr Fix the type of the MPI type (of the elements) stored in contig rearr --- src/clib/pio_rearr_contig.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clib/pio_rearr_contig.hpp b/src/clib/pio_rearr_contig.hpp index 19d03c0c32..6419b78248 100644 --- a/src/clib/pio_rearr_contig.hpp +++ b/src/clib/pio_rearr_contig.hpp @@ -130,7 +130,7 @@ namespace SPIO{ std::vector dim_chunk_sz_; int elem_pio_type_; - int elem_mpi_type_; + MPI_Datatype elem_mpi_type_; int elem_mpi_type_sz_; /* Gather scatter info for data aggregation */ From 21cdf50b9268ddf5480a111a161bc88ee3fac475 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 22 Jan 2025 10:56:52 -0600 Subject: [PATCH 043/194] Adding a meta data file for decomp files Adding a meta data file for saved decomposition files. The meta data file contains info on the file/variable that used the data decomposition --- src/clib/CMakeLists.txt | 1 + src/clib/pio_darray.cpp | 3 + src/clib/pioc.cpp | 7 ++ src/clib/spio_decomp_map_info_pool.cpp | 47 +++++++++++++ src/clib/spio_decomp_map_info_pool.hpp | 93 ++++++++++++++++++++++++++ 5 files changed, 151 insertions(+) create mode 100644 src/clib/spio_decomp_map_info_pool.cpp create mode 100644 src/clib/spio_decomp_map_info_pool.hpp diff --git a/src/clib/CMakeLists.txt b/src/clib/CMakeLists.txt index ad3756d63d..b41446b578 100644 --- a/src/clib/CMakeLists.txt +++ b/src/clib/CMakeLists.txt @@ -42,6 +42,7 @@ set (pio_lib_src pio_nc4.cpp bget.cpp pio_nc.cpp pio_put_nc.cpp pio_get_nc.cpp pio_getput_int.cpp pio_msg.cpp pio_varm.cpp pio_darray.cpp pio_darray_int.cpp spio_hash.cpp pio_sdecomps_regex.cpp spio_io_summary.cpp + spio_decomp_map_info_pool.cpp spio_ltimer.cpp spio_serializer.cpp spio_file_mvcache.cpp spio_tracer.cpp spio_tracer_mdata.cpp spio_tracer_decomp.cpp spio_rearrange_any.cpp) diff --git a/src/clib/pio_darray.cpp b/src/clib/pio_darray.cpp index 614793e59b..2c46daa1e1 100644 --- a/src/clib/pio_darray.cpp +++ b/src/clib/pio_darray.cpp @@ -21,6 +21,7 @@ #include "spio_gptl_utils.hpp" #include "spio_ltimer_utils.hpp" #include "pio_rearr_contig.hpp" +#include "spio_decomp_map_info_pool.hpp" /* uint64_t definition */ #ifdef _ADIOS2 @@ -2088,7 +2089,9 @@ int PIOc_write_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, c LOG((2, "Saving decomp map (write) to %s", filename)); PIOc_writemap_impl(filename, ioid, iodesc->ndims, iodesc->dimlen, iodesc->maplen, iodesc->map, ios->my_comm); iodesc->is_saved = true; + SPIO_Util::Decomp_Util::gdpool_mgr.get_decomp_map_info_pool()->add_decomp_map_info(ioid, filename); } + SPIO_Util::Decomp_Util::gdpool_mgr.get_decomp_map_info_pool()->add_var_info(ioid, file->pio_ncid, file->fname, varid, file->varlist[varid].vname); #endif /* Get var description. */ vdesc = &(file->varlist[varid]); diff --git a/src/clib/pioc.cpp b/src/clib/pioc.cpp index 1ea22b3215..389cb480af 100644 --- a/src/clib/pioc.cpp +++ b/src/clib/pioc.cpp @@ -22,6 +22,7 @@ #include "spio_gptl_utils.hpp" #include "pio_rearr_contig.hpp" #include "spio_dbg_utils.hpp" +#include "spio_decomp_map_info_pool.hpp" /* Include headers for HDF5 compression filters */ #if PIO_USE_HDF5 @@ -1033,6 +1034,8 @@ static int initdecomp(int iosysid, int pio_type, int ndims, const int *gdimlen, LOG((2, "Saving decomp map to %s", filename)); PIOc_writemap_impl(filename, *ioidp, ndims, gdimlen, maplen, (PIO_Offset *)compmap, ios->my_comm); iodesc->is_saved = true; + + SPIO_Util::Decomp_Util::gdpool_mgr.get_decomp_map_info_pool()->add_decomp_map_info(*ioidp, filename); } #endif @@ -1845,6 +1848,10 @@ int PIOc_finalize_impl(int iosysid) } } +#if PIO_SAVE_DECOMPS + SPIO_Util::Decomp_Util::serialize_decomp_map_info_pool(ios->union_comm); +#endif + ierr = spio_write_io_summary(ios); if(ierr != PIO_NOERR) { diff --git a/src/clib/spio_decomp_map_info_pool.cpp b/src/clib/spio_decomp_map_info_pool.cpp new file mode 100644 index 0000000000..e19a12645f --- /dev/null +++ b/src/clib/spio_decomp_map_info_pool.cpp @@ -0,0 +1,47 @@ +#include "spio_decomp_map_info_pool.hpp" +#include +#include +#include "mpi.h" + +SPIO_Util::Decomp_Util::Decomp_map_info_pool *SPIO_Util::Decomp_Util::Decomp_map_info_pool_manager::dpool_ = NULL; + +static SPIO_Util::Decomp_Util::Decomp_map_info_pool_manager gdpool_mgr; + +SPIO_Util::Decomp_Util::Decomp_map_info_pool * + SPIO_Util::Decomp_Util::Decomp_map_info_pool_manager::get_decomp_map_info_pool(void ) +{ + if(dpool_ == NULL){ + dpool_ = new SPIO_Util::Decomp_Util::Decomp_map_info_pool(); + } + + return dpool_; +} + +SPIO_Util::Decomp_Util::Decomp_map_info_pool_manager::~Decomp_map_info_pool_manager() +{ + if(dpool_){ + delete(dpool_); + dpool_ = NULL; + } +} + +void SPIO_Util::Decomp_Util::serialize_decomp_map_info_pool(MPI_Comm comm) +{ + static bool decomp_info_serialized = false; + + if(decomp_info_serialized) return; + + int rank = -1; + MPI_Comm_rank(comm, &rank); + if(rank != 0) return; + + SPIO_Util::Decomp_Util::Decomp_map_info_pool *dpool = SPIO_Util::Decomp_Util::gdpool_mgr.get_decomp_map_info_pool(); + std::string decomp_map_pool_info = dpool->to_string(); + + std::ofstream ostr("pio_decomp_map_info.txt"); + if(ostr.is_open()){ + ostr << decomp_map_pool_info.c_str() << "\n"; + ostr.close(); + decomp_info_serialized = true; + } +} diff --git a/src/clib/spio_decomp_map_info_pool.hpp b/src/clib/spio_decomp_map_info_pool.hpp new file mode 100644 index 0000000000..dade5f6a4b --- /dev/null +++ b/src/clib/spio_decomp_map_info_pool.hpp @@ -0,0 +1,93 @@ +#ifndef __SPIO_DECOMP_MAP_INFO_HPP__ +#define __SPIO_DECOMP_MAP_INFO_HPP__ + +#include +#include +#include +#include +#include +#include +#include + +#include "mpi.h" + +namespace SPIO_Util{ + namespace Decomp_Util{ + class Decomp_map_info_pool{ + public: + void add_decomp_map_info(int decomp_map_id, const char *decomp_map_fname){ + decomp_map_info_[decomp_map_id] = std::string(decomp_map_fname); + } + void add_var_info(int decomp_map_id, int fid, const char *fname, + int vid, const char *vname){ + Var_info vinfo = {vid, decomp_map_id, decomp_map_info_[decomp_map_id], std::string(vname)}; + + finfo_[fid].fid = fid; + finfo_[fid].fname = std::string(fname); + finfo_[fid].vinfo[vid] = vinfo; + } + + std::string to_string(void ) const{ + std::ostringstream ostr; + for(std::map::const_iterator finfo_iter = finfo_.cbegin(); + finfo_iter != finfo_.cend(); ++finfo_iter){ + ostr << (*finfo_iter).second.to_string() << "\n"; + } + return ostr.str(); + } + private: + struct Var_info{ + int vid; + int decomp_map_id; + std::string decomp_map_fname; + std::string vname; + + std::string to_string(void ) const{ + return std::string("{") + + std::string("vid = ") + std::to_string(vid) + + std::string(", decomp_map_id = ") + std::to_string(decomp_map_id) + + std::string(", decomp_map_fname = ") + decomp_map_fname + + std::string(", vname = ") + vname + + std::string("}"); + } + }; + + struct File_info{ + int fid; + std::string fname; + std::map vinfo; + + std::string to_string(void ) const{ + std::ostringstream ostr; + ostr << "{"; + ostr << "fid = " << fid; + ostr << ", fname = " << fname.c_str(); + ostr << ", vinfo = \n"; + for(std::map::const_iterator vinfo_iter = vinfo.cbegin(); + vinfo_iter != vinfo.cend(); ++vinfo_iter){ + ostr << (*vinfo_iter).second.to_string() << "\n"; + } + ostr << "}"; + return ostr.str(); + } + }; + + std::map decomp_map_info_; + std::map finfo_; + }; + + class Decomp_map_info_pool_manager{ + public: + static Decomp_map_info_pool *get_decomp_map_info_pool(void ); + ~Decomp_map_info_pool_manager(); + private: + static Decomp_map_info_pool *dpool_; + }; + + extern Decomp_map_info_pool_manager gdpool_mgr; + + void serialize_decomp_map_info_pool(MPI_Comm comm); + } // SPIO_Util +} // Decomp_Util + +#endif // __SPIO_DECOMP_MAP_INFO_HPP__ From e674bfbbacf74abcce75edb77bc4a9ffebda6853 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 24 Jan 2025 15:43:44 -0600 Subject: [PATCH 044/194] Util script for decomp meta data file Adding a utility script (and README on using it) for the new meta data file (that shows decomp info specific to file/variables) added for dumped I/O decompositions. --- .../README_parse_decomp_info_py.txt | 32 +++++++++ tests/performance/parse_decomp_info.py | 72 +++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 tests/performance/README_parse_decomp_info_py.txt create mode 100755 tests/performance/parse_decomp_info.py diff --git a/tests/performance/README_parse_decomp_info_py.txt b/tests/performance/README_parse_decomp_info_py.txt new file mode 100644 index 0000000000..12cb4343d8 --- /dev/null +++ b/tests/performance/README_parse_decomp_info_py.txt @@ -0,0 +1,32 @@ +Parse the pio_decomp_map_info.txt file (that contains the mapping between file/variable names and dumped decomposition file names) and filter out the decomposition files used by specified set of components. + +================ EXAMPLE ==================================== +$ ./parse_decomp_info.py --help +usage: parse_decomp_info.py [-h] [--filter-components= filter_component [filter_component ...]] [--decomp-map-info-file DECOMP_MAP_INFO_FNAME] [--log-level LOG_LEVEL] + +Parse decomp info file : pio_decomp_map_info.txt + +options: + -h, --help show this help message and exit + --filter-components= filter_component [filter_component ...] + The name of components to filter (Supported component names = ['eam', 'cpl', 'elm', 'mosart', 'mpaso', 'mpassi']) + --decomp-map-info-file DECOMP_MAP_INFO_FNAME + The complete path of pio_decomp_map_info.txt (or the file containing the decomp map info) + --log-level LOG_LEVEL + Specify the log level (Default is INFO, Available log levels are : dict_keys(['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'])) + + +================ EXAMPLE ==================================== + +$ ./parse_decomp_info.py --filter-components eam cpl --decomp-map-info-file ./pio_decomp_map_info.txt --log-level=INFO |& tee out.log +INFO:Decomposition map info parser tool +===================================================== + +{'piodecomp002049id16tasks04io01dims0242.dat', 'piodecomp002048id16tasks04io02dims0269.dat', 'piodecomp002049id16tasks04io01dims15.dat', 'piodecomp002048id16tasks04io02dims0267.dat', 'piodecomp002048id16tasks04io02dims0263.dat', 'piodecomp002049id16tasks04io01dims0256.dat', 'piodecomp002049id16tasks04io02dims0248.dat', 'piodecomp002048id16tasks04io02dims0268.dat', 'piodecomp002049id16tasks04io01dims0245.dat', 'piodecomp002048id16tasks04io02dims0259.dat', 'piodecomp002049id16tasks04io02dims0247.dat', 'piodecomp002048id16tasks04io02dims0270.dat', 'piodecomp002049id16tasks04io01dims0244.dat', 'piodecomp002049id16tasks04io01dims0252.dat', 'piodecomp002049id16tasks04io01dims0253.dat', 'piodecomp002049id16tasks04io01dims0254.dat', 'piodecomp002048id16tasks04io02dims0262.dat', 'piodecomp002049id16tasks04io02dims0249.dat', 'piodecomp002048id16tasks04io02dims0265.dat', 'piodecomp002048id16tasks04io02dims0261.dat', 'piodecomp002049id16tasks04io01dims0250.dat', 'piodecomp002049id16tasks04io02dims0243.dat', 'piodecomp002048id16tasks04io02dims0264.dat', 'piodecomp002048id16tasks04io02dims0260.dat', 'piodecomp002048id16tasks04io02dims0258.dat', 'piodecomp002049id16tasks04io01dims0246.dat', 'piodecomp002048id16tasks04io02dims0266.dat'} + +================ EXAMPLE ==================================== +./parse_decomp_info.py --filter-components mosart --decomp-map-info-file ./pio_decomp_map_info.txt --log-level=INFO | sed -e "s/'//g" +INFO:Decomposition map info parser tool +===================================================== + +{piodecomp002054id16tasks04io02dims0202.dat, piodecomp002054id16tasks04io02dims0201.dat} diff --git a/tests/performance/parse_decomp_info.py b/tests/performance/parse_decomp_info.py new file mode 100755 index 0000000000..6fc35e3d8d --- /dev/null +++ b/tests/performance/parse_decomp_info.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 +import sys +import argparse +import re +import logging + +#logger = logging.getLogger(__name__) + +component_names = ["eam", "cpl", "elm", "mosart", "mpaso", "mpassi"] +log_levels = {"DEBUG" : logging.DEBUG, "INFO" : logging.INFO, + "WARNING" : logging.WARNING, "ERROR" : logging.ERROR, + "CRITICAL" : logging.CRITICAL} + +tool_hdr_str = "Decomposition map info parser tool\n=====================================================\n" + +def set_log_level(log_level): + logging.basicConfig(format='%(levelname)s:%(message)s', level=log_levels[log_level]) + +def parse_command_line(argv): + parser = argparse.ArgumentParser(description ='Parse decomp info file : pio_decomp_map_info.txt') + parser.add_argument('--filter-components=', dest = 'filter_components', + default ='eam', + metavar ='filter_component', + nargs ='+', action ='store', + help ='The name of components to filter (Supported component names = ' + str(component_names) + ')') + parser.add_argument('--decomp-map-info-file', dest ='decomp_map_info_fname', + default ='./pio_decomp_map_info.txt', + action ='store', + help ='The complete path of pio_decomp_map_info.txt (or the file containing the decomp map info)') + parser.add_argument('--log-level', dest ='log_level', + default ='INFO', + action ='store', + help ='Specify the log level (Default is INFO, Available log levels are : ' + str(log_levels.keys()) + ')') + args = parser.parse_args() + return args.filter_components, args.decomp_map_info_fname, args.log_level + +def parse_decomp_map_info(fname, filter_components): + decomp_map_fnames = set() + with open(fname, 'r') as file: + component_begin_fname_rgx_str = r'^[{].*\sfname\s[=].*(' + r'|'.join(filter_components) + r').*$' + logging.debug("Using regex str \"{}\" to match files to filter".format(component_begin_fname_rgx_str)) + component_begin_fname_rgx = re.compile(component_begin_fname_rgx_str) + component_end_fname_rgx = re.compile(r'^[}]$') + collect_decomp_map_fnames = False + for line in file: + line = line.strip() + if component_begin_fname_rgx.match(line): + collect_decomp_map_fnames = True + logging.debug("Enabling collection of decomp map file names : Parsed string : {}".format(line)) + elif component_end_fname_rgx.match(line): + collect_decomp_map_fnames = False + logging.debug("Disabling collection of decomp map file names : Parsed string : {}".format(line)) + elif collect_decomp_map_fnames: + decomp_map_info = line.split(',') + decomp_map_fname = decomp_map_info[2].split('=')[1].strip() + decomp_map_fnames.add(decomp_map_fname) + return decomp_map_fnames + +def _main(argv): + #set_log_level('DEBUG') + filter_components, decomp_map_info_fname, log_level = parse_command_line(argv) + set_log_level(log_level) + logging.info(tool_hdr_str) + logging.debug("Parsing decomp info file : {}".format(decomp_map_info_fname)) + logging.debug("Filtering decomp file info of components : {}".format(str(filter_components))) + filtered_decomp_map_fnames = parse_decomp_map_info(decomp_map_info_fname, filter_components) + print(filtered_decomp_map_fnames) + +if __name__ == "__main__": + _main(sys.argv) + + From 6397f56f7d5790b3d96ba49c532f5a4f7196c820 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Sat, 25 Jan 2025 17:11:21 -0600 Subject: [PATCH 045/194] Add iosysid to decomp map info file name Adding iosysid to the meta data file containing decomposition map info (mapping btw decomp and file/vars). The file name is now pio_decomp_map_info_.txt --- src/clib/pioc.cpp | 2 +- src/clib/spio_decomp_map_info_pool.cpp | 7 +++++-- src/clib/spio_decomp_map_info_pool.hpp | 7 ++++++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/clib/pioc.cpp b/src/clib/pioc.cpp index 389cb480af..8bfc58b904 100644 --- a/src/clib/pioc.cpp +++ b/src/clib/pioc.cpp @@ -1849,7 +1849,7 @@ int PIOc_finalize_impl(int iosysid) } #if PIO_SAVE_DECOMPS - SPIO_Util::Decomp_Util::serialize_decomp_map_info_pool(ios->union_comm); + SPIO_Util::Decomp_Util::serialize_decomp_map_info_pool(ios); #endif ierr = spio_write_io_summary(ios); diff --git a/src/clib/spio_decomp_map_info_pool.cpp b/src/clib/spio_decomp_map_info_pool.cpp index e19a12645f..b27e2da37b 100644 --- a/src/clib/spio_decomp_map_info_pool.cpp +++ b/src/clib/spio_decomp_map_info_pool.cpp @@ -25,12 +25,14 @@ SPIO_Util::Decomp_Util::Decomp_map_info_pool_manager::~Decomp_map_info_pool_mana } } -void SPIO_Util::Decomp_Util::serialize_decomp_map_info_pool(MPI_Comm comm) +void SPIO_Util::Decomp_Util::serialize_decomp_map_info_pool(iosystem_desc_t *ios) { static bool decomp_info_serialized = false; + assert(ios); if(decomp_info_serialized) return; + MPI_Comm comm = ios->union_comm; int rank = -1; MPI_Comm_rank(comm, &rank); if(rank != 0) return; @@ -38,7 +40,8 @@ void SPIO_Util::Decomp_Util::serialize_decomp_map_info_pool(MPI_Comm comm) SPIO_Util::Decomp_Util::Decomp_map_info_pool *dpool = SPIO_Util::Decomp_Util::gdpool_mgr.get_decomp_map_info_pool(); std::string decomp_map_pool_info = dpool->to_string(); - std::ofstream ostr("pio_decomp_map_info.txt"); + std::string fname = std::string("pio_decomp_map_info_") + std::to_string(ios->iosysid) + std::string(".txt"); + std::ofstream ostr(fname.c_str()); if(ostr.is_open()){ ostr << decomp_map_pool_info.c_str() << "\n"; ostr.close(); diff --git a/src/clib/spio_decomp_map_info_pool.hpp b/src/clib/spio_decomp_map_info_pool.hpp index dade5f6a4b..da1c27905c 100644 --- a/src/clib/spio_decomp_map_info_pool.hpp +++ b/src/clib/spio_decomp_map_info_pool.hpp @@ -1,6 +1,11 @@ #ifndef __SPIO_DECOMP_MAP_INFO_HPP__ #define __SPIO_DECOMP_MAP_INFO_HPP__ +#include "pio_config.h" +#include "pio.h" +#include "pio_internal.h" +#include "pio_types.hpp" + #include #include #include @@ -86,7 +91,7 @@ namespace SPIO_Util{ extern Decomp_map_info_pool_manager gdpool_mgr; - void serialize_decomp_map_info_pool(MPI_Comm comm); + void serialize_decomp_map_info_pool(iosystem_desc_t *ios); } // SPIO_Util } // Decomp_Util From 6a4b417c2d550abf403602ec3d986ff663d83273 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Sat, 25 Jan 2025 23:35:29 -0600 Subject: [PATCH 046/194] Adding an example of replay tool usage Adding a simple example of replay tool usage in a small README --- tests/performance/README_pioperformance_rearr.txt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/performance/README_pioperformance_rearr.txt diff --git a/tests/performance/README_pioperformance_rearr.txt b/tests/performance/README_pioperformance_rearr.txt new file mode 100644 index 0000000000..31f633d495 --- /dev/null +++ b/tests/performance/README_pioperformance_rearr.txt @@ -0,0 +1,9 @@ +============ EXAMPLE ================== + +#!/bin/bash +for nioprocs in 2 4 8 12 16 +do + echo "Running with $nioprocs I/O procs" + mpiexec -n 16 ../scorpio_build/tests/performance/pioperf_rearr --pio-decompfiles='piodecomp002049id16tasks04io01dims0253.dat, piodecomp002049id16tasks04io02dims0247.dat, piodecomp002049id16tasks04io01dims0252.dat, piodecomp002049id16tasks04io02dims0248.dat' --pio-types='pnetcdf' --pio-rearrangers='1,2,3,4' --pio-nvars=1 --pio-niotasks=$nioprocs +done + From 7c1fe8718e30519a02bb93bfb355b07fff0f65f1 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Sat, 25 Jan 2025 23:41:22 -0600 Subject: [PATCH 047/194] Minor cleanup of replay tool Some minor cleanup of the code * Removing unused comm split * Removing allocs of unused arrays * Removing commented out code --- tests/performance/pioperformance_rearr.F90 | 77 +++++++++------------- 1 file changed, 32 insertions(+), 45 deletions(-) diff --git a/tests/performance/pioperformance_rearr.F90 b/tests/performance/pioperformance_rearr.F90 index fa5674b6cc..5e106924db 100644 --- a/tests/performance/pioperformance_rearr.F90 +++ b/tests/performance/pioperformance_rearr.F90 @@ -656,16 +656,10 @@ subroutine pioperformance_rearrtest(filename, piotypes, mype, npe_base, & #else call pio_readdof(filename, ndims, gdims, compmap, MPI_COMM_WORLD) #endif - -! print *,__FILE__,__LINE__,' gdims=',ndims endif maplen = size(compmap) -! color = 0 -! if(maplen>0) then - color = 1 -! endif - call MPI_Comm_split(MPI_COMM_WORLD, color, mype, comm, ierr) + comm = MPI_COMM_WORLD call MPI_Comm_size(comm, npe, ierr) call CheckMPIreturn(__LINE__,ierr) @@ -685,24 +679,36 @@ subroutine pioperformance_rearrtest(filename, piotypes, mype, npe_base, & gmaplen = product(gdims) endif +#ifdef VARINT allocate(ifld(maplen,nvars)) allocate(ifld_in(maplen,nvars,nframes)) + ifld = PIO_FILL_INT +#endif +#ifdef VARREAL allocate(rfld(maplen,nvars)) allocate(rfld_in(maplen,nvars,nframes)) + rfld = PIO_FILL_FLOAT +#endif +#ifdef VARDOUBLE allocate(dfld(maplen,nvars)) allocate(dfld_in(maplen,nvars,nframes)) - - ifld = PIO_FILL_INT - rfld = PIO_FILL_FLOAT dfld = PIO_FILL_DOUBLE +#endif + do nv=1,nvars do j=1,maplen if(compmap(j) > 0) then +#ifdef VARINT ifld(j,nv) = int(compmap(j)) - dfld(j,nv) = ifld(j,nv)/1000000.0 - rfld(j,nv) = 1.0E5*ifld(j,nv) +#endif +#ifdef VARREAL + rfld(j,nv) = 1.0E5*int(compmap(j)) +#endif +#ifdef VARDOUBLE + dfld(j,nv) = int(compmap(j))/1000000.0 +#endif endif enddo enddo @@ -714,9 +720,6 @@ subroutine pioperformance_rearrtest(filename, piotypes, mype, npe_base, & do k=1,size(piotypes) iotype = piotypes(k) call MPI_Barrier(comm,ierr) - if(mype==0) then - !print *,'iotype=',piotypes(k) - endif if(iotype==PIO_IOTYPE_PNETCDF) then mode = PIO_64BIT_DATA else @@ -740,7 +743,7 @@ subroutine pioperformance_rearrtest(filename, piotypes, mype, npe_base, & write(fname, '(a,i1,a,i5.5,a,i5.5,a,i5.5,a,i1,a,i5.5,a,i5.5,a)') 'pioperf-rearr-', rearr, & '-ncomptasks-', npe, '-niotasks-', ntasks, '-stride-', stride, '-iotype-', iotype, & '-nframes-',nframes,'-nvars-',nvars,'.nc' - + ierr = PIO_CreateFile(iosystem, File, iotype, trim(fname), mode) call WriteMetadata(File, gdims, vari, varr, vard, unlimdimindof) @@ -761,14 +764,11 @@ subroutine pioperformance_rearrtest(filename, piotypes, mype, npe_base, & endif wall(1) = MPI_Wtime() - ! print *,__FILE__,__LINE__,minval(dfld),maxval(dfld),minloc(dfld),maxloc(dfld) do frame=1,nframes recnum = frame if( unlimdimindof) then recnum = 1 + (frame-1)*gdims(ndims) -! compmap = compmap2 + (frame-1)*gdims(ndims) -! print *,__FILE__,__LINE__,compmap #ifdef VARINT call PIO_InitDecomp(iosystem, PIO_INT, gdims, compmap, iodesc_i4, rearr=rearr) #endif @@ -779,10 +779,8 @@ subroutine pioperformance_rearrtest(filename, piotypes, mype, npe_base, & call PIO_InitDecomp(iosystem, PIO_DOUBLE, gdims, compmap, iodesc_r8, rearr=rearr) #endif endif - !if(mype==0) print *,__FILE__,__LINE__,'Frame: ',recnum do nv=1,nvars - !if(mype==0) print *,__FILE__,__LINE__,'var: ',nv #ifdef VARINT call PIO_setframe(File, vari(nv), recnum) call pio_write_darray(File, vari(nv), iodesc_i4, ifld(:,nv) , ierr, fillval= PIO_FILL_INT) @@ -811,7 +809,6 @@ subroutine pioperformance_rearrtest(filename, piotypes, mype, npe_base, & wall_wr_darr(2) = MPI_Wtime() call pio_closefile(File) - call MPI_Barrier(comm,ierr) wall(2) = MPI_Wtime() @@ -915,15 +912,12 @@ subroutine pioperformance_rearrtest(filename, piotypes, mype, npe_base, & #ifdef VARINT #ifdef DEBUG write(*,'(a11,i2,a9,i11,a9,i11,a9,i2)') & - ' Int PE=',mype,'ifld=',ifld(j,nv),' ifld_in=',ifld_in(j,nv,frame),' compmap=',compmap(j) + ' Int PE=',mype,'ifld=',ifld(j,nv),' ifld_in=',ifld_in(j,nv,frame),' compmap=',compmap(j) #endif if(ifld(j,nv) /= ifld_in(j,nv,frame)) then - !if(errorcnt < 10) then - ! print *,__LINE__,'Int: ',mype,j,nv,ifld(j,nv),ifld_in(j,nv,frame),compmap(j) - !endif write(*,*) '***ERROR:Mismatch!***' write(*,'(a11,i2,a9,i11,a9,i11,a9,i2)') & - ' Int PE=',mype,'ifld=',ifld(j,nv),' ifld_in=',ifld_in(j,nv,frame),' compmap=',compmap(j) + ' Int PE=',mype,'ifld=',ifld(j,nv),' ifld_in=',ifld_in(j,nv,frame),' compmap=',compmap(j) errorcnt = errorcnt+1 endif @@ -931,16 +925,13 @@ subroutine pioperformance_rearrtest(filename, piotypes, mype, npe_base, & #ifdef VARREAL #ifdef DEBUG write(*,'(a11,i2,a9,f11.2,a9,f11.2,a9,i2)') & - ' Real PE=',mype,'rfld=',rfld(j,nv),' rfld_in=',rfld_in(j,nv,frame),' compmap=',compmap(j) + ' Real PE=',mype,'rfld=',rfld(j,nv),' rfld_in=',rfld_in(j,nv,frame),' compmap=',compmap(j) #endif if(rfld(j,nv) /= rfld_in(j,nv,frame) ) then - !if(errorcnt < 10) then - ! print *,__LINE__,'Real:', mype,j,nv,rfld(j,nv),rfld_in(j,nv,frame),compmap(j) - !endif write(*,*) '***ERROR:Mismatch!***' write(*,'(a11,i2,a9,f11.2,a9,f11.2,a9,i2)') & - ' Real PE=',mype,'rfld=',rfld(j,nv),' rfld_in=',rfld_in(j,nv,frame),' compmap=',compmap(j) + ' Real PE=',mype,'rfld=',rfld(j,nv),' rfld_in=',rfld_in(j,nv,frame),' compmap=',compmap(j) errorcnt = errorcnt+1 endif @@ -948,15 +939,12 @@ subroutine pioperformance_rearrtest(filename, piotypes, mype, npe_base, & #ifdef VARDOUBLE #ifdef DEBUG write(*,'(a11,i2,a9,d11.4,a9,d11.4,a9,i2)') & - 'Double PE=',mype,'dfld=',dfld(j,nv),'dfld_in=',dfld_in(j,nv,frame),'compmap=',compmap(j) + 'Double PE=',mype,'dfld=',dfld(j,nv),'dfld_in=',dfld_in(j,nv,frame),'compmap=',compmap(j) #endif if(dfld(j,nv) /= dfld_in(j,nv,frame) ) then - !if(errorcnt < 10) then - ! print *,__LINE__,'Dbl:',mype,j,nv,dfld(j,nv),dfld_in(j,nv,frame),compmap(j) - !endif write(*,*) '***ERROR:Mismatch!***' write(*,'(a11,i2,a9,d11.4,a9,d11.4,a9,i2)') & - 'Double PE=',mype,'dfld=',dfld(j,nv),'dfld_in=',dfld_in(j,nv,frame),'compmap=',compmap(j) + 'Double PE=',mype,'dfld=',dfld(j,nv),'dfld_in=',dfld_in(j,nv,frame),'compmap=',compmap(j) errorcnt = errorcnt+1 endif @@ -987,7 +975,7 @@ subroutine pioperformance_rearrtest(filename, piotypes, mype, npe_base, & rearr_name(rearr), piotypes(k), ntasks, nvars, & nvarmult*nvars*nframes*gmaplen*4.0D0/(1048576.0*wall(2)) #ifdef BGQTRY - call print_memusage() + call print_memusage() #endif end if #ifdef VARREAL @@ -1005,13 +993,12 @@ subroutine pioperformance_rearrtest(filename, piotypes, mype, npe_base, & enddo deallocate(compmap) deallocate(gdims) - deallocate(ifld) - deallocate(ifld_in) - deallocate(rfld) - deallocate(dfld) - deallocate(dfld_in) - deallocate(rfld_in) - call MPI_Comm_free(comm, ierr) + if(allocated(ifld)) deallocate(ifld) + if(allocated(ifld_in)) deallocate(ifld_in) + if(allocated(rfld)) deallocate(rfld) + if(allocated(rfld_in)) deallocate(rfld_in) + if(allocated(dfld)) deallocate(dfld) + if(allocated(dfld_in)) deallocate(dfld_in) endif end subroutine pioperformance_rearrtest From 52cef7fd77ebdc53364535632a213cdafe31b054 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 3 Feb 2025 09:54:10 -0600 Subject: [PATCH 048/194] Adding a node local comm to I/O sys Adding a node local (shared mem) comm in I/O system that can be used by the lib --- src/clib/pio_types.hpp | 4 ++++ src/clib/pioc.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/clib/pio_types.hpp b/src/clib/pio_types.hpp index 50d37c8ea8..4eb0c94be7 100644 --- a/src/clib/pio_types.hpp +++ b/src/clib/pio_types.hpp @@ -411,6 +411,10 @@ typedef struct iosystem_desc_t * non-async) or the union (for async) communicator. */ MPI_Comm my_comm; + /* Comm that includes procs from comp_comm that are local to this + * compute node (share the same memory) */ + MPI_Comm node_comm; + /** This MPI group contains the processors involved in * computation. */ MPI_Group compgroup; diff --git a/src/clib/pioc.cpp b/src/clib/pioc.cpp index 8bfc58b904..292af9035d 100644 --- a/src/clib/pioc.cpp +++ b/src/clib/pioc.cpp @@ -1433,6 +1433,7 @@ int PIOc_Init_Intracomm_impl(MPI_Comm comp_comm, int num_iotasks, int stride, in ios->sname[0] = '\0'; ios->io_comm = MPI_COMM_NULL; ios->intercomm = MPI_COMM_NULL; + ios->node_comm = MPI_COMM_NULL; ios->error_handler = default_error_handler; ios->default_rearranger = rearr; ios->num_iotasks = num_iotasks; @@ -1664,6 +1665,14 @@ int PIOc_Init_Intracomm_impl(MPI_Comm comp_comm, int num_iotasks, int stride, in ios->io_rank = -1; LOG((3, "ios->io_comm = %d ios->io_rank = %d", ios->io_comm, ios->io_rank)); + /* Create the node local comm - all procs in comp_comm that are local to + * this compute node (share memory) */ + mpierr = MPI_Comm_split_type(ios->comp_comm, MPI_COMM_TYPE_SHARED, 0, + ios->info, &(ios->node_comm)); + if(mpierr != MPI_SUCCESS){ + return check_mpi(ios, NULL, mpierr, __FILE__, __LINE__); + } + /* Rank in the union comm is the same as rank in the comp comm. */ ios->union_rank = ios->comp_rank; @@ -1983,6 +1992,8 @@ int PIOc_finalize_impl(int iosysid) MPI_Comm_free(&ios->union_comm); if (ios->io_comm != MPI_COMM_NULL) MPI_Comm_free(&ios->io_comm); + if (ios->node_comm != MPI_COMM_NULL) + MPI_Comm_free(&ios->node_comm); /* Delete the iosystem_desc_t data associated with this id. */ LOG((2, "About to delete iosysid %d.", iosysid)); @@ -2385,6 +2396,7 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li my_iosys->union_comm = MPI_COMM_NULL; my_iosys->intercomm = MPI_COMM_NULL; my_iosys->my_comm = MPI_COMM_NULL; + my_iosys->node_comm = MPI_COMM_NULL; my_iosys->async = 1; my_iosys->error_handler = default_error_handler; my_iosys->num_comptasks = num_procs_per_comp[cmp]; @@ -2572,6 +2584,14 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li { return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); } + + /* Create the node local comm - all procs in comp_comm that are local to + * this compute node (share memory) */ + mpierr = MPI_Comm_split_type(my_iosys->comp_comm, MPI_COMM_TYPE_SHARED, 0, + my_iosys->info, &(my_iosys->node_comm)); + if(mpierr != MPI_SUCCESS){ + return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); + } } LOG((3, "intercomm created for cmp = %d", cmp)); } @@ -2796,6 +2816,7 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, iosys[i]->comp_comm = MPI_COMM_NULL; iosys[i]->intercomm = MPI_COMM_NULL; iosys[i]->my_comm = MPI_COMM_NULL; + iosys[i]->node_comm = MPI_COMM_NULL; iosys[i]->compgroup = MPI_GROUP_NULL; iosys[i]->iogroup = MPI_GROUP_NULL; @@ -3167,6 +3188,14 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, } MPI_Group_free(&union_comm_group); + + /* Create the node local comm - all procs in comp_comm that are local to + * this compute node (share memory) */ + ret = MPI_Comm_split_type(iosys[i]->comp_comm, MPI_COMM_TYPE_SHARED, 0, + iosys[i]->info, &(iosys[i]->node_comm)); + if(ret != MPI_SUCCESS){ + return check_mpi(NULL, NULL, ret, __FILE__, __LINE__); + } } } From 9552003d6befffbcb573c0a0ddaf3db622a1d0c9 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 3 Feb 2025 23:45:06 -0600 Subject: [PATCH 049/194] Adding a decomp logger class Adding a decomp logger class to dump I/O decompositions. The decomp info is read/written using PnetCDF after node-local aggregation. This logger class would be helpful in dumping large decompositions --- src/clib/CMakeLists.txt | 2 +- src/clib/spio_decomp_logger.hpp | 213 ++++++++ src/clib/spio_decomp_nc_logger.cpp | 410 +++++++++++++++ src/clib/spio_decomp_txt_logger.cpp | 32 ++ tests/cunit/CMakeLists.txt | 8 + tests/cunit/test_spio_decomp_logger.cpp | 634 ++++++++++++++++++++++++ 6 files changed, 1298 insertions(+), 1 deletion(-) create mode 100644 src/clib/spio_decomp_logger.hpp create mode 100644 src/clib/spio_decomp_nc_logger.cpp create mode 100644 src/clib/spio_decomp_txt_logger.cpp create mode 100644 tests/cunit/test_spio_decomp_logger.cpp diff --git a/src/clib/CMakeLists.txt b/src/clib/CMakeLists.txt index b41446b578..56dd7483f3 100644 --- a/src/clib/CMakeLists.txt +++ b/src/clib/CMakeLists.txt @@ -42,7 +42,7 @@ set (pio_lib_src pio_nc4.cpp bget.cpp pio_nc.cpp pio_put_nc.cpp pio_get_nc.cpp pio_getput_int.cpp pio_msg.cpp pio_varm.cpp pio_darray.cpp pio_darray_int.cpp spio_hash.cpp pio_sdecomps_regex.cpp spio_io_summary.cpp - spio_decomp_map_info_pool.cpp + spio_decomp_map_info_pool.cpp spio_decomp_nc_logger.cpp spio_decomp_txt_logger.cpp spio_ltimer.cpp spio_serializer.cpp spio_file_mvcache.cpp spio_tracer.cpp spio_tracer_mdata.cpp spio_tracer_decomp.cpp spio_rearrange_any.cpp) diff --git a/src/clib/spio_decomp_logger.hpp b/src/clib/spio_decomp_logger.hpp new file mode 100644 index 0000000000..0a65accdfe --- /dev/null +++ b/src/clib/spio_decomp_logger.hpp @@ -0,0 +1,213 @@ +#ifndef __SPIO_DECOMP_LOGGER__ +#define __SPIO_DECOMP_LOGGER__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pio_config.h" +#include "pio.h" +#include "pio_internal.h" +#include "mpi.h" + +namespace SPIO_Util{ + namespace Decomp_Util{ + + /* FIXME: Allow multiple decompositions dumped into the same file */ + class Decomp_logger{ + public: + Decomp_logger(MPI_Comm comm, MPI_Comm io_comm, MPI_Comm agg_comm, std::string &log_fname):comm_(comm), io_comm_(io_comm), agg_comm_(agg_comm), is_io_proc_(io_comm != MPI_COMM_NULL), comm_sz_(-1), comm_rank_(-1), io_comm_sz_(-1), io_comm_rank_(-1), agg_comm_sz_(-1), agg_comm_rank_(-1), log_fname_(log_fname), mode_(OPEN_MODE_RD){ + int ret = MPI_SUCCESS; + + assert(comm_ != MPI_COMM_NULL); + assert(agg_comm_ != MPI_COMM_NULL); + + ret = MPI_Comm_size(comm_, &comm_sz_); assert(ret == MPI_SUCCESS); + ret = MPI_Comm_rank(comm_, &comm_rank_); assert(ret == MPI_SUCCESS); + if(is_io_proc_){ + ret = MPI_Comm_size(io_comm_, &io_comm_sz_); assert(ret == MPI_SUCCESS); + ret = MPI_Comm_rank(io_comm_, &io_comm_rank_); assert(ret == MPI_SUCCESS); + } + ret = MPI_Comm_size(agg_comm_, &agg_comm_sz_); assert(ret == MPI_SUCCESS); + ret = MPI_Comm_rank(agg_comm_, &agg_comm_rank_); assert(ret == MPI_SUCCESS); + } + + Decomp_logger &read_only(void ){ + mode_ |= OPEN_MODE_RD; + mode_ &= ~OPEN_MODE_WR; + return *this; + } + + Decomp_logger &write_only(void ){ + mode_ |= OPEN_MODE_WR; + mode_ &= ~OPEN_MODE_RD; + return *this; + } + + bool is_read_only(void ) const { + return (((mode_ & OPEN_MODE_WR) == 0) && ((mode_ & OPEN_MODE_RD) != 0)); + } + bool is_write_only(void ) const { + return (((mode_ & OPEN_MODE_RD) == 0) && ((mode_ & OPEN_MODE_WR) != 0)); + } + + std::string get_log_fname(void ) const { return log_fname_; } + + virtual Decomp_logger &open(void ) = 0; + + virtual void get_info(std::string &version, int &nprocs, int &ngdims, PIO_Offset &lcompmap_sz) = 0; + virtual void get_gdims(int *gdims, std::size_t gdims_sz) = 0; + virtual void get_lcompmap(PIO_Offset *lcompmap, std::size_t lcompmap_sz) = 0; + + virtual Decomp_logger &get(std::string &version, int &nprocs, std::vector &gdims, std::vector &lcompmap) = 0; + + virtual Decomp_logger &put(io_desc_t *iodesc) = 0; + + virtual void close(void ) = 0; + + virtual ~Decomp_logger(){ + MPI_Comm_free(&comm_); + if(io_comm_ != MPI_COMM_NULL){ + MPI_Comm_free(&io_comm_); + } + MPI_Comm_free(&agg_comm_); + } + protected: + static const char OPEN_MODE_RD = 0x1; + static const char OPEN_MODE_WR = 0x10; + + MPI_Comm comm_; + MPI_Comm io_comm_; + MPI_Comm agg_comm_; + bool is_io_proc_; + int comm_sz_; + int comm_rank_; + int io_comm_sz_; + int io_comm_rank_; + int agg_comm_sz_; + int agg_comm_rank_; + std::string log_fname_; + char mode_; + }; + + class Decomp_txt_logger : public Decomp_logger{ + public: + Decomp_txt_logger(MPI_Comm comm, MPI_Comm io_comm, MPI_Comm agg_comm, std::string log_fname) : Decomp_logger(comm, io_comm, agg_comm, log_fname){} + virtual Decomp_logger &open(void ); + + virtual void get_info(std::string &version, int &nprocs, int &ngdims, PIO_Offset &lcompmap_sz); + virtual void get_gdims(int *gdims, std::size_t gdims_sz); + virtual void get_lcompmap(PIO_Offset *lcompmap, std::size_t lcompmap_sz); + + virtual Decomp_logger &get(std::string &version, int &nprocs, std::vector &gdims, std::vector &lcompmap); + + virtual Decomp_logger &put(io_desc_t *iodesc); + + virtual void close(void ); + + virtual ~Decomp_txt_logger() {} + private: + }; + + class Decomp_nc_logger : public Decomp_logger{ + public: + Decomp_nc_logger(MPI_Comm comm, MPI_Comm io_comm, MPI_Comm agg_comm, std::string log_fname) : Decomp_logger(comm, io_comm, agg_comm, log_fname), ncid_(INVALID_ID), comm_sz_dimid_(INVALID_ID), info_cached_(false), version_att_name_("version"), nprocs_att_name_("nprocs"), ndims_att_name_("ndims"), gdimlen_att_name_("gdimlen"), comm_sz_dim_name_("comm_sz"), counts_var_name_("counts"), gmaplen_dim_name_("gmaplen"), gmap_var_name_("gmap"), ioid_att_name_("ioid"), nprocs_(0){ + } + virtual Decomp_logger &open(void ); + + virtual void get_info(std::string &version, int &nprocs, int &ngdims, PIO_Offset &lcompmap_sz); + virtual void get_gdims(int *gdims, std::size_t gdims_sz); + virtual void get_lcompmap(PIO_Offset *lcompmap, std::size_t lcompmap_sz); + + virtual Decomp_logger &get(std::string &version, int &nprocs, std::vector &gdims, std::vector &lcompmap); + + virtual Decomp_logger &put(io_desc_t *iodesc); + + virtual void close(void ); + + virtual ~Decomp_nc_logger() { assert(ncid_ == INVALID_ID); } + private: + static const int INVALID_ID = -1; + int ncid_; + int comm_sz_dimid_; + bool info_cached_; + + std::string version_; + const std::string version_att_name_; + const std::string nprocs_att_name_; + std::vector gdims_; + const std::string ndims_att_name_; + const std::string gdimlen_att_name_; + std::vector lcompmap_; + const std::string comm_sz_dim_name_; + const std::string counts_var_name_; + const std::string gmaplen_dim_name_; + const std::string gmap_var_name_; + const std::string ioid_att_name_; + int nprocs_; + + void gather_starts_counts(std::vector &agg_starts, std::vector &agg_counts, MPI_Offset &agg_io_chunk_sz, io_desc_t *iodesc); + void gather_gmap(const std::vector &starts, const std::vector &counts, std::vector &gmap_chunk, io_desc_t *iodesc); + void read_and_cache_info(void ); + }; + + inline Decomp_logger *create_decomp_logger(MPI_Comm comm, MPI_Comm io_comm, MPI_Comm agg_comm, std::string log_fname){ +#ifdef _PNETCDF + char NC_FILE_EXTN_SEP = '.'; + std::string NC_FILE_EXTN("NC"); + std::size_t file_extn_pos = log_fname.rfind(NC_FILE_EXTN_SEP); + std::string file_extn = (file_extn_pos != std::string::npos) ? log_fname.substr(file_extn_pos + 1) : ""; + + std::transform(file_extn.begin(), file_extn.end(), file_extn.begin(), [](unsigned char c){ return std::toupper(c); }); + + if(file_extn == NC_FILE_EXTN){ + return new Decomp_nc_logger(comm, io_comm, agg_comm, log_fname); + } +#endif + return new Decomp_txt_logger(comm, io_comm, agg_comm, log_fname); + } + + inline Decomp_logger *create_decomp_logger(MPI_Comm ucomm, std::string log_fname){ + MPI_Comm comm = MPI_COMM_NULL; + MPI_Comm io_comm = MPI_COMM_NULL; + MPI_Comm agg_comm = MPI_COMM_NULL; + int agg_comm_rank = -1; + int ret = MPI_SUCCESS; + + ret = MPI_Comm_dup(ucomm, &comm); assert(ret == MPI_SUCCESS); + ret = MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, 0, MPI_INFO_NULL, &agg_comm); assert(ret == MPI_SUCCESS); + ret = MPI_Comm_rank(agg_comm, &agg_comm_rank); assert(ret == MPI_SUCCESS); + + int color = (agg_comm_rank == 0) ? 0 : MPI_UNDEFINED; + ret = MPI_Comm_split(comm, color, 0, &io_comm); assert(ret == MPI_SUCCESS); + + return create_decomp_logger(comm, io_comm, agg_comm, log_fname); + } + + inline Decomp_logger *create_decomp_logger(iosystem_desc_t *ios, std::string log_fname){ + MPI_Comm comm = MPI_COMM_NULL; + MPI_Comm io_comm = MPI_COMM_NULL; + MPI_Comm agg_comm = MPI_COMM_NULL; + int agg_comm_rank = -1; + int ret = MPI_SUCCESS; + + ret = MPI_Comm_dup(ios->union_comm, &comm); assert(ret == MPI_SUCCESS); + ret = MPI_Comm_dup(ios->node_comm, &agg_comm); assert(ret == MPI_SUCCESS); + ret = MPI_Comm_rank(agg_comm, &agg_comm_rank); assert(ret == MPI_SUCCESS); + + int color = (agg_comm_rank == 0) ? 0 : MPI_UNDEFINED; + ret = MPI_Comm_split(comm, color, 0, &io_comm); assert(ret == MPI_SUCCESS); + return create_decomp_logger(comm, io_comm, agg_comm, log_fname); + } + + } //namespace Decomp_Util +} // namespace SPIO_Util +#endif // __SPIO_DECOMP_LOGGER__ diff --git a/src/clib/spio_decomp_nc_logger.cpp b/src/clib/spio_decomp_nc_logger.cpp new file mode 100644 index 0000000000..1c33b55e53 --- /dev/null +++ b/src/clib/spio_decomp_nc_logger.cpp @@ -0,0 +1,410 @@ +#include "spio_decomp_logger.hpp" +#include +#include +#include +#ifdef _PNETCDF +#include "pnetcdf.h" +#endif + +SPIO_Util::Decomp_Util::Decomp_logger& SPIO_Util::Decomp_Util::Decomp_nc_logger::open(void ) +{ +#ifdef _PNETCDF + int ret = MPI_SUCCESS; + + version_ = std::to_string(PIO_VERSION_MAJOR) + "." + + std::to_string(PIO_VERSION_MINOR) + "." + + std::to_string(PIO_VERSION_PATCH); + nprocs_ = comm_sz_; + + if(!is_io_proc_){ + return *this; + } + + MPI_Info info = MPI_INFO_NULL; + + ret = MPI_Info_create(&info); assert(ret == MPI_SUCCESS); + ret = MPI_Info_set(info, "nc_var_align_size", "1"); assert(ret == MPI_SUCCESS); + + int omode = NC_64BIT_DATA; + if(is_read_only()){ + omode |= NC_NOWRITE; + + ret = ncmpi_open(io_comm_, log_fname_.c_str(), omode, info, &ncid_); + if(ret != NC_NOERR){ + throw std::runtime_error(std::string("Opening decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); + } + + } + else{ + assert(is_write_only()); + omode |= (NC_WRITE | NC_CLOBBER); + + ret = ncmpi_create(io_comm_, log_fname_.c_str(), omode, info, &ncid_); + if(ret != NC_NOERR){ + throw std::runtime_error(std::string("Creating decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); + } + + ret = ncmpi_def_dim(ncid_, comm_sz_dim_name_.c_str(), comm_sz_, &comm_sz_dimid_); + if(ret != NC_NOERR){ + throw std::runtime_error(std::string("Defining comm_sz dimension in decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); + } + + ret = ncmpi_put_att_text(ncid_, NC_GLOBAL, version_att_name_.c_str(), version_.size() + 1, version_.c_str()); + if(ret == NC_NOERR){ + ret = ncmpi_put_att_int(ncid_, NC_GLOBAL, nprocs_att_name_.c_str(), NC_INT, 1, &nprocs_); + } + if(ret != NC_NOERR){ + throw std::runtime_error(std::string("Adding SCORPIO version/nprocs attributes to decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); + } + + ret = ncmpi_enddef(ncid_); + if(ret != NC_NOERR){ + throw std::runtime_error(std::string("Ending define mode for decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); + } + } + + MPI_Info_free(&info); +#endif + return *this; +} + +void SPIO_Util::Decomp_Util::Decomp_nc_logger::get_info(std::string &version, int &nprocs, int &ngdims, PIO_Offset &lcompmap_sz) +{ +#ifdef _PNETCDF + if(!info_cached_){ + read_and_cache_info(); + } +#endif + if(info_cached_){ + version = version_; + nprocs = nprocs_; + ngdims = static_cast(gdims_.size()); + lcompmap_sz = static_cast(lcompmap_.size()); + return; + } +} + +void SPIO_Util::Decomp_Util::Decomp_nc_logger::get_gdims(int *gdims, std::size_t gdims_sz) +{ +#ifdef _PNETCDF + if(!info_cached_){ + read_and_cache_info(); + } +#endif + if(info_cached_){ + assert(gdims && (gdims_sz == gdims_.size())); + std::copy(gdims_.cbegin(), gdims_.cend(), gdims); + return; + } +} + +void SPIO_Util::Decomp_Util::Decomp_nc_logger::get_lcompmap(PIO_Offset *lcompmap, std::size_t lcompmap_sz) +{ +#ifdef _PNETCDF + if(!info_cached_){ + read_and_cache_info(); + } +#endif + if(info_cached_){ + assert(lcompmap && (lcompmap_sz == lcompmap_.size())); + std::copy(lcompmap_.cbegin(), lcompmap_.cend(), lcompmap); + return; + } +} + +SPIO_Util::Decomp_Util::Decomp_logger& SPIO_Util::Decomp_Util::Decomp_nc_logger::get(std::string &version, int &nprocs, std::vector &gdims, std::vector &lcompmap) +{ +#ifdef _PNETCDF + if(!info_cached_){ + read_and_cache_info(); + } +#endif + if(info_cached_){ + version = version_; + nprocs = nprocs_; + gdims.resize(gdims_.size()); + std::copy(gdims_.cbegin(), gdims_.cend(), gdims.begin()); + lcompmap.resize(lcompmap_.size()); + std::copy(lcompmap_.cbegin(), lcompmap_.cend(), lcompmap.begin()); + } + return *this; +} + +void SPIO_Util::Decomp_Util::Decomp_nc_logger::read_and_cache_info(void ) +{ + int ret = NC_NOERR; +#ifdef _PNETCDF + MPI_Offset version_len = 0; + int ndims = 0; + std::vector agg_counts(agg_comm_sz_, 0); + std::vector agg_gmap_chunk; + if(is_io_proc_){ + assert(ncid_ != INVALID_ID); + + ret = ncmpi_inq_attlen(ncid_, NC_GLOBAL, version_att_name_.c_str(), &version_len); + if(ret == NC_NOERR){ + version_.resize(static_cast(version_len) + 1); + + char tmp_str[version_len + 1]; + tmp_str[version_len] = '\0'; + ret = ncmpi_get_att_text(ncid_, NC_GLOBAL, version_att_name_.c_str(), tmp_str); + version_.assign(tmp_str); + } + if(ret == NC_NOERR){ + ret = ncmpi_get_att_int(ncid_, NC_GLOBAL, nprocs_att_name_.c_str(), &nprocs_); + } + if(ret == NC_NOERR){ + ret = ncmpi_get_att_int(ncid_, NC_GLOBAL, ndims_att_name_.c_str(), &ndims); + if(ret == NC_NOERR){ + gdims_.resize(ndims); + ret = ncmpi_get_att_int(ncid_, NC_GLOBAL, gdimlen_att_name_.c_str(), gdims_.data()); + } + } + if(ret != NC_NOERR){ + throw std::runtime_error(std::string("Reading attributes (version/nprocs/ndims/gdimlen) from decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); + } + + //std::pair proc_range = {comm_rank_, comm_rank_ + agg_comm_sz_}; + + MPI_Offset start_var = comm_rank_; + MPI_Offset count_var = (comm_rank_ + agg_comm_sz_ <= comm_sz_) ? agg_comm_sz_ : (comm_sz_ - comm_rank_); + + int tmp_varid = -1; + ret = ncmpi_inq_varid(ncid_, counts_var_name_.c_str(), &tmp_varid); + if(ret == NC_NOERR){ + ret = ncmpi_get_vara_int_all(ncid_, tmp_varid, &start_var, &count_var, agg_counts.data()); + } + if(ret != NC_NOERR){ + throw std::runtime_error(std::string("Reading counts array from decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); + } + + MPI_Offset agg_io_chunk_sz = 0; + for(std::size_t i = 0; i < agg_counts.size(); i++){ + agg_io_chunk_sz += agg_counts[i]; + } + + MPI_Offset agg_io_chunk_start = agg_io_chunk_sz; + ret = MPI_Exscan(MPI_IN_PLACE, &agg_io_chunk_start, 1, MPI_OFFSET, MPI_SUM, io_comm_); assert(ret == MPI_SUCCESS); + if(io_comm_rank_ == 0){ + agg_io_chunk_start = 0; + } + + agg_gmap_chunk.resize(agg_io_chunk_sz); + ret = ncmpi_inq_varid(ncid_, gmap_var_name_.c_str(), &tmp_varid); + if(ret == NC_NOERR){ + ret = ncmpi_get_vara_longlong_all(ncid_, tmp_varid, &agg_io_chunk_start, + &agg_io_chunk_sz, agg_gmap_chunk.data()); + } + if(ret != NC_NOERR){ + throw std::runtime_error(std::string("Reading gmap array from decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); + } + } + + ret = MPI_Bcast(&version_len, 1, MPI_OFFSET, 0, agg_comm_); assert(ret == MPI_SUCCESS); + ret = MPI_Bcast(&nprocs_, 1, MPI_INT, 0, agg_comm_); assert(ret == MPI_SUCCESS); + ret = MPI_Bcast(&ndims, 1, MPI_INT, 0, agg_comm_); assert(ret == MPI_SUCCESS); + + char tmp_str[version_len + 1]; + tmp_str[version_len] = '\0'; + std::copy(version_.cbegin(), version_.cend(), tmp_str); + ret = MPI_Bcast(tmp_str, version_len, MPI_CHAR, 0, agg_comm_); assert(ret == MPI_SUCCESS); + if(agg_comm_rank_ != 0){ + version_.assign(tmp_str); + gdims_.resize(ndims); + } + ret = MPI_Bcast(gdims_.data(), ndims, MPI_INT, 0, agg_comm_); assert(ret == MPI_SUCCESS); + + int lcompmap_sz = 0; + ret = MPI_Scatter(agg_counts.data(), 1, MPI_INT, &lcompmap_sz, 1, MPI_INT, 0, agg_comm_); assert(ret == MPI_SUCCESS); + + lcompmap_.resize(lcompmap_sz); + std::vector agg_starts(agg_counts.size()); + int cur_start = 0; + for(std::size_t i = 0; i < agg_starts.size(); i++){ + agg_starts[i] = cur_start; + cur_start += agg_counts[i]; + } + ret = MPI_Scatterv(agg_gmap_chunk.data(), agg_counts.data(), agg_starts.data(), MPI_OFFSET, + lcompmap_.data(), lcompmap_sz, MPI_OFFSET, 0, agg_comm_); assert(ret == MPI_SUCCESS); + + info_cached_ = true; + +#endif +} + +SPIO_Util::Decomp_Util::Decomp_logger &SPIO_Util::Decomp_Util::Decomp_nc_logger::put(io_desc_t *iodesc) +{ +#ifdef _PNETCDF + int ret = MPI_SUCCESS; + + assert(iodesc); + + /* Cache the iodesc info */ + gdims_.resize(iodesc->ndims); + std::copy(iodesc->dimlen, iodesc->dimlen + iodesc->ndims, gdims_.begin()); + lcompmap_.resize(iodesc->maplen); + std::copy(iodesc->map, iodesc->map + iodesc->maplen, lcompmap_.begin()); + info_cached_ = true; + + std::vector agg_starts, agg_counts; + MPI_Offset agg_io_chunk_sz = 0; + + /* Aggregation of local map lengths & map happens in agg_comm_, the + * data is written out to the file using io_comm_. Each rank 0 proc in + * agg_comm is used to create the io_comm_ + */ + /* Gather/Aggregate local map lengths - map lengths of each compute proc + * should be available in agg_counts + * The starts/displacements (on the global map) for map chunks in each + * agg process should be available in agg_starts + * agg_io_chunk_sz : Total size of aggregated gmap chunk on this I/O proc + */ + agg_starts.resize(agg_comm_sz_); + agg_counts.resize(agg_comm_sz_); + gather_starts_counts(agg_starts, agg_counts, agg_io_chunk_sz, iodesc); + + std::vector gmap_chunk; + if(is_io_proc_){ + gmap_chunk.resize(agg_io_chunk_sz); + } + + /* Gather the local compmaps from compute procs to the I/O processes */ + gather_gmap(agg_starts, agg_counts, gmap_chunk, iodesc); + + if(!is_io_proc_){ + return *this; + } + + assert(sizeof(PIO_Offset) == sizeof(MPI_Offset)); + MPI_Offset agg_io_chunk_count = agg_io_chunk_sz; + + /* Find starts/Displacements for "counts" var and "gmap" var among I/O processes */ + std::array starts_for_counts_and_gmap = { static_cast(agg_comm_sz_), agg_io_chunk_count }; + ret = MPI_Exscan(MPI_IN_PLACE, starts_for_counts_and_gmap.data(), starts_for_counts_and_gmap.size(), MPI_OFFSET, MPI_SUM, io_comm_); assert(ret == MPI_SUCCESS); + if(io_comm_rank_ == 0){ + starts_for_counts_and_gmap = {0, 0}; + } + + MPI_Offset gmaplen = 0; + ret = MPI_Allreduce(&agg_io_chunk_count, &gmaplen, 1, MPI_OFFSET, MPI_SUM, io_comm_); assert(ret == MPI_SUCCESS); + + assert(ncid_ != INVALID_ID); + + ret = ncmpi_redef(ncid_); + if(ret != NC_NOERR){ + throw std::runtime_error(std::string("Redefine mode for decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); + } + + ret = ncmpi_put_att_int(ncid_, NC_GLOBAL, ioid_att_name_.c_str(), NC_INT, 1, &(iodesc->ioid)); + if(ret == NC_NOERR){ + ret = ncmpi_put_att_int(ncid_, NC_GLOBAL, ndims_att_name_.c_str(), NC_INT, 1, &(iodesc->ndims)); + } + if(ret == NC_NOERR){ + ret = ncmpi_put_att_int(ncid_, NC_GLOBAL, gdimlen_att_name_.c_str(), NC_INT, iodesc->ndims, iodesc->dimlen); + } + if(ret != NC_NOERR){ + throw std::runtime_error(std::string("Writing ioid/ndims/gdimlen to decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); + } + + assert(sizeof(MPI_Offset) == sizeof(int64_t)); + /* Global start offsets for reads/writes */ + int counts_varid = INVALID_ID; + int gmaplen_dimid = INVALID_ID; + int gmap_varid = INVALID_ID; + + ret = ncmpi_def_var(ncid_, counts_var_name_.c_str(), NC_INT, 1, &comm_sz_dimid_, &counts_varid); + if(ret != NC_NOERR){ + throw std::runtime_error(std::string("Defining counts var in decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); + } + + ret = ncmpi_def_dim(ncid_, gmaplen_dim_name_.c_str(), gmaplen, &gmaplen_dimid); + if(ret != NC_NOERR){ + throw std::runtime_error(std::string("Defining gmaplen dimension, size = ") + std::to_string(static_cast(gmaplen)) + std::string(", in decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); + } + + /* The global compmap */ + ret = ncmpi_def_var(ncid_, gmap_var_name_.c_str(), NC_INT64, 1, &gmaplen_dimid, &gmap_varid); + if(ret != NC_NOERR){ + throw std::runtime_error(std::string("Defining var to store global compmap in decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); + } + + ret = ncmpi_enddef(ncid_); + if(ret != NC_NOERR){ + throw std::runtime_error(std::string("Ending redefine mode for decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); + } + + /* Write compmap counts */ + MPI_Offset counts_start = starts_for_counts_and_gmap[0]; + MPI_Offset counts_count = agg_comm_sz_; + assert((counts_start < static_cast(comm_sz_)) && + (counts_count == static_cast(agg_counts.size()))); + ret = ncmpi_iput_vara_int(ncid_, counts_varid, &counts_start, &counts_count, agg_counts.data(), NULL); + if(ret != NC_NOERR){ + throw std::runtime_error(std::string("Writing gmap process counts to decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); + } + + MPI_Offset agg_io_chunk_start = starts_for_counts_and_gmap[1]; + assert((agg_io_chunk_start < gmaplen) && (agg_io_chunk_start + agg_io_chunk_count <= gmaplen)); + /* Write compmap */ + ret = ncmpi_iput_vara_longlong(ncid_, gmap_varid, &agg_io_chunk_start, &agg_io_chunk_count, gmap_chunk.data(), NULL); + if(ret != NC_NOERR){ + throw std::runtime_error(std::string("Writing gmap to decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); + } + + ret = ncmpi_wait_all(ncid_, NC_REQ_ALL, NULL, NULL); + if(ret != NC_NOERR){ + throw std::runtime_error(std::string("Waiting on writes of gmap/counts arrays to decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); + } + +#endif + return *this; +} + +void SPIO_Util::Decomp_Util::Decomp_nc_logger::gather_starts_counts(std::vector &agg_starts, std::vector &agg_counts, MPI_Offset &agg_io_chunk_sz, io_desc_t *iodesc) +{ + int ret = MPI_SUCCESS; + + assert(iodesc && (agg_comm_sz_ > 0)); + agg_io_chunk_sz = 0; + + int lmap_sz = iodesc->maplen; + + ret = MPI_Gather(&lmap_sz, 1, MPI_INT, agg_counts.data(), 1, MPI_INT, 0, agg_comm_); assert(ret == MPI_SUCCESS); + + int cur_start = 0; + for(std::size_t i = 0; i < agg_starts.size(); i++){ + agg_starts[i] = cur_start; + cur_start += agg_counts[i]; + agg_io_chunk_sz += static_cast(agg_counts[i]); + } +} + +void SPIO_Util::Decomp_Util::Decomp_nc_logger::gather_gmap(const std::vector &starts, const std::vector &counts, std::vector &gmap_chunk, io_desc_t *iodesc) +{ + int ret = MPI_SUCCESS; + + assert(iodesc); + assert((agg_comm_rank_ != 0) || ((gmap_chunk.size() > 0) && (counts.size() > 0) && (starts.size() > 0))); + + ret = MPI_Gatherv(iodesc->map, iodesc->maplen, MPI_OFFSET, gmap_chunk.data(), + counts.data(), starts.data(), MPI_OFFSET, 0, agg_comm_); assert(ret == MPI_SUCCESS); +} + +void SPIO_Util::Decomp_Util::Decomp_nc_logger::close(void ) +{ + int ret = MPI_SUCCESS; + +#ifdef _PNETCDF + if(!is_io_proc_){ + return; + } + + assert(ncid_ != INVALID_ID); + ret = ncmpi_close(ncid_); + if(ret != NC_NOERR){ + throw std::runtime_error(std::string("Closing decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); + } + + ncid_ = INVALID_ID; +#endif +} diff --git a/src/clib/spio_decomp_txt_logger.cpp b/src/clib/spio_decomp_txt_logger.cpp new file mode 100644 index 0000000000..c4aa8db8d5 --- /dev/null +++ b/src/clib/spio_decomp_txt_logger.cpp @@ -0,0 +1,32 @@ +#include "spio_decomp_logger.hpp" + +SPIO_Util::Decomp_Util::Decomp_logger& SPIO_Util::Decomp_Util::Decomp_txt_logger::open(void ) +{ + return *this; +} + +void SPIO_Util::Decomp_Util::Decomp_txt_logger::get_info(std::string &version, int &nprocs, int &ngdims, PIO_Offset &lcompmap_sz) +{ +} + +void SPIO_Util::Decomp_Util::Decomp_txt_logger::get_gdims(int *gdims, std::size_t gdims_sz) +{ +} + +void SPIO_Util::Decomp_Util::Decomp_txt_logger::get_lcompmap(PIO_Offset *lcompmap, std::size_t lcompmap_sz) +{ +} + +SPIO_Util::Decomp_Util::Decomp_logger& SPIO_Util::Decomp_Util::Decomp_txt_logger::get(std::string &version, int &nprocs, std::vector &gdims, std::vector &lcompmap) +{ + return *this; +} + +SPIO_Util::Decomp_Util::Decomp_logger& SPIO_Util::Decomp_Util::Decomp_txt_logger::put(io_desc_t *iodesc) +{ + return *this; +} + +void SPIO_Util::Decomp_Util::Decomp_txt_logger::close(void ) +{ +} diff --git a/tests/cunit/CMakeLists.txt b/tests/cunit/CMakeLists.txt index f951049e73..f63a8d78de 100644 --- a/tests/cunit/CMakeLists.txt +++ b/tests/cunit/CMakeLists.txt @@ -110,12 +110,14 @@ add_spio_executable (test_spio_rearr_utils_alltoall TRUE "" test_spio_rearr_util add_spio_executable (test_spio_rearr_contig TRUE "" test_spio_rearr_contig.cpp) add_spio_executable (test_spio_rearr_contig_nvars TRUE "" test_spio_rearr_contig_nvars.cpp) add_spio_executable (test_spio_rearr_contig_fillval TRUE "" test_spio_rearr_contig_fillval.cpp) +add_spio_executable (test_spio_decomp_logger TRUE "" test_spio_decomp_logger.cpp) add_spio_executable (test_sdecomp_regex TRUE "" test_sdecomp_regex.cpp test_common.cpp) add_spio_executable(test_req_block_wait TRUE "" test_req_block_wait.cpp test_common.cpp) add_dependencies (tests test_spmd test_spio_ltimer test_spio_serializer test_spio_tree test_spio_file_mvcache test_spio_rearr_utils_gather test_spio_rearr_utils_scatter test_spio_rearr_utils_alltoall test_spio_rearr_contig test_spio_rearr_contig_nvars test_spio_rearr_contig_fillval + test_spio_decomp_logger test_sdecomp_regex test_req_block_wait) if(PIO_USE_ASYNC_WR_THREAD) @@ -209,6 +211,12 @@ else () NUMPROCS ${nproc} TIMEOUT ${DEFAULT_TEST_TIMEOUT}) endforeach() + foreach(nproc RANGE 1 ${SPIO_TEST_MAX_NPROCS}) + add_mpi_test(test_spio_decomp_logger${nproc} + EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/test_spio_decomp_logger + NUMPROCS ${nproc} + TIMEOUT ${DEFAULT_TEST_TIMEOUT}) + endforeach() add_mpi_test(test_spmd EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/test_spmd NUMPROCS ${AT_LEAST_FOUR_TASKS} diff --git a/tests/cunit/test_spio_decomp_logger.cpp b/tests/cunit/test_spio_decomp_logger.cpp new file mode 100644 index 0000000000..730b3f7c3e --- /dev/null +++ b/tests/cunit/test_spio_decomp_logger.cpp @@ -0,0 +1,634 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pio_config.h" +#include "pio.h" +#include "pio_tests.h" +#include "spio_decomp_logger.hpp" + +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL +#include "gptl.h" +#endif +#endif + +#define LOG_RANK0(rank, ...) \ + do{ \ + if(rank == 0){ \ + fprintf(stderr, __VA_ARGS__); \ + } \ + }while(0); + +static const int FAIL = -1; + +template +bool cmp_result(int wrank, const std::vector &res, const std::vector &exp) +{ + + if(res.size() != exp.size()){ + LOG_RANK0(wrank, "ERROR: The result and expected vectors are of different sizes\n"); + return false; + } + + for(std::size_t i = 0; i < res.size(); i++){ + if(res[i] != exp[i]){ + std::ostringstream oss; + oss << "ERROR: Invalid/Unexpected value, array[ " << i << "] = " << res[i] + << " (Expected array[" << i << "] = " << exp[i] << ")"; + LOG_RANK0(wrank, "ERROR: %s\n", oss.str().c_str()); + return false; + } + } + + return true; +} + +iosystem_desc_t *get_iosystem(MPI_Comm comm, int wrank, int wsz, int nio_procs) +{ + int ret = PIO_NOERR; + static int iosysid = 1; + iosystem_desc_t *ios = (iosystem_desc_t *) calloc(1, sizeof(iosystem_desc_t)); + if(!ios){ + LOG_RANK0(wrank, "Unable to allocate memory for I/O system\n"); + return NULL; + } + + ios->iosysid = iosysid++; + ios->union_comm = comm; + ios->num_uniontasks = wsz; + ios->union_rank = wrank; + /* Every proc is a compute proc */ + ios->comp_comm = comm; + ios->num_comptasks = wsz; + ios->comp_rank = wrank; + ios->compproc = true; + + assert(nio_procs <= wsz); + + /* Assign first nio_procs procs as I/O processes */ + int color = (wrank/nio_procs == 0) ? 0 : 1; + + ret = MPI_Comm_split(comm, color, 0, &(ios->io_comm)); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "Unable to split comm for creating I/O system\n"); + free(ios); + return NULL; + } + + ios->num_iotasks = nio_procs; + ios->ioproc = (color == 0) ? true : false; + if(ios->ioproc){ + ret = MPI_Comm_rank(ios->io_comm, &(ios->io_rank)); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "Unable to get rank of I/O process\n"); + free(ios); + return NULL; + } + } + else{ + ios->io_rank = -1; + } + + return ios; +} + +void free_iosystem(iosystem_desc_t *ios){ + if(!ios){ + return; + } + + MPI_Comm_free(&(ios->io_comm)); + free(ios); +} + +io_desc_t *get_iodesc(int wrank, iosystem_desc_t *ios, const std::vector &compmap, const std::vector &gdimlen) +{ + io_desc_t *iodesc = NULL; + int ret = PIO_NOERR; + + ret = malloc_iodesc(ios, PIO_DOUBLE, static_cast(gdimlen.size()), static_cast(compmap.size()), &iodesc); + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "Unable to alloc mem for I/O desc\n"); + return iodesc; + } + + assert(iodesc->dimlen); + std::copy(gdimlen.cbegin(), gdimlen.cend(), iodesc->dimlen); + + assert(iodesc->map); + std::copy(compmap.cbegin(), compmap.cend(), iodesc->map); + + return iodesc; +} + +int test_create_decomp_logger(MPI_Comm comm, int wrank, int wsz) +{ + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; + iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + if(!ios){ + LOG_RANK0(wrank, "Unable to get I/O system\n"); + return PIO_EINTERNAL; + } + + try{ + std::string log_fname("piodecomplogger_test_01.nc"); + SPIO_Util::Decomp_Util::Decomp_logger *logger = + SPIO_Util::Decomp_Util::create_decomp_logger(ios->comp_comm, log_fname); + if(logger == NULL){ + LOG_RANK0(wrank, "Creating decomp logger failed\n"); + return PIO_EINTERNAL; + } + + delete logger; + } + catch(...){ + LOG_RANK0(wrank, "Creating decomp logger failed\n"); + return PIO_EINTERNAL; + } + + free_iosystem(ios); + return PIO_NOERR; +} + +int test_simple_decomp_logger(MPI_Comm comm, int wrank, int wsz) +{ + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; + iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + if(!ios){ + LOG_RANK0(wrank, "Unable to get I/O system\n"); + return PIO_EINTERNAL; + } + + try{ + std::string log_fname("piodecomplogger_test_simple_01.nc"); + SPIO_Util::Decomp_Util::Decomp_logger *logger = + SPIO_Util::Decomp_Util::create_decomp_logger(ios->comp_comm, log_fname); + if(logger == NULL){ + LOG_RANK0(wrank, "Creating decomp logger failed\n"); + free_iosystem(ios); + return PIO_EINTERNAL; + } + + const int LOCAL_COMPMAP_SZ = 4; + std::vector gdimlen = {LOCAL_COMPMAP_SZ * wsz}; + std::vector compmap(LOCAL_COMPMAP_SZ); + + std::iota(compmap.begin(), compmap.end(), wrank * LOCAL_COMPMAP_SZ); + + io_desc_t *iodesc = get_iodesc(wrank, ios, compmap, gdimlen); + if(iodesc == NULL){ + LOG_RANK0(wrank, "Create I/O descriptor failed\n"); + delete logger; + free_iosystem(ios); + return PIO_EINTERNAL; + } + + (*logger).write_only().open().put(iodesc).close(); + delete logger; + } + catch(...){ + LOG_RANK0(wrank, "Creating decomp logger failed\n"); + free_iosystem(ios); + return PIO_EINTERNAL; + } + + free_iosystem(ios); + return PIO_NOERR; +} + +int test_simple_decomp_logger_wr_cached_rd(MPI_Comm comm, int wrank, int wsz) +{ + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; + iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + if(!ios){ + LOG_RANK0(wrank, "Unable to get I/O system\n"); + return PIO_EINTERNAL; + } + + try{ + std::string log_fname("piodecomplogger_test_simple_01.nc"); + SPIO_Util::Decomp_Util::Decomp_logger *logger = + SPIO_Util::Decomp_Util::create_decomp_logger(ios->comp_comm, log_fname); + if(logger == NULL){ + LOG_RANK0(wrank, "Creating decomp logger failed\n"); + free_iosystem(ios); + return PIO_EINTERNAL; + } + + const int LOCAL_COMPMAP_SZ = 4; + std::vector gdimlen = {LOCAL_COMPMAP_SZ * wsz}; + std::vector compmap(LOCAL_COMPMAP_SZ); + + std::iota(compmap.begin(), compmap.end(), wrank * LOCAL_COMPMAP_SZ); + + io_desc_t *iodesc = get_iodesc(wrank, ios, compmap, gdimlen); + if(iodesc == NULL){ + LOG_RANK0(wrank, "Create I/O descriptor failed\n"); + delete logger; + free_iosystem(ios); + return PIO_EINTERNAL; + } + + (*logger).write_only().open().put(iodesc).close(); + + std::string version; + int rd_nprocs = -1; + std::vector rd_gdims; + std::vector rd_compmap; + + (*logger).get(version, rd_nprocs, rd_gdims, rd_compmap); + if(rd_nprocs != wsz){ + LOG_RANK0(wrank, "Read invalid nprocs (%d) from log file, expected = %d\n", rd_nprocs, wsz); + delete logger; + free_iosystem(ios); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rd_gdims, gdimlen)){ + LOG_RANK0(wrank, "Read invalid gdims from log file\n"); + delete logger; + free_iosystem(ios); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rd_compmap, compmap)){ + LOG_RANK0(wrank, "Read invalid map (local compmap) from log file\n"); + delete logger; + free_iosystem(ios); + return PIO_EINTERNAL; + } + + delete logger; + } + catch(...){ + LOG_RANK0(wrank, "Creating decomp logger failed\n"); + free_iosystem(ios); + return PIO_EINTERNAL; + } + + free_iosystem(ios); + return PIO_NOERR; +} + +int test_simple_decomp_logger_wr_rd(MPI_Comm comm, int wrank, int wsz) +{ + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; + iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + if(!ios){ + LOG_RANK0(wrank, "Unable to get I/O system\n"); + return PIO_EINTERNAL; + } + + try{ + std::string log_fname("piodecomplogger_test_simple_01.nc"); + SPIO_Util::Decomp_Util::Decomp_logger *logger = + SPIO_Util::Decomp_Util::create_decomp_logger(ios->comp_comm, log_fname); + if(logger == NULL){ + LOG_RANK0(wrank, "Creating decomp logger failed\n"); + free_iosystem(ios); + return PIO_EINTERNAL; + } + + const int LOCAL_COMPMAP_SZ = 4; + std::vector gdimlen = {LOCAL_COMPMAP_SZ * wsz}; + std::vector compmap(LOCAL_COMPMAP_SZ); + + std::iota(compmap.begin(), compmap.end(), wrank * LOCAL_COMPMAP_SZ); + + io_desc_t *iodesc = get_iodesc(wrank, ios, compmap, gdimlen); + if(iodesc == NULL){ + LOG_RANK0(wrank, "Create I/O descriptor failed\n"); + delete logger; + free_iosystem(ios); + return PIO_EINTERNAL; + } + + (*logger).write_only().open().put(iodesc).close(); + delete logger; + + logger = + SPIO_Util::Decomp_Util::create_decomp_logger(ios->comp_comm, log_fname); + if(logger == NULL){ + LOG_RANK0(wrank, "Creating decomp logger (for read) failed\n"); + free_iosystem(ios); + return PIO_EINTERNAL; + } + std::string version; + int rd_nprocs = -1; + std::vector rd_gdims; + std::vector rd_compmap; + + (*logger).read_only().open().get(version, rd_nprocs, rd_gdims, rd_compmap).close(); + if(rd_nprocs != wsz){ + LOG_RANK0(wrank, "Read invalid nprocs (%d) from log file, expected = %d\n", rd_nprocs, wsz); + delete logger; + free_iosystem(ios); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rd_gdims, gdimlen)){ + LOG_RANK0(wrank, "Read invalid gdims from log file\n"); + delete logger; + free_iosystem(ios); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rd_compmap, compmap)){ + LOG_RANK0(wrank, "Read invalid map (local compmap) from log file\n"); + delete logger; + free_iosystem(ios); + return PIO_EINTERNAL; + } + + delete logger; + } + catch(std::runtime_error &e){ + LOG_RANK0(wrank, "Creating decomp logger failedi (%s)\n", e.what()); + free_iosystem(ios); + return PIO_EINTERNAL; + } + catch(...){ + LOG_RANK0(wrank, "Creating decomp logger failed\n"); + free_iosystem(ios); + return PIO_EINTERNAL; + } + + free_iosystem(ios); + return PIO_NOERR; +} + +int test_vlen_decomp_logger(MPI_Comm comm, int wrank, int wsz) +{ + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; + iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + if(!ios){ + LOG_RANK0(wrank, "Unable to get I/O system\n"); + return PIO_EINTERNAL; + } + + try{ + std::string log_fname("piodecomplogger_test_vlen_01.nc"); + SPIO_Util::Decomp_Util::Decomp_logger *logger = + SPIO_Util::Decomp_Util::create_decomp_logger(ios->comp_comm, log_fname); + if(logger == NULL){ + LOG_RANK0(wrank, "Creating decomp logger failed\n"); + free_iosystem(ios); + return PIO_EINTERNAL; + } + + const int LOCAL_COMPMAP_SZ = wrank + 1; + std::vector gdimlen = {(wsz * (wsz + 1))/2}; + std::vector compmap(LOCAL_COMPMAP_SZ); + + std::iota(compmap.begin(), compmap.end(), (wrank * (wrank + 1))/2); + + io_desc_t *iodesc = get_iodesc(wrank, ios, compmap, gdimlen); + if(iodesc == NULL){ + LOG_RANK0(wrank, "Create I/O descriptor failed\n"); + delete logger; + free_iosystem(ios); + return PIO_EINTERNAL; + } + + (*logger).write_only().open().put(iodesc).close(); + + delete logger; + + logger = + SPIO_Util::Decomp_Util::create_decomp_logger(ios->comp_comm, log_fname); + if(logger == NULL){ + LOG_RANK0(wrank, "Creating decomp logger (for read) failed\n"); + free_iosystem(ios); + return PIO_EINTERNAL; + } + std::string version; + int rd_nprocs = -1; + std::vector rd_gdims; + std::vector rd_compmap; + + (*logger).read_only().open().get(version, rd_nprocs, rd_gdims, rd_compmap).close(); + if(rd_nprocs != wsz){ + LOG_RANK0(wrank, "Read invalid nprocs (%d) from log file, expected = %d\n", rd_nprocs, wsz); + delete logger; + free_iosystem(ios); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rd_gdims, gdimlen)){ + LOG_RANK0(wrank, "Read invalid gdims from log file\n"); + delete logger; + free_iosystem(ios); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rd_compmap, compmap)){ + LOG_RANK0(wrank, "Read invalid map (local compmap) from log file\n"); + delete logger; + free_iosystem(ios); + return PIO_EINTERNAL; + } + + delete logger; + } + catch(...){ + LOG_RANK0(wrank, "Creating decomp logger failed\n"); + free_iosystem(ios); + return PIO_EINTERNAL; + } + + free_iosystem(ios); + return PIO_NOERR; +} + +int test_rvlen_decomp_logger(MPI_Comm comm, int wrank, int wsz) +{ + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; + iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + if(!ios){ + LOG_RANK0(wrank, "Unable to get I/O system\n"); + return PIO_EINTERNAL; + } + + try{ + std::string log_fname("piodecomplogger_test_rvlen_01.nc"); + SPIO_Util::Decomp_Util::Decomp_logger *logger = + SPIO_Util::Decomp_Util::create_decomp_logger(ios->comp_comm, log_fname); + if(logger == NULL){ + LOG_RANK0(wrank, "Creating decomp logger failed\n"); + free_iosystem(ios); + return PIO_EINTERNAL; + } + + const int LOCAL_COMPMAP_SZ = (wsz - 1 - wrank) + 1; + std::vector gdimlen = {(wsz * (wsz + 1))/2}; + std::vector compmap(LOCAL_COMPMAP_SZ); + + std::iota(compmap.rbegin(), compmap.rend(), ((wsz - 1 - wrank) * (wsz - wrank))/2); + + io_desc_t *iodesc = get_iodesc(wrank, ios, compmap, gdimlen); + if(iodesc == NULL){ + LOG_RANK0(wrank, "Create I/O descriptor failed\n"); + delete logger; + free_iosystem(ios); + return PIO_EINTERNAL; + } + + (*logger).write_only().open().put(iodesc).close(); + + delete logger; + + logger = + SPIO_Util::Decomp_Util::create_decomp_logger(ios->comp_comm, log_fname); + if(logger == NULL){ + LOG_RANK0(wrank, "Creating decomp logger (for read) failed\n"); + free_iosystem(ios); + return PIO_EINTERNAL; + } + std::string version; + int rd_nprocs = -1; + std::vector rd_gdims; + std::vector rd_compmap; + + (*logger).read_only().open().get(version, rd_nprocs, rd_gdims, rd_compmap).close(); + if(rd_nprocs != wsz){ + LOG_RANK0(wrank, "Read invalid nprocs (%d) from log file, expected = %d\n", rd_nprocs, wsz); + delete logger; + free_iosystem(ios); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rd_gdims, gdimlen)){ + LOG_RANK0(wrank, "Read invalid gdims from log file\n"); + delete logger; + free_iosystem(ios); + return PIO_EINTERNAL; + } + + if(!cmp_result(wrank, rd_compmap, compmap)){ + LOG_RANK0(wrank, "Read invalid map (local compmap) from log file\n"); + delete logger; + free_iosystem(ios); + return PIO_EINTERNAL; + } + + delete logger; + } + catch(...){ + LOG_RANK0(wrank, "Creating decomp logger failed\n"); + free_iosystem(ios); + return PIO_EINTERNAL; + } + + free_iosystem(ios); + return PIO_NOERR; +} + +int test_driver(MPI_Comm comm, int wrank, int wsz, int *num_errors) +{ + int nerrs = 0, ret = PIO_NOERR, mpierr = MPI_SUCCESS; + assert((comm != MPI_COMM_NULL) && (wrank >= 0) && (wsz > 0) && num_errors); + + std::vector > > test_funcs = { + {"test_create_decomp_logger", test_create_decomp_logger}, + {"test_simple_decomp_logger", test_simple_decomp_logger}, + {"test_simple_decomp_logger_wr_cached_rd", test_simple_decomp_logger_wr_cached_rd}, + {"test_simple_decomp_logger_wr_rd", test_simple_decomp_logger_wr_rd}, + {"test_vlen_decomp_logger", test_vlen_decomp_logger}, + {"test_rvlen_decomp_logger", test_rvlen_decomp_logger} + }; + + for(std::size_t tid = 0; tid < test_funcs.size(); tid++){ + try{ + ret = test_funcs[tid].second(comm, wrank, wsz); + } + catch(...){ + ret = PIO_EINTERNAL; + nerrs++; + } + int lfail = (ret == PIO_NOERR) ? 0 : 1; + mpierr = MPI_Reduce(&lfail, &ret, 1, MPI_INT, MPI_SUM, 0, comm); + if(mpierr != MPI_SUCCESS){ + LOG_RANK0(wrank, "Test Driver failed: Unable to calculate total num errors\n"); + } + if(ret != 0){ + std::string non_root_fail_msg = std::string(", failed on ") + std::to_string(ret) + std::string(" non-root processes"); + LOG_RANK0(wrank, "%s() FAILED (ret = %d%s)\n", test_funcs[tid].first.c_str(), ret, (lfail) ? "" : non_root_fail_msg.c_str()); + nerrs++; + } + else{ + LOG_RANK0(wrank, "%s() PASSED\n", test_funcs[tid].first.c_str()); + } + } + + *num_errors += nerrs; + return nerrs; +} + +int main(int argc, char *argv[]) +{ + int ret; + int wrank, wsz; + int num_errors; +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL + ret = GPTLinitialize(); + if(ret != 0){ + LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + + ret = MPI_Init(&argc, &argv); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Init() FAILED, ret = %d\n", ret); + return ret; + } + + ret = MPI_Comm_rank(MPI_COMM_WORLD, &wrank); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); + return ret; + } + ret = MPI_Comm_size(MPI_COMM_WORLD, &wsz); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); + return ret; + } + + num_errors = 0; + ret = test_driver(MPI_COMM_WORLD, wrank, wsz, &num_errors); + if(ret != 0){ + LOG_RANK0(wrank, "Test driver FAILED\n"); + return FAIL; + } + else{ + LOG_RANK0(wrank, "All tests PASSED\n"); + } + + MPI_Finalize(); + +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL + ret = GPTLfinalize(); + if(ret != 0){ + LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + + if(num_errors != 0){ + LOG_RANK0(wrank, "Total errors = %d\n", num_errors); + return FAIL; + } + return 0; +} From 0887f2ecf0922cee6ac070f1c47fee69d9fe21f9 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 3 Feb 2025 23:47:01 -0600 Subject: [PATCH 050/194] Adding decomp logger class to dump I/O decomps For now the logger class works along side the old method to log decomps to text files (I/O decompositions are dumped into NetCDF and text files). Text based decompositions are read with old method while decomps in NetCDF files are read using the new class --- src/clib/pio_darray.cpp | 6 ++++ src/clib/pioc.cpp | 8 +++++ src/clib/pioc_support.cpp | 71 ++++++++++++++++++++++++++++++++------- 3 files changed, 72 insertions(+), 13 deletions(-) diff --git a/src/clib/pio_darray.cpp b/src/clib/pio_darray.cpp index 2c46daa1e1..ba02580084 100644 --- a/src/clib/pio_darray.cpp +++ b/src/clib/pio_darray.cpp @@ -22,6 +22,7 @@ #include "spio_ltimer_utils.hpp" #include "pio_rearr_contig.hpp" #include "spio_decomp_map_info_pool.hpp" +#include "spio_decomp_logger.hpp" /* uint64_t definition */ #ifdef _ADIOS2 @@ -2088,6 +2089,11 @@ int PIOc_write_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, c } LOG((2, "Saving decomp map (write) to %s", filename)); PIOc_writemap_impl(filename, ioid, iodesc->ndims, iodesc->dimlen, iodesc->maplen, iodesc->map, ios->my_comm); + char log_fname[PIO_MAX_NAME]; + ierr = pio_create_uniq_str(ios, iodesc, log_fname, PIO_MAX_NAME, "piodecomp", ".nc"); + SPIO_Util::Decomp_Util::Decomp_logger *logger = SPIO_Util::Decomp_Util::create_decomp_logger(ios->comp_comm, std::string(log_fname)); + (*logger).write_only().open().put(iodesc).close(); + delete logger; iodesc->is_saved = true; SPIO_Util::Decomp_Util::gdpool_mgr.get_decomp_map_info_pool()->add_decomp_map_info(ioid, filename); } diff --git a/src/clib/pioc.cpp b/src/clib/pioc.cpp index 292af9035d..a76f8bec7e 100644 --- a/src/clib/pioc.cpp +++ b/src/clib/pioc.cpp @@ -23,6 +23,7 @@ #include "pio_rearr_contig.hpp" #include "spio_dbg_utils.hpp" #include "spio_decomp_map_info_pool.hpp" +#include "spio_decomp_logger.hpp" /* Include headers for HDF5 compression filters */ #if PIO_USE_HDF5 @@ -1033,6 +1034,13 @@ static int initdecomp(int iosysid, int pio_type, int ndims, const int *gdimlen, } LOG((2, "Saving decomp map to %s", filename)); PIOc_writemap_impl(filename, *ioidp, ndims, gdimlen, maplen, (PIO_Offset *)compmap, ios->my_comm); + + char log_fname[PIO_MAX_NAME]; + ierr = pio_create_uniq_str(ios, iodesc, log_fname, PIO_MAX_NAME, "piodecomp", ".nc"); + SPIO_Util::Decomp_Util::Decomp_logger *logger = SPIO_Util::Decomp_Util::create_decomp_logger(ios->comp_comm, std::string(log_fname)); + (*logger).write_only().open().put(iodesc).close(); + delete logger; + iodesc->is_saved = true; SPIO_Util::Decomp_Util::gdpool_mgr.get_decomp_map_info_pool()->add_decomp_map_info(*ioidp, filename); diff --git a/src/clib/pioc_support.cpp b/src/clib/pioc_support.cpp index 3a62af45d5..c1b21f47a1 100644 --- a/src/clib/pioc_support.cpp +++ b/src/clib/pioc_support.cpp @@ -26,6 +26,11 @@ #include "spio_file_mvcache.h" #include "spio_hash.h" #include "pio_rearr_contig.hpp" +#include "spio_decomp_logger.hpp" +#include +#include +#include +#include /* Include headers for HDF5 compression filters */ #if PIO_USE_HDF5 @@ -1885,19 +1890,7 @@ int PIOc_freedecomp_impl(int iosysid, int ioid) return ret; } -/** - * Read a decomposition map from a file. The decomp file is only read - * by task 0 in the communicator. - * - * @param file the filename - * @param ndims pointer to an int with the number of dims. - * @param gdims pointer to an array of dimension ids. - * @param fmaplen - * @param map - * @param comm - * @returns 0 for success, error code otherwise. - */ -int PIOc_readmap_impl(const char *file, int *ndims, int **gdims, PIO_Offset *fmaplen, +int PIOc_readmap_txt_impl(const char *file, int *ndims, int **gdims, PIO_Offset *fmaplen, PIO_Offset **map, MPI_Comm comm) { int npes, myrank; @@ -2030,6 +2023,58 @@ int PIOc_readmap_impl(const char *file, int *ndims, int **gdims, PIO_Offset *fma return PIO_NOERR; } +/** + * Read a decomposition map from a file. The decomp file is only read + * by task 0 in the communicator. + * + * @param file the filename + * @param ndims pointer to an int with the number of dims. + * @param gdims pointer to an array of dimension ids. + * @param fmaplen + * @param map + * @param comm + * @returns 0 for success, error code otherwise. + */ +int PIOc_readmap_impl(const char *file, int *ndims, int **gdims, PIO_Offset *fmaplen, + PIO_Offset **map, MPI_Comm comm) +{ + if(!file || !ndims || !gdims || !fmaplen || !map){ + return pio_err(NULL, NULL, PIO_EINVAL, __FILE__, __LINE__, + "Reading I/O decomposition failed. Invalid arguments provided, file is %s (expected not NULL), ndims is %s (expected not NULL), gdims is %s (expected not NULL), fmaplen is %s (expected not NULL), map is %s (expected not NULL)", PIO_IS_NULL(file), PIO_IS_NULL(ndims), PIO_IS_NULL(gdims), PIO_IS_NULL(fmaplen), PIO_IS_NULL(map)); + } + + std::string log_fname(file); + SPIO_Util::Decomp_Util::Decomp_logger *logger = + SPIO_Util::Decomp_Util::create_decomp_logger(comm, log_fname); + if(typeid(*logger) == typeid(SPIO_Util::Decomp_Util::Decomp_txt_logger)){ + delete logger; + return PIOc_readmap_txt_impl(file, ndims, gdims, fmaplen, map, comm); + } + + std::string version; + int nprocs; + std::vector rd_gdims; + std::vector rd_compmap; + + (*logger).read_only().open().get(version, nprocs, rd_gdims, rd_compmap).close(); + + *ndims = static_cast(rd_gdims.size()); + *gdims = (int *) malloc(*ndims * sizeof(int)); + if(*gdims == NULL){ + return pio_err(NULL, NULL, PIO_ENOMEM, __FILE__, __LINE__, "Unable to allocate (%lld bytes) to store gdims while reading decomposition file (%s)", static_cast(*ndims * sizeof(int)), log_fname.c_str()); + } + std::copy(rd_gdims.cbegin(), rd_gdims.cend(), *gdims); + *fmaplen = static_cast(rd_compmap.size()); + *map = (PIO_Offset *) malloc(*fmaplen * sizeof(PIO_Offset)); + if(*map == NULL){ + return pio_err(NULL, NULL, PIO_ENOMEM, __FILE__, __LINE__, "Unable to allocate (%lld bytes) to store gmap while reading decomposition file (%s)", static_cast(*fmaplen * sizeof(PIO_Offset)), log_fname.c_str()); + } + std::copy(rd_compmap.cbegin(), rd_compmap.cend(), *map); + + delete logger; + return PIO_NOERR; +} + /** * Read a decomposition map from file. * From 596add1285cd34b361743163a1f5aa15f745fdb3 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 19 Feb 2025 14:40:28 -0600 Subject: [PATCH 051/194] Support logging map regions Adding support for logging map regions instead of the entire I/O decomp map. Using map regions for logging helps with reducing the size of the saved data for some maps. Although we are now including both the map (entire map) and the map region info, we will eventually decide at runtime on how to record maps. --- src/clib/spio_decomp_logger.hpp | 9 +- src/clib/spio_decomp_nc_logger.cpp | 214 +++++++++++++++++++++++++++-- 2 files changed, 214 insertions(+), 9 deletions(-) diff --git a/src/clib/spio_decomp_logger.hpp b/src/clib/spio_decomp_logger.hpp index 0a65accdfe..ffb0198e92 100644 --- a/src/clib/spio_decomp_logger.hpp +++ b/src/clib/spio_decomp_logger.hpp @@ -119,7 +119,7 @@ namespace SPIO_Util{ class Decomp_nc_logger : public Decomp_logger{ public: - Decomp_nc_logger(MPI_Comm comm, MPI_Comm io_comm, MPI_Comm agg_comm, std::string log_fname) : Decomp_logger(comm, io_comm, agg_comm, log_fname), ncid_(INVALID_ID), comm_sz_dimid_(INVALID_ID), info_cached_(false), version_att_name_("version"), nprocs_att_name_("nprocs"), ndims_att_name_("ndims"), gdimlen_att_name_("gdimlen"), comm_sz_dim_name_("comm_sz"), counts_var_name_("counts"), gmaplen_dim_name_("gmaplen"), gmap_var_name_("gmap"), ioid_att_name_("ioid"), nprocs_(0){ + Decomp_nc_logger(MPI_Comm comm, MPI_Comm io_comm, MPI_Comm agg_comm, std::string log_fname) : Decomp_logger(comm, io_comm, agg_comm, log_fname), ncid_(INVALID_ID), comm_sz_dimid_(INVALID_ID), info_cached_(false), version_att_name_("version"), nprocs_att_name_("nprocs"), ndims_att_name_("ndims"), gdimlen_att_name_("gdimlen"), comm_sz_dim_name_("comm_sz"), counts_var_name_("counts"), nregions_var_name_("nregions"), gmaplen_dim_name_("gmaplen"), gmap_var_name_("gmap"), gmap_nregions_dim_name_("gmap_nregions"), gmap_regions_var_name_("gmap_regions"), ioid_att_name_("ioid"), nprocs_(0){ } virtual Decomp_logger &open(void ); @@ -149,14 +149,21 @@ namespace SPIO_Util{ std::vector lcompmap_; const std::string comm_sz_dim_name_; const std::string counts_var_name_; + const std::string nregions_var_name_; const std::string gmaplen_dim_name_; const std::string gmap_var_name_; + const std::string gmap_nregions_dim_name_; + const std::string gmap_regions_var_name_; const std::string ioid_att_name_; int nprocs_; void gather_starts_counts(std::vector &agg_starts, std::vector &agg_counts, MPI_Offset &agg_io_chunk_sz, io_desc_t *iodesc); + void gather_nregions_starts_counts(std::vector &agg_nregions_starts, std::vector &agg_nregions_counts, MPI_Offset &agg_nregions, const std::vector &lregions); void gather_gmap(const std::vector &starts, const std::vector &counts, std::vector &gmap_chunk, io_desc_t *iodesc); + void gather_gmap_regions(const std::vector &starts, const std::vector &counts, std::vector &gmap_regions, const std::vector &lregions); void read_and_cache_info(void ); + void get_contig_map_regions(std::vector &lregions, io_desc_t *iodesc); + void get_map_from_regions(std::vector &lregions, std::vector &lcompmap); }; inline Decomp_logger *create_decomp_logger(MPI_Comm comm, MPI_Comm io_comm, MPI_Comm agg_comm, std::string log_fname){ diff --git a/src/clib/spio_decomp_nc_logger.cpp b/src/clib/spio_decomp_nc_logger.cpp index 1c33b55e53..8480ca1269 100644 --- a/src/clib/spio_decomp_nc_logger.cpp +++ b/src/clib/spio_decomp_nc_logger.cpp @@ -1,4 +1,5 @@ #include "spio_decomp_logger.hpp" +#include "spio_dbg_utils.hpp" #include #include #include @@ -137,7 +138,9 @@ void SPIO_Util::Decomp_Util::Decomp_nc_logger::read_and_cache_info(void ) MPI_Offset version_len = 0; int ndims = 0; std::vector agg_counts(agg_comm_sz_, 0); + std::vector agg_nregions(agg_comm_sz_, 0); std::vector agg_gmap_chunk; + std::vector agg_gmap_regions; if(is_io_proc_){ assert(ncid_ != INVALID_ID); @@ -178,15 +181,31 @@ void SPIO_Util::Decomp_Util::Decomp_nc_logger::read_and_cache_info(void ) throw std::runtime_error(std::string("Reading counts array from decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); } + ret = ncmpi_inq_varid(ncid_, nregions_var_name_.c_str(), &tmp_varid); + if(ret == NC_NOERR){ + ret = ncmpi_get_vara_int_all(ncid_, tmp_varid, &start_var, &count_var, agg_nregions.data()); + } + if(ret != NC_NOERR){ + throw std::runtime_error(std::string("Reading nregions array from decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); + } + MPI_Offset agg_io_chunk_sz = 0; + MPI_Offset tot_agg_nregions = 0; for(std::size_t i = 0; i < agg_counts.size(); i++){ agg_io_chunk_sz += agg_counts[i]; + tot_agg_nregions += agg_nregions[i]; } - MPI_Offset agg_io_chunk_start = agg_io_chunk_sz; - ret = MPI_Exscan(MPI_IN_PLACE, &agg_io_chunk_start, 1, MPI_OFFSET, MPI_SUM, io_comm_); assert(ret == MPI_SUCCESS); - if(io_comm_rank_ == 0){ - agg_io_chunk_start = 0; + //MPI_Offset agg_io_chunk_start = agg_io_chunk_sz; + std::vector agg_info_start = {agg_io_chunk_sz, tot_agg_nregions}; + ret = MPI_Exscan(MPI_IN_PLACE, agg_info_start.data(), + static_cast(agg_info_start.size()), MPI_OFFSET, + MPI_SUM, io_comm_); assert(ret == MPI_SUCCESS); + MPI_Offset agg_io_chunk_start = 0; + MPI_Offset agg_regions_start = 0; + if(io_comm_rank_ != 0){ + agg_io_chunk_start = agg_info_start[0]; + agg_regions_start = agg_info_start[1]; } agg_gmap_chunk.resize(agg_io_chunk_sz); @@ -198,6 +217,16 @@ void SPIO_Util::Decomp_Util::Decomp_nc_logger::read_and_cache_info(void ) if(ret != NC_NOERR){ throw std::runtime_error(std::string("Reading gmap array from decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); } + + agg_gmap_regions.resize(tot_agg_nregions); + ret = ncmpi_inq_varid(ncid_, gmap_regions_var_name_.c_str(), &tmp_varid); + if(ret == NC_NOERR){ + ret = ncmpi_get_vara_longlong_all(ncid_, tmp_varid, &agg_regions_start, + &tot_agg_nregions, agg_gmap_regions.data()); + } + if(ret != NC_NOERR){ + throw std::runtime_error(std::string("Reading gmap (sc format) array from decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); + } } ret = MPI_Bcast(&version_len, 1, MPI_OFFSET, 0, agg_comm_); assert(ret == MPI_SUCCESS); @@ -227,6 +256,33 @@ void SPIO_Util::Decomp_Util::Decomp_nc_logger::read_and_cache_info(void ) ret = MPI_Scatterv(agg_gmap_chunk.data(), agg_counts.data(), agg_starts.data(), MPI_OFFSET, lcompmap_.data(), lcompmap_sz, MPI_OFFSET, 0, agg_comm_); assert(ret == MPI_SUCCESS); + int lcompmap_nregions = 0; + ret = MPI_Scatter(agg_nregions.data(), 1, MPI_INT, &lcompmap_nregions, 1, MPI_INT, 0, agg_comm_); assert(ret == MPI_SUCCESS); + + std::vector lcompmap_regions; + lcompmap_regions.resize(lcompmap_nregions); + std::vector lcompmap_region_starts(agg_nregions.size()); + cur_start = 0; + for(std::size_t i = 0; i < agg_nregions.size(); i++){ + lcompmap_region_starts[i] = cur_start; + cur_start += agg_nregions[i]; + } + ret = MPI_Scatterv(agg_gmap_regions.data(), agg_nregions.data(), + lcompmap_region_starts.data(), MPI_OFFSET, + lcompmap_regions.data(), lcompmap_nregions, MPI_OFFSET, + 0, agg_comm_); assert(ret == MPI_SUCCESS); + + std::vector lcompmap; + + get_map_from_regions(lcompmap_regions, lcompmap); + + assert(lcompmap.size() == lcompmap_.size()); + for(std::size_t i = 0; i < lcompmap_.size(); i++){ + assert(lcompmap[i] == lcompmap_[i]); + } + + //SPIO_Util::Dbg_Util::print_1dvec(lcompmap); + info_cached_ = true; #endif @@ -247,7 +303,10 @@ SPIO_Util::Decomp_Util::Decomp_logger &SPIO_Util::Decomp_Util::Decomp_nc_logger: info_cached_ = true; std::vector agg_starts, agg_counts; + std::vector agg_nregions_starts, agg_nregions_counts; MPI_Offset agg_io_chunk_sz = 0; + MPI_Offset agg_nregions = 0; + std::vector lregions; /* Aggregation of local map lengths & map happens in agg_comm_, the * data is written out to the file using io_comm_. Each rank 0 proc in @@ -263,14 +322,23 @@ SPIO_Util::Decomp_Util::Decomp_logger &SPIO_Util::Decomp_Util::Decomp_nc_logger: agg_counts.resize(agg_comm_sz_); gather_starts_counts(agg_starts, agg_counts, agg_io_chunk_sz, iodesc); + agg_nregions_starts.resize(agg_comm_sz_); + agg_nregions_counts.resize(agg_comm_sz_); + get_contig_map_regions(lregions, iodesc); + gather_nregions_starts_counts(agg_nregions_starts, agg_nregions_counts, agg_nregions, lregions); + std::vector gmap_chunk; + std::vector gmap_regions; if(is_io_proc_){ gmap_chunk.resize(agg_io_chunk_sz); + gmap_regions.resize(agg_nregions); } /* Gather the local compmaps from compute procs to the I/O processes */ gather_gmap(agg_starts, agg_counts, gmap_chunk, iodesc); + gather_gmap_regions(agg_nregions_starts, agg_nregions_counts, gmap_regions, lregions); + if(!is_io_proc_){ return *this; } @@ -279,14 +347,20 @@ SPIO_Util::Decomp_Util::Decomp_logger &SPIO_Util::Decomp_Util::Decomp_nc_logger: MPI_Offset agg_io_chunk_count = agg_io_chunk_sz; /* Find starts/Displacements for "counts" var and "gmap" var among I/O processes */ - std::array starts_for_counts_and_gmap = { static_cast(agg_comm_sz_), agg_io_chunk_count }; + std::array starts_for_counts_and_gmap = { static_cast(agg_comm_sz_), agg_io_chunk_count, agg_nregions }; ret = MPI_Exscan(MPI_IN_PLACE, starts_for_counts_and_gmap.data(), starts_for_counts_and_gmap.size(), MPI_OFFSET, MPI_SUM, io_comm_); assert(ret == MPI_SUCCESS); if(io_comm_rank_ == 0){ - starts_for_counts_and_gmap = {0, 0}; + starts_for_counts_and_gmap = {0, 0, 0}; } - MPI_Offset gmaplen = 0; - ret = MPI_Allreduce(&agg_io_chunk_count, &gmaplen, 1, MPI_OFFSET, MPI_SUM, io_comm_); assert(ret == MPI_SUCCESS); + std::vector gmap_lsizes = {agg_io_chunk_sz, agg_nregions}; + std::vector gmap_gsizes = {0, 0}; + ret = MPI_Allreduce(gmap_lsizes.data(), gmap_gsizes.data(), + static_cast(gmap_lsizes.size()), MPI_OFFSET, + MPI_SUM, io_comm_); assert(ret == MPI_SUCCESS); + + MPI_Offset gmaplen = gmap_gsizes[0]; + MPI_Offset gmap_nregions = gmap_gsizes[1]; assert(ncid_ != INVALID_ID); @@ -311,23 +385,41 @@ SPIO_Util::Decomp_Util::Decomp_logger &SPIO_Util::Decomp_Util::Decomp_nc_logger: int counts_varid = INVALID_ID; int gmaplen_dimid = INVALID_ID; int gmap_varid = INVALID_ID; + int nregions_varid = INVALID_ID; + int gmap_nregions_dimid = INVALID_ID; + int gmap_regions_varid = INVALID_ID; ret = ncmpi_def_var(ncid_, counts_var_name_.c_str(), NC_INT, 1, &comm_sz_dimid_, &counts_varid); if(ret != NC_NOERR){ throw std::runtime_error(std::string("Defining counts var in decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); } + ret = ncmpi_def_var(ncid_, nregions_var_name_.c_str(), NC_INT, 1, &comm_sz_dimid_, &nregions_varid); + if(ret != NC_NOERR){ + throw std::runtime_error(std::string("Defining nregions var in decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); + } + ret = ncmpi_def_dim(ncid_, gmaplen_dim_name_.c_str(), gmaplen, &gmaplen_dimid); if(ret != NC_NOERR){ throw std::runtime_error(std::string("Defining gmaplen dimension, size = ") + std::to_string(static_cast(gmaplen)) + std::string(", in decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); } + ret = ncmpi_def_dim(ncid_, gmap_nregions_dim_name_.c_str(), gmap_nregions, &gmap_nregions_dimid); + if(ret != NC_NOERR){ + throw std::runtime_error(std::string("Defining gmap_nregions dimension, size = ") + std::to_string(static_cast(gmaplen)) + std::string(", in decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); + } + /* The global compmap */ ret = ncmpi_def_var(ncid_, gmap_var_name_.c_str(), NC_INT64, 1, &gmaplen_dimid, &gmap_varid); if(ret != NC_NOERR){ throw std::runtime_error(std::string("Defining var to store global compmap in decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); } + ret = ncmpi_def_var(ncid_, gmap_regions_var_name_.c_str(), NC_INT64, 1, &gmap_nregions_dimid, &gmap_regions_varid); + if(ret != NC_NOERR){ + throw std::runtime_error(std::string("Defining var to store global compmap regions in decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); + } + ret = ncmpi_enddef(ncid_); if(ret != NC_NOERR){ throw std::runtime_error(std::string("Ending redefine mode for decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); @@ -343,6 +435,15 @@ SPIO_Util::Decomp_Util::Decomp_logger &SPIO_Util::Decomp_Util::Decomp_nc_logger: throw std::runtime_error(std::string("Writing gmap process counts to decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); } + MPI_Offset nregions_start = starts_for_counts_and_gmap[0]; + MPI_Offset nregions_count = agg_comm_sz_; + assert((nregions_start < static_cast(comm_sz_)) && + (nregions_count == static_cast(agg_counts.size()))); + ret = ncmpi_iput_vara_int(ncid_, nregions_varid, &nregions_start, &nregions_count, agg_nregions_counts.data(), NULL); + if(ret != NC_NOERR){ + throw std::runtime_error(std::string("Writing gmap nregions per process to decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); + } + MPI_Offset agg_io_chunk_start = starts_for_counts_and_gmap[1]; assert((agg_io_chunk_start < gmaplen) && (agg_io_chunk_start + agg_io_chunk_count <= gmaplen)); /* Write compmap */ @@ -351,6 +452,14 @@ SPIO_Util::Decomp_Util::Decomp_logger &SPIO_Util::Decomp_Util::Decomp_nc_logger: throw std::runtime_error(std::string("Writing gmap to decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); } + MPI_Offset agg_nregions_start = starts_for_counts_and_gmap[2]; + assert((agg_nregions_start < gmap_nregions) && (agg_nregions_start + agg_nregions <= gmap_nregions)); + /* Write compmap */ + ret = ncmpi_iput_vara_longlong(ncid_, gmap_regions_varid, &agg_nregions_start, &agg_nregions, gmap_regions.data(), NULL); + if(ret != NC_NOERR){ + throw std::runtime_error(std::string("Writing gmap (sc format) to decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); + } + ret = ncmpi_wait_all(ncid_, NC_REQ_ALL, NULL, NULL); if(ret != NC_NOERR){ throw std::runtime_error(std::string("Waiting on writes of gmap/counts arrays to decomp log file, \"") + log_fname_ + std::string("\", failed, ierr =") + std::to_string(ret) + std::string(" ( ") + std::string(ncmpi_strerror(ret)) + std::string(")")); @@ -379,6 +488,84 @@ void SPIO_Util::Decomp_Util::Decomp_nc_logger::gather_starts_counts(std::vector< } } +/* The contiguous regions in iodesc->map[] are stored in sets of {start, count} in the + * lregions array + * e.g. iodesc->map[] = {3,4,5,8,11,12} => lregions.size = starts/counts for 3 regions + * lregions = {3, 3, 8, 1, 11, 2} + */ +void SPIO_Util::Decomp_Util::Decomp_nc_logger::get_contig_map_regions(std::vector &lregions, io_desc_t *iodesc) +{ + assert(iodesc && (lregions.size() == 0)); + + PIO_Offset prev_map_val = 0; + for(int i = 0; i < iodesc->maplen; i++){ + if(lregions.size() > 0){ + if(iodesc->map[i] == prev_map_val + 1){ + /* Update region : count */ + lregions.back() += 1; + } + else if((iodesc->map[i] == 0) && (prev_map_val == 0)){ + /* Update region : count */ + lregions.back() += 1; + } + else{ + /* Add new region : start & count */ + lregions.push_back(iodesc->map[i]); + lregions.push_back(1); + } + } + else{ + /* Add first region : start & count */ + lregions.push_back(iodesc->map[i]); + lregions.push_back(1); + } + prev_map_val = iodesc->map[i]; + } +} + +void SPIO_Util::Decomp_Util::Decomp_nc_logger::get_map_from_regions(std::vector &lregions, std::vector &lcompmap) +{ + assert(lregions.size() % 2 == 0); + for(std::size_t i = 0; i < lregions.size(); i += 2){ + PIO_Offset start = lregions[i]; + PIO_Offset count = lregions[i + 1]; + if(start != 0){ + std::generate_n(std::back_inserter(lcompmap), count, [&start] () mutable { return start++; }); + } + else{ + std::fill_n(std::back_inserter(lcompmap), count, 0); + } + } +} + +/* Get the starts/counts required to write the "nregions" variable from each I/O proc */ +void SPIO_Util::Decomp_Util::Decomp_nc_logger::gather_nregions_starts_counts(std::vector &agg_nregions_starts, std::vector &agg_nregions_counts, MPI_Offset &agg_nregions, const std::vector &lregions) +{ + int ret = MPI_SUCCESS; + + assert(agg_comm_sz_ > 0); + assert(lregions.size() % 2 == 0); + + if(is_io_proc_){ + assert(agg_nregions_starts.size() == agg_comm_sz_); + assert(agg_nregions_counts.size() == agg_comm_sz_); + } + + agg_nregions = 0; + + /* lnregions = Number of region infos local to this compute proc, each region info is a {start, count} pair */ + int lnregions = static_cast(lregions.size()); + + ret = MPI_Gather(&lnregions, 1, MPI_INT, agg_nregions_counts.data(), 1, MPI_INT, 0, agg_comm_); assert(ret == MPI_SUCCESS); + + int cur_start = 0; + for(std::size_t i = 0; i < agg_nregions_starts.size(); i++){ + agg_nregions_starts[i] = cur_start; + cur_start += agg_nregions_counts[i]; + agg_nregions += static_cast(agg_nregions_counts[i]); + } +} + void SPIO_Util::Decomp_Util::Decomp_nc_logger::gather_gmap(const std::vector &starts, const std::vector &counts, std::vector &gmap_chunk, io_desc_t *iodesc) { int ret = MPI_SUCCESS; @@ -390,6 +577,17 @@ void SPIO_Util::Decomp_Util::Decomp_nc_logger::gather_gmap(const std::vector &starts, const std::vector &counts, std::vector &gmap_regions, const std::vector &lregions) +{ + int ret = MPI_SUCCESS; + + assert((agg_comm_rank_ != 0) || ((gmap_regions.size() > 0) && (counts.size() > 0) && (starts.size() > 0))); + + ret = MPI_Gatherv(static_cast(lregions.data()), static_cast(lregions.size()), + MPI_OFFSET, gmap_regions.data(), + counts.data(), starts.data(), MPI_OFFSET, 0, agg_comm_); assert(ret == MPI_SUCCESS); +} + void SPIO_Util::Decomp_Util::Decomp_nc_logger::close(void ) { int ret = MPI_SUCCESS; From d2bcbba91e70d8b7ea7266864baef17b3bdacf78 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 4 Mar 2025 21:18:15 -0600 Subject: [PATCH 052/194] Adding missing pio_internal.h hdr pio_internal.h is required for sources that use the GPTL functions (GPTL[start|stop]). Adding missing header file. Without the fix the build of the conversion tool fails when timing is turned off (gptl_skel.h contains the no-op defns for the GPTL functions) Also see #7e360e3320fe7251e0ee4de7fdc330648dc85c0a --- tools/adios2pio-nm/adios2pio-nm.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/adios2pio-nm/adios2pio-nm.cxx b/tools/adios2pio-nm/adios2pio-nm.cxx index d8c30c9b2a..d4cb4e19e7 100644 --- a/tools/adios2pio-nm/adios2pio-nm.cxx +++ b/tools/adios2pio-nm/adios2pio-nm.cxx @@ -4,6 +4,7 @@ #endif #include #include +#include "pio_internal.h" #include "adios2pio-nm-lib.h" #include "argparser.h" From 71700b391ec8a0f71720e99a131d3978fa3f4085 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 5 Mar 2025 12:23:30 -0600 Subject: [PATCH 053/194] Adding some GPTL timers in contig rearr Adding some GPTL timers in the contig rearranger functions --- src/clib/pio_rearr_contig.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/clib/pio_rearr_contig.cpp b/src/clib/pio_rearr_contig.cpp index 2a69d73e08..a698e6b474 100644 --- a/src/clib/pio_rearr_contig.cpp +++ b/src/clib/pio_rearr_contig.cpp @@ -10,6 +10,7 @@ #include "pio_rearr_contig.hpp" #include "pio_rearr_utils.hpp" #include "spio_dbg_utils.hpp" +#include "spio_gptl_utils.hpp" namespace SPIO_Util{ template @@ -53,6 +54,8 @@ int SPIO::DataRearr::Contig_rearr::init(int pio_type, const int *gdimlen, int ndims, io_desc_t *iodesc) { int ret = PIO_NOERR; + SPIO_Util::GPTL_Util::GPTL_wrapper contig_init_timer("PIO:Contig_rearr::init"); + assert(ios_); assert(ndims > 0); @@ -324,6 +327,8 @@ int SPIO::DataRearr::Contig_rearr::aggregate_data(const void *sbuf, std::size_t void *abuf, std::size_t abuf_sz, int nvars) { int ret = PIO_NOERR; + SPIO_Util::GPTL_Util::GPTL_wrapper contig_agg_timer("PIO:Contig_rearr::aggregate_data"); + assert(is_init_); /* Gather data from compute processes in this aggregating comm to the aggregating/IO process */ @@ -409,6 +414,8 @@ int SPIO::DataRearr::Contig_rearr::disperse_data(const void *abuf, std::size_t a void *rbuf, std::size_t rbuf_sz, int nvars) { int ret = PIO_NOERR; + SPIO_Util::GPTL_Util::GPTL_wrapper contig_dis_timer("PIO:Contig_rearr::disperse_data"); + assert(is_init_); /* When scattering/dispersing data from aggregate process to compute processes, @@ -608,6 +615,7 @@ int SPIO::DataRearr::Contig_rearr::aggregate_compmap(const PIO_Offset *lcompmap, std::vector &gcompmap_displs) { int ret = PIO_NOERR; + SPIO_Util::GPTL_Util::GPTL_wrapper ftimer("PIO:Contig_rearr::aggregate_compmap"); assert(ios_ && (agg_comm_ != MPI_COMM_NULL)); /* Get the compmap sizes from all procs in this aggregation comm */ @@ -728,6 +736,7 @@ int SPIO::DataRearr::Contig_rearr::setup_data_agg_info(const PIO_Offset *lcompma const std::vector &to_proc) { int ret = PIO_NOERR; + SPIO_Util::GPTL_Util::GPTL_wrapper ftimer("PIO:Contig_rearr::setup_data_agg_info"); assert(ios_); /* Setup gather scatter info for sending/receiving data from compute procs to @@ -763,6 +772,7 @@ int SPIO::DataRearr::Contig_rearr::setup_data_agg_info(const PIO_Offset *lcompma std::vector gcompmap_idx(gcompmap.size()); std::iota(gcompmap_idx.begin(), gcompmap_idx.end(), 0); + GPTLstart("PIO:Contig_rearr::setup_data_agg_info::sort"); std::sort(gcompmap_idx.begin(), gcompmap_idx.end(), [&gcompmap,&to_proc](PIO_Offset a, PIO_Offset b){ if(to_proc[a] == to_proc[b]){ @@ -774,6 +784,7 @@ int SPIO::DataRearr::Contig_rearr::setup_data_agg_info(const PIO_Offset *lcompma return to_proc[a] < to_proc[b]; } }); + GPTLstop("PIO:Contig_rearr::setup_data_agg_info::sort"); /* Aggregate compmap sorter can be used to sort any user data based on gcompmap */ agg_compmap_sorter_.resize(gcompmap.size()); @@ -832,6 +843,7 @@ int SPIO::DataRearr::Contig_rearr::init_agg_recv_types(const std::vector &g const std::vector &compmap_sorter) { int ret = PIO_NOERR; + SPIO_Util::GPTL_Util::GPTL_wrapper ftimer("PIO:Contig_rearr::init_agg_recv_types"); /* The compmap_sorter has the indices of the sorted data (based on to_proc & compmap) * So look for contiguous ranges in compmap_sorter array * We need to receive data in the aggregating process such that all data being sent @@ -1009,6 +1021,7 @@ int SPIO::DataRearr::Contig_rearr::setup_data_rearr_info(std::vector const int *gdimlen, int ndims) { int ret = PIO_NOERR; + SPIO_Util::GPTL_Util::GPTL_wrapper ftimer("PIO:Contig_rearr::setup_data_rearr_info"); assert(ios_); if(!ios_->ioproc){ @@ -1140,6 +1153,7 @@ int SPIO::DataRearr::Contig_rearr::init_rearr_send_types( const std::vector &displs_counts_sent) { int ret = PIO_NOERR; + SPIO_Util::GPTL_Util::GPTL_wrapper ftimer("PIO:Contig_rearr::init_rearr_send_types"); assert(ios_ && ios_->ioproc); assert(rearr_comm_sz_ > 0); @@ -1200,6 +1214,7 @@ int SPIO::DataRearr::Contig_rearr::init_rearr_recvd_types( const std::vector &displs_counts_recvd) { int ret = PIO_NOERR; + SPIO_Util::GPTL_Util::GPTL_wrapper ftimer("PIO:Contig_rearr::init_rearr_recvd_types"); assert(ios_ && ios_->ioproc); assert(rearr_comm_sz_ > 0); @@ -1268,6 +1283,8 @@ int SPIO::DataRearr::Contig_rearr::rearrange_data(const void *sbuf, std::size_t void *rbuf, std::size_t rbuf_sz, int nvars, bool agg2rearr) { int ret = PIO_NOERR; + SPIO_Util::GPTL_Util::GPTL_wrapper contig_rearr_timer("PIO:Contig_rearr::rearrange_data"); + assert(is_init_); assert(ios_); From 65089780feccb144c81264a67d717a3f6ec835ba Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 24 Mar 2025 16:28:54 -0500 Subject: [PATCH 054/194] Adding a kway merge sort util Adding a kway merge sort algorithm for vectors --- src/clib/spio_sort_utils.hpp | 63 +++++++ tests/cunit/CMakeLists.txt | 4 +- tests/cunit/test_spio_sort_utils.cpp | 257 +++++++++++++++++++++++++++ 3 files changed, 323 insertions(+), 1 deletion(-) create mode 100644 src/clib/spio_sort_utils.hpp create mode 100644 tests/cunit/test_spio_sort_utils.cpp diff --git a/src/clib/spio_sort_utils.hpp b/src/clib/spio_sort_utils.hpp new file mode 100644 index 0000000000..a96b380c35 --- /dev/null +++ b/src/clib/spio_sort_utils.hpp @@ -0,0 +1,63 @@ +#ifndef _SPIO_SORT_UTILS_HPP_ +#define _SPIO_SORT_UTILS_HPP_ + +#include +#include +#include + +#include +#include +#include +#include + +namespace SPIO_Util{ + template + void vec_kway_merge_sort(std::vector &v, const std::vector > &ranges) + { + std::vector vtmp(v); + + /* Each pair in the priority queue : + (idx of range in ranges, idx of next element in v in this range) */ + auto range_comp = [&vtmp](const std::pair &a, const std::pair &b){ return vtmp[a.second] > vtmp[b.second]; }; + std::priority_queue, std::vector >, decltype(range_comp)> range_idx_info(range_comp); + + std::vector cur_range_idx(ranges.size()); + /* Add range info from each range to the priority queue */ + for(std::size_t i = 0; i < ranges.size(); i++){ + cur_range_idx[i] = ranges[i].first; + + if(cur_range_idx[i] < ranges[i].second){ + range_idx_info.push(std::make_pair(i, cur_range_idx[i])); + } + } + + std::size_t v_idx = 0; + while(!range_idx_info.empty()){ + const std::pair &range_info = range_idx_info.top(); + + std::size_t current_range = range_info.first; + std::size_t r_idx = range_info.second; + + if(r_idx < ranges[current_range].second){ + v[v_idx++] = vtmp[r_idx++]; + } + + while(r_idx < ranges[current_range].second){ + if(vtmp[r_idx] == vtmp[r_idx - 1] + 1){ + v[v_idx++] = vtmp[r_idx++]; + } + else{ + break; + } + } + + range_idx_info.pop(); + + if(r_idx < ranges[current_range].second){ + range_idx_info.push(std::make_pair(current_range, r_idx)); + } + } + } +} // namespace SPIO_Util + +#endif // _SPIO_SORT_UTILS_HPP_ diff --git a/tests/cunit/CMakeLists.txt b/tests/cunit/CMakeLists.txt index f63a8d78de..9ce34633c4 100644 --- a/tests/cunit/CMakeLists.txt +++ b/tests/cunit/CMakeLists.txt @@ -104,6 +104,7 @@ add_spio_executable (test_spio_ltimer TRUE "" test_spio_ltimer.cpp) add_spio_executable (test_spio_serializer TRUE "" test_spio_serializer.cpp) add_spio_executable (test_spio_tree TRUE "" test_spio_tree.cpp) add_spio_executable (test_spio_file_mvcache TRUE "" test_spio_file_mvcache.cpp) +add_spio_executable (test_spio_sort_utils TRUE "" test_spio_sort_utils.cpp) add_spio_executable (test_spio_rearr_utils_gather TRUE "" test_spio_rearr_utils_gather.cpp) add_spio_executable (test_spio_rearr_utils_scatter TRUE "" test_spio_rearr_utils_scatter.cpp) add_spio_executable (test_spio_rearr_utils_alltoall TRUE "" test_spio_rearr_utils_alltoall.cpp) @@ -114,7 +115,7 @@ add_spio_executable (test_spio_decomp_logger TRUE "" test_spio_decomp_logger.cpp add_spio_executable (test_sdecomp_regex TRUE "" test_sdecomp_regex.cpp test_common.cpp) add_spio_executable(test_req_block_wait TRUE "" test_req_block_wait.cpp test_common.cpp) add_dependencies (tests test_spmd test_spio_ltimer test_spio_serializer test_spio_tree - test_spio_file_mvcache test_spio_rearr_utils_gather + test_spio_file_mvcache test_spio_sort_utils test_spio_rearr_utils_gather test_spio_rearr_utils_scatter test_spio_rearr_utils_alltoall test_spio_rearr_contig test_spio_rearr_contig_nvars test_spio_rearr_contig_fillval test_spio_decomp_logger @@ -148,6 +149,7 @@ add_test(NAME test_spio_serializer COMMAND test_spio_serializer) add_test(NAME test_spio_tree COMMAND test_spio_tree) add_test(NAME test_spio_file_mvcache COMMAND test_spio_file_mvcache) add_test(NAME test_sdecomp_regex COMMAND test_sdecomp_regex) +add_test(NAME test_spio_sort_utils COMMAND test_spio_sort_utils) if(PIO_USE_ASYNC_WR_THREAD) add_test(NAME test_mtq COMMAND test_mtq) diff --git a/tests/cunit/test_spio_sort_utils.cpp b/tests/cunit/test_spio_sort_utils.cpp new file mode 100644 index 0000000000..7005316436 --- /dev/null +++ b/tests/cunit/test_spio_sort_utils.cpp @@ -0,0 +1,257 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pio_config.h" +#include "pio.h" +#include "pio_tests.h" +#include "spio_sort_utils.hpp" + +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL +#include "gptl.h" +#endif +#endif + +#define LOG_RANK0(rank, ...) \ + do{ \ + if(rank == 0) \ + { \ + fprintf(stderr, __VA_ARGS__); \ + } \ + }while(0); + +static const int FAIL = -1; + +template +bool cmp_result(int wrank, const std::vector &res, const std::vector &exp) +{ + + if(res.size() != exp.size()){ + LOG_RANK0(wrank, "ERROR: The result and expected vectors are of different sizes\n"); + return false; + } + + for(std::size_t i = 0; i < res.size(); i++){ + if(res[i] != exp[i]){ + if(wrank == 0){ + std::cerr << "ERROR: Invalid/Unexpected value, array[ " << i << "] = " << res[i] + << " (Expected array[" << i << "] = " << exp[i] << ")\n"; + } + return false; + } + } + + return true; +} + +int test_simple_kway_merge_sort(MPI_Comm comm, int wrank, int wsz) +{ + std::vector data_range1 = {12, 28, 32, 36, 37, 68, 69, 70}; + std::vector data_range2 = {2, 3, 4, 6, 9, 10, 13, 14, 30, 81}; + + std::vector data; + data.insert(data.end(), data_range1.begin(), data_range1.end()); + data.insert(data.end(), data_range2.begin(), data_range2.end()); + + std::vector > ranges = + { {0, data_range1.size()}, {data_range1.size(), data_range1.size() + data_range2.size()} }; + + std::vector exp_data(data); + std::sort(exp_data.begin(), exp_data.end()); + + try{ + SPIO_Util::vec_kway_merge_sort(data, ranges); + + if(!cmp_result(wrank, data, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/Invalid data in sorted buffer\n"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Kway merge sort of Vector failed\n"); + return PIO_EINTERNAL; + } + + return PIO_NOERR; +} + +int test_odd_even_kway_merge_sort(MPI_Comm comm, int wrank, int wsz) +{ + const std::size_t NELEMS = 32; + std::vector data_range1; + std::vector data_range2; + + for(std::size_t i = 0; i < NELEMS; i+=2){ + data_range1.push_back(i); + data_range2.push_back(i + 1); + } + + std::vector data; + data.insert(data.end(), data_range1.begin(), data_range1.end()); + data.insert(data.end(), data_range2.begin(), data_range2.end()); + + std::vector > ranges = + { {0, data_range1.size()}, {data_range1.size(), data_range1.size() + data_range2.size()} }; + + std::vector exp_data(data); + std::sort(exp_data.begin(), exp_data.end()); + + try{ + SPIO_Util::vec_kway_merge_sort(data, ranges); + + if(!cmp_result(wrank, data, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/Invalid data in sorted buffer\n"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Kway merge sort of Vector failed\n"); + return PIO_EINTERNAL; + } + + return PIO_NOERR; +} + +int test_rev_kway_merge_sort(MPI_Comm comm, int wrank, int wsz) +{ + std::vector data_range1 = {11, 12, 13, 14}; + std::vector data_range2 = {5, 6, 7, 8, 9}; + std::vector data_range3 = {2, 4}; + + std::vector data; + data.insert(data.end(), data_range1.begin(), data_range1.end()); + data.insert(data.end(), data_range2.begin(), data_range2.end()); + data.insert(data.end(), data_range3.begin(), data_range3.end()); + + std::vector > ranges = + { {0, data_range1.size()}, + {data_range1.size(), data_range1.size() + data_range2.size()}, + {data_range1.size() + data_range2.size(), + data_range1.size() + data_range2.size() + data_range3.size()} + }; + + std::vector exp_data(data); + std::sort(exp_data.begin(), exp_data.end()); + + try{ + SPIO_Util::vec_kway_merge_sort(data, ranges); + + if(!cmp_result(wrank, data, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/Invalid data in sorted buffer\n"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Kway merge sort of Vector failed\n"); + return PIO_EINTERNAL; + } + + return PIO_NOERR; +} + +int test_driver(MPI_Comm comm, int wrank, int wsz, int *num_errors) +{ + int nerrs = 0, ret = PIO_NOERR, mpierr = MPI_SUCCESS; + assert((comm != MPI_COMM_NULL) && (wrank >= 0) && (wsz > 0) && num_errors); + + std::vector > > test_funcs = { + {"test_simple_kway_merge_sort", test_simple_kway_merge_sort}, + {"test_odd_even_kway_merge_sort", test_odd_even_kway_merge_sort}, + {"test_rev_kway_merge_sort", test_rev_kway_merge_sort} + }; + + for(std::size_t tid = 0; tid < test_funcs.size(); tid++){ + try{ + ret = test_funcs[tid].second(comm, wrank, wsz); + } + catch(...){ + ret = PIO_EINTERNAL; + nerrs++; + } + int lfail = (ret == PIO_NOERR) ? 0 : 1; + mpierr = MPI_Reduce(&ret, &lfail, 1, MPI_INT, MPI_SUM, 0, comm); + if(mpierr != MPI_SUCCESS){ + LOG_RANK0(wrank, "Test Driver failed: Unable to calculate total num errors\n"); + } + if(ret != 0){ + std::string non_root_fail_msg = std::string(", failed on ") + std::to_string(ret) + std::string(" non-root processes"); + LOG_RANK0(wrank, "%s() FAILED (ret = %d%s)\n", test_funcs[tid].first.c_str(), ret, (lfail) ? "" : non_root_fail_msg.c_str()); + nerrs++; + } + else{ + LOG_RANK0(wrank, "%s() PASSED\n", test_funcs[tid].first.c_str()); + } + } + + *num_errors += nerrs; + return nerrs; +} + +int main(int argc, char *argv[]) +{ + int ret; + int wrank, wsz; + int num_errors; +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL + ret = GPTLinitialize(); + if(ret != 0){ + LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + + ret = MPI_Init(&argc, &argv); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Init() FAILED, ret = %d\n", ret); + return ret; + } + + ret = MPI_Comm_rank(MPI_COMM_WORLD, &wrank); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); + return ret; + } + ret = MPI_Comm_size(MPI_COMM_WORLD, &wsz); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); + return ret; + } + + num_errors = 0; + ret = test_driver(MPI_COMM_WORLD, wrank, wsz, &num_errors); + if(ret != 0){ + LOG_RANK0(wrank, "Test driver FAILED\n"); + } + else{ + LOG_RANK0(wrank, "All tests PASSED\n"); + } + + MPI_Finalize(); + +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL + ret = GPTLfinalize(); + if(ret != 0){ + LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + + if(num_errors != 0){ + LOG_RANK0(wrank, "Total errors = %d\n", num_errors); + return FAIL; + } + return 0; +} From 606eb9bf8ad5f4510a54d08e2161c6ada63bad18 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 26 Mar 2025 14:24:35 -0500 Subject: [PATCH 055/194] Fix buffer sizes passed to contig for rearr Make sure that the buffer sizes passed during data rearrangement to the contig rearranger are consistent. * The size of the buffer in bytes (not elements) * The size of buffers is always the entire size of the buffer (not for a single variable in the case where we read/write multiple variables) Also updated the unit tests accordingly --- src/clib/pio_darray.cpp | 4 +-- src/clib/pio_rearr_contig.cpp | 4 +-- tests/cunit/test_spio_rearr_contig_nvars.cpp | 26 ++++++++++---------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/clib/pio_darray.cpp b/src/clib/pio_darray.cpp index ba02580084..f1c35762a2 100644 --- a/src/clib/pio_darray.cpp +++ b/src/clib/pio_darray.cpp @@ -321,7 +321,7 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar /* Move data from compute to IO tasks. */ if(iodesc->rearranger == PIO_REARR_CONTIG){ - ierr = iodesc->rearr->rearrange_comp2io(array, arraylen, mv_iobuf, rlen * iodesc->mpitype_size, nvars); + ierr = iodesc->rearr->rearrange_comp2io(array, arraylen * nvars * iodesc->mpitype_size, mv_iobuf, rlen * iodesc->mpitype_size, nvars); } else{ ierr = rearrange_comp2io(ios, iodesc, file, array, mv_iobuf, nvars); @@ -3686,7 +3686,7 @@ int PIOc_read_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, #endif /* Rearrange the data. */ if(iodesc->rearranger == PIO_REARR_CONTIG){ - ierr = iodesc->rearr->rearrange_io2comp(iobuf, rlen, array, iodesc->ndof * iodesc->mpitype_size, 1); + ierr = iodesc->rearr->rearrange_io2comp(iobuf, rlen * iodesc->mpitype_size, array, iodesc->ndof * iodesc->mpitype_size, 1); } else{ ierr = rearrange_io2comp(ios, iodesc, iobuf, array); diff --git a/src/clib/pio_rearr_contig.cpp b/src/clib/pio_rearr_contig.cpp index a698e6b474..152f0bb4a9 100644 --- a/src/clib/pio_rearr_contig.cpp +++ b/src/clib/pio_rearr_contig.cpp @@ -367,7 +367,7 @@ int SPIO::DataRearr::Contig_rearr::aggregate_data(const void *sbuf, std::size_t } } if(agg_gs_info_.stype != MPI_DATATYPE_NULL){ - MPI_Aint stride_between_vars = static_cast(sbuf_sz * elem_mpi_type_sz_); + MPI_Aint stride_between_vars = static_cast(sbuf_sz / nvars); ret = MPI_Type_hvector(nvars, 1, stride_between_vars, agg_gs_info_.stype, &agg_stype_nvars); if(ret == MPI_SUCCESS){ ret = MPI_Type_commit(&agg_stype_nvars); @@ -456,7 +456,7 @@ int SPIO::DataRearr::Contig_rearr::disperse_data(const void *abuf, std::size_t a } } if(agg_gs_info_.stype != MPI_DATATYPE_NULL){ - MPI_Aint stride_between_vars = static_cast(abuf_sz / nvars); + MPI_Aint stride_between_vars = static_cast(rbuf_sz / nvars); ret = MPI_Type_hvector(nvars, 1, stride_between_vars, agg_gs_info_.stype, &dis_rtype_nvars); if(ret == MPI_SUCCESS){ ret = MPI_Type_commit(&dis_rtype_nvars); diff --git a/tests/cunit/test_spio_rearr_contig_nvars.cpp b/tests/cunit/test_spio_rearr_contig_nvars.cpp index b9b6e85e6f..2002b78dfb 100644 --- a/tests/cunit/test_spio_rearr_contig_nvars.cpp +++ b/tests/cunit/test_spio_rearr_contig_nvars.cpp @@ -152,7 +152,7 @@ int test_c2i_block_data_rearr_nvars(MPI_Comm comm, int wrank, int wsz, int nvars LOG_RANK0(wrank, "Initializing contig rearranger failed"); return PIO_EINTERNAL; } - ret = rearr.rearrange_comp2io(sdata.data(), compmap.size(), + ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), rdata.data(), rdata.size() * sizeof(double), nvars); if(ret != PIO_NOERR){ LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); @@ -223,7 +223,7 @@ int test_block_data_rearr_nvars(MPI_Comm comm, int wrank, int wsz, int nvars) LOG_RANK0(wrank, "Initializing contig rearranger failed"); return PIO_EINTERNAL; } - ret = rearr.rearrange_comp2io(sdata.data(), compmap.size(), + ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), rdata.data(), rdata.size() * sizeof(double), nvars); if(ret != PIO_NOERR){ LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); @@ -241,8 +241,8 @@ int test_block_data_rearr_nvars(MPI_Comm comm, int wrank, int wsz, int nvars) std::copy(sdata.begin(), sdata.end(), exp_data.begin()); std::fill(sdata.begin(), sdata.end(), PIO_FILL_DOUBLE); - ret = rearr.rearrange_io2comp(rdata.data(), compmap.size(), - sdata.data(), compmap.size() * sizeof(double), nvars); + ret = rearr.rearrange_io2comp(rdata.data(), rdata.size() * sizeof(double), + sdata.data(), sdata.size() * sizeof(double), nvars); if(ret != PIO_NOERR){ LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); return PIO_EINTERNAL; @@ -315,7 +315,7 @@ int test_rev_block_data_rearr_nvars(MPI_Comm comm, int wrank, int wsz, int nvars LOG_RANK0(wrank, "Initializing contig rearranger failed"); return PIO_EINTERNAL; } - ret = rearr.rearrange_comp2io(sdata.data(), compmap.size(), + ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), rdata.data(), rdata.size() * sizeof(double), nvars); if(ret != PIO_NOERR){ LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); @@ -333,8 +333,8 @@ int test_rev_block_data_rearr_nvars(MPI_Comm comm, int wrank, int wsz, int nvars std::copy(sdata.begin(), sdata.end(), exp_data.begin()); std::fill(sdata.begin(), sdata.end(), PIO_FILL_DOUBLE); - ret = rearr.rearrange_io2comp(rdata.data(), compmap.size(), - sdata.data(), compmap.size() * sizeof(double), nvars); + ret = rearr.rearrange_io2comp(rdata.data(), rdata.size() * sizeof(double), + sdata.data(), sdata.size() * sizeof(double), nvars); if(ret != PIO_NOERR){ LOG_RANK0(wrank, "Rearranging data using contig rearranger failed (I/O to compute procs)"); return PIO_EINTERNAL; @@ -409,7 +409,7 @@ int test_mrange_block_data_rearr_nvars(MPI_Comm comm, int wrank, int wsz, int nv LOG_RANK0(wrank, "Initializing contig rearranger failed"); return PIO_EINTERNAL; } - ret = rearr.rearrange_comp2io(sdata.data(), compmap.size(), + ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), rdata.data(), rdata.size() * sizeof(double), nvars); if(ret != PIO_NOERR){ LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); @@ -427,8 +427,8 @@ int test_mrange_block_data_rearr_nvars(MPI_Comm comm, int wrank, int wsz, int nv std::copy(sdata.begin(), sdata.end(), exp_data.begin()); std::fill(sdata.begin(), sdata.end(), PIO_FILL_DOUBLE); - ret = rearr.rearrange_io2comp(rdata.data(), compmap.size(), - sdata.data(), compmap.size() * sizeof(double), nvars); + ret = rearr.rearrange_io2comp(rdata.data(), rdata.size() * sizeof(double), + sdata.data(), sdata.size() * sizeof(double), nvars); if(ret != PIO_NOERR){ LOG_RANK0(wrank, "Rearranging data using contig rearranger failed (I/O to compute procs)"); return PIO_EINTERNAL; @@ -515,7 +515,7 @@ int test_mrange_oddz_data_rearr_nvars(MPI_Comm comm, int wrank, int wsz, int nva LOG_RANK0(wrank, "Initializing contig rearranger failed"); return PIO_EINTERNAL; } - ret = rearr.rearrange_comp2io(sdata.data(), compmap.size(), + ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), rdata.data(), rdata.size() * sizeof(double), nvars); if(ret != PIO_NOERR){ LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); @@ -539,8 +539,8 @@ int test_mrange_oddz_data_rearr_nvars(MPI_Comm comm, int wrank, int wsz, int nva std::copy(sdata.begin(), sdata.end(), exp_data.begin()); std::fill(sdata.begin(), sdata.end(), PIO_FILL_DOUBLE); - ret = rearr.rearrange_io2comp(rdata.data(), compmap.size(), - sdata.data(), compmap.size() * sizeof(double), nvars); + ret = rearr.rearrange_io2comp(rdata.data(), rdata.size() * sizeof(double), + sdata.data(), sdata.size() * sizeof(double), nvars); if(ret != PIO_NOERR){ LOG_RANK0(wrank, "Rearranging data using contig rearranger failed (I/O to compute procs)"); return PIO_EINTERNAL; From ee863d6560b6e540f82f236d411edbb3c333bb23 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 15 Apr 2025 11:45:25 -0500 Subject: [PATCH 056/194] Fix generation of compmap from range Fixing a bug when generating local compmap from the compmap range read from the file. The old code incorrectly "fill"ed instead of "generating" the compmap for the first range. --- src/clib/spio_decomp_nc_logger.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/clib/spio_decomp_nc_logger.cpp b/src/clib/spio_decomp_nc_logger.cpp index 8480ca1269..4d923ad08e 100644 --- a/src/clib/spio_decomp_nc_logger.cpp +++ b/src/clib/spio_decomp_nc_logger.cpp @@ -529,12 +529,8 @@ void SPIO_Util::Decomp_Util::Decomp_nc_logger::get_map_from_regions(std::vector< for(std::size_t i = 0; i < lregions.size(); i += 2){ PIO_Offset start = lregions[i]; PIO_Offset count = lregions[i + 1]; - if(start != 0){ - std::generate_n(std::back_inserter(lcompmap), count, [&start] () mutable { return start++; }); - } - else{ - std::fill_n(std::back_inserter(lcompmap), count, 0); - } + + std::generate_n(std::back_inserter(lcompmap), count, [&start] () mutable { return start++; }); } } From 1b0f9af1b780635d0fb512f8a2cff20e59dbb71e Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 15 Apr 2025 11:47:18 -0500 Subject: [PATCH 057/194] Free iodesc in decomp logger tests Ensure that the iodesc allocated is freed correctly in the decomp logger unit tests --- tests/cunit/test_spio_decomp_logger.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/cunit/test_spio_decomp_logger.cpp b/tests/cunit/test_spio_decomp_logger.cpp index 730b3f7c3e..377910841a 100644 --- a/tests/cunit/test_spio_decomp_logger.cpp +++ b/tests/cunit/test_spio_decomp_logger.cpp @@ -129,6 +129,20 @@ io_desc_t *get_iodesc(int wrank, iosystem_desc_t *ios, const std::vectorfirstregion->start); + free(iodesc->firstregion->count); + free(iodesc->firstregion); + free(iodesc->map); + free(iodesc->dimlen); + free(iodesc); +} + int test_create_decomp_logger(MPI_Comm comm, int wrank, int wsz) { int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; @@ -192,6 +206,7 @@ int test_simple_decomp_logger(MPI_Comm comm, int wrank, int wsz) } (*logger).write_only().open().put(iodesc).close(); + free_iodesc(iodesc); delete logger; } catch(...){ @@ -238,6 +253,7 @@ int test_simple_decomp_logger_wr_cached_rd(MPI_Comm comm, int wrank, int wsz) } (*logger).write_only().open().put(iodesc).close(); + free_iodesc(iodesc); std::string version; int rd_nprocs = -1; @@ -312,6 +328,7 @@ int test_simple_decomp_logger_wr_rd(MPI_Comm comm, int wrank, int wsz) } (*logger).write_only().open().put(iodesc).close(); + free_iodesc(iodesc); delete logger; logger = @@ -399,6 +416,7 @@ int test_vlen_decomp_logger(MPI_Comm comm, int wrank, int wsz) } (*logger).write_only().open().put(iodesc).close(); + free_iodesc(iodesc); delete logger; @@ -482,6 +500,7 @@ int test_rvlen_decomp_logger(MPI_Comm comm, int wrank, int wsz) } (*logger).write_only().open().put(iodesc).close(); + free_iodesc(iodesc); delete logger; From 4b5415d321dfb4a09ae3dd8f3ef4d293430c0cc8 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 15 Apr 2025 12:15:43 -0500 Subject: [PATCH 058/194] Add missing frees for map in test_pioc Adding missing frees for map/dimlen in the iodesc allocated in unit test, test_pioc --- tests/cunit/test_pioc.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/cunit/test_pioc.cpp b/tests/cunit/test_pioc.cpp index 69656813f1..09bb5d70e3 100644 --- a/tests/cunit/test_pioc.cpp +++ b/tests/cunit/test_pioc.cpp @@ -1648,6 +1648,8 @@ int test_malloc_iodesc2(int iosysid, int my_rank) ioid = pio_add_to_iodesc_list(iodesc, MPI_COMM_NULL); if (iodesc->firstregion) free_region_list(iodesc->firstregion); + free(iodesc->map); + free(iodesc->dimlen); if ((ret = pio_delete_iodesc_from_list(ioid))) return ret; } From 1da79fdf8d08993aedafeda7cb685b6162185629 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 22 Apr 2025 10:14:02 -0500 Subject: [PATCH 059/194] Handle type related compiler warnings Handling compiler warnings related to variable type * Stricter type checking/casting * Rm unused vars * Const correctness --- src/clib/pio_rearr_contig.cpp | 12 ++++++------ src/clib/pio_timer.cpp | 2 +- src/clib/pio_timer.h | 2 +- src/clib/pioc.cpp | 2 +- src/clib/spio_async_tpool.cpp | 1 - src/clib/spio_async_utils.cpp | 2 +- src/clib/spio_decomp_nc_logger.cpp | 4 ++-- tests/cunit/test_async_mtq.cpp | 6 +++--- tests/cunit/test_async_mtq_signal.cpp | 2 +- tests/pnetcdf/test_pnetcdf_4d.cpp | 14 +++++++------- 10 files changed, 23 insertions(+), 24 deletions(-) diff --git a/src/clib/pio_rearr_contig.cpp b/src/clib/pio_rearr_contig.cpp index 152f0bb4a9..fd9a9ececf 100644 --- a/src/clib/pio_rearr_contig.cpp +++ b/src/clib/pio_rearr_contig.cpp @@ -1157,7 +1157,7 @@ int SPIO::DataRearr::Contig_rearr::init_rearr_send_types( assert(ios_ && ios_->ioproc); assert(rearr_comm_sz_ > 0); - assert(nregion_infos_sent.size() == rearr_comm_sz_); + assert(static_cast(nregion_infos_sent.size()) == rearr_comm_sz_); rearr_alltoall_info_.scounts.reserve(rearr_comm_sz_); rearr_alltoall_info_.sdispls.reserve(rearr_comm_sz_); @@ -1218,7 +1218,7 @@ int SPIO::DataRearr::Contig_rearr::init_rearr_recvd_types( assert(ios_ && ios_->ioproc); assert(rearr_comm_sz_ > 0); - assert(nregion_infos_recvd.size() == rearr_comm_sz_); + assert(static_cast(nregion_infos_recvd.size()) == rearr_comm_sz_); rearr_alltoall_info_.rcounts.reserve(rearr_comm_sz_); rearr_alltoall_info_.rdispls.reserve(rearr_comm_sz_); @@ -1232,7 +1232,7 @@ int SPIO::DataRearr::Contig_rearr::init_rearr_recvd_types( for(int i = 0; i < rearr_comm_sz_; i++){ if(nregion_infos_recvd[i] != 0){ /* We receive an indexed type based on the region info we received from each process */ - int data_ranki_idx = static_cast(data_idx); + //int data_ranki_idx = static_cast(data_idx); int nregions = nregion_infos_recvd[i] / 2; assert(nregions > 0); @@ -1335,9 +1335,9 @@ int SPIO::DataRearr::Contig_rearr::rearrange_data(const void *sbuf, std::size_t rearr_stypes_nvars.reserve(rearr_comm_sz_); rearr_rtypes_nvars.reserve(rearr_comm_sz_); - assert(rearr_alltoall_info_.stypes.size() == rearr_comm_sz_); - assert(rearr_alltoall_info_.rtypes.size() == rearr_comm_sz_); - for(std::size_t i = 0; i < rearr_comm_sz_; i++){ + assert(static_cast(rearr_alltoall_info_.stypes.size()) == rearr_comm_sz_); + assert(static_cast(rearr_alltoall_info_.rtypes.size()) == rearr_comm_sz_); + for(int i = 0; i < rearr_comm_sz_; i++){ MPI_Datatype rearr_stype = MPI_DATATYPE_NULL; MPI_Datatype rearr_rtype = MPI_DATATYPE_NULL; /* Send type for block of vars */ diff --git a/src/clib/pio_timer.cpp b/src/clib/pio_timer.cpp index b7d2de60c1..4eecb3fc70 100644 --- a/src/clib/pio_timer.cpp +++ b/src/clib/pio_timer.cpp @@ -76,7 +76,7 @@ int mtimer_init(mtimer_type_t type) * comm : MPI communicator where the timer runs * log_fname : File name for the timer logs */ -mtimer_t mtimer_create(const char *name, MPI_Comm comm, char *log_fname) +mtimer_t mtimer_create(const char *name, MPI_Comm comm, const char *log_fname) { assert((name != NULL) && (log_fname != NULL)); mtimer_t mt = (mtimer_t )malloc(sizeof(struct mtimer_info)); diff --git a/src/clib/pio_timer.h b/src/clib/pio_timer.h index f737c41b41..4c472a00c6 100644 --- a/src/clib/pio_timer.h +++ b/src/clib/pio_timer.h @@ -69,7 +69,7 @@ extern "C" { /* Init timer framework - needs to be called once before using timers */ int mtimer_init(mtimer_type_t type); /* Create/Start/Stop/Destroy a timer */ -mtimer_t mtimer_create(const char *name, MPI_Comm comm, char *log_fname); +mtimer_t mtimer_create(const char *name, MPI_Comm comm, const char *log_fname); int mtimer_start(mtimer_t mt); int mtimer_stop(mtimer_t mt, const char *log_msg); int mtimer_destroy(mtimer_t *pmt); diff --git a/src/clib/pioc.cpp b/src/clib/pioc.cpp index a76f8bec7e..711c32a6cd 100644 --- a/src/clib/pioc.cpp +++ b/src/clib/pioc.cpp @@ -744,7 +744,7 @@ static void init_iodesc_contig_rearr_fields(iosystem_desc_t *ios, io_desc_t *iod LOG((1, "Contig rearranger : iodesc {ioid=%d, llen=%lld, maxiobuflen=%lld, ndims=%d, dimlen=%s, maxregions=%lld", iodesc->ioid, static_cast(iodesc->llen), static_cast(iodesc->maxiobuflen), iodesc->ndims, SPIO_Util::Dbg_Util::vec1d_to_string(iodesc->dimlen, iodesc->dimlen + iodesc->ndims).c_str(), static_cast(off_ranges.size()))); // FIXME : Move to C++ lists for region list - for(int i = 0; i < off_ranges.size(); i++){ + for(std::size_t i = 0; i < off_ranges.size(); i++){ if(cur_region == NULL){ alloc_region2(ios, iodesc->ndims, &cur_region); prev_region->next = cur_region; diff --git a/src/clib/spio_async_tpool.cpp b/src/clib/spio_async_tpool.cpp index f57236aa58..3bdda90f77 100644 --- a/src/clib/spio_async_tpool.cpp +++ b/src/clib/spio_async_tpool.cpp @@ -127,7 +127,6 @@ int pio_async_tpool_create(void ) int pio_async_tpool_op_add(pio_async_op_t *op) { - int ret; PIO_Util::PIO_async_tpool *tpool = tpool_mgr.get_tpool_instance(); assert(tpool); LOG((2, "pio_async_tpool_op_add(): Adding op")); diff --git a/src/clib/spio_async_utils.cpp b/src/clib/spio_async_utils.cpp index 261c26cc90..7db310738a 100644 --- a/src/clib/spio_async_utils.cpp +++ b/src/clib/spio_async_utils.cpp @@ -556,7 +556,7 @@ int pio_var_rearr_and_cache(file_desc_t *file, var_desc_t *vdesc, /* viobuf cache list keeps track of iobuf that contains the * rearranged data */ - viobuf_cache_t *p = vdesc->viobuf_ltail; + //viobuf_cache_t *p = vdesc->viobuf_ltail; pnew = (viobuf_cache_t *)calloc(1, sizeof(viobuf_cache_t)); if(!pnew){ return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, diff --git a/src/clib/spio_decomp_nc_logger.cpp b/src/clib/spio_decomp_nc_logger.cpp index 4d923ad08e..2acea244e7 100644 --- a/src/clib/spio_decomp_nc_logger.cpp +++ b/src/clib/spio_decomp_nc_logger.cpp @@ -543,8 +543,8 @@ void SPIO_Util::Decomp_Util::Decomp_nc_logger::gather_nregions_starts_counts(std assert(lregions.size() % 2 == 0); if(is_io_proc_){ - assert(agg_nregions_starts.size() == agg_comm_sz_); - assert(agg_nregions_counts.size() == agg_comm_sz_); + assert(static_cast(agg_nregions_starts.size()) == agg_comm_sz_); + assert(static_cast(agg_nregions_counts.size()) == agg_comm_sz_); } agg_nregions = 0; diff --git a/tests/cunit/test_async_mtq.cpp b/tests/cunit/test_async_mtq.cpp index 0764a79d2f..f711b45fb0 100644 --- a/tests/cunit/test_async_mtq.cpp +++ b/tests/cunit/test_async_mtq.cpp @@ -148,7 +148,7 @@ int test_enq_deq_int(int wrank, const int max_elems_in_q, const int nthreads, /* Verify that we dequeued all elements in the queue */ std::vector elem_in_q(max_elems_in_q, false); for(int i=0; i= max_elems_in_q)){ /* Invalid element in queue */ @@ -253,7 +253,7 @@ int test_enq_deq_utype(int wrank, const int max_elems_in_q, const int nthreads) /* Verify that we dequeued all elements in the queue */ std::vector elem_in_q(max_elems_in_q, false); for(int i=0; i elem_in_q(max_elems_in_q, false); for(int i=0; ii; int idx = ioval; float foval = ((ovals[i])[j])->f; diff --git a/tests/cunit/test_async_mtq_signal.cpp b/tests/cunit/test_async_mtq_signal.cpp index 8d7a5241d7..3a17f4bb71 100644 --- a/tests/cunit/test_async_mtq_signal.cpp +++ b/tests/cunit/test_async_mtq_signal.cpp @@ -177,7 +177,7 @@ int test_signal_mtq(int wrank, const int max_elems_in_q, const int nthreads, /* Verify that we dequeued all elements in the queue */ std::vector elem_in_q(max_elems_in_q, false); for(int i=0; i= max_elems_in_q)){ /* Invalid element in queue */ diff --git a/tests/pnetcdf/test_pnetcdf_4d.cpp b/tests/pnetcdf/test_pnetcdf_4d.cpp index 8e23d90ffc..a12a9c5f7d 100644 --- a/tests/pnetcdf/test_pnetcdf_4d.cpp +++ b/tests/pnetcdf/test_pnetcdf_4d.cpp @@ -80,7 +80,7 @@ static int verbose; static void usage(char *argv0) { - char *help = + const char *help = "Usage: %s [-h] | [-q] [-k format] [file_name]\n" " [-h] Print help\n" " [-q] Quiet mode (reports when fail)\n" @@ -127,7 +127,7 @@ void convert_gidx_to_dim_idx(int gidx, int ndims, const MPI_Offset *gdimlen, std int dim_chunk_sz[ndims]; assert(ndims > 0); - assert(gdimlen && (dim_idx.size() == ndims)); + assert(gdimlen && (static_cast(dim_idx.size()) == ndims)); dim_chunk_sz[ndims - 1] = 1; for(int i = ndims - 2; i >= 0; i--){ @@ -216,7 +216,6 @@ int validate_starts_counts(MPI_Offset start_off, MPI_Offset end_off, const std::vector > &counts) { const int FAIL = 1, SUCCESS = 0; - MPI_Offset cur_off; if(start_off > end_off){ std::cerr << "ERROR: Start offset provided needs to be <= end offset\n"; @@ -315,9 +314,9 @@ static inline void convert_off_to_start_dim_idx(const std::vector &d static inline void convert_off_to_count_dim_idx(int ndims, const MPI_Offset *gdimlen, const std::vector &dim_chunk_sz, int count_off, std::vector &count_dim_idx) { assert(dim_chunk_sz.size() == count_dim_idx.size()); - assert(count_dim_idx.size() == ndims); + assert(static_cast(count_dim_idx.size()) == ndims); - for(std::size_t i = 0; i < ndims; i++){ + for(int i = 0; i < ndims; i++){ count_dim_idx[i] = gdimlen[i]; } for(std::size_t i = 0; i < dim_chunk_sz.size(); i++){ @@ -435,7 +434,8 @@ pnetcdf_io(MPI_Comm comm, char *filename, int cmode) int var3did, buf3d[NZ][NY][NX], var3d_rankid, buf3d_rank[NZ][NY][NX]; char str_att[128]; float float_att[100]; - MPI_Offset global_nz, global_ny, global_nx, global_tot_sz, gdimlen[3]; + MPI_Offset global_nz, global_ny, global_nx, gdimlen[3]; + //MPI_Offset global_tot_sz; MPI_Offset global_nx_1d2d; MPI_Offset start[3], count[3]; std::vector > starts, counts; @@ -456,7 +456,7 @@ pnetcdf_io(MPI_Comm comm, char *filename, int cmode) global_nx = NX; global_nx_1d2d = NX * nprocs; - global_tot_sz = global_nz * global_ny * global_nx; + //global_tot_sz = global_nz * global_ny * global_nx; gdimlen[0] = global_nz; gdimlen[1] = global_ny; gdimlen[2] = global_nx; From 2c5f221bb56511195cbec1e05ed1df1f6709cdeb Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 24 Apr 2025 17:28:18 -0500 Subject: [PATCH 060/194] Adding a comparator and consec range checker Adding a comparator and consecutive range checker for the k-way merge sort util --- src/clib/spio_sort_utils.hpp | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/clib/spio_sort_utils.hpp b/src/clib/spio_sort_utils.hpp index a96b380c35..640e88897c 100644 --- a/src/clib/spio_sort_utils.hpp +++ b/src/clib/spio_sort_utils.hpp @@ -9,16 +9,20 @@ #include #include #include +#include namespace SPIO_Util{ - template - void vec_kway_merge_sort(std::vector &v, const std::vector > &ranges) + /* K-way merge sort a vector with multiple sorted ranges, where ranges are in {start_idx, end_idx + 1} format + e.g. vec_kway_merge_sort({2, 3, 4, 6, 7}, {{0, 3}, {3, 5}}) + */ + template> + void vec_kway_merge_sort(std::vector &v, const std::vector > &ranges, ContigRangeChecker &&crc, Comp cmp = Comp{}) { std::vector vtmp(v); /* Each pair in the priority queue : (idx of range in ranges, idx of next element in v in this range) */ - auto range_comp = [&vtmp](const std::pair &a, const std::pair &b){ return vtmp[a.second] > vtmp[b.second]; }; + auto range_comp = [&vtmp, &cmp](const std::pair &a, const std::pair &b){ return cmp(vtmp[b.second], vtmp[a.second]); }; std::priority_queue, std::vector >, decltype(range_comp)> range_idx_info(range_comp); std::vector cur_range_idx(ranges.size()); @@ -35,15 +39,20 @@ namespace SPIO_Util{ while(!range_idx_info.empty()){ const std::pair &range_info = range_idx_info.top(); + /* current_range : Index of current range in ranges[] */ std::size_t current_range = range_info.first; + /* r_idx : Index in v[] of the next element to be sorted in this range */ std::size_t r_idx = range_info.second; if(r_idx < ranges[current_range].second){ + /* This element, vtmp[r_idx], is the next element in the sorted result, v[] */ v[v_idx++] = vtmp[r_idx++]; } + /* Add consecutive elements in this sorted range to the final sorted list, v[] */ while(r_idx < ranges[current_range].second){ - if(vtmp[r_idx] == vtmp[r_idx - 1] + 1){ + /* If vtmp[r_idx] is consecutive in range, after vtmp[r_idx - 1], add it to the sorted list */ + if(crc(vtmp[r_idx - 1], vtmp[r_idx])){ v[v_idx++] = vtmp[r_idx++]; } else{ @@ -53,11 +62,27 @@ namespace SPIO_Util{ range_idx_info.pop(); + /* If there are still elements in this range (after adding all consecutive elems), add it in to + * the priority queue - for comparison across ranges + */ if(r_idx < ranges[current_range].second){ + /* Add the next range info, + {idx of current range in ranges[], Next index - in vtmp[] - of element in this range}, + for next element in this range to the priority queue + */ range_idx_info.push(std::make_pair(current_range, r_idx)); } } } + + /* K-way merge sort a vector with multiple sorted ranges, where ranges are in {start_idx, end_idx + 1} format + e.g. vec_kway_merge_sort({2, 3, 4, 6, 7}, {{0, 3}, {3, 5}}) + */ + template + void vec_kway_merge_sort(std::vector &v, const std::vector > &ranges) + { + return vec_kway_merge_sort(v, ranges, [](const T &a, const T &b) { return (a + 1) == b; }); + } } // namespace SPIO_Util #endif // _SPIO_SORT_UTILS_HPP_ From 6f22b5665ff8c4f8d9a876d6d0b7d911bef53e93 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 24 Apr 2025 23:31:50 -0500 Subject: [PATCH 061/194] Adding kway sort test via indices Adding more tests for kway merge sort util function. These tests sort the data indirectly by passing in the comparator function --- tests/cunit/test_spio_sort_utils.cpp | 137 ++++++++++++++++++++++++++- 1 file changed, 136 insertions(+), 1 deletion(-) diff --git a/tests/cunit/test_spio_sort_utils.cpp b/tests/cunit/test_spio_sort_utils.cpp index 7005316436..d779c204c1 100644 --- a/tests/cunit/test_spio_sort_utils.cpp +++ b/tests/cunit/test_spio_sort_utils.cpp @@ -158,6 +158,138 @@ int test_rev_kway_merge_sort(MPI_Comm comm, int wrank, int wsz) return PIO_NOERR; } +int test_indirect_simple_kway_merge_sort(MPI_Comm comm, int wrank, int wsz) +{ + std::vector data_range1 = {12, 28, 32, 36, 37, 68, 69, 70}; + std::vector data_range2 = {2, 3, 4, 6, 9, 10, 13, 14, 30, 81}; + + std::vector data; + data.insert(data.end(), data_range1.begin(), data_range1.end()); + data.insert(data.end(), data_range2.begin(), data_range2.end()); + + std::vector data_idx(data.size()); + std::iota(data_idx.begin(), data_idx.end(), 0); + + std::vector > ranges = + { {0, data_range1.size()}, {data_range1.size(), data_range1.size() + data_range2.size()} }; + + std::vector exp_data(data); + std::sort(exp_data.begin(), exp_data.end()); + + try{ + SPIO_Util::vec_kway_merge_sort(data_idx, ranges, + [&data](const std::size_t a, const std::size_t b){ return (data[a] + 1 == data[b]); }, + [&data](const std::size_t a, const std::size_t b){ return data[a] < data[b]; }); + + std::vector sorted_data(data.size()); + std::transform(data_idx.cbegin(), data_idx.cend(), + sorted_data.begin(), [&data](const std::size_t idx){ return data[idx]; }); + + if(!cmp_result(wrank, sorted_data, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/Invalid data in sorted buffer\n"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Kway merge sort of Vector failed\n"); + return PIO_EINTERNAL; + } + + return PIO_NOERR; +} + +int test_indirect_odd_even_kway_merge_sort(MPI_Comm comm, int wrank, int wsz) +{ + const std::size_t NELEMS = 32; + std::vector data_range1; + std::vector data_range2; + + for(std::size_t i = 0; i < NELEMS; i+=2){ + data_range1.push_back(i); + data_range2.push_back(i + 1); + } + + std::vector data; + data.insert(data.end(), data_range1.begin(), data_range1.end()); + data.insert(data.end(), data_range2.begin(), data_range2.end()); + + std::vector data_idx(data.size()); + std::iota(data_idx.begin(), data_idx.end(), 0); + + std::vector > ranges = + { {0, data_range1.size()}, {data_range1.size(), data_range1.size() + data_range2.size()} }; + + std::vector exp_data(data); + std::sort(exp_data.begin(), exp_data.end()); + + try{ + SPIO_Util::vec_kway_merge_sort(data_idx, ranges, + [&data](const std::size_t a, const std::size_t b){ return (data[a] + 1 == data[b]); }, + [&data](const std::size_t a, const std::size_t b){ return data[a] < data[b]; }); + + std::vector sorted_data(data.size()); + std::transform(data_idx.cbegin(), data_idx.cend(), + sorted_data.begin(), [&data](const std::size_t idx){ return data[idx]; }); + + if(!cmp_result(wrank, sorted_data, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/Invalid data in sorted buffer\n"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Kway merge sort of Vector failed\n"); + return PIO_EINTERNAL; + } + + return PIO_NOERR; +} + +int test_indirect_rev_kway_merge_sort(MPI_Comm comm, int wrank, int wsz) +{ + std::vector data_range1 = {11, 12, 13, 14}; + std::vector data_range2 = {5, 6, 7, 8, 9}; + std::vector data_range3 = {2, 4}; + + std::vector data; + data.insert(data.end(), data_range1.begin(), data_range1.end()); + data.insert(data.end(), data_range2.begin(), data_range2.end()); + data.insert(data.end(), data_range3.begin(), data_range3.end()); + + std::vector data_idx(data.size()); + std::iota(data_idx.begin(), data_idx.end(), 0); + + std::vector > ranges = + { {0, data_range1.size()}, + {data_range1.size(), data_range1.size() + data_range2.size()}, + {data_range1.size() + data_range2.size(), + data_range1.size() + data_range2.size() + data_range3.size()} + }; + + std::vector exp_data(data); + std::sort(exp_data.begin(), exp_data.end()); + + try{ + SPIO_Util::vec_kway_merge_sort(data_idx, ranges, + [&data](const std::size_t a, const std::size_t b){ return (data[a] + 1 == data[b]); }, + [&data](const std::size_t a, const std::size_t b){ return data[a] < data[b]; }); + + std::vector sorted_data(data.size()); + std::transform(data_idx.cbegin(), data_idx.cend(), + sorted_data.begin(), [&data](const std::size_t idx){ return data[idx]; }); + + if(!cmp_result(wrank, sorted_data, exp_data)){ + LOG_RANK0(wrank, "ERROR: Unexpected/Invalid data in sorted buffer\n"); + return PIO_EINTERNAL; + } + } + catch(...){ + LOG_RANK0(wrank, "Kway merge sort of Vector failed\n"); + return PIO_EINTERNAL; + } + + return PIO_NOERR; +} + int test_driver(MPI_Comm comm, int wrank, int wsz, int *num_errors) { int nerrs = 0, ret = PIO_NOERR, mpierr = MPI_SUCCESS; @@ -166,7 +298,10 @@ int test_driver(MPI_Comm comm, int wrank, int wsz, int *num_errors) std::vector > > test_funcs = { {"test_simple_kway_merge_sort", test_simple_kway_merge_sort}, {"test_odd_even_kway_merge_sort", test_odd_even_kway_merge_sort}, - {"test_rev_kway_merge_sort", test_rev_kway_merge_sort} + {"test_rev_kway_merge_sort", test_rev_kway_merge_sort}, + {"test_indirect_simple_kway_merge_sort", test_indirect_simple_kway_merge_sort}, + {"test_indirect_odd_even_kway_merge_sort", test_indirect_odd_even_kway_merge_sort}, + {"test_indirect_rev_kway_merge_sort", test_indirect_rev_kway_merge_sort} }; for(std::size_t tid = 0; tid < test_funcs.size(); tid++){ From 438cc8fa9165a7238fb9b7f4a902227655f0e009 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Sun, 4 May 2025 14:37:35 -0500 Subject: [PATCH 062/194] Cache the data chunk size in agg process Caching the number of elements of the aggregated data in the aggregating process (instead of querying it from the sorter map) --- src/clib/pio_rearr_contig.cpp | 18 +++++++----------- src/clib/pio_rearr_contig.hpp | 4 +++- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/clib/pio_rearr_contig.cpp b/src/clib/pio_rearr_contig.cpp index fd9a9ececf..ff47067f89 100644 --- a/src/clib/pio_rearr_contig.cpp +++ b/src/clib/pio_rearr_contig.cpp @@ -287,8 +287,7 @@ int SPIO::DataRearr::Contig_rearr::rearrange_comp2io(const void *sbuf, std::size int ret = PIO_NOERR; assert(is_init_); - /* FIXME: We need a better way to find this info out */ - std::size_t agg_data_nelems = agg_compmap_sorter_.size(); + std::size_t agg_data_nelems = agg_iochunk_sz_; /* Aggregate data */ void *agg_buf = NULL; @@ -335,8 +334,7 @@ int SPIO::DataRearr::Contig_rearr::aggregate_data(const void *sbuf, std::size_t MPI_Datatype agg_stype_nvars = MPI_DATATYPE_NULL; std::vector agg_rtypes_nvars; - /* FIXME: We need a better way to find this info out */ - std::size_t agg_data_nelems = agg_compmap_sorter_.size(); + std::size_t agg_data_nelems = agg_iochunk_sz_; assert(abuf_sz == nvars * agg_data_nelems * elem_mpi_type_sz_); // std::cout << "DBG: sbuf[], abuf[] before gather :" << abuf_sz << "," << nvars << "," << elem_mpi_type_sz_ << ":" << std::flush; @@ -428,8 +426,7 @@ int SPIO::DataRearr::Contig_rearr::disperse_data(const void *abuf, std::size_t a MPI_Datatype dis_rtype_nvars = MPI_DATATYPE_NULL; std::vector dis_stypes_nvars; - /* FIXME: We need a better way to find this info out */ - std::size_t agg_data_nelems = agg_compmap_sorter_.size(); + std::size_t agg_data_nelems = agg_iochunk_sz_; assert(abuf_sz == nvars * agg_data_nelems * elem_mpi_type_sz_); if(nvars > 1){ @@ -505,8 +502,7 @@ int SPIO::DataRearr::Contig_rearr::rearrange_io2comp(const void *sbuf, std::size int ret = PIO_NOERR; assert(is_init_); - /* FIXME: We need a better way to find this info out */ - std::size_t agg_data_nelems = agg_compmap_sorter_.size(); + std::size_t agg_data_nelems = agg_iochunk_sz_; /* Disperse/scatter data */ void *agg_buf = NULL; @@ -787,7 +783,8 @@ int SPIO::DataRearr::Contig_rearr::setup_data_agg_info(const PIO_Offset *lcompma GPTLstop("PIO:Contig_rearr::setup_data_agg_info::sort"); /* Aggregate compmap sorter can be used to sort any user data based on gcompmap */ - agg_compmap_sorter_.resize(gcompmap.size()); + agg_iochunk_sz_ = gcompmap.size(); + agg_compmap_sorter_.resize(agg_iochunk_sz_); for(std::size_t i = 0; i < gcompmap_idx.size(); i++){ agg_compmap_sorter_[gcompmap_idx[i]] = i; } @@ -1297,8 +1294,7 @@ int SPIO::DataRearr::Contig_rearr::rearrange_data(const void *sbuf, std::size_t //std::vector agg_rtypes_nvars; std::vector rearr_stypes_nvars, rearr_rtypes_nvars; - /* FIXME: We need a better way to find this info out */ - std::size_t agg_data_nelems = agg_compmap_sorter_.size(); + std::size_t agg_data_nelems = agg_iochunk_sz_; //assert(abuf_sz == nvars * agg_data_nelems * elem_mpi_type_sz_); //std::cout << "DBG: sbuf[], rbuf[] before rearrange :\n" << std::flush; diff --git a/src/clib/pio_rearr_contig.hpp b/src/clib/pio_rearr_contig.hpp index 6419b78248..57a6825a99 100644 --- a/src/clib/pio_rearr_contig.hpp +++ b/src/clib/pio_rearr_contig.hpp @@ -59,7 +59,7 @@ namespace SPIO{ Contig_rearr(iosystem_desc_t *ios):is_init_(false), ios_(ios), iodesc_(NULL), lcompmap_sz_(0), elem_pio_type_(PIO_NAT), elem_mpi_type_(MPI_DATATYPE_NULL), elem_mpi_type_sz_(0), agg_comm_(MPI_COMM_NULL), is_agg_root_(false), - agg_comm_sz_(0), rearr_comm_(MPI_COMM_NULL), rearr_comm_sz_(0), + agg_comm_sz_(0), agg_iochunk_sz_(0), rearr_comm_(MPI_COMM_NULL), rearr_comm_sz_(0), rearr_comm_iochunk_sz_(0){} /* Initialize the rearranger */ int init(int pio_type, const PIO_Offset *compmap, std::size_t compmap_sz, @@ -137,6 +137,8 @@ namespace SPIO{ MPI_Comm agg_comm_; bool is_agg_root_; int agg_comm_sz_; + /* Size/Num of elements of the data chunk in this aggregating process */ + std::size_t agg_iochunk_sz_; std::vector agg_compmap_sorter_; /* The byte displacements for each process, that is part of agg_comm_, in the aggregated data */ std::vector agg_data_byte_displs_; From 05fd7e8b877148a9ae28f7592aca3d0c77935c24 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Sun, 4 May 2025 14:50:44 -0500 Subject: [PATCH 063/194] Use version range for CMake min ver Using a range of CMake versions that we have tested, instead of a single version, for the min version of CMake required by the projects. This gets rid of CMake warnings with recent CMake versions that remove support for (compatibility with) older CMake versions. --- CMakeLists.txt | 2 +- src/clib/CMakeLists.txt | 2 +- src/flib/CMakeLists.txt | 2 +- src/flib_legacy/CMakeLists.txt | 2 +- src/gptl/CMakeLists.txt | 2 +- tests/CMakeLists.txt | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dd2172f8fe..28a09d2b67 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 3.7) +cmake_minimum_required (VERSION 3.7...4.0.1) project (SCORPIO C CXX Fortran) #cmake_policy(VERSION 3.5.2) diff --git a/src/clib/CMakeLists.txt b/src/clib/CMakeLists.txt index 56dd7483f3..79fec03896 100644 --- a/src/clib/CMakeLists.txt +++ b/src/clib/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 3.7) +cmake_minimum_required (VERSION 3.7...4.0.1) include (CheckFunctionExists) include(CheckTypeSize) include(SPIOTypeUtils) diff --git a/src/flib/CMakeLists.txt b/src/flib/CMakeLists.txt index 65cc5cfc2a..cf91b94dd3 100644 --- a/src/flib/CMakeLists.txt +++ b/src/flib/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 3.7) +cmake_minimum_required (VERSION 3.7...4.0.1) project (PIOF Fortran) include (CheckFunctionExists) include (ExternalProject) diff --git a/src/flib_legacy/CMakeLists.txt b/src/flib_legacy/CMakeLists.txt index ba408d86f1..0366ca45a5 100644 --- a/src/flib_legacy/CMakeLists.txt +++ b/src/flib_legacy/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 3.7) +cmake_minimum_required (VERSION 3.7...4.0.1) project (PIOF Fortran) include (CheckFunctionExists) include (ExternalProject) diff --git a/src/gptl/CMakeLists.txt b/src/gptl/CMakeLists.txt index 9d8f956834..d62d77153c 100644 --- a/src/gptl/CMakeLists.txt +++ b/src/gptl/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 3.7) +cmake_minimum_required (VERSION 3.7...4.0.1) project (GPTL C Fortran) include (CheckFunctionExists) include(CheckSymbolExists) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8288f9098b..5f9097a32a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 3.7) +cmake_minimum_required (VERSION 3.7...4.0.1) project (PIOTests C Fortran) #============================================================================== From 371db14d9dd05779512913c9145f7dd6ced819d1 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 15 May 2025 15:54:39 -0500 Subject: [PATCH 064/194] Moving timers for functions to API layer Moving GPTL timers for all SCORPIO C API functions to the API layer. Also using the GPTL wrapper util for the timers. This change reduces timer related clutter (stop on err etc)in the C library --- src/clib/api/spio_ddata_api.cpp | 7 ++ src/clib/api/spio_dim_api.cpp | 7 ++ src/clib/api/spio_err_api.cpp | 3 + src/clib/api/spio_file_api.cpp | 12 +++ src/clib/api/spio_file_md_api.cpp | 11 +++ src/clib/api/spio_get_att_api.cpp | 14 +++ src/clib/api/spio_get_var1_api.cpp | 14 +++ src/clib/api/spio_get_var_api.cpp | 14 +++ src/clib/api/spio_get_vara_api.cpp | 14 +++ src/clib/api/spio_get_varm_api.cpp | 13 +++ src/clib/api/spio_get_vars_api.cpp | 14 +++ src/clib/api/spio_io_decomp_api.cpp | 12 +++ src/clib/api/spio_io_sys_api.cpp | 45 +++++++++ src/clib/api/spio_misc_att_api.cpp | 9 ++ src/clib/api/spio_misc_var_api.cpp | 21 ++++ src/clib/api/spio_put_att_api.cpp | 14 +++ src/clib/api/spio_put_var1_api.cpp | 14 +++ src/clib/api/spio_put_var_api.cpp | 14 +++ src/clib/api/spio_put_vara_api.cpp | 14 +++ src/clib/api/spio_put_varm_api.cpp | 14 +++ src/clib/api/spio_put_vars_api.cpp | 14 +++ src/clib/pio_darray.cpp | 13 --- src/clib/pio_file.cpp | 50 ---------- src/clib/pio_getput_int.cpp | 148 ---------------------------- src/clib/pioc.cpp | 21 ---- src/clib/pioc_support.cpp | 9 -- 26 files changed, 294 insertions(+), 241 deletions(-) diff --git a/src/clib/api/spio_ddata_api.cpp b/src/clib/api/spio_ddata_api.cpp index 98ebfb2fba..6a926f116a 100644 --- a/src/clib/api/spio_ddata_api.cpp +++ b/src/clib/api/spio_ddata_api.cpp @@ -3,10 +3,12 @@ #include "pio_internal.h" #include "pio_api_impl.h" #include "spio_tracer.hpp" +#include "spio_gptl_utils.hpp" /* ================= Read/Write APIs for distributed data ================ */ int PIOc_advanceframe(int ncid, int varid) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_advanceframe"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_advanceframe"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid).flush(); @@ -16,6 +18,7 @@ int PIOc_advanceframe(int ncid, int varid) int PIOc_setframe(int ncid, int varid, int frame) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_setframe"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_setframe"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid). @@ -27,6 +30,7 @@ int PIOc_setframe(int ncid, int varid, int frame) int PIOc_write_darray(int ncid, int varid, int ioid, PIO_Offset arraylen, const void *array, const void *fillvalue) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_write_darray"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_write_darray"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid). @@ -39,6 +43,7 @@ int PIOc_write_darray(int ncid, int varid, int ioid, PIO_Offset arraylen, const int PIOc_write_darray_multi(int ncid, const int *varids, int ioid, int nvars, PIO_Offset arraylen, const void *array, const int *frame, const void **fillvalue, bool flushtodisk) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_write_darray_multi"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_write_darray_multi"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("*varids", varids). @@ -54,6 +59,7 @@ int PIOc_write_darray_multi(int ncid, const int *varids, int ioid, int nvars, PI int PIOc_read_darray(int ncid, int varid, int ioid, PIO_Offset arraylen, void *array) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_read_darray"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_read_darray"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid). @@ -65,6 +71,7 @@ int PIOc_read_darray(int ncid, int varid, int ioid, PIO_Offset arraylen, void *a int PIOc_get_local_array_size(int ioid) { + //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_local_array_size"); /* FIXME: How should we trace these non I/O system specific functions? */ return PIOc_get_local_array_size_impl(ioid); } diff --git a/src/clib/api/spio_dim_api.cpp b/src/clib/api/spio_dim_api.cpp index 437a7b9eb2..97bb4c822c 100644 --- a/src/clib/api/spio_dim_api.cpp +++ b/src/clib/api/spio_dim_api.cpp @@ -3,11 +3,13 @@ #include "pio_internal.h" #include "pio_api_impl.h" #include "spio_tracer.hpp" +#include "spio_gptl_utils.hpp" /* ================= File meta-data APIs ============== */ /* APIs for variable dimensions */ int PIOc_inq_dim(int ncid, int dimid, char *name, PIO_Offset *lenp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_dimx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_dim"); @@ -24,6 +26,7 @@ int PIOc_inq_dim(int ncid, int dimid, char *name, PIO_Offset *lenp) int PIOc_inq_dimid(int ncid, const char *name, int *idp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_dimx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_dimid"); @@ -41,6 +44,7 @@ int PIOc_inq_dimid(int ncid, const char *name, int *idp) int PIOc_inq_dimname(int ncid, int dimid, char *name) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_dimx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_dimname"); @@ -57,6 +61,7 @@ int PIOc_inq_dimname(int ncid, int dimid, char *name) int PIOc_inq_dimlen(int ncid, int dimid, PIO_Offset *lenp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_dimx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_dimlen"); @@ -73,6 +78,7 @@ int PIOc_inq_dimlen(int ncid, int dimid, PIO_Offset *lenp) int PIOc_rename_dim(int ncid, int dimid, const char *name) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_rename_dim"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_rename_dim"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("dimid", dimid). @@ -83,6 +89,7 @@ int PIOc_rename_dim(int ncid, int dimid, const char *name) int PIOc_def_dim(int ncid, const char *name, PIO_Offset len, int *idp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_def_dim"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_def_dim"); diff --git a/src/clib/api/spio_err_api.cpp b/src/clib/api/spio_err_api.cpp index 53fa1b7162..11bed90165 100644 --- a/src/clib/api/spio_err_api.cpp +++ b/src/clib/api/spio_err_api.cpp @@ -2,16 +2,19 @@ #include "pio.h" #include "pio_internal.h" #include "pio_api_impl.h" +//#include "spio_gptl_utils.hpp" /* ========== Error handling APIs =========== */ int PIOc_strerror(int pioerr, char *errmsg, size_t errmsg_sz) { + //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_strerror"); /* FIXME: Handle non I/O system specific calls */ return PIOc_strerror_impl(pioerr, errmsg, errmsg_sz); } int PIOc_set_log_level(int level) { + //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_set_log_level"); /* FIXME: Handle non I/O system specific calls */ return PIOc_set_log_level_impl(level); } diff --git a/src/clib/api/spio_file_api.cpp b/src/clib/api/spio_file_api.cpp index b1eeb23a32..1a9a988581 100644 --- a/src/clib/api/spio_file_api.cpp +++ b/src/clib/api/spio_file_api.cpp @@ -3,10 +3,12 @@ #include "pio_internal.h" #include "pio_api_impl.h" #include "spio_tracer.hpp" +#include "spio_gptl_utils.hpp" /* ================= File APIs ================= */ int PIOc_deletefile(int iosysid, const char *filename) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_deletefile"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_deletefile"); tr.set_iosys_id(iosysid).add_arg("iosysid", iosysid). @@ -17,6 +19,7 @@ int PIOc_deletefile(int iosysid, const char *filename) int PIOc_createfile(int iosysid, int *ncidp, const int *iotype, const char *fname, int mode) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_createfile"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_createfile"); @@ -34,6 +37,7 @@ int PIOc_createfile(int iosysid, int *ncidp, const int *iotype, const char *fnam int PIOc_create(int iosysid, const char *path, int cmode, int *ncidp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_create"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_create"); @@ -51,6 +55,7 @@ int PIOc_create(int iosysid, const char *path, int cmode, int *ncidp) int PIOc_openfile(int iosysid, int *ncidp, int *iotype, const char *fname, int mode) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_openfile"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_openfile"); @@ -68,6 +73,7 @@ int PIOc_openfile(int iosysid, int *ncidp, int *iotype, const char *fname, int m int PIOc_openfile2(int iosysid, int *ncidp, int *iotype, const char *fname, int mode) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_openfile2"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_openfile2"); @@ -86,6 +92,7 @@ int PIOc_openfile2(int iosysid, int *ncidp, int *iotype, const char *fname, int int PIOc_openfile_retry(int iosysid, int *ncidp, int *iotype, const char *filename, int mode, int retry) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_openfile_retry"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_openfile_retry"); @@ -103,6 +110,7 @@ int PIOc_openfile_retry(int iosysid, int *ncidp, int *iotype, int PIOc_open(int iosysid, const char *path, int mode, int *ncidp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_open"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_open"); @@ -120,6 +128,7 @@ int PIOc_open(int iosysid, const char *path, int mode, int *ncidp) int PIOc_closefile(int ncid) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_closefile"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_closefile"); tr.set_file_id(ncid).add_arg("ncid", ncid).flush(); @@ -129,6 +138,7 @@ int PIOc_closefile(int ncid) int PIOc_File_is_Open(int ncid) { + //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_File_is_Open"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_File_is_Open"); tr.set_file_id(ncid).add_arg("ncid", ncid).flush(); @@ -139,6 +149,7 @@ int PIOc_File_is_Open(int ncid) /* Set the error hanlding for a file. */ int PIOc_Set_File_Error_Handling(int ncid, int method) { + //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_Set_File_Error_Handling"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_Set_File_Error_Handling"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("method", method).flush(); @@ -148,6 +159,7 @@ int PIOc_Set_File_Error_Handling(int ncid, int method) int PIOc_sync(int ncid) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_sync"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_sync"); tr.set_file_id(ncid).add_arg("ncid", ncid).flush(); diff --git a/src/clib/api/spio_file_md_api.cpp b/src/clib/api/spio_file_md_api.cpp index 79258c0eb7..9ff12077f4 100644 --- a/src/clib/api/spio_file_md_api.cpp +++ b/src/clib/api/spio_file_md_api.cpp @@ -3,10 +3,12 @@ #include "pio_internal.h" #include "pio_api_impl.h" #include "spio_tracer.hpp" +#include "spio_gptl_utils.hpp" /* ================= File meta-data APIs ============== */ int PIOc_redef(int ncid) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_redef"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_redef"); tr.set_file_id(ncid).add_arg("ncid", ncid).flush(); @@ -16,6 +18,7 @@ int PIOc_redef(int ncid) int PIOc_enddef(int ncid) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_enddef"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_enddef"); tr.set_file_id(ncid).add_arg("ncid", ncid).flush(); @@ -25,6 +28,7 @@ int PIOc_enddef(int ncid) int PIOc_inq_format(int ncid, int *formatp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inqx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING @@ -42,6 +46,7 @@ int PIOc_inq_format(int ncid, int *formatp) int PIOc_inq(int ncid, int *ndimsp, int *nvarsp, int *ngattsp, int *unlimdimidp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inqx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING @@ -61,6 +66,7 @@ int PIOc_inq(int ncid, int *ndimsp, int *nvarsp, int *ngattsp, int *unlimdimidp) int PIOc_inq_ndims(int ncid, int *ndimsp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inqx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING @@ -78,6 +84,7 @@ int PIOc_inq_ndims(int ncid, int *ndimsp) int PIOc_inq_nvars(int ncid, int *nvarsp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inqx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING @@ -95,6 +102,7 @@ int PIOc_inq_nvars(int ncid, int *nvarsp) int PIOc_inq_natts(int ncid, int *ngattsp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inqx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING @@ -112,6 +120,7 @@ int PIOc_inq_natts(int ncid, int *ngattsp) int PIOc_inq_unlimdim(int ncid, int *unlimdimidp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inqx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING @@ -129,6 +138,7 @@ int PIOc_inq_unlimdim(int ncid, int *unlimdimidp) int PIOc_inq_unlimdims(int ncid, int *nunlimdimsp, int *unlimdimidsp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inqx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING @@ -150,6 +160,7 @@ int PIOc_inq_unlimdims(int ncid, int *nunlimdimsp, int *unlimdimidsp) int PIOc_inq_type(int ncid, nc_type xtype, char *name, PIO_Offset *sizep) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inqx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING diff --git a/src/clib/api/spio_get_att_api.cpp b/src/clib/api/spio_get_att_api.cpp index 4ec8cb5988..9e977a31e9 100644 --- a/src/clib/api/spio_get_att_api.cpp +++ b/src/clib/api/spio_get_att_api.cpp @@ -3,10 +3,12 @@ #include "pio_internal.h" #include "pio_api_impl.h" #include "spio_tracer.hpp" +#include "spio_gptl_utils.hpp" /* APIs for reading file/variable attributes */ int PIOc_get_att(int ncid, int varid, const char *name, void *ip) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -18,6 +20,7 @@ int PIOc_get_att(int ncid, int varid, const char *name, void *ip) int PIOc_get_att_text(int ncid, int varid, const char *name, char *ip) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att_text"); @@ -35,6 +38,7 @@ int PIOc_get_att_text(int ncid, int varid, const char *name, char *ip) int PIOc_get_att_schar(int ncid, int varid, const char *name, signed char *ip) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att_schar"); @@ -52,6 +56,7 @@ int PIOc_get_att_schar(int ncid, int varid, const char *name, signed char *ip) int PIOc_get_att_short(int ncid, int varid, const char *name, short *ip) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att_short"); @@ -69,6 +74,7 @@ int PIOc_get_att_short(int ncid, int varid, const char *name, short *ip) int PIOc_get_att_int(int ncid, int varid, const char *name, int *ip) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att_int"); @@ -86,6 +92,7 @@ int PIOc_get_att_int(int ncid, int varid, const char *name, int *ip) int PIOc_get_att_long(int ncid, int varid, const char *name, long *ip) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att_long"); @@ -103,6 +110,7 @@ int PIOc_get_att_long(int ncid, int varid, const char *name, long *ip) int PIOc_get_att_float(int ncid, int varid, const char *name, float *ip) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att_float"); @@ -120,6 +128,7 @@ int PIOc_get_att_float(int ncid, int varid, const char *name, float *ip) int PIOc_get_att_double(int ncid, int varid, const char *name, double *ip) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att_double"); @@ -137,6 +146,7 @@ int PIOc_get_att_double(int ncid, int varid, const char *name, double *ip) int PIOc_get_att_uchar(int ncid, int varid, const char *name, unsigned char *ip) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att_uchar"); @@ -154,6 +164,7 @@ int PIOc_get_att_uchar(int ncid, int varid, const char *name, unsigned char *ip) int PIOc_get_att_ushort(int ncid, int varid, const char *name, unsigned short *ip) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att_ushort"); @@ -171,6 +182,7 @@ int PIOc_get_att_ushort(int ncid, int varid, const char *name, unsigned short *i int PIOc_get_att_uint(int ncid, int varid, const char *name, unsigned int *ip) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att_uint"); @@ -188,6 +200,7 @@ int PIOc_get_att_uint(int ncid, int varid, const char *name, unsigned int *ip) int PIOc_get_att_longlong(int ncid, int varid, const char *name, long long *ip) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att_longlong"); @@ -205,6 +218,7 @@ int PIOc_get_att_longlong(int ncid, int varid, const char *name, long long *ip) int PIOc_get_att_ulonglong(int ncid, int varid, const char *name, unsigned long long *ip) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att_ulonglong"); diff --git a/src/clib/api/spio_get_var1_api.cpp b/src/clib/api/spio_get_var1_api.cpp index 61d976da1c..f8a48d9fa4 100644 --- a/src/clib/api/spio_get_var1_api.cpp +++ b/src/clib/api/spio_get_var1_api.cpp @@ -4,10 +4,12 @@ #include "pio_api_impl.h" #include "spio_tracer.hpp" #include "spio_get_utils.hpp" +#include "spio_gptl_utils.hpp" /* APIs for reading non-distributed data/variable at a specified index */ int PIOc_get_var1(int ncid, int varid, const PIO_Offset *index, void *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -19,6 +21,7 @@ int PIOc_get_var1(int ncid, int varid, const PIO_Offset *index, void *buf) int PIOc_get_var1_text(int ncid, int varid, const PIO_Offset *index, char *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1_text"); @@ -36,6 +39,7 @@ int PIOc_get_var1_text(int ncid, int varid, const PIO_Offset *index, char *buf) int PIOc_get_var1_schar(int ncid, int varid, const PIO_Offset *index, signed char *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1_schar"); @@ -53,6 +57,7 @@ int PIOc_get_var1_schar(int ncid, int varid, const PIO_Offset *index, signed cha int PIOc_get_var1_short(int ncid, int varid, const PIO_Offset *index, short *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1_short"); @@ -70,6 +75,7 @@ int PIOc_get_var1_short(int ncid, int varid, const PIO_Offset *index, short *buf int PIOc_get_var1_int(int ncid, int varid, const PIO_Offset *index, int *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1_int"); @@ -87,6 +93,7 @@ int PIOc_get_var1_int(int ncid, int varid, const PIO_Offset *index, int *buf) int PIOc_get_var1_long(int ncid, int varid, const PIO_Offset *index, long *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1_long"); @@ -104,6 +111,7 @@ int PIOc_get_var1_long(int ncid, int varid, const PIO_Offset *index, long *buf) int PIOc_get_var1_float(int ncid, int varid, const PIO_Offset *index, float *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1_float"); @@ -121,6 +129,7 @@ int PIOc_get_var1_float(int ncid, int varid, const PIO_Offset *index, float *buf int PIOc_get_var1_double(int ncid, int varid, const PIO_Offset *index, double *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1_double"); @@ -138,6 +147,7 @@ int PIOc_get_var1_double(int ncid, int varid, const PIO_Offset *index, double *b int PIOc_get_var1_uchar(int ncid, int varid, const PIO_Offset *index, unsigned char *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1_uchar"); @@ -155,6 +165,7 @@ int PIOc_get_var1_uchar(int ncid, int varid, const PIO_Offset *index, unsigned c int PIOc_get_var1_ushort(int ncid, int varid, const PIO_Offset *index, unsigned short *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1_ushort"); @@ -172,6 +183,7 @@ int PIOc_get_var1_ushort(int ncid, int varid, const PIO_Offset *index, unsigned int PIOc_get_var1_uint(int ncid, int varid, const PIO_Offset *index, unsigned int *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1_uint"); @@ -189,6 +201,7 @@ int PIOc_get_var1_uint(int ncid, int varid, const PIO_Offset *index, unsigned in int PIOc_get_var1_longlong(int ncid, int varid, const PIO_Offset *index, long long *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1_longlong"); @@ -206,6 +219,7 @@ int PIOc_get_var1_longlong(int ncid, int varid, const PIO_Offset *index, long lo int PIOc_get_var1_ulonglong(int ncid, int varid, const PIO_Offset *index, unsigned long long *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1_ulonglong"); diff --git a/src/clib/api/spio_get_var_api.cpp b/src/clib/api/spio_get_var_api.cpp index a95d849711..91af33400a 100644 --- a/src/clib/api/spio_get_var_api.cpp +++ b/src/clib/api/spio_get_var_api.cpp @@ -4,10 +4,12 @@ #include "pio_api_impl.h" #include "spio_tracer.hpp" #include "spio_get_utils.hpp" +#include "spio_gptl_utils.hpp" /* APIs for reading entire non-distributed data/variable */ int PIOc_get_var(int ncid, int varid, void *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -18,6 +20,7 @@ int PIOc_get_var(int ncid, int varid, void *buf) int PIOc_get_var_text(int ncid, int varid, char *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_text"); @@ -35,6 +38,7 @@ int PIOc_get_var_text(int ncid, int varid, char *buf) int PIOc_get_var_schar(int ncid, int varid, signed char *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_schar"); @@ -51,6 +55,7 @@ int PIOc_get_var_schar(int ncid, int varid, signed char *buf) int PIOc_get_var_short(int ncid, int varid, short *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_short"); @@ -67,6 +72,7 @@ int PIOc_get_var_short(int ncid, int varid, short *buf) int PIOc_get_var_int(int ncid, int varid, int *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_int"); @@ -83,6 +89,7 @@ int PIOc_get_var_int(int ncid, int varid, int *buf) int PIOc_get_var_long(int ncid, int varid, long *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_long"); @@ -99,6 +106,7 @@ int PIOc_get_var_long(int ncid, int varid, long *buf) int PIOc_get_var_float(int ncid, int varid, float *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_float"); @@ -115,6 +123,7 @@ int PIOc_get_var_float(int ncid, int varid, float *buf) int PIOc_get_var_double(int ncid, int varid, double *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_double"); @@ -131,6 +140,7 @@ int PIOc_get_var_double(int ncid, int varid, double *buf) int PIOc_get_var_uchar(int ncid, int varid, unsigned char *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_uchar"); @@ -147,6 +157,7 @@ int PIOc_get_var_uchar(int ncid, int varid, unsigned char *buf) int PIOc_get_var_ushort(int ncid, int varid, unsigned short *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_ushort"); @@ -163,6 +174,7 @@ int PIOc_get_var_ushort(int ncid, int varid, unsigned short *buf) int PIOc_get_var_uint(int ncid, int varid, unsigned int *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_uint"); @@ -179,6 +191,7 @@ int PIOc_get_var_uint(int ncid, int varid, unsigned int *buf) int PIOc_get_var_longlong(int ncid, int varid, long long *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_longlong"); @@ -195,6 +208,7 @@ int PIOc_get_var_longlong(int ncid, int varid, long long *buf) int PIOc_get_var_ulonglong(int ncid, int varid, unsigned long long *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_ulonglong"); diff --git a/src/clib/api/spio_get_vara_api.cpp b/src/clib/api/spio_get_vara_api.cpp index 14b91f2d03..7d3fec58b6 100644 --- a/src/clib/api/spio_get_vara_api.cpp +++ b/src/clib/api/spio_get_vara_api.cpp @@ -4,11 +4,13 @@ #include "pio_api_impl.h" #include "spio_tracer.hpp" #include "spio_get_utils.hpp" +#include "spio_gptl_utils.hpp" #include /* APIs for reading a hyperslab of non-distributed data/variable */ int PIOc_get_vara(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, void *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -22,6 +24,7 @@ int PIOc_get_vara(int ncid, int varid, const PIO_Offset *start, const PIO_Offset int PIOc_get_vara_text(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, char *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara_text"); @@ -40,6 +43,7 @@ int PIOc_get_vara_text(int ncid, int varid, const PIO_Offset *start, const PIO_O int PIOc_get_vara_schar(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, signed char *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara_schar"); @@ -58,6 +62,7 @@ int PIOc_get_vara_schar(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_get_vara_short(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, short *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara_short"); @@ -76,6 +81,7 @@ int PIOc_get_vara_short(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_get_vara_int(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, int *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara_int"); @@ -94,6 +100,7 @@ int PIOc_get_vara_int(int ncid, int varid, const PIO_Offset *start, const PIO_Of int PIOc_get_vara_float(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, float *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara_float"); @@ -112,6 +119,7 @@ int PIOc_get_vara_float(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_get_vara_long(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, long *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara_long"); @@ -130,6 +138,7 @@ int PIOc_get_vara_long(int ncid, int varid, const PIO_Offset *start, const PIO_O int PIOc_get_vara_double(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, double *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara_double"); @@ -148,6 +157,7 @@ int PIOc_get_vara_double(int ncid, int varid, const PIO_Offset *start, int PIOc_get_vara_uchar(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, unsigned char *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara_uchar"); @@ -166,6 +176,7 @@ int PIOc_get_vara_uchar(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_get_vara_ushort(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, unsigned short *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara_ushort"); @@ -184,6 +195,7 @@ int PIOc_get_vara_ushort(int ncid, int varid, const PIO_Offset *start, const PIO int PIOc_get_vara_uint(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, unsigned int *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara_uint"); @@ -202,6 +214,7 @@ int PIOc_get_vara_uint(int ncid, int varid, const PIO_Offset *start, const PIO_O int PIOc_get_vara_longlong(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, long long *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara_longlong"); @@ -220,6 +233,7 @@ int PIOc_get_vara_longlong(int ncid, int varid, const PIO_Offset *start, const P int PIOc_get_vara_ulonglong(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, unsigned long long *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara_ulonglong"); diff --git a/src/clib/api/spio_get_varm_api.cpp b/src/clib/api/spio_get_varm_api.cpp index 968ad655fa..c387213333 100644 --- a/src/clib/api/spio_get_varm_api.cpp +++ b/src/clib/api/spio_get_varm_api.cpp @@ -4,6 +4,7 @@ #include "pio_api_impl.h" #include "spio_tracer.hpp" #include "spio_get_utils.hpp" +#include "spio_gptl_utils.hpp" /* APIs for reading/writing a hyperslab of strided non-distributed data/variable * with a mapped array. The mapped array maps between memory and variable data @@ -14,6 +15,7 @@ int PIOc_get_varm_schar(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, signed char *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_varm_schar"); @@ -32,6 +34,7 @@ int PIOc_get_varm_schar(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_get_varm_short(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, short *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_varm_short"); @@ -50,6 +53,7 @@ int PIOc_get_varm_short(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_get_varm_ulonglong(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, unsigned long long *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_varm_ulonglong"); @@ -68,6 +72,7 @@ int PIOc_get_varm_ulonglong(int ncid, int varid, const PIO_Offset *start, const int PIOc_get_varm_ushort(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, unsigned short *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_varm_ushort"); @@ -86,6 +91,7 @@ int PIOc_get_varm_ushort(int ncid, int varid, const PIO_Offset *start, const PIO int PIOc_get_varm_longlong(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, long long *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_varm_longlong"); @@ -104,6 +110,7 @@ int PIOc_get_varm_longlong(int ncid, int varid, const PIO_Offset *start, const P int PIOc_get_varm_double(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, double *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_varm_double"); @@ -122,6 +129,7 @@ int PIOc_get_varm_double(int ncid, int varid, const PIO_Offset *start, const PIO int PIOc_get_varm_text(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, char *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_varm_text"); @@ -140,6 +148,7 @@ int PIOc_get_varm_text(int ncid, int varid, const PIO_Offset *start, const PIO_O int PIOc_get_varm_int(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, int *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_varm_int"); @@ -158,6 +167,7 @@ int PIOc_get_varm_int(int ncid, int varid, const PIO_Offset *start, const PIO_Of int PIOc_get_varm_uint(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, unsigned int *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_varm_uint"); @@ -177,6 +187,7 @@ int PIOc_get_varm(int ncid, int varid, const PIO_Offset *start, const PIO_Offset const PIO_Offset *stride, const PIO_Offset *imap, void *buf, PIO_Offset bufcount, MPI_Datatype buftype) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_varm"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid). @@ -191,6 +202,7 @@ int PIOc_get_varm(int ncid, int varid, const PIO_Offset *start, const PIO_Offset int PIOc_get_varm_float(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, float *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_varm_float"); @@ -209,6 +221,7 @@ int PIOc_get_varm_float(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_get_varm_long(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, long *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_varm_long"); diff --git a/src/clib/api/spio_get_vars_api.cpp b/src/clib/api/spio_get_vars_api.cpp index 2ce44bd535..92d24de594 100644 --- a/src/clib/api/spio_get_vars_api.cpp +++ b/src/clib/api/spio_get_vars_api.cpp @@ -4,11 +4,13 @@ #include "pio_api_impl.h" #include "spio_tracer.hpp" #include "spio_get_utils.hpp" +#include "spio_gptl_utils.hpp" /* APIs for reading a hyperslab of strided non-distributed data/variable */ int PIOc_get_vars(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, void *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid). @@ -21,6 +23,7 @@ int PIOc_get_vars(int ncid, int varid, const PIO_Offset *start, const PIO_Offset int PIOc_get_vars_text(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, char *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars_text"); @@ -39,6 +42,7 @@ int PIOc_get_vars_text(int ncid, int varid, const PIO_Offset *start, const PIO_O int PIOc_get_vars_schar(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, signed char *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars_schar"); @@ -57,6 +61,7 @@ int PIOc_get_vars_schar(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_get_vars_short(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, short *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars_short"); @@ -75,6 +80,7 @@ int PIOc_get_vars_short(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_get_vars_int(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, int *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars_int"); @@ -93,6 +99,7 @@ int PIOc_get_vars_int(int ncid, int varid, const PIO_Offset *start, const PIO_Of int PIOc_get_vars_long(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, long *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars_long"); @@ -111,6 +118,7 @@ int PIOc_get_vars_long(int ncid, int varid, const PIO_Offset *start, const PIO_O int PIOc_get_vars_float(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, float *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars_float"); @@ -129,6 +137,7 @@ int PIOc_get_vars_float(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_get_vars_double(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, double *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars_double"); @@ -147,6 +156,7 @@ int PIOc_get_vars_double(int ncid, int varid, const PIO_Offset *start, const PIO int PIOc_get_vars_uchar(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, unsigned char *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars_uchar"); @@ -165,6 +175,7 @@ int PIOc_get_vars_uchar(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_get_vars_ushort(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, unsigned short *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars_ushort"); @@ -183,6 +194,7 @@ int PIOc_get_vars_ushort(int ncid, int varid, const PIO_Offset *start, const PIO int PIOc_get_vars_uint(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, unsigned int *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars_uint"); @@ -201,6 +213,7 @@ int PIOc_get_vars_uint(int ncid, int varid, const PIO_Offset *start, const PIO_O int PIOc_get_vars_longlong(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, long long *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars_longlong"); @@ -220,6 +233,7 @@ int PIOc_get_vars_ulonglong(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, unsigned long long *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars_ulonglong"); diff --git a/src/clib/api/spio_io_decomp_api.cpp b/src/clib/api/spio_io_decomp_api.cpp index af37eaf4f9..34a7d65bfd 100644 --- a/src/clib/api/spio_io_decomp_api.cpp +++ b/src/clib/api/spio_io_decomp_api.cpp @@ -3,6 +3,7 @@ #include "pio_internal.h" #include "pio_api_impl.h" #include "spio_tracer.hpp" +#include "spio_gptl_utils.hpp" /* ========== APIs to handle I/O Decomposition =============== */ @@ -11,6 +12,7 @@ int PIOc_InitDecomp(int iosysid, int pio_type, int ndims, const int *gdimlen, in const PIO_Offset *compmap, int *ioidp, const int *rearr, const PIO_Offset *iostart, const PIO_Offset *iocount) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_InitDecomp"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_InitDecomp"); @@ -33,6 +35,7 @@ int PIOc_InitDecomp(int iosysid, int pio_type, int ndims, const int *gdimlen, in int PIOc_InitDecomp_bc(int iosysid, int basetype, int ndims, const int *gdimlen, const long int *start, const long int *count, int *ioidp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_InitDecomp_bc"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_InitDecomp_bc"); @@ -56,6 +59,7 @@ int PIOc_init_decomp(int iosysid, int pio_type, int ndims, const int *gdimlen, i const PIO_Offset *compmap, int *ioidp, int rearranger, const PIO_Offset *iostart, const PIO_Offset *iocount) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_init_decomp"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_init_decomp"); @@ -80,6 +84,7 @@ int PIOc_init_decomp(int iosysid, int pio_type, int ndims, const int *gdimlen, i /* Free resources associated with a decomposition. */ int PIOc_freedecomp(int iosysid, int ioid) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_freedecomp"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_freedecomp"); tr.set_iosys_id(iosysid).add_arg("iosysid", iosysid).add_arg("ioid", ioid).flush(); @@ -92,6 +97,7 @@ int PIOc_freedecomp(int iosysid, int ioid) int PIOc_readmap(const char *file, int *ndims, int **gdims, PIO_Offset *fmaplen, PIO_Offset **map, MPI_Comm comm) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_readmap"); /* FIXME: Add support for tracing comm-specific calls */ return PIOc_readmap_impl(file, ndims, gdims, fmaplen, map, comm); } @@ -99,6 +105,7 @@ int PIOc_readmap(const char *file, int *ndims, int **gdims, PIO_Offset *fmaplen, int PIOc_readmap_from_f90(const char *file,int *ndims, int **gdims, PIO_Offset *maplen, PIO_Offset **map, int f90_comm) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_readmap_from_f90"); /* FIXME: Add support for tracing comm-specific calls */ return PIOc_readmap_from_f90_impl(file, ndims, gdims, maplen, map, f90_comm); } @@ -106,6 +113,7 @@ int PIOc_readmap_from_f90(const char *file,int *ndims, int **gdims, PIO_Offset * int PIOc_writemap(const char *file, int ioid, int ndims, const int *gdims, PIO_Offset maplen, const PIO_Offset *map, MPI_Comm comm) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_writemap"); /* FIXME: Add support for tracing comm-specific calls */ return PIOc_writemap_impl(file, ioid, ndims, gdims, maplen, map, comm); } @@ -113,6 +121,7 @@ int PIOc_writemap(const char *file, int ioid, int ndims, const int *gdims, PIO_O int PIOc_writemap_from_f90(const char *file, int ioid, int ndims, const int *gdims, PIO_Offset maplen, const PIO_Offset *map, int f90_comm) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_writemap_from_f90"); /* FIXME: Add support for tracing comm-specific calls */ return PIOc_writemap_from_f90_impl(file, ioid, ndims, gdims, maplen, map, f90_comm); } @@ -121,6 +130,7 @@ int PIOc_writemap_from_f90(const char *file, int ioid, int ndims, const int *gdi /* Write a decomposition file. */ int PIOc_write_decomp(const char *file, int iosysid, int ioid, MPI_Comm comm) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_write_decomp"); /* FIXME: Add support for tracing comm-specific calls */ return PIOc_write_decomp_impl(file, iosysid, ioid, comm); } @@ -130,6 +140,7 @@ int PIOc_write_decomp(const char *file, int iosysid, int ioid, MPI_Comm comm) int PIOc_write_nc_decomp(int iosysid, const char *filename, int cmode, int ioid, const char *title, const char *history, int fortran_order) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_write_nc_decomp"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_write_nc_decomp"); tr.set_iosys_id(iosysid).add_arg("iosysid", iosysid). @@ -146,6 +157,7 @@ int PIOc_write_nc_decomp(int iosysid, const char *filename, int cmode, int ioid, int PIOc_read_nc_decomp(int iosysid, const char *filename, int *ioid, MPI_Comm comm, int pio_type, char *title, char *history, int *fortran_order) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_read_nc_decomp"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_read_nc_decomp"); tr.set_iosys_id(iosysid).add_arg("iosysid", iosysid). diff --git a/src/clib/api/spio_io_sys_api.cpp b/src/clib/api/spio_io_sys_api.cpp index bca8ce8792..7ef9c9bfa4 100644 --- a/src/clib/api/spio_io_sys_api.cpp +++ b/src/clib/api/spio_io_sys_api.cpp @@ -3,6 +3,7 @@ #include "pio_internal.h" #include "pio_api_impl.h" #include "spio_tracer.hpp" +#include "spio_gptl_utils.hpp" /* ============= APIs for an I/O system (like MPI communicators) =================== */ /* Initializing I/O system for asynchronous I/O */ @@ -10,6 +11,12 @@ int PIOc_init_async(MPI_Comm world, int num_io_procs, const int *io_proc_list, i const int *num_procs_per_comp, const int **proc_list, MPI_Comm *io_comm, MPI_Comm *comp_comm, int rearranger, int *iosysidp) { +#ifdef TIMING +#ifdef TIMING_INTERNAL + pio_init_gptl(); +#endif +#endif + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_init_async"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_init_async"); @@ -34,6 +41,12 @@ int PIOc_init_intercomm(int component_count, const MPI_Comm peer_comm, const MPI_Comm *ucomp_comms, const MPI_Comm uio_comm, int rearranger, int *iosysidps) { +#ifdef TIMING +#ifdef TIMING_INTERNAL + pio_init_gptl(); +#endif +#endif + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_Init_Intercommx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_init_intercomm"); @@ -70,6 +83,12 @@ int PIOc_Init_Intercomm_from_F90(int component_count, int f90_peer_comm, const int *f90_comp_comms, int f90_io_comm, int rearranger, int *iosysidps) { +#ifdef TIMING +#ifdef TIMING_INTERNAL + pio_init_gptl(); +#endif +#endif + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_Init_Intercommx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_Init_Intercomm_from_F90"); @@ -107,6 +126,7 @@ int PIOc_Init_Intercomm_from_F90(int component_count, int f90_peer_comm, int PIOc_get_numiotasks(int iosysid, int *numiotasks) { + //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_numiotasks"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_num_iotasks"); @@ -124,6 +144,12 @@ int PIOc_get_numiotasks(int iosysid, int *numiotasks) int PIOc_Init_Intracomm(MPI_Comm comp_comm, int num_iotasks, int stride, int base, int rearr, int *iosysidp) { +#ifdef TIMING +#ifdef TIMING_INTERNAL + pio_init_gptl(); +#endif +#endif + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_Init_Intracommx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_Init_Intracomm"); @@ -145,6 +171,12 @@ int PIOc_Init_Intracomm_from_F90(int f90_comp_comm, const int base, const int rearr, rearr_opt_t *rearr_opts, int *iosysidp) { +#ifdef TIMING +#ifdef TIMING_INTERNAL + pio_init_gptl(); +#endif +#endif + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_Init_Intracommx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_Init_Intracomm_from_F90"); @@ -165,6 +197,7 @@ int PIOc_Init_Intracomm_from_F90(int f90_comp_comm, /* Finalize an I/O system */ int PIOc_finalize(int iosysid) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_finalize"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_finalize"); @@ -179,6 +212,7 @@ int PIOc_finalize(int iosysid) /* Set error handling for entire io system. */ int PIOc_Set_IOSystem_Error_Handling(int iosysid, int method) { + //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_Set_IOSystem_Error_Handling"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_Set_IOSystem_Error_Handling"); tr.set_iosys_id(iosysid).add_arg("iosysid", iosysid).add_arg("method", method).flush(); @@ -190,6 +224,7 @@ int PIOc_Set_IOSystem_Error_Handling(int iosysid, int method) /* Set error handling for entire io system. */ int PIOc_set_iosystem_error_handling(int iosysid, int method, int *old_method) { + //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_set_iosystem_error_handling"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_set_iosystem_error_handling"); tr.set_iosys_id(iosysid).add_arg("iosysid", iosysid).add_arg("method", method). @@ -201,6 +236,7 @@ int PIOc_set_iosystem_error_handling(int iosysid, int method, int *old_method) int PIOc_iam_iotask(int iosysid, bool *ioproc) { + //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_iam_iotask"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_iam_iotask"); @@ -216,6 +252,7 @@ int PIOc_iam_iotask(int iosysid, bool *ioproc) int PIOc_iotask_rank(int iosysid, int *iorank) { + //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_iotask_rank"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_iotask_rank"); @@ -231,6 +268,7 @@ int PIOc_iotask_rank(int iosysid, int *iorank) int PIOc_iosystem_is_active(int iosysid, bool *active) { + //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_iosystem_is_active"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_iosystem_is_active"); @@ -246,6 +284,7 @@ int PIOc_iosystem_is_active(int iosysid, bool *active) int PIOc_iotype_available(int iotype) { + //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_iotype_available"); /* FIXME: Figure out how to trace these non I/O system specific calls */ return PIOc_iotype_available_impl(iotype); } @@ -256,6 +295,7 @@ int PIOc_set_rearr_opts(int iosysid, int comm_type, int fcd, bool enable_hs_i2c, bool enable_isend_i2c, int max_pend_req_i2c) { + //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_set_rearr_opts"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_set_rearr_opts"); tr.set_iosys_id(iosysid).add_arg("iosysid", iosysid). @@ -276,6 +316,7 @@ int PIOc_set_rearr_opts(int iosysid, int comm_type, int fcd, int PIOc_set_hint(int iosysid, const char *hint, const char *hintval) { + //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_set_hint"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_set_hint"); tr.set_iosys_id(iosysid).add_arg("iosysid", iosysid). @@ -287,6 +328,7 @@ int PIOc_set_hint(int iosysid, const char *hint, const char *hintval) int PIOc_set_chunk_cache(int iosysid, int iotype, PIO_Offset size, PIO_Offset nelems, float preemption) { + //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_set_chunk_cache"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_set_chunk_cache"); tr.set_iosys_id(iosysid).add_arg("iosysid", iosysid).add_arg("iotype", iotype). @@ -300,6 +342,7 @@ int PIOc_set_chunk_cache(int iosysid, int iotype, PIO_Offset size, PIO_Offset ne int PIOc_get_chunk_cache(int iosysid, int iotype, PIO_Offset *sizep, PIO_Offset *nelemsp, float *preemptionp) { + //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_chunk_cache"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_chunk_cache"); @@ -319,6 +362,7 @@ int PIOc_get_chunk_cache(int iosysid, int iotype, PIO_Offset *sizep, PIO_Offset int PIOc_set_blocksize(int newblocksize) { + //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_set_blocksize"); /* FIXME: Figure out how to trace these non I/O system specific calls */ return PIOc_set_blocksize_impl(newblocksize); } @@ -326,6 +370,7 @@ int PIOc_set_blocksize(int newblocksize) /* Set the IO node data buffer size limit. */ PIO_Offset PIOc_set_buffer_size_limit(PIO_Offset limit) { + //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_set_buffer_size_limit"); /* FIXME: Figure out how to trace these non I/O system specific calls */ return PIOc_set_buffer_size_limit_impl(limit); } diff --git a/src/clib/api/spio_misc_att_api.cpp b/src/clib/api/spio_misc_att_api.cpp index 753f12a05f..343144fd3e 100644 --- a/src/clib/api/spio_misc_att_api.cpp +++ b/src/clib/api/spio_misc_att_api.cpp @@ -3,11 +3,13 @@ #include "pio_internal.h" #include "pio_api_impl.h" #include "spio_tracer.hpp" +#include "spio_gptl_utils.hpp" /* ================= File meta-data APIs ============== */ /* APIs for file/variable attributes */ int PIOc_rename_att(int ncid, int varid, const char *name, const char *newname) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_rename_att"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_rename_att"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -19,6 +21,7 @@ int PIOc_rename_att(int ncid, int varid, const char *name, const char *newname) int PIOc_del_att(int ncid, int varid, const char *name) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_del_att"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_del_att"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -30,6 +33,7 @@ int PIOc_del_att(int ncid, int varid, const char *name) int PIOc_inq_att(int ncid, int varid, const char *name, nc_type *xtypep, PIO_Offset *lenp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_att"); @@ -48,6 +52,7 @@ int PIOc_inq_att(int ncid, int varid, const char *name, nc_type *xtypep, int PIOc_inq_attid(int ncid, int varid, const char *name, int *idp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_attid"); @@ -65,6 +70,7 @@ int PIOc_inq_attid(int ncid, int varid, const char *name, int *idp) int PIOc_inq_attlen(int ncid, int varid, const char *name, PIO_Offset *lenp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_attlen"); @@ -82,6 +88,7 @@ int PIOc_inq_attlen(int ncid, int varid, const char *name, PIO_Offset *lenp) int PIOc_inq_atttype(int ncid, int varid, const char *name, nc_type *xtypep) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_atttype"); @@ -99,6 +106,7 @@ int PIOc_inq_atttype(int ncid, int varid, const char *name, nc_type *xtypep) int PIOc_inq_attname(int ncid, int varid, int attnum, char *name) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_attname"); @@ -116,6 +124,7 @@ int PIOc_inq_attname(int ncid, int varid, int attnum, char *name) int PIOc_copy_att(int incid, int ivarid, const char *name, int oncid, int ovarid) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_copy_att"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_copy_att"); tr.set_file_id(incid).add_arg("incid", incid). diff --git a/src/clib/api/spio_misc_var_api.cpp b/src/clib/api/spio_misc_var_api.cpp index 36ac255371..04b1bee290 100644 --- a/src/clib/api/spio_misc_var_api.cpp +++ b/src/clib/api/spio_misc_var_api.cpp @@ -3,10 +3,12 @@ #include "pio_internal.h" #include "pio_api_impl.h" #include "spio_tracer.hpp" +#include "spio_gptl_utils.hpp" /* APIs for file variables */ int PIOc_inq_varid(int ncid, const char *name, int *varidp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_varid"); @@ -25,6 +27,7 @@ int PIOc_inq_varid(int ncid, const char *name, int *varidp) int PIOc_inq_var(int ncid, int varid, char *name, int namelen, nc_type *xtypep, int *ndimsp, int *dimidsp, int *nattsp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_var"); @@ -55,6 +58,7 @@ int PIOc_inq_var(int ncid, int varid, char *name, int namelen, nc_type *xtypep, int PIOc_inq_varname(int ncid, int varid, char *name, int namelen) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_varname"); @@ -71,6 +75,7 @@ int PIOc_inq_varname(int ncid, int varid, char *name, int namelen) int PIOc_inq_vartype(int ncid, int varid, nc_type *xtypep) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_vartype"); @@ -87,6 +92,7 @@ int PIOc_inq_vartype(int ncid, int varid, nc_type *xtypep) int PIOc_inq_varndims(int ncid, int varid, int *ndimsp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_varndims"); @@ -103,6 +109,7 @@ int PIOc_inq_varndims(int ncid, int varid, int *ndimsp) int PIOc_inq_vardimid(int ncid, int varid, int *dimidsp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_vardimid"); @@ -123,6 +130,7 @@ int PIOc_inq_vardimid(int ncid, int varid, int *dimidsp) int PIOc_inq_varnatts(int ncid, int varid, int *nattsp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_varnatts"); @@ -140,6 +148,7 @@ int PIOc_inq_varnatts(int ncid, int varid, int *nattsp) int PIOc_def_var(int ncid, const char *name, nc_type xtype, int ndims, const int *dimidsp, int *varidp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_def_var"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING assert(ndims >= 0); @@ -160,6 +169,7 @@ int PIOc_def_var(int ncid, const char *name, nc_type xtype, int ndims, int PIOc_set_fill(int ncid, int fillmode, int *old_modep) { + //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_set_fill"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_set_fill"); @@ -176,6 +186,7 @@ int PIOc_set_fill(int ncid, int fillmode, int *old_modep) int PIOc_def_var_fill(int ncid, int varid, int no_fill, const void *fill_value) { + //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_def_var_fill"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_def_var_fill"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid). @@ -186,6 +197,7 @@ int PIOc_def_var_fill(int ncid, int varid, int no_fill, const void *fill_value) int PIOc_inq_var_fill(int ncid, int varid, int *no_fill, void *fill_valuep) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_var_fill"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid). @@ -196,6 +208,7 @@ int PIOc_inq_var_fill(int ncid, int varid, int *no_fill, void *fill_valuep) int PIOc_rename_var(int ncid, int varid, const char *name) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_rename_var"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_rename_var"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid). @@ -208,6 +221,7 @@ int PIOc_rename_var(int ncid, int varid, const char *name) int PIOc_def_var_deflate(int ncid, int varid, int shuffle, int deflate, int deflate_level) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_def_var_deflate"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_def_var_deflate"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid). @@ -220,6 +234,7 @@ int PIOc_def_var_deflate(int ncid, int varid, int shuffle, int deflate, int PIOc_inq_var_deflate(int ncid, int varid, int *shufflep, int *deflatep, int *deflate_levelp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_var_deflate"); @@ -246,6 +261,7 @@ int PIOc_inq_var_szip(int ncid, int varid, int *options_maskp, int *pixels_per_b int PIOc_def_var_chunking(int ncid, int varid, int storage, const PIO_Offset *chunksizesp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_def_var_chunking"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_def_var_chunking"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid). @@ -256,6 +272,7 @@ int PIOc_def_var_chunking(int ncid, int varid, int storage, const PIO_Offset *ch int PIOc_inq_var_chunking(int ncid, int varid, int *storagep, PIO_Offset *chunksizesp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_var_chunking"); @@ -273,6 +290,7 @@ int PIOc_inq_var_chunking(int ncid, int varid, int *storagep, PIO_Offset *chunks int PIOc_def_var_endian(int ncid, int varid, int endian) { + //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_def_var_endian"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_def_var_endian"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid). @@ -283,6 +301,7 @@ int PIOc_def_var_endian(int ncid, int varid, int endian) int PIOc_inq_var_endian(int ncid, int varid, int *endianp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_var_endian"); @@ -300,6 +319,7 @@ int PIOc_inq_var_endian(int ncid, int varid, int *endianp) int PIOc_set_var_chunk_cache(int ncid, int varid, PIO_Offset size, PIO_Offset nelems, float preemption) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_set_var_chunk_cache"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_set_var_chunk_cache"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid). @@ -313,6 +333,7 @@ int PIOc_set_var_chunk_cache(int ncid, int varid, PIO_Offset size, PIO_Offset ne int PIOc_get_var_chunk_cache(int ncid, int varid, PIO_Offset *sizep, PIO_Offset *nelemsp, float *preemptionp) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_chunk_cache"); diff --git a/src/clib/api/spio_put_att_api.cpp b/src/clib/api/spio_put_att_api.cpp index 44ce5dc3c0..1dde56bffa 100644 --- a/src/clib/api/spio_put_att_api.cpp +++ b/src/clib/api/spio_put_att_api.cpp @@ -3,10 +3,12 @@ #include "pio_internal.h" #include "pio_api_impl.h" #include "spio_tracer.hpp" +#include "spio_gptl_utils.hpp" /* Write APIs for file/variable attributes */ int PIOc_put_att(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const void *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -20,6 +22,7 @@ int PIOc_put_att(int ncid, int varid, const char *name, nc_type xtype, PIO_Offse int PIOc_put_att_text(int ncid, int varid, const char *name, PIO_Offset len, const char *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att_text"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -33,6 +36,7 @@ int PIOc_put_att_text(int ncid, int varid, const char *name, PIO_Offset len, con int PIOc_put_att_schar(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const signed char *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att_schar"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -47,6 +51,7 @@ int PIOc_put_att_schar(int ncid, int varid, const char *name, nc_type xtype, PIO int PIOc_put_att_short(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const short *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att_short"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -61,6 +66,7 @@ int PIOc_put_att_short(int ncid, int varid, const char *name, nc_type xtype, PIO int PIOc_put_att_int(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const int *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att_int"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -75,6 +81,7 @@ int PIOc_put_att_int(int ncid, int varid, const char *name, nc_type xtype, PIO_O int PIOc_put_att_long(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const long *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att_long"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -89,6 +96,7 @@ int PIOc_put_att_long(int ncid, int varid, const char *name, nc_type xtype, PIO_ int PIOc_put_att_float(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const float *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att_float"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -103,6 +111,7 @@ int PIOc_put_att_float(int ncid, int varid, const char *name, nc_type xtype, PIO int PIOc_put_att_double(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const double *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att_double"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -117,6 +126,7 @@ int PIOc_put_att_double(int ncid, int varid, const char *name, nc_type xtype, PI int PIOc_put_att_uchar(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const unsigned char *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att_uchar"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -131,6 +141,7 @@ int PIOc_put_att_uchar(int ncid, int varid, const char *name, nc_type xtype, PIO int PIOc_put_att_ushort(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const unsigned short *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att_ushort"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -145,6 +156,7 @@ int PIOc_put_att_ushort(int ncid, int varid, const char *name, nc_type xtype, PI int PIOc_put_att_uint(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const unsigned int *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att_uint"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -159,6 +171,7 @@ int PIOc_put_att_uint(int ncid, int varid, const char *name, nc_type xtype, PIO_ int PIOc_put_att_longlong(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const long long *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att_longlong"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -173,6 +186,7 @@ int PIOc_put_att_longlong(int ncid, int varid, const char *name, nc_type xtype, int PIOc_put_att_ulonglong(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const unsigned long long *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att_ulonglong"); tr.set_file_id(ncid).add_arg("ncid", ncid). diff --git a/src/clib/api/spio_put_var1_api.cpp b/src/clib/api/spio_put_var1_api.cpp index d71719a30b..cccad7a76c 100644 --- a/src/clib/api/spio_put_var1_api.cpp +++ b/src/clib/api/spio_put_var1_api.cpp @@ -3,10 +3,12 @@ #include "pio_internal.h" #include "pio_api_impl.h" #include "spio_tracer.hpp" +#include "spio_gptl_utils.hpp" /* APIs for writing non-distributed data/variable at a specified index */ int PIOc_put_var1(int ncid, int varid, const PIO_Offset *index, const void *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -18,6 +20,7 @@ int PIOc_put_var1(int ncid, int varid, const PIO_Offset *index, const void *buf) int PIOc_put_var1_text(int ncid, int varid, const PIO_Offset *index, const char *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1_text"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -29,6 +32,7 @@ int PIOc_put_var1_text(int ncid, int varid, const PIO_Offset *index, const char int PIOc_put_var1_schar(int ncid, int varid, const PIO_Offset *index, const signed char *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1_schar"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -40,6 +44,7 @@ int PIOc_put_var1_schar(int ncid, int varid, const PIO_Offset *index, const sign int PIOc_put_var1_short(int ncid, int varid, const PIO_Offset *index, const short *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1_short"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -51,6 +56,7 @@ int PIOc_put_var1_short(int ncid, int varid, const PIO_Offset *index, const shor int PIOc_put_var1_int(int ncid, int varid, const PIO_Offset *index, const int *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1_int"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -62,6 +68,7 @@ int PIOc_put_var1_int(int ncid, int varid, const PIO_Offset *index, const int *o int PIOc_put_var1_long(int ncid, int varid, const PIO_Offset *index, const long *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1_long"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -73,6 +80,7 @@ int PIOc_put_var1_long(int ncid, int varid, const PIO_Offset *index, const long int PIOc_put_var1_float(int ncid, int varid, const PIO_Offset *index, const float *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1_float"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -84,6 +92,7 @@ int PIOc_put_var1_float(int ncid, int varid, const PIO_Offset *index, const floa int PIOc_put_var1_double(int ncid, int varid, const PIO_Offset *index, const double *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1_double"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -96,6 +105,7 @@ int PIOc_put_var1_double(int ncid, int varid, const PIO_Offset *index, const dou int PIOc_put_var1_uchar(int ncid, int varid, const PIO_Offset *index, const unsigned char *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1_uchar"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -108,6 +118,7 @@ int PIOc_put_var1_uchar(int ncid, int varid, const PIO_Offset *index, int PIOc_put_var1_ushort(int ncid, int varid, const PIO_Offset *index, const unsigned short *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1_ushort"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -120,6 +131,7 @@ int PIOc_put_var1_ushort(int ncid, int varid, const PIO_Offset *index, int PIOc_put_var1_uint(int ncid, int varid, const PIO_Offset *index, const unsigned int *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1_uint"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -131,6 +143,7 @@ int PIOc_put_var1_uint(int ncid, int varid, const PIO_Offset *index, int PIOc_put_var1_longlong(int ncid, int varid, const PIO_Offset *index, const long long *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1_longlong"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -143,6 +156,7 @@ int PIOc_put_var1_longlong(int ncid, int varid, const PIO_Offset *index, const l int PIOc_put_var1_ulonglong(int ncid, int varid, const PIO_Offset *index, const unsigned long long *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1_ulonglong"); tr.set_file_id(ncid).add_arg("ncid", ncid). diff --git a/src/clib/api/spio_put_var_api.cpp b/src/clib/api/spio_put_var_api.cpp index e861a48f7e..17f9d374ec 100644 --- a/src/clib/api/spio_put_var_api.cpp +++ b/src/clib/api/spio_put_var_api.cpp @@ -3,10 +3,12 @@ #include "pio_internal.h" #include "pio_api_impl.h" #include "spio_tracer.hpp" +#include "spio_gptl_utils.hpp" /* APIs for writing entire non-distributed data/variable */ int PIOc_put_var(int ncid, int varid, const void *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -17,6 +19,7 @@ int PIOc_put_var(int ncid, int varid, const void *buf) int PIOc_put_var_text(int ncid, int varid, const char *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var_text"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -27,6 +30,7 @@ int PIOc_put_var_text(int ncid, int varid, const char *op) int PIOc_put_var_schar(int ncid, int varid, const signed char *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var_schar"); /* Both bytes and chars are written using this interface, trying to trace/log @@ -40,6 +44,7 @@ int PIOc_put_var_schar(int ncid, int varid, const signed char *op) int PIOc_put_var_short(int ncid, int varid, const short *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var_short"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -50,6 +55,7 @@ int PIOc_put_var_short(int ncid, int varid, const short *op) int PIOc_put_var_int(int ncid, int varid, const int *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var_int"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -60,6 +66,7 @@ int PIOc_put_var_int(int ncid, int varid, const int *op) int PIOc_put_var_long(int ncid, int varid, const long *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var_long"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -70,6 +77,7 @@ int PIOc_put_var_long(int ncid, int varid, const long *op) int PIOc_put_var_float(int ncid, int varid, const float *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var_float"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -80,6 +88,7 @@ int PIOc_put_var_float(int ncid, int varid, const float *op) int PIOc_put_var_double(int ncid, int varid, const double *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var_double"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -90,6 +99,7 @@ int PIOc_put_var_double(int ncid, int varid, const double *op) int PIOc_put_var_uchar(int ncid, int varid, const unsigned char *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var_uchar"); /* Both bytes and chars are written using this interface, trying to trace/log @@ -103,6 +113,7 @@ int PIOc_put_var_uchar(int ncid, int varid, const unsigned char *op) int PIOc_put_var_ushort(int ncid, int varid, const unsigned short *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var_ushort"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -113,6 +124,7 @@ int PIOc_put_var_ushort(int ncid, int varid, const unsigned short *op) int PIOc_put_var_uint(int ncid, int varid, const unsigned int *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var_uint"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -123,6 +135,7 @@ int PIOc_put_var_uint(int ncid, int varid, const unsigned int *op) int PIOc_put_var_longlong(int ncid, int varid, const long long *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var_longlong"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -133,6 +146,7 @@ int PIOc_put_var_longlong(int ncid, int varid, const long long *op) int PIOc_put_var_ulonglong(int ncid, int varid, const unsigned long long *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var_ulonglong"); tr.set_file_id(ncid).add_arg("ncid", ncid). diff --git a/src/clib/api/spio_put_vara_api.cpp b/src/clib/api/spio_put_vara_api.cpp index 4e028f7d53..73e4c616b7 100644 --- a/src/clib/api/spio_put_vara_api.cpp +++ b/src/clib/api/spio_put_vara_api.cpp @@ -3,11 +3,13 @@ #include "pio_internal.h" #include "pio_api_impl.h" #include "spio_tracer.hpp" +#include "spio_gptl_utils.hpp" /* APIs for writing a hyperslab of non-distributed data/variable */ int PIOc_put_vara(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const void *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -20,6 +22,7 @@ int PIOc_put_vara(int ncid, int varid, const PIO_Offset *start, const PIO_Offset int PIOc_put_vara_text(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const char *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara_text"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -32,6 +35,7 @@ int PIOc_put_vara_text(int ncid, int varid, const PIO_Offset *start, int PIOc_put_vara_schar(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const signed char *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara_schar"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -44,6 +48,7 @@ int PIOc_put_vara_schar(int ncid, int varid, const PIO_Offset *start, int PIOc_put_vara_short(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const short *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara_short"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -56,6 +61,7 @@ int PIOc_put_vara_short(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_put_vara_int(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const int *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara_int"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -68,6 +74,7 @@ int PIOc_put_vara_int(int ncid, int varid, const PIO_Offset *start, const PIO_Of int PIOc_put_vara_long(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const long *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara_long"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -80,6 +87,7 @@ int PIOc_put_vara_long(int ncid, int varid, const PIO_Offset *start, const PIO_O int PIOc_put_vara_float(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const float *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara_float"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -92,6 +100,7 @@ int PIOc_put_vara_float(int ncid, int varid, const PIO_Offset *start, int PIOc_put_vara_double(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const double *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara_double"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -104,6 +113,7 @@ int PIOc_put_vara_double(int ncid, int varid, const PIO_Offset *start, const PIO int PIOc_put_vara_uchar(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const unsigned char *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara_uchar"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -116,6 +126,7 @@ int PIOc_put_vara_uchar(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_put_vara_ushort(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const unsigned short *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara_ushort"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -128,6 +139,7 @@ int PIOc_put_vara_ushort(int ncid, int varid, const PIO_Offset *start, int PIOc_put_vara_uint(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const unsigned int *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara_uint"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -140,6 +152,7 @@ int PIOc_put_vara_uint(int ncid, int varid, const PIO_Offset *start, int PIOc_put_vara_longlong(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const long long *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara_longlong"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -152,6 +165,7 @@ int PIOc_put_vara_longlong(int ncid, int varid, const PIO_Offset *start, int PIOc_put_vara_ulonglong(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const unsigned long long *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara_ulonglong"); tr.set_file_id(ncid).add_arg("ncid", ncid). diff --git a/src/clib/api/spio_put_varm_api.cpp b/src/clib/api/spio_put_varm_api.cpp index a8e55a1f0f..bed506b96c 100644 --- a/src/clib/api/spio_put_varm_api.cpp +++ b/src/clib/api/spio_put_varm_api.cpp @@ -3,11 +3,13 @@ #include "pio_internal.h" #include "pio_api_impl.h" #include "spio_tracer.hpp" +#include "spio_gptl_utils.hpp" int PIOc_put_varm(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, const void *buf, PIO_Offset bufcount, MPI_Datatype buftype) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -23,6 +25,7 @@ int PIOc_put_varm_uchar(int ncid, int varid, const PIO_Offset *start, const PIO_ const PIO_Offset *stride, const PIO_Offset *imap, const unsigned char *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm_uchar"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -36,6 +39,7 @@ int PIOc_put_varm_uchar(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_put_varm_short(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, const short *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm_ushort"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -50,6 +54,7 @@ int PIOc_put_varm_text(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, const char *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm_text"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -63,6 +68,7 @@ int PIOc_put_varm_text(int ncid, int varid, const PIO_Offset *start, int PIOc_put_varm_ushort(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, const unsigned short *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm_ushort"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -77,6 +83,7 @@ int PIOc_put_varm_ulonglong(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, const unsigned long long *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm_ulonglong"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -91,6 +98,7 @@ int PIOc_put_varm_int(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, const int *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm_int"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -105,6 +113,7 @@ int PIOc_put_varm_float(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, const float *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm_float"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -119,6 +128,7 @@ int PIOc_put_varm_long(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, const long *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm_long"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -133,6 +143,7 @@ int PIOc_put_varm_uint(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, const unsigned int *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm_uint"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -146,6 +157,7 @@ int PIOc_put_varm_uint(int ncid, int varid, const PIO_Offset *start, int PIOc_put_varm_double(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, const double *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm_double"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -159,6 +171,7 @@ int PIOc_put_varm_double(int ncid, int varid, const PIO_Offset *start, const PIO int PIOc_put_varm_schar(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, const signed char *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm_schar"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -172,6 +185,7 @@ int PIOc_put_varm_schar(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_put_varm_longlong(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, const long long *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm_longlong"); tr.set_file_id(ncid).add_arg("ncid", ncid). diff --git a/src/clib/api/spio_put_vars_api.cpp b/src/clib/api/spio_put_vars_api.cpp index 8ed83f5cb1..f25a13d126 100644 --- a/src/clib/api/spio_put_vars_api.cpp +++ b/src/clib/api/spio_put_vars_api.cpp @@ -3,11 +3,13 @@ #include "pio_internal.h" #include "pio_api_impl.h" #include "spio_tracer.hpp" +#include "spio_gptl_utils.hpp" /* APIs for writing a hyperslab of strided non-distributed data/variable */ int PIOc_put_vars(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const void *buf) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -20,6 +22,7 @@ int PIOc_put_vars(int ncid, int varid, const PIO_Offset *start, const PIO_Offset int PIOc_put_vars_text(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const char *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars_text"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -33,6 +36,7 @@ int PIOc_put_vars_schar(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const signed char *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars_shcar"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -45,6 +49,7 @@ int PIOc_put_vars_schar(int ncid, int varid, const PIO_Offset *start, int PIOc_put_vars_short(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const short *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars_short"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -57,6 +62,7 @@ int PIOc_put_vars_short(int ncid, int varid, const PIO_Offset *start, int PIOc_put_vars_int(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const int *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars_int"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -69,6 +75,7 @@ int PIOc_put_vars_int(int ncid, int varid, const PIO_Offset *start, const PIO_Of int PIOc_put_vars_float(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const float *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars_float"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -81,6 +88,7 @@ int PIOc_put_vars_float(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_put_vars_double(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const double *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars_double"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -93,6 +101,7 @@ int PIOc_put_vars_double(int ncid, int varid, const PIO_Offset *start, int PIOc_put_vars_long(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const long *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars_long"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -105,6 +114,7 @@ int PIOc_put_vars_long(int ncid, int varid, const PIO_Offset *start, const PIO_O int PIOc_put_vars_uchar(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const unsigned char *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars_uchar"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -117,6 +127,7 @@ int PIOc_put_vars_uchar(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_put_vars_ushort(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const unsigned short *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars_ushort"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -129,6 +140,7 @@ int PIOc_put_vars_ushort(int ncid, int varid, const PIO_Offset *start, const PIO int PIOc_put_vars_uint(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const unsigned int *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars_uint"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -141,6 +153,7 @@ int PIOc_put_vars_uint(int ncid, int varid, const PIO_Offset *start, const PIO_O int PIOc_put_vars_longlong(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const long long *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars_longlong"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -154,6 +167,7 @@ int PIOc_put_vars_ulonglong(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const unsigned long long *op) { + SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars_ulonglong"); tr.set_file_id(ncid).add_arg("ncid", ncid). diff --git a/src/clib/pio_darray.cpp b/src/clib/pio_darray.cpp index f1c35762a2..887672cd4a 100644 --- a/src/clib/pio_darray.cpp +++ b/src/clib/pio_darray.cpp @@ -1958,7 +1958,6 @@ int PIOc_write_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, c int mpierr = MPI_SUCCESS; /* Return code from MPI functions. */ int ierr = PIO_NOERR; /* Return code. */ - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer1("PIO:PIOc_write_darray"); SPIO_Util::GPTL_Util::GPTL_wrapper func_timer2("PIO:write_total"); LOG((1, "PIOc_write_darray ncid = %d varid = %d ioid = %d arraylen = %d", ncid, varid, ioid, arraylen)); @@ -1978,7 +1977,6 @@ int PIOc_write_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, c SPIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer_wrapper ios_fstats_tot_timer(ios->io_fstats->tot_timer_name); if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ - GPTLstart("PIO:PIOc_write_darray_adios"); GPTLstart("PIO:write_total_adios"); } @@ -1991,7 +1989,6 @@ int PIOc_write_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, c /* Can we write to this file? */ if(!(file->mode & PIO_WRITE)){ if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ - GPTLstop("PIO:PIOc_write_darray_adios"); GPTLstop("PIO:write_total_adios"); } return pio_err(ios, file, PIO_EPERM, __FILE__, __LINE__, @@ -2001,7 +1998,6 @@ int PIOc_write_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, c /* Get decomposition information. */ if(!(iodesc = pio_get_iodesc_from_id(ioid))){ if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ - GPTLstop("PIO:PIOc_write_darray_adios"); GPTLstop("PIO:write_total_adios"); } return pio_err(ios, file, PIO_EBADID, __FILE__, __LINE__, @@ -2014,7 +2010,6 @@ int PIOc_write_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, c * if it is too big (the excess values will be ignored.) */ if(arraylen < iodesc->ndof){ if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ - GPTLstop("PIO:PIOc_write_darray_adios"); GPTLstop("PIO:write_total_adios"); } return pio_err(ios, file, PIO_EINVAL, __FILE__, __LINE__, @@ -2081,7 +2076,6 @@ int PIOc_write_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, c ierr = pio_create_uniq_str(ios, iodesc, filename, PIO_MAX_NAME, "piodecomp", ".dat"); if(ierr != PIO_NOERR){ if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ - GPTLstop("PIO:PIOc_write_darray_adios"); GPTLstop("PIO:write_total_adios"); } return pio_err(ios, NULL, ierr, __FILE__, __LINE__, @@ -2150,7 +2144,6 @@ int PIOc_write_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, c spio_ltimer_stop(file->io_fstats->tot_timer_name); if((ierr = find_var_fillvalue(file, varid, vdesc))){ if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ - GPTLstop("PIO:PIOc_write_darray_adios"); GPTLstop("PIO:write_total_adios"); } return pio_err(ios, file, PIO_EBADID, __FILE__, __LINE__, @@ -2181,7 +2174,6 @@ int PIOc_write_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, c if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ ierr = PIO_NOERR; ierr = PIOc_write_darray_adios(file, varid, ioid, iodesc, arraylen, array, fillvalue); - GPTLstop("PIO:PIOc_write_darray_adios"); GPTLstop("PIO:write_total_adios"); return ierr; } @@ -2282,7 +2274,6 @@ int PIOc_write_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, c spio_ltimer_stop(file->io_fstats->wr_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); if((ierr = flush_buffer(ncid, wmb, (needsflush == 2)))){ - GPTLstop("PIO:PIOc_write_darray"); GPTLstop("PIO:write_total"); return pio_err(ios, file, ierr, __FILE__, __LINE__, "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Flushing data (multiple cached variables with the same decomposition) from compute processes to I/O processes %s failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, (needsflush == 2) ? "and to disk" : ""); @@ -3443,7 +3434,6 @@ int PIOc_read_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, #ifdef _ADIOS2 adios_var_desc_t *vdesc_adios2; /* Info about the variable from the adios structure */ #endif - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("PIO:PIOc_read_darray"); /* Get the file info. */ if((ierr = pio_get_file(ncid, &file))){ @@ -3664,15 +3654,12 @@ int PIOc_read_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, #ifdef _ADIOS2 case PIO_IOTYPE_ADIOS: case PIO_IOTYPE_ADIOSC: - GPTLstart("PIO:PIOc_read_darray_adios"); if((ierr = PIOc_read_darray_adios(file, fndims, iodesc, varid, array))){ - GPTLstop("PIO:PIOc_read_darray_adios"); return pio_err(ios, file, ierr, __FILE__, __LINE__, "Reading variable (%s, varid=%d) from file (%s, ncid=%d) using ADIOS iotype failed. " "Reading variable in parallel failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), ncid); } - GPTLstop("PIO:PIOc_read_darray_adios"); return PIO_NOERR; #endif default: diff --git a/src/clib/pio_file.cpp b/src/clib/pio_file.cpp index c9d2ba4b82..36abf58940 100644 --- a/src/clib/pio_file.cpp +++ b/src/clib/pio_file.cpp @@ -136,22 +136,18 @@ int PIOc_createfile_impl(int iosysid, int *ncidp, const int *iotype, const char iosystem_desc_t *ios; /* Pointer to io system information. */ int ret; /* Return code from function calls. */ - GPTLstart("PIO:PIOc_createfile"); GPTLstart("PIO:write_total"); if ((*iotype == PIO_IOTYPE_ADIOS) || (*iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstart("PIO:PIOc_createfile_adios"); GPTLstart("PIO:write_total_adios"); } /* Get the IO system info from the id. */ if (!(ios = pio_get_iosystem_from_id(iosysid))) { - GPTLstop("PIO:PIOc_createfile"); GPTLstop("PIO:write_total"); if ((*iotype == PIO_IOTYPE_ADIOS) || (*iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstop("PIO:PIOc_createfile_adios"); GPTLstop("PIO:write_total_adios"); } return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, @@ -164,13 +160,11 @@ int PIOc_createfile_impl(int iosysid, int *ncidp, const int *iotype, const char /* Create the file. */ if ((ret = spio_createfile_int(iosysid, ncidp, iotype, filename, mode))) { - GPTLstop("PIO:PIOc_createfile"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); if ((*iotype == PIO_IOTYPE_ADIOS) || (*iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstop("PIO:PIOc_createfile_adios"); GPTLstop("PIO:write_total_adios"); } @@ -189,11 +183,9 @@ int PIOc_createfile_impl(int iosysid, int *ncidp, const int *iotype, const char spio_ltimer_stop(ios->io_fstats->tot_timer_name); if ((ret = PIOc_set_fill_impl(*ncidp, NC_NOFILL, NULL))) { - GPTLstop("PIO:PIOc_createfile"); GPTLstop("PIO:write_total"); if ((*iotype == PIO_IOTYPE_ADIOS) || (*iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstop("PIO:PIOc_createfile_adios"); GPTLstop("PIO:write_total_adios"); } return pio_err(ios, NULL, ret, __FILE__, __LINE__, @@ -203,13 +195,11 @@ int PIOc_createfile_impl(int iosysid, int *ncidp, const int *iotype, const char spio_ltimer_start(ios->io_fstats->tot_timer_name); } - GPTLstop("PIO:PIOc_createfile"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); if ((*iotype == PIO_IOTYPE_ADIOS) || (*iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstop("PIO:PIOc_createfile_adios"); GPTLstop("PIO:write_total_adios"); } @@ -498,8 +488,6 @@ int PIOc_closefile_impl(int ncid) if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstart("PIO:PIOc_closefile_adios"); - if (file->mode & PIO_WRITE) { GPTLstart("PIO:write_total_adios"); @@ -510,8 +498,6 @@ int PIOc_closefile_impl(int ncid) } else { - GPTLstart("PIO:PIOc_closefile"); - if (file->mode & PIO_WRITE) { GPTLstart("PIO:PIOc_closefile_write_mode"); @@ -563,8 +549,6 @@ int PIOc_closefile_impl(int ncid) { if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstop("PIO:PIOc_closefile_adios"); - if (file->mode & PIO_WRITE) GPTLstop("PIO:write_total_adios"); @@ -581,8 +565,6 @@ int PIOc_closefile_impl(int ncid) } else { - GPTLstop("PIO:PIOc_closefile"); - if (file->mode & PIO_WRITE) { GPTLstop("PIO:PIOc_closefile_write_mode"); @@ -615,7 +597,6 @@ int PIOc_closefile_impl(int ncid) { if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstop("PIO:PIOc_closefile_adios"); GPTLstop("PIO:write_total_adios"); #ifndef _ADIOS_BP2NC_TEST GPTLstop("PIO:write_total"); @@ -627,7 +608,6 @@ int PIOc_closefile_impl(int ncid) } else { - GPTLstop("PIO:PIOc_closefile"); GPTLstop("PIO:PIOc_closefile_write_mode"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); @@ -649,7 +629,6 @@ int PIOc_closefile_impl(int ncid) { if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstop("PIO:PIOc_closefile_adios"); GPTLstop("PIO:write_total_adios"); #ifndef _ADIOS_BP2NC_TEST GPTLstop("PIO:write_total"); @@ -661,8 +640,6 @@ int PIOc_closefile_impl(int ncid) } else { - GPTLstop("PIO:PIOc_closefile"); - GPTLstop("PIO:PIOc_closefile_write_mode"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); @@ -710,7 +687,6 @@ int PIOc_closefile_impl(int ncid) { if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstop("PIO:PIOc_closefile_adios"); GPTLstop("PIO:write_total_adios"); #ifndef _ADIOS_BP2NC_TEST GPTLstop("PIO:write_total"); @@ -722,7 +698,6 @@ int PIOc_closefile_impl(int ncid) } else { - GPTLstop("PIO:PIOc_closefile"); GPTLstop("PIO:PIOc_closefile_write_mode"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); @@ -739,7 +714,6 @@ int PIOc_closefile_impl(int ncid) { if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstop("PIO:PIOc_closefile_adios"); GPTLstop("PIO:write_total_adios"); #ifndef _ADIOS_BP2NC_TEST @@ -752,7 +726,6 @@ int PIOc_closefile_impl(int ncid) } else { - GPTLstop("PIO:PIOc_closefile"); GPTLstop("PIO:PIOc_closefile_write_mode"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); @@ -772,7 +745,6 @@ int PIOc_closefile_impl(int ncid) adiosErr = adios2_close(file->engineH); if (adiosErr != adios2_error_none) { - GPTLstop("PIO:PIOc_closefile_adios"); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, @@ -789,7 +761,6 @@ int PIOc_closefile_impl(int ncid) adiosErr = adios2_remove_io(&result, ios->adios_readerH, file->io_name_reader); if (adiosErr != adios2_error_none) { - GPTLstop("PIO:PIOc_closefile_adios"); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, @@ -800,7 +771,6 @@ int PIOc_closefile_impl(int ncid) if (result == adios2_false) { - GPTLstop("PIO:PIOc_closefile_adios"); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, @@ -941,13 +911,10 @@ int PIOc_closefile_impl(int ncid) { if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstop("PIO:PIOc_closefile_adios"); GPTLstop("PIO:write_total_adios"); } else { - GPTLstop("PIO:PIOc_closefile"); - if (file->mode & PIO_WRITE) { GPTLstop("PIO:PIOc_closefile_write_mode"); @@ -971,8 +938,6 @@ int PIOc_closefile_impl(int ncid) if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstop("PIO:PIOc_closefile_adios"); - if (file->mode & PIO_WRITE) GPTLstop("PIO:write_total_adios"); @@ -989,8 +954,6 @@ int PIOc_closefile_impl(int ncid) } else { - GPTLstop("PIO:PIOc_closefile"); - if (file->mode & PIO_WRITE) { GPTLstop("PIO:PIOc_closefile_write_mode"); @@ -1046,7 +1009,6 @@ int PIOc_closefile_impl(int ncid) break; #endif default: - GPTLstop("PIO:PIOc_closefile"); if (file->mode & PIO_WRITE) { GPTLstop("PIO:PIOc_closefile_write_mode"); @@ -1064,7 +1026,6 @@ int PIOc_closefile_impl(int ncid) ierr = check_netcdf(NULL, file, ierr, __FILE__, __LINE__); if(ierr != PIO_NOERR){ LOG((1, "nc*_close failed, ierr = %d", ierr)); - GPTLstop("PIO:PIOc_closefile"); if (file->mode & PIO_WRITE) { GPTLstop("PIO:PIOc_closefile_write_mode"); @@ -1132,7 +1093,6 @@ int PIOc_closefile_impl(int ncid) /* Delete file from our list of open files. */ pio_delete_file_from_list(ncid); - GPTLstop("PIO:PIOc_closefile"); return ierr; } @@ -1152,13 +1112,11 @@ int PIOc_deletefile_impl(int iosysid, const char *filename) int msg = PIO_MSG_DELETE_FILE; size_t len; - GPTLstart("PIO:PIOc_deletefile"); LOG((1, "PIOc_deletefile iosysid = %d filename = %s", iosysid, filename)); /* Get the IO system info from the id. */ if (!(ios = pio_get_iosystem_from_id(iosysid))) { - GPTLstop("PIO:PIOc_deletefile"); return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, "Deleting file (%s) failed. Invalid I/O system id (iosysid=%d) specified.", (filename) ? filename : "NULL", iosysid); } @@ -1174,7 +1132,6 @@ int PIOc_deletefile_impl(int iosysid, const char *filename) PIO_SEND_ASYNC_MSG(ios, msg, &ierr, len, filename); if(ierr != PIO_NOERR) { - GPTLstop("PIO:PIOc_deletefile"); spio_ltimer_stop(ios->io_fstats->tot_timer_name); return pio_err(ios, NULL, ierr, __FILE__, __LINE__, "Deleting file (%s) failed. Sending async message, PIO_MSG_DELETE_FILE, failed", (filename) ? filename : "NULL"); @@ -1198,7 +1155,6 @@ int PIOc_deletefile_impl(int iosysid, const char *filename) char *adios_bp_filename = (char *) calloc(adios_bp_filename_len, sizeof(char)); if (adios_bp_filename == NULL) { - GPTLstop("PIO:PIOc_deletefile"); spio_ltimer_stop(ios->io_fstats->tot_timer_name); return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, "Deleting file (%s) failed. Allocating memory for adios filename failed", (filename) ? filename : "NULL"); @@ -1234,13 +1190,11 @@ int PIOc_deletefile_impl(int iosysid, const char *filename) ierr = check_netcdf(ios, NULL, ierr, __FILE__, __LINE__); if(ierr != PIO_NOERR){ - GPTLstop("PIO:PIOc_deletefile"); spio_ltimer_stop(ios->io_fstats->tot_timer_name); return pio_err(ios, NULL, ierr, __FILE__, __LINE__, "Deleting file (%s) failed. Internal I/O library call failed.", (filename) ? filename : "NULL"); } - GPTLstop("PIO:PIOc_deletefile"); spio_ltimer_stop(ios->io_fstats->tot_timer_name); return ierr; } @@ -1262,13 +1216,11 @@ int PIOc_sync_impl(int ncid) file_desc_t *file = NULL; /* Pointer to file information. */ int ierr = PIO_NOERR; /* Return code from function calls. */ - GPTLstart("PIO:PIOc_sync"); LOG((1, "PIOc_sync ncid = %d", ncid)); /* Get the file info from the ncid. */ if ((ierr = pio_get_file(ncid, &file))) { - GPTLstop("PIO:PIOc_sync"); return pio_err(NULL, NULL, ierr, __FILE__, __LINE__, "Syncing file (ncid=%d) failed. Invalid file id. Unable to find internal structure associated with the file id", ncid); } @@ -1290,7 +1242,5 @@ int PIOc_sync_impl(int ncid) GPTLstop("PIO:write_total_adios"); } - GPTLstop("PIO:PIOc_sync"); - return ierr; } diff --git a/src/clib/pio_getput_int.cpp b/src/clib/pio_getput_int.cpp index 1dc0643ce2..adb93acfb7 100644 --- a/src/clib/pio_getput_int.cpp +++ b/src/clib/pio_getput_int.cpp @@ -41,12 +41,10 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, int mpierr = MPI_SUCCESS; /* Return code from MPI function codes. */ int ierr = PIO_NOERR; /* Return code from function calls. */ - GPTLstart("PIO:spio_put_att_tc"); GPTLstart("PIO:write_total"); /* Find the info about this file. */ if ((ierr = pio_get_file(ncid, &file))) { - GPTLstop("PIO:spio_put_att_tc"); GPTLstop("PIO:write_total"); return pio_err(NULL, NULL, ierr, __FILE__, __LINE__, "Writing variable (varid=%d) attribute (%s) to file failed. Invalid file id (ncid=%d) provided", varid, (name) ? name : "NULL", ncid); @@ -83,14 +81,12 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstart("PIO:spio_put_att_tc_adios"); GPTLstart("PIO:write_total_adios"); } /* User must provide some valid parameters. */ if (!name || !op || strlen(name) > PIO_MAX_NAME || len < 0) { - GPTLstop("PIO:spio_put_att_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); @@ -98,7 +94,6 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, spio_ltimer_stop(file->io_fstats->tot_timer_name); if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstop("PIO:spio_put_att_tc_adios"); GPTLstop("PIO:write_total_adios"); } return pio_err(ios, file, PIO_EINVAL, __FILE__, __LINE__, @@ -120,11 +115,9 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, ierr = PIOc_inq_type_impl(ncid, atttype, NULL, &atttype_len); if(ierr != PIO_NOERR){ LOG((1, "PIOc_inq_type failed, ierr = %d", ierr)); - GPTLstop("PIO:spio_put_att_tc"); GPTLstop("PIO:write_total"); if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstop("PIO:spio_put_att_tc_adios"); GPTLstop("PIO:write_total_adios"); } return ierr; @@ -137,11 +130,9 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, { ierr = PIOc_inq_type_impl(ncid, memtype, NULL, &memtype_len); if(ierr != PIO_NOERR){ - GPTLstop("PIO:spio_put_att_tc"); GPTLstop("PIO:write_total"); if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstop("PIO:spio_put_att_tc_adios"); GPTLstop("PIO:write_total_adios"); } LOG((1, "PIOc_inq_type failed, ierr = %d", ierr)); @@ -166,7 +157,6 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, len * memtype_len, op); if(ierr != PIO_NOERR) { - GPTLstop("PIO:spio_put_att_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); @@ -174,7 +164,6 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, spio_ltimer_stop(file->io_fstats->tot_timer_name); if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstop("PIO:spio_put_att_tc_adios"); GPTLstop("PIO:write_total_adios"); } return pio_err(ios, NULL, ierr, __FILE__, __LINE__, @@ -184,7 +173,6 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, /* Broadcast values currently only known on computation tasks to IO tasks. */ if ((mpierr = MPI_Bcast(&atttype_len, 1, MPI_OFFSET, ios->comproot, ios->my_comm))) { - GPTLstop("PIO:spio_put_att_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); @@ -192,14 +180,12 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, spio_ltimer_stop(file->io_fstats->tot_timer_name); if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstop("PIO:spio_put_att_tc_adios"); GPTLstop("PIO:write_total_adios"); } return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); } if ((mpierr = MPI_Bcast(&memtype_len, 1, MPI_OFFSET, ios->comproot, ios->my_comm))) { - GPTLstop("PIO:spio_put_att_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); @@ -207,7 +193,6 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, spio_ltimer_stop(file->io_fstats->tot_timer_name); if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstop("PIO:spio_put_att_tc_adios"); GPTLstop("PIO:write_total_adios"); } return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); @@ -225,13 +210,11 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, ierr = begin_adios2_step(file, ios); if (ierr != PIO_NOERR) { - GPTLstop("PIO:spio_put_att_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->wr_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); - GPTLstop("PIO:spio_put_att_tc_adios"); GPTLstop("PIO:write_total_adios"); return pio_err(NULL, file, ierr, __FILE__, __LINE__, "adios2_begin_step failed for file (%s)", pio_get_fname_from_file(file)); @@ -256,13 +239,11 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, int num_attrs = file->num_attrs; if (num_attrs >= PIO_MAX_ATTRS) { - GPTLstop("PIO:spio_put_att_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->wr_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); - GPTLstop("PIO:spio_put_att_tc_adios"); GPTLstop("PIO:write_total_adios"); return pio_err(ios, file, PIO_EMAXATTS, __FILE__, __LINE__, "Writing variable (%s, varid=%d) attribute (%s) to file (%s, ncid=%d) using ADIOS iotype failed. " @@ -273,13 +254,11 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, file->adios_attrs[num_attrs].att_name = spio_strdup(name); if (file->adios_attrs[num_attrs].att_name == NULL) { - GPTLstop("PIO:spio_put_att_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->wr_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); - GPTLstop("PIO:spio_put_att_tc_adios"); GPTLstop("PIO:write_total_adios"); return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, "Writing variable (%s, varid=%d) attribute (%s) to file (%s, ncid=%d) using ADIOS iotype failed. " @@ -320,13 +299,11 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, if (attributeH == NULL) { - GPTLstop("PIO:spio_put_att_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->wr_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); - GPTLstop("PIO:spio_put_att_tc_adios"); GPTLstop("PIO:write_total_adios"); return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, "Defining (ADIOS) attribute (name=%s) failed for file (%s, ncid=%d)", @@ -342,13 +319,11 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, } } - GPTLstop("PIO:spio_put_att_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->wr_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); - GPTLstop("PIO:spio_put_att_tc_adios"); GPTLstop("PIO:write_total_adios"); return PIO_NOERR; @@ -361,7 +336,6 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, int num_attrs = file->hdf5_num_attrs; if (num_attrs >= PIO_MAX_ATTRS) { - GPTLstop("PIO:spio_put_att_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); @@ -376,7 +350,6 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, file->hdf5_attrs[num_attrs].att_name = spio_strdup(name); if (file->hdf5_attrs[num_attrs].att_name == NULL) { - GPTLstop("PIO:spio_put_att_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); @@ -449,7 +422,6 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, ierr = ncmpi_put_att_ulonglong(file->fh, varid, name, atttype, len, (const unsigned long long int *) op); break; default: - GPTLstop("PIO:spio_put_att_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); @@ -529,7 +501,6 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, /* break; */ #endif /* _NETCDF */ default: - GPTLstop("PIO:spio_put_att_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); @@ -544,7 +515,6 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, ierr = check_netcdf(NULL, file, ierr, __FILE__, __LINE__); if(ierr != PIO_NOERR){ LOG((1, "nc*_put_att_* failed, ierr = %d", ierr)); - GPTLstop("PIO:spio_put_att_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); @@ -554,7 +524,6 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, "Writing variable (%s, varid=%d) attribute (%s) to file (%s, ncid=%d) failed. Internal I/O library (%s) call failed", pio_get_vname_from_file(file, varid), varid, name, pio_get_fname_from_file(file), file->pio_ncid, pio_iotype_to_string(file->iotype)); } - GPTLstop("PIO:spio_put_att_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); @@ -592,11 +561,9 @@ int spio_get_att_tc(int ncid, int varid, const char *name, nc_type memtype, void int mpierr = MPI_SUCCESS; /* Return code from MPI function calls. */ int ierr = PIO_NOERR; /* Return code from function calls. */ - GPTLstart("PIO:spio_get_att_tc"); /* Find the info about this file. */ if ((ierr = pio_get_file(ncid, &file))) { - GPTLstop("PIO:spio_get_att_tc"); return pio_err(NULL, NULL, ierr, __FILE__, __LINE__, "Reading attribute (%s) from file failed. Invalid file id (ncid=%d) provided", (name) ? name : "NULL", ncid); } @@ -612,7 +579,6 @@ int spio_get_att_tc(int ncid, int varid, const char *name, nc_type memtype, void /* User must provide a name and destination pointer. */ if (!name || !ip || strlen(name) > PIO_MAX_NAME) { - GPTLstop("PIO:spio_get_att_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -636,7 +602,6 @@ int spio_get_att_tc(int ncid, int varid, const char *name, nc_type memtype, void ierr = PIOc_inq_att_impl(ncid, varid, name, &atttype, &attlen); if(ierr != PIO_NOERR){ LOG((1, "PIOc_inq_att failed, ierr = %d", ierr)); - GPTLstop("PIO:spio_get_att_tc"); return ierr; } LOG((2, "atttype = %d attlen = %d", atttype, attlen)); @@ -645,7 +610,6 @@ int spio_get_att_tc(int ncid, int varid, const char *name, nc_type memtype, void ierr = PIOc_inq_type_impl(ncid, atttype, NULL, &atttype_len); if(ierr != PIO_NOERR){ LOG((1, "PIOc_inq_type failed, ierr=%d", ierr)); - GPTLstop("PIO:spio_get_att_tc"); return ierr; } @@ -658,7 +622,6 @@ int spio_get_att_tc(int ncid, int varid, const char *name, nc_type memtype, void ierr = PIOc_inq_type_impl(ncid, memtype, NULL, &memtype_len); if(ierr != PIO_NOERR){ LOG((1, "PIOc_inq_type failed, ierr = %d", ierr)); - GPTLstop("PIO:spio_get_att_tc"); return ierr; } } @@ -680,7 +643,6 @@ int spio_get_att_tc(int ncid, int varid, const char *name, nc_type memtype, void if(ierr != PIO_NOERR) { LOG((1, "Error sending async msg for PIO_MSG_GET_ATT")); - GPTLstop("PIO:spio_get_att_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -693,7 +655,6 @@ int spio_get_att_tc(int ncid, int varid, const char *name, nc_type memtype, void LOG((2, "spio_get_att_tc bcast from comproot = %d attlen = %d atttype_len = %d", ios->comproot, attlen, atttype_len)); if ((mpierr = MPI_Bcast(&attlen, 1, MPI_OFFSET, ios->comproot, ios->my_comm))) { - GPTLstop("PIO:spio_get_att_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -702,7 +663,6 @@ int spio_get_att_tc(int ncid, int varid, const char *name, nc_type memtype, void } if ((mpierr = MPI_Bcast(&atttype_len, 1, MPI_OFFSET, ios->comproot, ios->my_comm))) { - GPTLstop("PIO:spio_get_att_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -711,7 +671,6 @@ int spio_get_att_tc(int ncid, int varid, const char *name, nc_type memtype, void } if ((mpierr = MPI_Bcast(&memtype_len, 1, MPI_OFFSET, ios->comproot, ios->my_comm))) { - GPTLstop("PIO:spio_get_att_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -739,7 +698,6 @@ int spio_get_att_tc(int ncid, int varid, const char *name, nc_type memtype, void full_name = (char *) calloc(full_name_len, 1); if (full_name == NULL) { - GPTLstop("PIO:spio_get_att_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -760,7 +718,6 @@ int spio_get_att_tc(int ncid, int varid, const char *name, nc_type memtype, void full_name = (char *) calloc(full_name_len, 1); if (full_name == NULL) { - GPTLstop("PIO:spio_get_att_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -801,7 +758,6 @@ int spio_get_att_tc(int ncid, int varid, const char *name, nc_type memtype, void adiosErr = adios2_attribute_data(ip, &size_attr, attr); if (adiosErr != adios2_error_none) { - GPTLstop("PIO:spio_get_att_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -817,7 +773,6 @@ int spio_get_att_tc(int ncid, int varid, const char *name, nc_type memtype, void break; } default: - GPTLstop("PIO:spio_get_att_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -830,7 +785,6 @@ int spio_get_att_tc(int ncid, int varid, const char *name, nc_type memtype, void free(full_name); - GPTLstop("PIO:spio_get_att_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -886,7 +840,6 @@ int spio_get_att_tc(int ncid, int varid, const char *name, nc_type memtype, void ierr = ncmpi_get_att_ulonglong(file->fh, varid, name, (unsigned long long int *) ip); break; default: - GPTLstop("PIO:spio_get_att_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -944,7 +897,6 @@ int spio_get_att_tc(int ncid, int varid, const char *name, nc_type memtype, void /* break; */ #endif /* _NETCDF */ default: - GPTLstop("PIO:spio_get_att_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -958,7 +910,6 @@ int spio_get_att_tc(int ncid, int varid, const char *name, nc_type memtype, void ierr = check_netcdf(NULL, file, ierr, __FILE__, __LINE__); if(ierr != PIO_NOERR){ LOG((1, "nc*_get_att_* failed, ierr = %d", ierr)); - GPTLstop("PIO:spio_get_att_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -972,7 +923,6 @@ int spio_get_att_tc(int ncid, int varid, const char *name, nc_type memtype, void if ((mpierr = MPI_Bcast(ip, (int)attlen * memtype_len, MPI_BYTE, ios->ioroot, ios->my_comm))) { - GPTLstop("PIO:spio_get_att_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -981,7 +931,6 @@ int spio_get_att_tc(int ncid, int varid, const char *name, nc_type memtype, void } LOG((2, "get_att_tc data bcast complete")); - GPTLstop("PIO:spio_get_att_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1039,7 +988,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off int mpierr = MPI_SUCCESS; /* Return code from MPI function codes. */ int ierr = PIO_NOERR; /* Return code. */ - GPTLstart("PIO:spio_get_vars_tc"); LOG((1, "spio_get_vars_tc ncid = %d varid = %d xtype = %d start_present = %d " "count_present = %d stride_present = %d", ncid, varid, xtype, start_present, count_present, stride_present)); @@ -1047,7 +995,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off /* Find the info about this file. */ if ((ierr = pio_get_file(ncid, &file))) { - GPTLstop("PIO:spio_get_vars_tc"); return pio_err(NULL, NULL, ierr, __FILE__, __LINE__, "Reading variable (varid=%d) from file failed. Invalid file id (ncid=%d) provided", varid, ncid); } @@ -1063,7 +1010,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off /* User must provide a place to put some data. */ if (!buf) { - GPTLstop("PIO:spio_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1083,7 +1029,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off spio_ltimer_stop(file->io_fstats->tot_timer_name); ierr = PIOc_inq_vartype_impl(ncid, varid, &vartype); if(ierr != PIO_NOERR){ - GPTLstop("PIO:spio_get_vars_tc"); return pio_err(NULL, NULL, ierr, __FILE__, __LINE__, "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed. Inquiring the variable type failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), ncid); } @@ -1099,7 +1044,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off { ierr = PIOc_inq_type_impl(ncid, xtype, NULL, &typelen); if(ierr != PIO_NOERR){ - GPTLstop("PIO:spio_get_vars_tc"); return pio_err(NULL, NULL, ierr, __FILE__, __LINE__, "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed. Inquiring the variable type length failed", pio_get_vname_from_file(file, varid), varid, pio_get_vname_from_file(file, varid), ncid); } @@ -1108,7 +1052,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off /* Get the number of dims for this var. */ ierr = PIOc_inq_varndims_impl(ncid, varid, &ndims); if(ierr != PIO_NOERR){ - GPTLstop("PIO:spio_get_vars_tc"); return pio_err(NULL, NULL, ierr, __FILE__, __LINE__, "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed. Inquiring the number of variable dimensions failed", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), ncid); } @@ -1163,7 +1106,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off xtype, num_elem, typelen); if(ierr != PIO_NOERR) { - GPTLstop("PIO:spio_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1188,7 +1130,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off /* Broadcast values currently only known on computation tasks to IO tasks. */ if ((mpierr = MPI_Bcast(&ndims, 1, MPI_INT, ios->comproot, ios->my_comm))) { - GPTLstop("PIO:spio_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1197,7 +1138,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off } if ((mpierr = MPI_Bcast(&num_elem, 1, MPI_OFFSET, ios->comproot, ios->my_comm))) { - GPTLstop("PIO:spio_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1206,7 +1146,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off } if ((mpierr = MPI_Bcast(&typelen, 1, MPI_OFFSET, ios->comproot, ios->my_comm))) { - GPTLstop("PIO:spio_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1215,7 +1154,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off } if ((mpierr = MPI_Bcast(&xtype, 1, MPI_INT, ios->comproot, ios->my_comm))) { - GPTLstop("PIO:spio_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1236,7 +1174,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off /* Turn on independent access for pnetcdf file. */ if ((ierr = ncmpi_begin_indep_data(file->fh))) { - GPTLstop("PIO:spio_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1288,7 +1225,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off ierr = ncmpi_get_vars_ulonglong(file->fh, varid, start, count, stride, (unsigned long long int *) buf); break; default: - GPTLstop("PIO:spio_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1301,7 +1237,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off /* Turn off independent access for pnetcdf file. */ if ((ierr = ncmpi_end_indep_data(file->fh))) { - GPTLstop("PIO:spio_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1323,7 +1258,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off cnt = (PIO_Offset*) calloc(ndims, sizeof(PIO_Offset)); if (cnt == NULL) { - GPTLstop("PIO:spio_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1374,7 +1308,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off ierr = ncmpi_get_vars_ulonglong_all(file->fh, varid, start, count, stride, (unsigned long long int *) buf); break; default: - GPTLstop("PIO:spio_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1448,7 +1381,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off /* break; */ #endif /* _NETCDF */ default: - GPTLstop("PIO:spio_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1463,7 +1395,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off { if (varid < 0 || varid >= file->num_vars) { - GPTLstop("PIO:PIOc_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1477,7 +1408,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off /* Check put_var tag */ if (strncmp(file->adios_vars[varid].nc_op_tag, "put_var", 7) != 0) { - GPTLstop("PIO:PIOc_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1504,7 +1434,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off adiosErr = adios2_current_step(¤t_adios_step, file->engineH); if (adiosErr != adios2_error_none) { - GPTLstop("PIO:PIOc_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1524,7 +1453,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off adiosErr = adios2_end_step(file->engineH); if (adiosErr != adios2_error_none) { - GPTLstop("PIO:PIOc_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1541,7 +1469,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off adiosErr = adios2_close(file->engineH); if (adiosErr != adios2_error_none) { - GPTLstop("PIO:PIOc_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1555,7 +1482,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off file->engineH = adios2_open(file->ioH, file->fname, adios2_mode_read); if (file->engineH == NULL) { - GPTLstop("PIO:PIOc_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1578,7 +1504,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off adiosErr = adios2_end_step(file->engineH); if (adiosErr != adios2_error_none) { - GPTLstop("PIO:PIOc_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1603,7 +1528,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off adiosErr = adios2_end_step(file->engineH); if (adiosErr != adios2_error_none) { - GPTLstop("PIO:PIOc_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1619,7 +1543,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off adiosErr = adios2_begin_step(file->engineH, adios2_step_mode_read, -1.0, &status); if (adiosErr != adios2_error_none) { - GPTLstop("PIO:PIOc_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1704,7 +1627,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off av->adios_varid = adios2_inquire_variable(file->ioH, vname); if (av->adios_varid == NULL) { - GPTLstop("PIO:PIOc_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1729,7 +1651,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off mem_buffer = (char *) calloc(av->adios_type_size, 1); if (mem_buffer == NULL) { - GPTLstop("PIO:PIOc_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1743,7 +1664,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off adiosErr = adios2_get(file->engineH, av->adios_varid, mem_buffer, adios2_mode_sync); if (adiosErr != adios2_error_none) { - GPTLstop("PIO:PIOc_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1770,7 +1690,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off /* This is not a scalar var. */ if (stride_present) { - GPTLstop("PIO:PIOc_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1833,7 +1752,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off av->adios_varid = adios2_inquire_variable(file->ioH, vname); if (av->adios_varid == NULL) { - GPTLstop("PIO:PIOc_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1851,7 +1769,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off adios2_varinfo *data_blocks = adios2_inquire_blockinfo(file->engineH, av->adios_varid, required_adios_step); if (data_blocks == NULL) { - GPTLstop("PIO:PIOc_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1879,7 +1796,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off adiosErr = adios2_variable_type(&read_type, av->adios_varid); if (adiosErr != adios2_error_none) { - GPTLstop("PIO:PIOc_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1910,7 +1826,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off mem_buffer_size = (char *) calloc(1, sizeof(size_t)); if (mem_buffer_size == NULL) { - GPTLstop("PIO:PIOc_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1924,7 +1839,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off adiosErr = adios2_set_block_selection(av->adios_varid, block_id); if (adiosErr != adios2_error_none) { - GPTLstop("PIO:PIOc_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1938,7 +1852,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off adiosErr = adios2_selection_size(&var_size, av->adios_varid); if (adiosErr != adios2_error_none) { - GPTLstop("PIO:PIOc_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1966,7 +1879,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off mem_buffer = (char *) calloc(var_size, av->adios_type_size); if (mem_buffer == NULL) { - GPTLstop("PIO:PIOc_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -1980,7 +1892,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off adiosErr = adios2_get(file->engineH, av->adios_varid, mem_buffer, adios2_mode_sync); if (adiosErr != adios2_error_none) { - GPTLstop("PIO:PIOc_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -2225,7 +2136,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off } else { - GPTLstop("PIO:PIOc_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -2246,7 +2156,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off ierr = check_netcdf(NULL, file, ierr, __FILE__, __LINE__); if(ierr != PIO_NOERR){ LOG((1, "nc*_get_vars_* failed, ierr = %d", ierr)); - GPTLstop("PIO:spio_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -2260,7 +2169,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off typelen, ios->ioroot)); if ((mpierr = MPI_Bcast(buf, num_elem * typelen, MPI_BYTE, ios->ioroot, ios->my_comm))) { - GPTLstop("PIO:spio_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -2272,7 +2180,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off ios->io_fstats->rb += num_elem * typelen; file->io_fstats->rb += num_elem * typelen; - GPTLstop("PIO:spio_get_vars_tc"); spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); @@ -2463,7 +2370,6 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off int mpierr = MPI_SUCCESS; /* Return code from MPI function codes. */ int ierr = PIO_NOERR; /* Return code from function calls. */ - GPTLstart("PIO:spio_put_vars_tc"); GPTLstart("PIO:write_total"); LOG((1, "spio_put_vars_tc ncid = %d varid = %d start_present = %d " "count_present = %d stride_present = %d xtype = %d", ncid, varid, @@ -2472,7 +2378,6 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off /* Get file info. */ if ((ierr = pio_get_file(ncid, &file))) { - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); return pio_err(NULL, NULL, ierr, __FILE__, __LINE__, "Writing variable (varid=%d) to file failed. Invalid file id (ncid=%d) provided", varid, ncid); @@ -2509,14 +2414,12 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstart("PIO:spio_put_vars_tc_adios"); GPTLstart("PIO:write_total_adios"); } /* User must provide a place to put some data. */ if (!buf) { - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); @@ -2524,7 +2427,6 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off spio_ltimer_stop(file->io_fstats->tot_timer_name); if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstop("PIO:spio_put_vars_tc_adios"); GPTLstop("PIO:write_total_adios"); } return pio_err(ios, file, PIO_EINVAL, __FILE__, __LINE__, @@ -2542,11 +2444,9 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off spio_ltimer_stop(file->io_fstats->tot_timer_name); ierr = PIOc_inq_vartype_impl(ncid, varid, &vartype); if(ierr != PIO_NOERR){ - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstop("PIO:spio_put_vars_tc_adios"); GPTLstop("PIO:write_total_adios"); } return pio_err(NULL, NULL, ierr, __FILE__, __LINE__, @@ -2560,11 +2460,9 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off /* Get the number of dims for this var. */ ierr = PIOc_inq_varndims_impl(ncid, varid, &ndims); if(ierr != PIO_NOERR){ - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstop("PIO:spio_put_vars_tc_adios"); GPTLstop("PIO:write_total_adios"); } return pio_err(NULL, NULL, ierr, __FILE__, __LINE__, @@ -2578,11 +2476,9 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off { ierr = PIOc_inq_type_impl(ncid, xtype, NULL, &typelen); if(ierr != PIO_NOERR){ - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstop("PIO:spio_put_vars_tc_adios"); GPTLstop("PIO:write_total_adios"); } return pio_err(NULL, NULL, ierr, __FILE__, __LINE__, @@ -2636,7 +2532,6 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off num_elem * typelen, buf); if(ierr != PIO_NOERR) { - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); @@ -2644,7 +2539,6 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off spio_ltimer_stop(file->io_fstats->tot_timer_name); if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstop("PIO:spio_put_vars_tc_adios"); GPTLstop("PIO:write_total_adios"); } return pio_err(ios, NULL, ierr, __FILE__, __LINE__, @@ -2668,7 +2562,6 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off LOG((2, "spio_put_vars_tc bcast from comproot")); if ((mpierr = MPI_Bcast(&ndims, 1, MPI_INT, ios->comproot, ios->my_comm))) { - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); @@ -2676,14 +2569,12 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off spio_ltimer_stop(file->io_fstats->tot_timer_name); if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstop("PIO:spio_put_vars_tc_adios"); GPTLstop("PIO:write_total_adios"); } return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); } if ((mpierr = MPI_Bcast(&xtype, 1, MPI_INT, ios->comproot, ios->my_comm))) { - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); @@ -2691,7 +2582,6 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off spio_ltimer_stop(file->io_fstats->tot_timer_name); if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { - GPTLstop("PIO:spio_put_vars_tc_adios"); GPTLstop("PIO:write_total_adios"); } return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); @@ -2705,13 +2595,11 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off { if (varid < 0 || varid >= file->num_vars) { - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->wr_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); - GPTLstop("PIO:spio_put_vars_tc_adios"); GPTLstop("PIO:write_total_adios"); return pio_err(ios, file, PIO_EBADID, __FILE__, __LINE__, "Writing variable to file (%s, ncid=%d) failed. Invalid variable id (varid=%d, expected >=0 and < number of variables in the file, %d) provided", @@ -2721,13 +2609,11 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off ierr = begin_adios2_step(file, ios); if (ierr != PIO_NOERR) { - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->wr_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); - GPTLstop("PIO:spio_put_vars_tc_adios"); GPTLstop("PIO:write_total_adios"); return pio_err(NULL, file, ierr, __FILE__, __LINE__, "adios2_begin_step failed for file (%s)", pio_get_fname_from_file(file)); @@ -2805,13 +2691,11 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off adios2_constant_dims_false); if (av->adios_varid == NULL) { - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->wr_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); - GPTLstop("PIO:spio_put_vars_tc_adios"); GPTLstop("PIO:write_total_adios"); return pio_err(NULL, file, PIO_EADIOS2ERR, __FILE__, __LINE__, "Defining (ADIOS) variable (name=%s) failed for file (%s, ncid=%d)", @@ -2822,13 +2706,11 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off adiosErr = adios2_put(file->engineH, av->adios_varid, buf, adios2_mode_sync); if (adiosErr != adios2_error_none) { - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->wr_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); - GPTLstop("PIO:spio_put_vars_tc_adios"); GPTLstop("PIO:write_total_adios"); return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, "Putting (ADIOS) variable (name=%s) failed (adios2_error=%s) for file (%s, ncid=%d)", @@ -2846,13 +2728,11 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off LOG((2, "ADIOS does not support striding %s:%s\n" "Variable %s will be corrupted in the output" , __FILE__, __func__, av->name)); - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->wr_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); - GPTLstop("PIO:spio_put_vars_tc_adios"); GPTLstop("PIO:write_total_adios"); return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, "ADIOS does not support striding. Variable %s file (%s, ncid=%d)", @@ -2930,13 +2810,11 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off adios2_constant_dims_false); if (av->adios_varid == NULL) { - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->wr_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); - GPTLstop("PIO:spio_put_vars_tc_adios"); GPTLstop("PIO:write_total_adios"); return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, "Defining (ADIOS) variable (name=%s) failed for file (%s, ncid=%d)", @@ -2948,13 +2826,11 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off adiosErr = adios2_set_selection(av->adios_varid, 1, NULL, &av_size); if (adiosErr != adios2_error_none) { - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->wr_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); - GPTLstop("PIO:spio_put_vars_tc_adios"); GPTLstop("PIO:write_total_adios"); return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, "Setting (ADIOS) selection to variable (name=%s) failed (adios2_error=%s) for file (%s, ncid=%d)", @@ -2981,13 +2857,11 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off char *mem_buffer = (char*)calloc(av_size, sizeof(char)); if (mem_buffer == NULL) { - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->wr_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); - GPTLstop("PIO:spio_put_vars_tc_adios"); GPTLstop("PIO:write_total_adios"); return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Out of memory, allocating memory (%lld bytes) for putting ADIOS variable (name = %s)", @@ -3004,13 +2878,11 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off mem_buffer = NULL; if (adiosErr != adios2_error_none) { - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->wr_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); - GPTLstop("PIO:spio_put_vars_tc_adios"); GPTLstop("PIO:write_total_adios"); return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, "Putting (ADIOS) variable (name=%s) failed (adios2_error=%s) for file (%s, ncid=%d)", @@ -3035,13 +2907,11 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off attributeH = adios2_define_attribute_array(file->ioH, att_name, adios2_type_string, dimnames, av->ndims); if (attributeH == NULL) { - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->wr_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); - GPTLstop("PIO:spio_put_vars_tc_adios"); GPTLstop("PIO:write_total_adios"); return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, "Defining (ADIOS) attribute array (name=%s, size=%d) failed for file (%s, ncid=%d)", @@ -3064,13 +2934,11 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off attributeH = adios2_define_attribute(file->ioH, att_name, adios2_type_int32_t, &av->ndims); if (attributeH == NULL) { - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->wr_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); - GPTLstop("PIO:spio_put_vars_tc_adios"); GPTLstop("PIO:write_total_adios"); return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, "Defining (ADIOS) attribute (name=%s) failed for file (%s, ncid=%d)", @@ -3086,13 +2954,11 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off attributeH = adios2_define_attribute(file->ioH, att_name, adios2_type_int32_t, &av->nc_type); if (attributeH == NULL) { - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->wr_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); - GPTLstop("PIO:spio_put_vars_tc_adios"); GPTLstop("PIO:write_total_adios"); return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, "Defining (ADIOS) attribute (name=%s) failed for file (%s, ncid=%d)", @@ -3110,13 +2976,11 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off attributeH = adios2_define_attribute(file->ioH, att_name, adios2_type_int32_t, &save_adios_type); if (attributeH == NULL) { - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->wr_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); - GPTLstop("PIO:spio_put_vars_tc_adios"); GPTLstop("PIO:write_total_adios"); return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, "Defining (ADIOS) attribute (name=%s) failed for file (%s, ncid=%d)", @@ -3132,13 +2996,11 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off attributeH = adios2_define_attribute(file->ioH, att_name, adios2_type_string, "put_var"); if (attributeH == NULL) { - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->wr_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); - GPTLstop("PIO:spio_put_vars_tc_adios"); GPTLstop("PIO:write_total_adios"); return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, "Defining (ADIOS) attribute (name=%s) failed for file (%s, ncid=%d)", @@ -3148,13 +3010,11 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off file->num_written_blocks += 4; } - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->wr_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); - GPTLstop("PIO:spio_put_vars_tc_adios"); GPTLstop("PIO:write_total_adios"); return PIO_NOERR; @@ -3174,7 +3034,6 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off if (!(vdesc->request = (int *) realloc(vdesc->request, sizeof(int) * (vdesc->nreqs + PIO_REQUEST_ALLOC_CHUNK)))) { - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); @@ -3190,7 +3049,6 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off PIO_REQUEST_ALLOC_CHUNK)); if(!(vdesc->request_sz)) { - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); @@ -3282,7 +3140,6 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off ierr = ncmpi_bput_var_ulonglong(file->fh, varid, (const unsigned long long int *) buf, request); break; default: - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); @@ -3317,7 +3174,6 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off LOG((2, "stride not present")); if (!(fake_stride = (PIO_Offset *) malloc(ndims * sizeof(PIO_Offset)))) { - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); @@ -3376,7 +3232,6 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off ierr = ncmpi_bput_vars_ulonglong(file->fh, varid, start, count, fake_stride, (const unsigned long long int *) buf, request); break; default: - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); @@ -3486,7 +3341,6 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off /* break; */ #endif /* _NETCDF */ default: - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); @@ -3502,7 +3356,6 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off ierr = check_netcdf(NULL, file, ierr, __FILE__, __LINE__); if(ierr != PIO_NOERR){ LOG((1, "nc*_put_vars_* failed, ierr = %d", ierr)); - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); @@ -3515,7 +3368,6 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off LOG((2, "spio_put_vars_tc bcast netcdf return code %d complete", ierr)); - GPTLstop("PIO:spio_put_vars_tc"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); diff --git a/src/clib/pioc.cpp b/src/clib/pioc.cpp index 711c32a6cd..b3067ac6f2 100644 --- a/src/clib/pioc.cpp +++ b/src/clib/pioc.cpp @@ -866,7 +866,6 @@ static int initdecomp(int iosysid, int pio_type, int ndims, const int *gdimlen, int mpierr = MPI_SUCCESS; /* Return code from MPI function calls. */ int ierr; /* Return code. */ - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("PIO:PIOc_initdecomp"); LOG((1, "PIOc_InitDecomp iosysid = %d pio_type = %d ndims = %d maplen = %d", iosysid, pio_type, ndims, maplen)); @@ -1382,12 +1381,6 @@ int PIOc_Init_Intracomm_impl(MPI_Comm comp_comm, int num_iotasks, int stride, in /* TIMING_INTERNAL implies that the timing statistics are gathered/ * displayed by pio */ -#ifdef TIMING -#ifdef TIMING_INTERNAL - pio_init_gptl(); -#endif -#endif - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("PIO:PIOc_Init_Intracomm"); /* Turn on the logging system. */ pio_init_logging(); @@ -1834,7 +1827,6 @@ int PIOc_finalize_impl(int iosysid) char gptl_log_fname[PIO_MAX_NAME]; #endif - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("PIO:PIOc_finalize"); LOG((1, "PIOc_finalize iosysid = %d MPI_COMM_NULL = %d", iosysid, MPI_COMM_NULL)); @@ -2191,13 +2183,6 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li /* TIMING_INTERNAL implies that the timing statistics are gathered/ * displayed by pio */ -#ifdef TIMING -#ifdef TIMING_INTERNAL - pio_init_gptl(); -#endif -#endif - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("PIO:PIOc_init_async"); - /* Check input parameters. */ if (num_io_procs < 1 || component_count < 1 || !num_procs_per_comp || !iosysidp || (rearranger != PIO_REARR_BOX && rearranger != PIO_REARR_SUBSET)) @@ -2741,12 +2726,6 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, /* TIMING_INTERNAL implies that the timing statistics are gathered/ * displayed by pio */ -#ifdef TIMING -#ifdef TIMING_INTERNAL - pio_init_gptl(); -#endif -#endif - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("PIO:PIOc_init_intercomm"); assert((component_count > 0) && ucomp_comms && iosysidps); if((component_count <= 0) || (ucomp_comms == NULL) || ((rearranger != PIO_REARR_BOX) && (rearranger != PIO_REARR_SUBSET)) || diff --git a/src/clib/pioc_support.cpp b/src/clib/pioc_support.cpp index c1b21f47a1..c844ccec58 100644 --- a/src/clib/pioc_support.cpp +++ b/src/clib/pioc_support.cpp @@ -1774,10 +1774,8 @@ int PIOc_freedecomp_impl(int iosysid, int ioid) int mpierr = MPI_SUCCESS; /* Return code from MPI function calls. */ int ret = 0; - GPTLstart("PIO:PIOc_freedecomp"); if (!(ios = pio_get_iosystem_from_id(iosysid))) { - GPTLstop("PIO:PIOc_freedecomp"); return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, "Freeing PIO decomposition failed. Invalid iosystem id (%d) provided", iosysid); } @@ -1786,7 +1784,6 @@ int PIOc_freedecomp_impl(int iosysid, int ioid) if (!(iodesc = pio_get_iodesc_from_id(ioid))) { - GPTLstop("PIO:PIOc_freedecomp"); spio_ltimer_stop(ios->io_fstats->tot_timer_name); return pio_err(ios, NULL, PIO_EBADID, __FILE__, __LINE__, "Freeing PIO decomposition failed. Invalid io decomposition id (%d) provided", ioid); @@ -1800,7 +1797,6 @@ int PIOc_freedecomp_impl(int iosysid, int ioid) PIO_SEND_ASYNC_MSG(ios, msg, &ret, iosysid, ioid); if(ret != PIO_NOERR) { - GPTLstop("PIO:PIOc_freedecomp"); spio_ltimer_stop(ios->io_fstats->tot_timer_name); return pio_err(ios, NULL, ret, __FILE__, __LINE__, "Freeing PIO decomposition failed (iosysid = %d, iodesc id=%d). Error sending asynchronous message, PIO_MSG_FREEDECOMP, on iosystem", iosysid, ioid); @@ -1822,7 +1818,6 @@ int PIOc_freedecomp_impl(int iosysid, int ioid) if (iodesc->rtype[i] != MPI_DATATYPE_NULL) if ((mpierr = MPI_Type_free(&iodesc->rtype[i]))) { - GPTLstop("PIO:PIOc_freedecomp"); spio_ltimer_stop(ios->io_fstats->tot_timer_name); return check_mpi(ios, NULL, mpierr, __FILE__, __LINE__); } @@ -1836,7 +1831,6 @@ int PIOc_freedecomp_impl(int iosysid, int ioid) if (iodesc->stype[i] != MPI_DATATYPE_NULL) if ((mpierr = MPI_Type_free(iodesc->stype + i))) { - GPTLstop("PIO:PIOc_freedecomp"); spio_ltimer_stop(ios->io_fstats->tot_timer_name); return check_mpi(ios, NULL, mpierr, __FILE__, __LINE__); } @@ -1866,7 +1860,6 @@ int PIOc_freedecomp_impl(int iosysid, int ioid) if (iodesc->rearranger == PIO_REARR_SUBSET) if ((mpierr = MPI_Comm_free(&iodesc->subset_comm))) { - GPTLstop("PIO:PIOc_freedecomp"); spio_ltimer_stop(ios->io_fstats->tot_timer_name); return check_mpi(ios, NULL, mpierr, __FILE__, __LINE__); } @@ -1879,12 +1872,10 @@ int PIOc_freedecomp_impl(int iosysid, int ioid) ret = pio_delete_iodesc_from_list(ioid); if (ret != PIO_NOERR) { - GPTLstop("PIO:PIOc_freedecomp"); spio_ltimer_stop(ios->io_fstats->tot_timer_name); return pio_err(ios, NULL, ret, __FILE__, __LINE__, "Freeing PIO decomposition failed (iosysid = %d, ioid=%d). Error while trying to delete I/O descriptor from internal list", iosysid, ioid); } - GPTLstop("PIO:PIOc_freedecomp"); spio_ltimer_stop(ios->io_fstats->tot_timer_name); return ret; From afc7a12923aa05e1d4c2f4163c9ff87ae0679b40 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Sun, 18 May 2025 14:07:11 -0500 Subject: [PATCH 065/194] Add map sorter Adding a map sorter class that abstracts the logic to sort via map --- src/clib/spio_map_sorter.hpp | 104 +++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 src/clib/spio_map_sorter.hpp diff --git a/src/clib/spio_map_sorter.hpp b/src/clib/spio_map_sorter.hpp new file mode 100644 index 0000000000..1a2ec1ffc5 --- /dev/null +++ b/src/clib/spio_map_sorter.hpp @@ -0,0 +1,104 @@ +#ifndef __SPIO_MAP_SORTER_HPP__ +#define __SPIO_MAP_SORTER_HPP__ + +#include "pio_config.h" +#include "pio.h" +#include "pio_internal.h" +#include "pio_types.hpp" + +#include +#include +#include +#include + +namespace SPIO_Util{ + + class Map_sorter{ + public: + Map_sorter(){} + + /* Create sorter map based on values in vector v, the comparator passed + should be for comparing values in v + */ + template > + Map_sorter(const std::vector &v, Comp cmp = Comp{}):sort_map_(v.size()) + { + auto sort_map_cmp = [&v, &cmp](T a, T b){ return cmp(v[a], v[b]); }; + init_sort_map(sort_map_cmp); + } + + /* Create sorter based on the given comparator, the comparator passed + should be for comparing sort map values + */ + template + Map_sorter(std::size_t sz, Comp cmp):sort_map_(sz) + { + init_sort_map(cmp); + } + + /* Init sorter map based on values in vector v, the comparator passed + should be for comparing values in v + */ + template > + void init(const std::vector &v, Comp cmp = Comp{}) + { + /* Don't allow reinits */ + assert(sort_map_.size() == 0); + + sort_map_.resize(v.size()); + auto sort_map_cmp = [&v, &cmp](T a, T b){ return cmp(v[a], v[b]); }; + init_sort_map(sort_map_cmp); + } + + /* Init sorter based on the given comparator, the comparator passed + should be for comparing sort map values + */ + template + void init(std::size_t sz, Comp cmp) + { + /* Don't allow reinits */ + assert(sort_map_.size() == 0); + + sort_map_.resize(sz); + init_sort_map(cmp); + } + + template + void sort(std::vector &v) + { + std::vector vtmp(v); + assert(v.size() == sort_map_.size()); + + for(std::size_t i = 0; i < vtmp.size(); i++){ + v[sort_map_[i]] = vtmp[i]; + } + } + + /* FIXME: Get rid of this function that exposes the sort map + Current code needs this map for creating recv types. We need to find + an alternate way to create these types + */ + const std::vector &get_sort_map(void ) { return sort_map_; } + + std::size_t size(void ) const { return sort_map_.size(); } + private: + std::vector sort_map_; + + template + void init_sort_map(Comp cmp) + { + /* FIXME: Do we need a push sort map - isn't pull map enough ? */ + /* pull_sort_map => mapping for pulling values from source to sorted */ + std::vector pull_sort_map(sort_map_.size()); + std::iota(pull_sort_map.begin(), pull_sort_map.end(), 0); + std::sort(pull_sort_map.begin(), pull_sort_map.end(), cmp); + /* sort_map_ is push map => mapping for pushing values from source to sorted */ + for(std::size_t i = 0; i < pull_sort_map.size(); i++){ + sort_map_[pull_sort_map[i]] = i; + } + } + }; + +} // namespace SPIO_Util + +#endif // __SPIO_MAP_SORTER_HPP__ From 534d62619847c52239e404516c314fab837e0593 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Sun, 18 May 2025 14:09:39 -0500 Subject: [PATCH 066/194] Move to new map sorter class Moving to use the new map sorter class in contig rearranger --- src/clib/pio_rearr_contig.cpp | 31 +++++++++++++++++++++++++------ src/clib/pio_rearr_contig.hpp | 4 +++- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/clib/pio_rearr_contig.cpp b/src/clib/pio_rearr_contig.cpp index ff47067f89..a5021aa2e0 100644 --- a/src/clib/pio_rearr_contig.cpp +++ b/src/clib/pio_rearr_contig.cpp @@ -765,6 +765,7 @@ int SPIO::DataRearr::Contig_rearr::setup_data_agg_info(const PIO_Offset *lcompma /* Sort the indices of gcompmap to a view that we need for data rearrangement between * aggregator/IO procs */ + /* std::vector gcompmap_idx(gcompmap.size()); std::iota(gcompmap_idx.begin(), gcompmap_idx.end(), 0); @@ -772,22 +773,23 @@ int SPIO::DataRearr::Contig_rearr::setup_data_agg_info(const PIO_Offset *lcompma std::sort(gcompmap_idx.begin(), gcompmap_idx.end(), [&gcompmap,&to_proc](PIO_Offset a, PIO_Offset b){ if(to_proc[a] == to_proc[b]){ - /* Sort all data to send to each proc */ + // Sort all data to send to each proc return gcompmap[a] < gcompmap[b]; } else{ - /* Aggregate all data to send to a proc together */ + // Aggregate all data to send to a proc together return to_proc[a] < to_proc[b]; } }); GPTLstop("PIO:Contig_rearr::setup_data_agg_info::sort"); - /* Aggregate compmap sorter can be used to sort any user data based on gcompmap */ + // Aggregate compmap sorter can be used to sort any user data based on gcompmap agg_iochunk_sz_ = gcompmap.size(); agg_compmap_sorter_.resize(agg_iochunk_sz_); for(std::size_t i = 0; i < gcompmap_idx.size(); i++){ agg_compmap_sorter_[gcompmap_idx[i]] = i; } + */ /* for(std::size_t i = 0; i < gcompmap_idx.size(); i++){ if(gcompmap[gcompmap_idx[i]] == -1){ @@ -803,7 +805,22 @@ int SPIO::DataRearr::Contig_rearr::setup_data_agg_info(const PIO_Offset *lcompma // std::cout << "DBG: agg_compmap_sorter_ : " << std::flush; // SPIO_Util::Dbg_Util::print_1dvec(agg_compmap_sorter_); - ret = init_agg_recv_types(gcompmap_counts, agg_compmap_sorter_); + agg_iochunk_sz_ = gcompmap.size(); + GPTLstart("PIO:Contig_rearr::setup_data_agg_info::sort"); + agg_compmap_sorter_.init(gcompmap.size(), + [&gcompmap,&to_proc](std::size_t a, std::size_t b){ + if(to_proc[a] == to_proc[b]){ + // Sort all data to send to each proc + return gcompmap[a] < gcompmap[b]; + } + else{ + // Aggregate all data to send to a proc together + return to_proc[a] < to_proc[b]; + } + }); + GPTLstop("PIO:Contig_rearr::setup_data_agg_info::sort"); + + ret = init_agg_recv_types(gcompmap_counts, agg_compmap_sorter_.get_sort_map()); return ret; } @@ -1029,8 +1046,10 @@ int SPIO::DataRearr::Contig_rearr::setup_data_rearr_info(std::vector assert(to_proc.size() == gcompmap.size()); /* Sort gcompmap (the aggregated compmap from compute procs) based on compmap sorter map */ - SPIO_Util::vec_map_sort(gcompmap, agg_compmap_sorter_); - SPIO_Util::vec_map_sort(to_proc, agg_compmap_sorter_); + //SPIO_Util::vec_map_sort(gcompmap, agg_compmap_sorter_); + //SPIO_Util::vec_map_sort(to_proc, agg_compmap_sorter_); + agg_compmap_sorter_.sort(gcompmap); + agg_compmap_sorter_.sort(to_proc); /* Exchange information about the data being sent from each process, * 1) The number of regions (a single region is a contiguous chunk/block of elements/data) diff --git a/src/clib/pio_rearr_contig.hpp b/src/clib/pio_rearr_contig.hpp index 57a6825a99..cedba25cda 100644 --- a/src/clib/pio_rearr_contig.hpp +++ b/src/clib/pio_rearr_contig.hpp @@ -5,6 +5,7 @@ #include "pio.h" #include "pio_internal.h" #include "pio_types.hpp" +#include "spio_map_sorter.hpp" #include #include @@ -139,7 +140,8 @@ namespace SPIO{ int agg_comm_sz_; /* Size/Num of elements of the data chunk in this aggregating process */ std::size_t agg_iochunk_sz_; - std::vector agg_compmap_sorter_; + //std::vector agg_compmap_sorter_; + SPIO_Util::Map_sorter agg_compmap_sorter_; /* The byte displacements for each process, that is part of agg_comm_, in the aggregated data */ std::vector agg_data_byte_displs_; GatherScatter_info agg_gs_info_; From 69b8fa8131d55a95bf5ae6c58b970594ef3611f2 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 19 May 2025 09:40:41 -0500 Subject: [PATCH 067/194] Simplify sort when setting up agg info Since the destination procs are decided based on the order of the decomp map index, simplify the sorting to just compare the decomp map indices (and ignore the dest proc info) while setting up the data aggregation info --- src/clib/pio_rearr_contig.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/clib/pio_rearr_contig.cpp b/src/clib/pio_rearr_contig.cpp index a5021aa2e0..e1872417bb 100644 --- a/src/clib/pio_rearr_contig.cpp +++ b/src/clib/pio_rearr_contig.cpp @@ -809,14 +809,8 @@ int SPIO::DataRearr::Contig_rearr::setup_data_agg_info(const PIO_Offset *lcompma GPTLstart("PIO:Contig_rearr::setup_data_agg_info::sort"); agg_compmap_sorter_.init(gcompmap.size(), [&gcompmap,&to_proc](std::size_t a, std::size_t b){ - if(to_proc[a] == to_proc[b]){ - // Sort all data to send to each proc - return gcompmap[a] < gcompmap[b]; - } - else{ - // Aggregate all data to send to a proc together - return to_proc[a] < to_proc[b]; - } + // Sort all data to send to each proc + return gcompmap[a] < gcompmap[b]; }); GPTLstop("PIO:Contig_rearr::setup_data_agg_info::sort"); From 563b3179c50334c27d098cee5206eb3e8984a011 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Sun, 30 Nov 2025 18:53:58 -0600 Subject: [PATCH 068/194] Adding NetCDF support for contig rearr Adding support for NetCDF in the contig rearranger. * Updating the maxregions in the I/O descriptor to the maximum of the number of ranges across all I/O tasks (for the contig rearranger) --- src/clib/pio_rearr_contig.cpp | 36 +++++++++++++++++++++++++++++++++++ src/clib/pio_rearr_contig.hpp | 26 ++++++++++++++++++++++++- src/clib/pioc.cpp | 2 +- 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/clib/pio_rearr_contig.cpp b/src/clib/pio_rearr_contig.cpp index e1872417bb..45eca0b599 100644 --- a/src/clib/pio_rearr_contig.cpp +++ b/src/clib/pio_rearr_contig.cpp @@ -202,6 +202,42 @@ void SPIO::DataRearr::Contig_rearr::get_contig_ranges_from_off_range(std::vector assert(count == 0); } +std::size_t SPIO::DataRearr::Contig_rearr::get_ncontig_ranges_from_off_range(PIO_Offset start_off, PIO_Offset count) const +{ + std::size_t nranges = 0; + std::size_t last_contig_dim = 0; + std::size_t ndims = gdimlen_.size(); + std::vector start_dim_idx(ndims, 0); + + while(count > 0){ + convert_off_to_start_dim_idx(start_off, start_dim_idx, last_contig_dim); + PIO_Offset last_contig_dim_nchunks = gdimlen_[last_contig_dim] - start_dim_idx[last_contig_dim]; + PIO_Offset dim_nchunks = count / dim_chunk_sz_[last_contig_dim]; + PIO_Offset range_sz = 0; + if(dim_nchunks > 0){ + dim_nchunks = std::min(dim_nchunks, last_contig_dim_nchunks); + range_sz = dim_nchunks * dim_chunk_sz_[last_contig_dim]; + } + else{ + for(std::size_t idx = last_contig_dim + 1; idx < ndims; idx++){ + dim_nchunks = count / dim_chunk_sz_[idx]; + if(dim_nchunks > 0){ + dim_nchunks = std::min(dim_nchunks, static_cast(gdimlen_[idx])); + range_sz = dim_nchunks * dim_chunk_sz_[idx]; + break; + } + } + } + nranges++; + start_off += range_sz; + count -= range_sz; + } + + assert(count == 0); + + return nranges; +} + std::vector > SPIO::DataRearr::Contig_rearr::get_rearr_decomp_map_contig_ranges(int iorank) { assert(gdecomp_sz_ > 0); diff --git a/src/clib/pio_rearr_contig.hpp b/src/clib/pio_rearr_contig.hpp index cedba25cda..f9d37c8255 100644 --- a/src/clib/pio_rearr_contig.hpp +++ b/src/clib/pio_rearr_contig.hpp @@ -104,6 +104,15 @@ namespace SPIO{ return get_rearr_decomp_map_contig_ranges(rearr_comm_rank_); } + std::size_t get_rearr_decomp_map_contig_max_nranges(void ) + { + std::size_t max_nranges = 0; + for(int i = 0; i < rearr_comm_sz_; i++){ + max_nranges = std::max(max_nranges, get_rearr_decomp_map_nranges(i)); + } + return max_nranges; + } + void off_range_to_dim_range(PIO_Offset start_off, PIO_Offset end_off, PIO_Offset *start, PIO_Offset *count) const; @@ -195,7 +204,7 @@ namespace SPIO{ } void convert_off_to_start_dim_idx(PIO_Offset start_off, std::vector &start_dim_idx, - std::size_t &last_contig_dim) + std::size_t &last_contig_dim) const { last_contig_dim = 0; for(std::size_t i = 0; i < start_dim_idx.size(); i++){ @@ -225,8 +234,23 @@ namespace SPIO{ return std::make_pair(start, end); } + std::size_t get_rearr_decomp_map_nranges(int iorank) const + { + assert(gdecomp_sz_ > 0); + assert(rearr_comm_iochunk_sz_ > 0); + + PIO_Offset iochunk = rearr_comm_iochunk_sz_; + PIO_Offset start = iorank * iochunk; + PIO_Offset end = start + iochunk; + if(iorank == (rearr_comm_sz_ - 1)){ + end = gdecomp_sz_; + } + return get_ncontig_ranges_from_off_range(start, end - start); + } + void get_contig_ranges_from_off_range(std::vector > &contig_map_ranges, PIO_Offset start_off, PIO_Offset count); + std::size_t get_ncontig_ranges_from_off_range(PIO_Offset start_off, PIO_Offset count) const; int create_agg_comm(void ); static void get_non_fval_lcompmap_counts_displs(const PIO_Offset *lcompmap, std::size_t lcompmap_sz, diff --git a/src/clib/pioc.cpp b/src/clib/pioc.cpp index b3067ac6f2..4050cebd59 100644 --- a/src/clib/pioc.cpp +++ b/src/clib/pioc.cpp @@ -759,7 +759,7 @@ static void init_iodesc_contig_rearr_fields(iosystem_desc_t *ios, io_desc_t *iod prev_region = cur_region; cur_region = cur_region->next; } - iodesc->maxregions = off_ranges.size(); + iodesc->maxregions = iodesc->rearr->get_rearr_decomp_map_contig_max_nranges(); } } From 2076ec59733465db002fd01d200e918813e93223 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 2 Dec 2025 17:08:52 -0600 Subject: [PATCH 069/194] Fix hdf5 redef issue Ensure that dimensions and attributes for coordinate variables are only created once. When users call enddef multiple times (redef + enddef) ensure that only newly created dimensions & variables are processed. --- src/clib/pio_nc.cpp | 2 + src/clib/pioc_support.cpp | 190 ++++++++++++++++++-------------------- 2 files changed, 91 insertions(+), 101 deletions(-) diff --git a/src/clib/pio_nc.cpp b/src/clib/pio_nc.cpp index d3683671af..a218276ce3 100644 --- a/src/clib/pio_nc.cpp +++ b/src/clib/pio_nc.cpp @@ -3204,6 +3204,7 @@ int PIOc_def_dim_impl(int ncid, const char *name, PIO_Offset len, int *idp) file->hdf5_dims[file->hdf5_num_dims].len = len; file->hdf5_dims[file->hdf5_num_dims].has_coord_var = false; + file->hdf5_dims[file->hdf5_num_dims].hdf5_dataset_id = H5I_INVALID_HID; *idp = file->hdf5_num_dims; file->hdf5_num_dims++; } @@ -3548,6 +3549,7 @@ int PIOc_def_var_impl(int ncid, const char *name, nc_type xtype, int ndims, file->hdf5_vars[file->hdf5_num_vars].nc_type = xtype; file->hdf5_vars[file->hdf5_num_vars].ndims = ndims; file->hdf5_vars[file->hdf5_num_vars].is_coord_var = false; + file->hdf5_vars[file->hdf5_num_vars].hdf5_dataset_id = H5I_INVALID_HID; file->hdf5_vars[file->hdf5_num_vars].hdf5_dimids = (int*)malloc(ndims * sizeof(int)); if (file->hdf5_vars[file->hdf5_num_vars].hdf5_dimids == NULL) diff --git a/src/clib/pioc_support.cpp b/src/clib/pioc_support.cpp index c844ccec58..c624d1f898 100644 --- a/src/clib/pioc_support.cpp +++ b/src/clib/pioc_support.cpp @@ -7115,7 +7115,10 @@ int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) for (i = 0; i < file->hdf5_num_dims; i++) { - if (!file->hdf5_dims[i].has_coord_var) + /* For dimensions without an associated coordinate var, define them here. However since the + * the user can call redef() multiple times define it only its not already defined/valid + */ + if (!file->hdf5_dims[i].has_coord_var && (file->hdf5_dims[i].hdf5_dataset_id == H5I_INVALID_HID)) { hid_t space_id, dcpl_id = H5I_INVALID_HID, dimscale_id; hsize_t dims[1], max_dims[1], chunk_dims[1] = {1}; @@ -7278,119 +7281,104 @@ int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) } } - for (i = 0; i < file->hdf5_num_vars; i++) - { - /* Upgrade the dataset of a coordinate variable to a dimension scale */ - if (file->hdf5_vars[i].is_coord_var) - { - if (H5DSset_scale(file->hdf5_vars[i].hdf5_dataset_id, file->hdf5_vars[i].name) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to convert a dataset (for coordinate variable %s) to a dimension scale", - pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_vars[i].name); - } + for(i = 0; i < file->hdf5_num_vars; i++){ + /* Upgrade the dataset of a coordinate variable to a dimension scale */ + if(file->hdf5_vars[i].is_coord_var){ + /* Write a special attribute (_Netcdf4Dimid) for the netCDF-4 dimension ID. */ + hid_t dimscale_id = file->hdf5_vars[i].hdf5_dataset_id; + hid_t dimid_att_id; + htri_t attr_exists; - assert(file->hdf5_vars[i].ndims > 0); - int dimid = file->hdf5_vars[i].hdf5_dimids[0]; - file->hdf5_dims[dimid].hdf5_dataset_id = file->hdf5_vars[i].hdf5_dataset_id; + /* Writing _Netcdf4Dimid attribute */ + const char* attr_name = "_Netcdf4Dimid"; - /* Write a special attribute (_Netcdf4Dimid) for the netCDF-4 dimension ID. */ - hid_t dimscale_id = file->hdf5_vars[i].hdf5_dataset_id; - hid_t dimid_att_id; - htri_t attr_exists; + attr_exists = H5Aexists(dimscale_id, attr_name); + if(attr_exists < 0){ + /* Error determining whether an attribute with a given name exists on an object */ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to determine whether an attribute (%s) exists on a dimension scale (%s)", + pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); + } - hid_t dimid_space_id = H5Screate(H5S_SCALAR); - if (dimid_space_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new scalar dataspace", - pio_get_fname_from_file(file), file->pio_ncid); - } + if(attr_exists > 0){ + /* If redef/enddef is called, potentially multiple times, + * this attribute might already have been created + */ + continue; + } - /* Writing _Netcdf4Dimid attribute */ - const char* attr_name = "_Netcdf4Dimid"; + if(H5DSset_scale(file->hdf5_vars[i].hdf5_dataset_id, file->hdf5_vars[i].name) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to convert a dataset (for coordinate variable %s) to a dimension scale", + pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_vars[i].name); + } - attr_exists = H5Aexists(dimscale_id, attr_name); - if (attr_exists > 0) - { - assert(0); - } - else if (attr_exists == 0) - { - dimid_att_id = H5Acreate2(dimscale_id, attr_name, - H5T_NATIVE_INT, dimid_space_id, H5P_DEFAULT, H5P_DEFAULT); - if (dimid_att_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new attribute (%s) attached to a dimension scale (%s)", - pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); - } - } - else - { - /* Error determining whether an attribute with a given name exists on an object */ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to determine whether an attribute (%s) exists on a dimension scale (%s)", - pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); - } + assert(file->hdf5_vars[i].ndims > 0); + int dimid = file->hdf5_vars[i].hdf5_dimids[0]; + file->hdf5_dims[dimid].hdf5_dataset_id = file->hdf5_vars[i].hdf5_dataset_id; - if (H5Awrite(dimid_att_id, H5T_NATIVE_INT, &dimid) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to write an attribute (%s) attached to a dimension scale (%s)", - pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); - } + hid_t dimid_space_id = H5Screate(H5S_SCALAR); + if(dimid_space_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new scalar dataspace", + pio_get_fname_from_file(file), file->pio_ncid); + } - if (H5Sclose(dimid_space_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a scalar dataspace", - pio_get_fname_from_file(file), file->pio_ncid); - } + dimid_att_id = H5Acreate2(dimscale_id, attr_name, + H5T_NATIVE_INT, dimid_space_id, H5P_DEFAULT, H5P_DEFAULT); + if(dimid_att_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new attribute (%s) attached to a dimension scale (%s)", + pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); + } - if (H5Aclose(dimid_att_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to close an attribute (%s) attached to a dimension scale (%s)", - pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); - } + if(H5Awrite(dimid_att_id, H5T_NATIVE_INT, &dimid) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to write an attribute (%s) attached to a dimension scale (%s)", + pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); } - } - for (i = 0; i < file->hdf5_num_vars; i++) - { - if (!file->hdf5_vars[i].is_coord_var) - { - int ndims = file->hdf5_vars[i].ndims; - if (ndims > 0) - { - int* dimids = file->hdf5_vars[i].hdf5_dimids; - for (int j = 0; j < ndims; j++) - { - if (H5DSattach_scale(file->hdf5_vars[i].hdf5_dataset_id, file->hdf5_dims[dimids[j]].hdf5_dataset_id, j) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to attach a dimension scale (for dimension %s) to %dth dimension of a dataset (for variable %s)", - pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_dims[dimids[j]].name, j, file->hdf5_vars[i].name); - } + if(H5Aclose(dimid_att_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to close an attribute (%s) attached to a dimension scale (%s)", + pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); + } - /* According to HDF5 developers, the H5DS routines are not parallel, so all the ranks are going to be - * doing the same operations. At some point, with enough iterations of the loop, HDF5 might get out of - * step between the ranks. - * Workaround: place a barrier to sync H5DSattach_scale calls. - */ - MPI_Barrier(ios->io_comm); - } + if(H5Sclose(dimid_space_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a scalar dataspace", + pio_get_fname_from_file(file), file->pio_ncid); + } + } + else{ + /* Not a coordinate var */ + int ndims = file->hdf5_vars[i].ndims; + if(ndims > 0){ + int* dimids = file->hdf5_vars[i].hdf5_dimids; + for(int j = 0; j < ndims; j++){ + if(H5DSattach_scale(file->hdf5_vars[i].hdf5_dataset_id, file->hdf5_dims[dimids[j]].hdf5_dataset_id, j) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to attach a dimension scale (for dimension %s) to %dth dimension of a dataset (for variable %s)", + pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_dims[dimids[j]].name, j, file->hdf5_vars[i].name); } + + /* According to HDF5 developers, the H5DS routines are not parallel, so all the ranks are going to be + * doing the same operations. At some point, with enough iterations of the loop, HDF5 might get out of + * step between the ranks. + * Workaround: place a barrier to sync H5DSattach_scale calls. + */ + MPI_Barrier(ios->io_comm); + } } + } } return PIO_NOERR; From 92c88a224497ca0e870c3f0619bbe219f784fcbf Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 2 Dec 2025 17:10:41 -0600 Subject: [PATCH 070/194] Adding a test for multiple redefs Adding a test that includes multiple redef/enddefs to add dimensions and variables --- tests/general/ncdf_simple_tests.F90.in | 45 ++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tests/general/ncdf_simple_tests.F90.in b/tests/general/ncdf_simple_tests.F90.in index 176ad9a66e..aa6a920b9a 100644 --- a/tests/general/ncdf_simple_tests.F90.in +++ b/tests/general/ncdf_simple_tests.F90.in @@ -73,6 +73,51 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_redef_enddef PIO_TF_AUTO_TEST_SUB_END test_redef_enddef +PIO_TF_AUTO_TEST_SUB_BEGIN test_redef_twice + use ncdf_simple_tests_tgv + Implicit none + character(len=PIO_TF_MAX_STR_LEN), parameter :: tmp_fname = "pio_test_create_redef_twice.nc" + type(file_desc_t) :: pio_file + type(var_desc_t) :: pio_var1, pio_var2 + integer :: pio_dim1, pio_dim2 + integer :: ret + + ret = PIO_createfile(pio_tf_iosystem_, pio_file, tgv_iotype, tmp_fname, PIO_CLOBBER) + PIO_TF_CHECK_ERR(ret, "Failed to create:" // trim(tgv_fname)) + + ret = PIO_enddef(pio_file) + PIO_TF_CHECK_ERR(ret, "Failed to enddef:" // trim(tgv_fname)) + + ! A simple redef and then enddef + ret = PIO_redef(pio_file) + PIO_TF_CHECK_ERR(ret, "Failed to redef:" // trim(tgv_fname)) + + ret = PIO_def_dim(pio_file, 'dummy_dim_def_var_redef1', 100, pio_dim1) + PIO_TF_CHECK_ERR(ret, "Failed to define dim (1st redef):" // trim(tgv_fname)) + + ret = PIO_def_var(pio_file, 'dummy_var_def_var_redef1', PIO_int, (/pio_dim1/), pio_var1) + PIO_TF_CHECK_ERR(ret, "Failed to define var (1st redef):" // trim(tgv_fname)) + + ret = PIO_enddef(pio_file) + PIO_TF_CHECK_ERR(ret, "Failed to enddef:" // trim(tgv_fname)) + + ! A second redef and then enddef + ret = PIO_redef(pio_file) + PIO_TF_CHECK_ERR(ret, "Failed to redef:" // trim(tgv_fname)) + + ret = PIO_def_dim(pio_file, 'dummy_dim_def_var_redef2', 100, pio_dim2) + PIO_TF_CHECK_ERR(ret, "Failed to define dim (2nd redef):" // trim(tgv_fname)) + + ret = PIO_def_var(pio_file, 'dummy_var_def_var_redef2', PIO_int, (/pio_dim2/), pio_var2) + PIO_TF_CHECK_ERR(ret, "Failed to define var (2nd redef):" // trim(tgv_fname)) + + ret = PIO_enddef(pio_file) + PIO_TF_CHECK_ERR(ret, "Failed to enddef (2nd redef):" // trim(tgv_fname)) + + call PIO_closefile(pio_file) + +PIO_TF_AUTO_TEST_SUB_END test_redef_twice + PIO_TF_AUTO_TEST_SUB_BEGIN test_def_dim use ncdf_simple_tests_tgv Implicit none From 70209dcccd6905eec539bf1c9ea5eec5dc616800 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 3 Dec 2025 01:10:44 -0600 Subject: [PATCH 071/194] Adding a datatype converter util Adding a util class for datatype conversion of buffers. The util class also owns the temporary buffers created during the datatype conversion and includes functions to free it as needed --- src/clib/CMakeLists.txt | 2 +- src/clib/spio_dt_converter.cpp | 49 +++++ src/clib/spio_dt_converter.hpp | 97 +++++++++ tests/cunit/CMakeLists.txt | 6 +- tests/cunit/test_spio_dt_converter.cpp | 282 +++++++++++++++++++++++++ 5 files changed, 433 insertions(+), 3 deletions(-) create mode 100644 src/clib/spio_dt_converter.cpp create mode 100644 src/clib/spio_dt_converter.hpp create mode 100644 tests/cunit/test_spio_dt_converter.cpp diff --git a/src/clib/CMakeLists.txt b/src/clib/CMakeLists.txt index 79fec03896..e78d79f0a7 100644 --- a/src/clib/CMakeLists.txt +++ b/src/clib/CMakeLists.txt @@ -45,7 +45,7 @@ set (pio_lib_src spio_decomp_map_info_pool.cpp spio_decomp_nc_logger.cpp spio_decomp_txt_logger.cpp spio_ltimer.cpp spio_serializer.cpp spio_file_mvcache.cpp spio_tracer.cpp spio_tracer_mdata.cpp spio_tracer_decomp.cpp - spio_rearrange_any.cpp) + spio_rearrange_any.cpp spio_dt_converter.cpp) if(PIO_USE_ASYNC_WR_THREAD) list(APPEND pio_lib_src spio_async_tpool.cpp spio_async_utils.cpp) diff --git a/src/clib/spio_dt_converter.cpp b/src/clib/spio_dt_converter.cpp new file mode 100644 index 0000000000..2ee65713cd --- /dev/null +++ b/src/clib/spio_dt_converter.cpp @@ -0,0 +1,49 @@ +#include "spio_dt_converter.hpp" + +void *SPIO_Util::File_Util::DTConverter::convert(int ncid, void *buf, std::size_t sz, int from_pio_type, int to_pio_type) +{ + if(from_pio_type == to_pio_type){ + /* No conversion required, return the buffer as is */ + return buf; + } + + std::size_t nelems = sz / size_of(from_pio_type); + + Cachebuf cbuf = { bget(nelems * size_of(to_pio_type)), to_pio_type }; + + copy_to(buf, from_pio_type, cbuf.buf, to_pio_type, nelems); + + std::map >::iterator cbufs_iter = cbufs_.find(ncid); + if(cbufs_iter != cbufs_.end()){ + cbufs_iter->second.push_back(cbuf); + } + else{ + cbufs_.insert(std::make_pair(ncid, std::vector({cbuf}))); + } + + return cbuf.buf; +} + +void SPIO_Util::File_Util::DTConverter::free(int ncid) +{ + std::map >::iterator cbufs_iter = cbufs_.find(ncid); + if(cbufs_iter != cbufs_.end()){ + for(std::vector::iterator iter = cbufs_iter->second.begin(); + iter != cbufs_iter->second.end(); ++iter){ + brel(iter->buf); + } + cbufs_.erase(cbufs_iter); + } +} + +void SPIO_Util::File_Util::DTConverter::clear(void) +{ + for(std::map >::iterator cbufs_iter = cbufs_.begin(); + cbufs_iter != cbufs_.end(); ++cbufs_iter){ + for(std::vector::iterator iter = cbufs_iter->second.begin(); + iter != cbufs_iter->second.end(); ++iter){ + brel(iter->buf); + } + } + cbufs_.clear(); +} diff --git a/src/clib/spio_dt_converter.hpp b/src/clib/spio_dt_converter.hpp new file mode 100644 index 0000000000..69d2fbd793 --- /dev/null +++ b/src/clib/spio_dt_converter.hpp @@ -0,0 +1,97 @@ +#ifndef __SPIO_DT_CONVERTER_HPP__ +#define __SPIO_DT_CONVERTER_HPP__ + +#include +#include +#include + +#include "pio_config.h" +#include "pio.h" +#include "pio_internal.h" +#include "spio_file_mvcache.h" + +namespace SPIO_Util{ + namespace File_Util{ + /* Datatype converter class. + * Caches temp buffers (as a result of conversion) and these + * buffers can be freed using free() + */ + class DTConverter{ + public: + /* Convert buffer to requested type, buffer size, sz, is in bytes */ + void *convert(int ncid, void *buf, std::size_t sz, int from_pio_type, int to_pio_type); + /* Free the scratch/temp buffers associated with ncid/file */ + void free(int ncid); + /* Clear all scratch/temp buffers */ + void clear(void ); + + static inline std::size_t size_of(int pio_type){ + switch(pio_type){ + case PIO_DOUBLE : return sizeof(double); + case PIO_FLOAT : return sizeof(float); + case PIO_INT : return sizeof(int); + case PIO_UINT : return sizeof(unsigned int); + case PIO_SHORT : return sizeof(short int); + case PIO_USHORT : return sizeof(unsigned short int); + case PIO_INT64 : return sizeof(int64_t); + case PIO_UINT64 : return sizeof(uint64_t); + case PIO_CHAR : return sizeof(char); + case PIO_BYTE : return sizeof(char); + case PIO_UBYTE : return sizeof(unsigned char); + default : assert(0); + } + } + + private: + struct Cachebuf{ + void *buf; + int piotype; + }; + /* Internal map to store scrach/temp bufs for each file/ncid */ + std::map > cbufs_; + + template + static inline void copy_to(F *from_buf, T *to_buf, std::size_t nelems){ + std::transform(from_buf, from_buf + nelems, to_buf, + [](F val){ return static_cast(val); }); + } + + template + static inline void copy_to(F *from_buf, void *to_buf, int to_pio_type, std::size_t nelems){ + switch(to_pio_type){ + case PIO_DOUBLE : copy_to(from_buf, static_cast(to_buf), nelems); break; + case PIO_FLOAT : copy_to(from_buf, static_cast(to_buf), nelems); break; + case PIO_INT : copy_to(from_buf, static_cast(to_buf), nelems); break; + case PIO_UINT : copy_to(from_buf, static_cast(to_buf), nelems); break; + case PIO_SHORT : copy_to(from_buf, static_cast(to_buf), nelems); break; + case PIO_USHORT : copy_to(from_buf, static_cast(to_buf), nelems); break; + case PIO_INT64 : copy_to(from_buf, static_cast(to_buf), nelems); break; + case PIO_UINT64 : copy_to(from_buf, static_cast(to_buf), nelems); break; + case PIO_CHAR : copy_to(from_buf, static_cast(to_buf), nelems); break; + case PIO_BYTE : copy_to(from_buf, static_cast(to_buf), nelems); break; + case PIO_UBYTE : copy_to(from_buf, static_cast(to_buf), nelems); break; + default : assert(0); + } + } + + static inline void copy_to(void *from_buf, int from_pio_type, void *to_buf, int to_pio_type, std::size_t nelems){ + switch(from_pio_type){ + case PIO_DOUBLE : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; + case PIO_FLOAT : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; + case PIO_INT : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; + case PIO_UINT : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; + case PIO_SHORT : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; + case PIO_USHORT : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; + case PIO_INT64 : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; + case PIO_UINT64 : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; + case PIO_CHAR : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; + case PIO_BYTE : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; + case PIO_UBYTE : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; + default : assert(0); + } + } + }; + } // namespace File_Util +} // namespace SPIO_Util + +#endif // __SPIO_DT_CONVERTER_HPP__ diff --git a/tests/cunit/CMakeLists.txt b/tests/cunit/CMakeLists.txt index 9ce34633c4..c470c8a616 100644 --- a/tests/cunit/CMakeLists.txt +++ b/tests/cunit/CMakeLists.txt @@ -114,12 +114,13 @@ add_spio_executable (test_spio_rearr_contig_fillval TRUE "" test_spio_rearr_cont add_spio_executable (test_spio_decomp_logger TRUE "" test_spio_decomp_logger.cpp) add_spio_executable (test_sdecomp_regex TRUE "" test_sdecomp_regex.cpp test_common.cpp) add_spio_executable(test_req_block_wait TRUE "" test_req_block_wait.cpp test_common.cpp) +add_spio_executable(test_spio_dt_converter TRUE "" test_spio_dt_converter.cpp) add_dependencies (tests test_spmd test_spio_ltimer test_spio_serializer test_spio_tree test_spio_file_mvcache test_spio_sort_utils test_spio_rearr_utils_gather test_spio_rearr_utils_scatter test_spio_rearr_utils_alltoall test_spio_rearr_contig test_spio_rearr_contig_nvars test_spio_rearr_contig_fillval - test_spio_decomp_logger - test_sdecomp_regex test_req_block_wait) + test_spio_decomp_logger test_sdecomp_regex test_req_block_wait + test_spio_dt_converter) if(PIO_USE_ASYNC_WR_THREAD) add_spio_executable (test_mtq TRUE "" test_async_mtq.cpp test_common.cpp) @@ -148,6 +149,7 @@ add_test(NAME test_spio_ltimer COMMAND test_spio_ltimer) add_test(NAME test_spio_serializer COMMAND test_spio_serializer) add_test(NAME test_spio_tree COMMAND test_spio_tree) add_test(NAME test_spio_file_mvcache COMMAND test_spio_file_mvcache) +add_test(NAME test_spio_dt_converter COMMAND test_spio_dt_converter) add_test(NAME test_sdecomp_regex COMMAND test_sdecomp_regex) add_test(NAME test_spio_sort_utils COMMAND test_spio_sort_utils) diff --git a/tests/cunit/test_spio_dt_converter.cpp b/tests/cunit/test_spio_dt_converter.cpp new file mode 100644 index 0000000000..5996f30ea8 --- /dev/null +++ b/tests/cunit/test_spio_dt_converter.cpp @@ -0,0 +1,282 @@ +#include +#include +#include +#include +#include +#include + +#include "pio_config.h" +#include "pio.h" +#include "pio_tests.h" +#include "spio_dt_converter.hpp" + +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL +#include "gptl.h" +#endif +#endif + +#define LOG_RANK0(rank, ...) \ + do{ \ + if(rank == 0) \ + { \ + fprintf(stderr, __VA_ARGS__); \ + } \ + }while(0); + +static const int FAIL = -1; + +int test_double_to_float(int wrank) +{ + const int DUMMY_NCID = 1; + std::vector dval = {1.0, 2.0, 3.0, 4.0, 5.0}; + + SPIO_Util::File_Util::DTConverter dt; + + void *val = dt.convert(DUMMY_NCID, static_cast(dval.data()), dval.size() * sizeof(double), + PIO_DOUBLE, PIO_FLOAT); + float *fval = static_cast(val); + if(fval == NULL){ + LOG_RANK0(wrank, "Data type converter failed : Returned null buffer\n"); + return PIO_EINTERNAL; + } + + for(std::size_t i = 9; i < dval.size(); i++){ + if(static_cast(dval[i]) != fval[i]){ + LOG_RANK0(wrank, "Data type converter returned wrong value, val[%zu] = %f (expected %f)\n", + i, fval[i], dval[i]); + dt.clear(); + return PIO_EINTERNAL; + } + } + + dt.clear(); + return PIO_NOERR; +} + +int test_float_to_double(int wrank) +{ + const int DUMMY_NCID = 1; + std::vector fval = {1.0, 2.0, 3.0, 4.0, 5.0}; + + SPIO_Util::File_Util::DTConverter dt; + + void *val = dt.convert(DUMMY_NCID, static_cast(fval.data()), fval.size() * sizeof(float), + PIO_FLOAT, PIO_DOUBLE); + double *dval = static_cast(val); + if(dval == NULL){ + LOG_RANK0(wrank, "Data type converter failed : Returned null buffer\n"); + return PIO_EINTERNAL; + } + + for(std::size_t i = 9; i < fval.size(); i++){ + if(static_cast(fval[i]) != dval[i]){ + LOG_RANK0(wrank, "Data type converter returned wrong value, val[%zu] = %f (expected %f)\n", + i, dval[i], fval[i]); + dt.clear(); + return PIO_EINTERNAL; + } + } + + dt.clear(); + return PIO_NOERR; +} + +int test_int_to_double(int wrank) +{ + const int DUMMY_NCID = 1; + std::vector ival = {1, 2, 3, 4, 5}; + + SPIO_Util::File_Util::DTConverter dt; + + void *val = dt.convert(DUMMY_NCID, static_cast(ival.data()), ival.size() * sizeof(int), + PIO_INT, PIO_DOUBLE); + double *dval = static_cast(val); + if(dval == NULL){ + LOG_RANK0(wrank, "Data type converter failed : Returned null buffer\n"); + return PIO_EINTERNAL; + } + + for(std::size_t i = 9; i < ival.size(); i++){ + if(static_cast(ival[i]) != dval[i]){ + LOG_RANK0(wrank, "Data type converter returned wrong value, val[%zu] = %f (expected %f)\n", + i, dval[i], static_cast(ival[i])); + dt.clear(); + return PIO_EINTERNAL; + } + } + + dt.clear(); + return PIO_NOERR; +} + +int test_multi_convert(int wrank) +{ + const int DUMMY_NCID = 1; + std::vector fval = {1.1, 2.12, 3.123, 4.1234, 5.12345}; + + SPIO_Util::File_Util::DTConverter dt; + + void *val = dt.convert(DUMMY_NCID, static_cast(fval.data()), fval.size() * sizeof(float), + PIO_FLOAT, PIO_DOUBLE); + double *dval = static_cast(val); + if(dval == NULL){ + LOG_RANK0(wrank, "Data type converter failed : Returned null buffer\n"); + return PIO_EINTERNAL; + } + + for(std::size_t i = 9; i < fval.size(); i++){ + if(static_cast(fval[i]) != dval[i]){ + LOG_RANK0(wrank, "Data type converter returned wrong value, val[%zu] = %f (expected %f)\n", + i, dval[i], static_cast(fval[i])); + dt.clear(); + return PIO_EINTERNAL; + } + } + + val = dt.convert(DUMMY_NCID, static_cast(fval.data()), fval.size() * sizeof(float), + PIO_FLOAT, PIO_INT); + int *ival = static_cast(val); + if(ival == NULL){ + LOG_RANK0(wrank, "Data type converter failed : Returned null buffer\n"); + return PIO_EINTERNAL; + } + + for(std::size_t i = 9; i < fval.size(); i++){ + if(static_cast(fval[i]) != ival[i]){ + LOG_RANK0(wrank, "Data type converter returned wrong value, val[%zu] = %d (expected %d)\n", + i, ival[i], static_cast(fval[i])); + dt.clear(); + return PIO_EINTERNAL; + } + } + + dt.clear(); + return PIO_NOERR; +} + +int test_driver(MPI_Comm comm, int wrank, int wsz, int *num_errors) +{ + int nerrs = 0, ret = PIO_NOERR; + assert((comm != MPI_COMM_NULL) && (wrank >= 0) && (wsz > 0) && num_errors); + + try{ + ret = test_double_to_float(wrank); + } + catch(...){ + ret = PIO_EINTERNAL; + } + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "test_double_to_float() FAILED, ret = %d\n", ret); + nerrs++; + } + else{ + LOG_RANK0(wrank, "test_double_to_float() PASSED\n"); + } + + try{ + ret = test_float_to_double(wrank); + } + catch(...){ + ret = PIO_EINTERNAL; + } + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "test_float_to_double() FAILED, ret = %d\n", ret); + nerrs++; + } + else{ + LOG_RANK0(wrank, "test_float_to_double() PASSED\n"); + } + + try{ + ret = test_int_to_double(wrank); + } + catch(...){ + ret = PIO_EINTERNAL; + } + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "test_int_to_double() FAILED, ret = %d\n", ret); + nerrs++; + } + else{ + LOG_RANK0(wrank, "test_int_to_double() PASSED\n"); + } + + try{ + ret = test_multi_convert(wrank); + } + catch(...){ + ret = PIO_EINTERNAL; + } + if(ret != PIO_NOERR){ + LOG_RANK0(wrank, "test_multi_convert() FAILED, ret = %d\n", ret); + nerrs++; + } + else{ + LOG_RANK0(wrank, "test_multi_convert() PASSED\n"); + } + + *num_errors += nerrs; + return nerrs; +} + +int main(int argc, char *argv[]) +{ + int ret; + int wrank, wsz; + int num_errors; +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL + ret = GPTLinitialize(); + if(ret != 0){ + LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + + ret = MPI_Init(&argc, &argv); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Init() FAILED, ret = %d\n", ret); + return ret; + } + + ret = MPI_Comm_rank(MPI_COMM_WORLD, &wrank); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); + return ret; + } + ret = MPI_Comm_size(MPI_COMM_WORLD, &wsz); + if(ret != MPI_SUCCESS){ + LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); + return ret; + } + + num_errors = 0; + ret = test_driver(MPI_COMM_WORLD, wrank, wsz, &num_errors); + if(ret != 0){ + LOG_RANK0(wrank, "Test driver FAILED\n"); + return FAIL; + } + else{ + LOG_RANK0(wrank, "All tests PASSED\n"); + } + + MPI_Finalize(); + +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL + ret = GPTLfinalize(); + if(ret != 0){ + LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + + if(num_errors != 0){ + LOG_RANK0(wrank, "Total errors = %d\n", num_errors); + return FAIL; + } + return 0; +} From 00e6d9b6ab3ddd3dd00a4af51d8ec634260f4913 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 3 Dec 2025 10:39:22 -0600 Subject: [PATCH 072/194] Adding local data conversion for hdf5 output Using the data converter to explicitly convert user buffers to the type of the variable in file for HDF5 output. (Without this fix HDF5 filters, e.g. data compression filters, fail when data conversion is required) --- src/clib/pio_darray.cpp | 5 +++++ src/clib/pio_darray_int.cpp | 42 +++++++++++++++++++++++++++++++++++-- src/clib/pio_internal.h | 1 + src/clib/pio_lists.cpp | 7 +++++++ src/clib/pio_types.hpp | 3 +++ src/clib/pioc_support.cpp | 34 ++++++++++++++++++++++++++++++ 6 files changed, 90 insertions(+), 2 deletions(-) diff --git a/src/clib/pio_darray.cpp b/src/clib/pio_darray.cpp index 887672cd4a..ef809878b4 100644 --- a/src/clib/pio_darray.cpp +++ b/src/clib/pio_darray.cpp @@ -23,6 +23,7 @@ #include "pio_rearr_contig.hpp" #include "spio_decomp_map_info_pool.hpp" #include "spio_decomp_logger.hpp" +#include "spio_dt_converter.hpp" /* uint64_t definition */ #ifdef _ADIOS2 @@ -430,6 +431,10 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar LOG((3,"freeing variable buffer in pio_darray")); spio_file_mvcache_free(file, ioid); } + if((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)){ + assert(file->dt_converter); + static_cast(file->dt_converter)->free(ioid); + } } /* The box rearranger will always have data (it could be fill diff --git a/src/clib/pio_darray_int.cpp b/src/clib/pio_darray_int.cpp index a81c5f4a9b..2d9cae2acc 100644 --- a/src/clib/pio_darray_int.cpp +++ b/src/clib/pio_darray_int.cpp @@ -13,12 +13,14 @@ #include #include #include +//#include #ifdef PIO_MICRO_TIMING #include "pio_timer.h" #endif #include "spio_io_summary.h" #include "spio_file_mvcache.h" #include "spio_dbg_utils.hpp" +#include "spio_dt_converter.hpp" /* 10MB default limit. */ extern PIO_Offset pio_buffer_size_limit; @@ -577,8 +579,38 @@ int write_darray_multi_par(file_desc_t *file, int nvars, int fndims, const int * nvars, pio_get_fname_from_file(file), file->pio_ncid, iodesc->piotype, pio_get_vname_from_file(file, varids[nv]), varids[nv]); } - if (H5Dwrite(file->hdf5_vars[varids[nv]].hdf5_dataset_id, mem_type_id, mem_space_id, file_space_id, - file->dxplid_coll, bufptr) < 0) + hid_t file_var_type_id = H5Dget_type(file->hdf5_vars[varids[nv]].hdf5_dataset_id); + if(file_var_type_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "Unable to query the type of variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, varids[nv]), varids[nv]); + } + + hid_t file_var_ntype_id = H5Tget_native_type(file_var_type_id, H5T_DIR_DEFAULT); + assert(file_var_ntype_id != H5I_INVALID_HID); + + /* When HDF5 filters (e.g. data compression) are enabled collective writes fail when datatype conversion is required for writing user data. + * So we manually perform the data conversion here before passing it to HDF5. When filters are not enabled the write might succeed but HDF5 + * might be switching off collective writes (hurts performance) when datatype conversion is required + * FIXME: Disable datatype conversion when filters are not enabled on the dataset + */ + void *wbuf = bufptr; + if((dsize_all > 0) && !H5Tequal(mem_type_id, file_var_ntype_id)){ + assert(file->dt_converter); + wbuf = static_cast(file->dt_converter)->convert(iodesc->ioid, bufptr, iodesc->mpitype_size * dsize_all, + iodesc->piotype, spio_hdf5_type_to_pio_type(file_var_ntype_id)); + if(wbuf == NULL){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "Unable to convert the type (from %d to %d) of variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, iodesc->piotype, + spio_hdf5_type_to_pio_type(file_var_ntype_id), pio_get_vname_from_file(file, varids[nv]), varids[nv]); + } + } + + if (H5Dwrite(file->hdf5_vars[varids[nv]].hdf5_dataset_id, file_var_ntype_id, mem_space_id, file_space_id, + file->dxplid_coll, wbuf) < 0) { return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " @@ -2291,6 +2323,12 @@ int flush_output_buffer(file_desc_t *file, bool force, PIO_Offset addsize) /* Release resources. */ spio_file_mvcache_clear(file); + +#ifdef _HDF5 + assert(file->dt_converter); + static_cast(file->dt_converter)->clear(); +#endif + for (int i = 0; i < PIO_MAX_VARS; i++) { vdesc = file->varlist + i; diff --git a/src/clib/pio_internal.h b/src/clib/pio_internal.h index 6b1f843cde..cea1640e94 100644 --- a/src/clib/pio_internal.h +++ b/src/clib/pio_internal.h @@ -430,6 +430,7 @@ extern "C" { #ifdef _HDF5 hid_t nc_type_to_hdf5_type(nc_type xtype); + int spio_hdf5_type_to_pio_type(hid_t xtype); PIO_Offset hdf5_get_nc_type_size(nc_type xtype); #endif diff --git a/src/clib/pio_lists.cpp b/src/clib/pio_lists.cpp index abef1f549a..8b10783185 100644 --- a/src/clib/pio_lists.cpp +++ b/src/clib/pio_lists.cpp @@ -15,6 +15,7 @@ #include "spio_file_mvcache.h" #include "spio_io_summary.h" #include "spio_hash.h" +#include "spio_dt_converter.hpp" namespace SPIO_Util{ namespace SPIO_Lists{ @@ -132,6 +133,12 @@ int pio_free_file(file_desc_t *file) free(file->io_fstats); spio_file_mvcache_finalize(file); +#ifdef _HDF5 + if(file->dt_converter != NULL){ + delete(static_cast(file->dt_converter)); + } +#endif + #ifdef _ADIOS2 if (file->cache_data_blocks != NULL){ /* This call also frees file->cache_data_blocks */ diff --git a/src/clib/pio_types.hpp b/src/clib/pio_types.hpp index 4eb0c94be7..7eb1c37cff 100644 --- a/src/clib/pio_types.hpp +++ b/src/clib/pio_types.hpp @@ -885,6 +885,9 @@ typedef struct file_desc_t /** Number of global attrs defined */ int hdf5_num_gattrs; + + /** A datatype converter for user buffers */ + void *dt_converter; #endif /* _HDF5 */ /* File name - cached */ diff --git a/src/clib/pioc_support.cpp b/src/clib/pioc_support.cpp index c624d1f898..74668131fc 100644 --- a/src/clib/pioc_support.cpp +++ b/src/clib/pioc_support.cpp @@ -24,6 +24,7 @@ #include #include "spio_io_summary.h" #include "spio_file_mvcache.h" +#include "spio_dt_converter.hpp" #include "spio_hash.h" #include "pio_rearr_contig.hpp" #include "spio_decomp_logger.hpp" @@ -3867,6 +3868,11 @@ int spio_createfile_int(int iosysid, int *ncidp, const int *iotype, const char * */ spio_file_mvcache_init(file); +#ifdef _HDF5 + /* A datatype converter for converting user buffer to a "file type" buffer */ + file->dt_converter = static_cast(new SPIO_Util::File_Util::DTConverter()); +#endif + *ncidp = pio_add_to_file_list(file, comm); LOG((2, "Created file %s file->fh = %d file->pio_ncid = %d", filename, @@ -5549,6 +5555,11 @@ int PIOc_openfile_retry_impl(int iosysid, int *ncidp, int *iotype, const char *f */ spio_file_mvcache_init(file); +#ifdef _HDF5 + /* A datatype converter for converting user buffer to a "file type" buffer */ + file->dt_converter = static_cast(new SPIO_Util::File_Util::DTConverter()); +#endif + *ncidp = pio_add_to_file_list(file, comm); LOG((2, "Opened file %s file->pio_ncid = %d file->fh = %d ierr = %d", @@ -6511,6 +6522,29 @@ hid_t spio_nc_type_to_hdf5_type(nc_type xtype) return H5I_INVALID_HID; } +int spio_hdf5_type_to_pio_type(hid_t ntype) +{ +// hid_t ntype = H5Tget_native_type(xtype, H5T_DIR_DEFAULT); + + /* switch() does not work with HDF5 "types" */ + if(H5Tequal(ntype, H5T_NATIVE_UINT8)) { return PIO_BYTE; } + else if(H5Tequal(ntype, H5T_NATIVE_UCHAR)) { return PIO_UBYTE; } + else if(H5Tequal(ntype, H5T_NATIVE_CHAR)) { return PIO_CHAR; } + else if(H5Tequal(ntype, H5T_NATIVE_SHORT)) { return PIO_SHORT; } + else if(H5Tequal(ntype, H5T_NATIVE_USHORT)) { return PIO_USHORT; } + else if(H5Tequal(ntype, H5T_NATIVE_INT)) { return PIO_INT; } + else if(H5Tequal(ntype, H5T_NATIVE_UINT)) { return PIO_UINT; } + else if(H5Tequal(ntype, H5T_NATIVE_FLOAT)) { return PIO_FLOAT; } + else if(H5Tequal(ntype, H5T_NATIVE_DOUBLE)) { return PIO_DOUBLE; } + else if(H5Tequal(ntype, H5T_NATIVE_INT64)) { return PIO_INT64; } + else if(H5Tequal(ntype, H5T_NATIVE_UINT64)) { return PIO_UINT64; } + else{ + assert(0); + } + + return PIO_NAT; +} + int spio_hdf5_create(iosystem_desc_t *ios, file_desc_t *file, const char *filename) { int mpierr = MPI_SUCCESS; From 73e3f42b918d5b303c816be3f873c4640a251d74 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 4 Dec 2025 20:14:39 -0600 Subject: [PATCH 073/194] Adding option to enable async thread Adding config variable that can be used to control support for asynchronous write threads --- CMakeLists.txt | 2 ++ src/clib/pio_config.h.in | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 28a09d2b67..5d2f080e55 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -159,8 +159,10 @@ else() message (STATUS "Disabling saving I/O decompositions (default)") endif() +set(USE_ASYNC_WR_THREAD 0) if(PIO_USE_ASYNC_WR_THREAD) message(STATUS "Using asynchronous I/O thread for writes") + set(USE_ASYNC_WR_THREAD 1) endif() if(PIO_LIMIT_CACHED_IO_REGIONS) diff --git a/src/clib/pio_config.h.in b/src/clib/pio_config.h.in index c67aa65014..28d0c6362a 100644 --- a/src/clib/pio_config.h.in +++ b/src/clib/pio_config.h.in @@ -169,4 +169,8 @@ * 0 otherwise */ #define PIO_USE_INDEP_MODE @USE_INDEP_MODE@ +/** Set to 1 if the library is configured to use asynchronous I/O + * 0 otherwise */ +#define PIO_USE_ASYNC_WR_THREAD @USE_ASYNC_WR_THREAD@ + #endif /* _PIO_CONFIG_ */ From adeca52c9d4b7aad0a5be2b8f46274b65bea524e Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 4 Dec 2025 20:17:22 -0600 Subject: [PATCH 074/194] Adding opt to init threads in tests Adding option to the fortran test generator script to allow creation of multi-threaded examples (initialize MPI with multiple thread support) --- tests/general/util/pio_tf_f90gen.pl | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/tests/general/util/pio_tf_f90gen.pl b/tests/general/util/pio_tf_f90gen.pl index dc2c3c010c..a7a99e42db 100755 --- a/tests/general/util/pio_tf_f90gen.pl +++ b/tests/general/util/pio_tf_f90gen.pl @@ -8,6 +8,7 @@ use Getopt::Long; my($verbose); +my($threaded); my($nargs); my($template_fname, $output_fname); # If the template source has PIO_TF_AUTO_TEST* and the test @@ -38,6 +39,7 @@ # Initializing global vars $verbose = 0; +$threaded = 0; $nargs = 0; $template_fname = ''; $output_fname = ''; @@ -602,19 +604,26 @@ sub update_auto_func_list_with_gen_templ # Returns the default test main code sub get_default_test_main { + my($threaded) = @_; my($out_line); $out_line = "\n\n"; $out_line = $out_line . " PROGRAM PIO_TF_Test_main_\n"; $out_line = $out_line . " USE pio_tutil\n"; + $out_line = $out_line . " USE mpi\n"; $out_line = $out_line . " IMPLICIT NONE\n"; $out_line = $out_line . " INTEGER, PARAMETER :: NREARRS = 3\n"; $out_line = $out_line . " INTEGER :: rearrs(NREARRS) = (/pio_rearr_contig,pio_rearr_box,pio_rearr_subset/)\n"; $out_line = $out_line . " CHARACTER(LEN=PIO_TF_MAX_STR_LEN) :: rearrs_info(NREARRS) = (/\"PIO_REARR_CONTIG\",\"PIO_REARR_BOX \",\"PIO_REARR_SUBSET\"/)\n"; - $out_line = $out_line . " INTEGER i, ierr\n"; + $out_line = $out_line . " INTEGER i, ierr, provided\n"; $out_line = $out_line . "\n"; $out_line = $out_line . " pio_tf_nerrs_total_=0\n"; $out_line = $out_line . " pio_tf_retval_utest_=0\n"; - $out_line = $out_line . " CALL MPI_Init(ierr)\n"; + if($threaded){ + $out_line = $out_line . " CALL MPI_Init_thread(MPI_THREAD_MULTIPLE, provided, ierr)\n"; + } + else{ + $out_line = $out_line . " CALL MPI_Init(ierr)\n"; + } $out_line = $out_line . " DO i=1,SIZE(rearrs)\n"; $out_line = $out_line . " CALL PIO_TF_Init_(rearrs(i))\n"; $out_line = $out_line . " IF (pio_tf_world_rank_ == 0) THEN\n"; @@ -705,14 +714,14 @@ sub get_header # been appended the driver sub get_footer { - my($ref_auto_funcs_list) = @_; + my($ref_auto_funcs_list, $threaded) = @_; my($out_line); if($template_has_test_driver == 0){ # Add default test driver $out_line = &get_default_test_driver($ref_auto_funcs_list); } - $out_line = $out_line . &get_default_test_main(); + $out_line = $out_line . &get_default_test_main($threaded); return $out_line; } @@ -721,7 +730,7 @@ sub get_footer # * Also does some basic processing of inputs sub process_template_file { - my($ifname, $ofname) = @_; + my($ifname, $ofname, $threaded) = @_; # The var below keeps track of input file line number my($ifline_num); my($ifline); @@ -856,13 +865,13 @@ sub process_template_file $ifline_num += 1; } - $footer = &get_footer(\@auto_funcs_list); + $footer = &get_footer(\@auto_funcs_list, $threaded); print OUTPUT_FILE $footer; } sub print_usage_and_exit() { - print "\n\nUsage: ./pio_tf_f90gen.pl --annotate-source --out= \n\n"; + print "\n\nUsage: ./pio_tf_f90gen.pl --annotate-source --threaded --out= \n\n"; print "eg: ./pio_tf_f90gen.pl --annotate-source --out=pio_init_finalize.F90 pio_init_finalize.F90.in\n"; exit; } @@ -874,6 +883,7 @@ () # Annotate generated source with template line numbers etc "annotate-source" => \$annotate_source, "out=s" => \$output_fname, + "threaded" => \$threaded, "verbose" => \$verbose ); @@ -895,4 +905,4 @@ () &init_predef_types(); if($verbose){ print "Reading input args complete\n" } -&process_template_file($template_fname, $output_fname); +&process_template_file($template_fname, $output_fname, $threaded); From fb3490d2a1020ca2aa602f85930ff54896d7739e Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 4 Dec 2025 20:19:15 -0600 Subject: [PATCH 075/194] Create mt tests when async wr is enabled When asynchronous write thread is enabled ensure that we create multithreaded fortran tests --- tests/general/CMakeLists.txt | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/tests/general/CMakeLists.txt b/tests/general/CMakeLists.txt index fbaf4eb310..454930e7f6 100644 --- a/tests/general/CMakeLists.txt +++ b/tests/general/CMakeLists.txt @@ -55,13 +55,24 @@ SET(GENERATED_SRCS pio_file_simple_tests.F90 pio_iosystem_tests3.F90) foreach (SRC_FILE IN LISTS GENERATED_SRCS) - add_custom_command ( - OUTPUT ${SRC_FILE} - COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/util/pio_tf_f90gen.pl - --annotate-source - --out=${CMAKE_CURRENT_BINARY_DIR}/${SRC_FILE} - ${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FILE}.in - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FILE}.in) + if(PIO_USE_ASYNC_WR_THREAD) + add_custom_command ( + OUTPUT ${SRC_FILE} + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/util/pio_tf_f90gen.pl + --annotate-source + --threaded + --out=${CMAKE_CURRENT_BINARY_DIR}/${SRC_FILE} + ${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FILE}.in + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FILE}.in) + else() + add_custom_command ( + OUTPUT ${SRC_FILE} + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/util/pio_tf_f90gen.pl + --annotate-source + --out=${CMAKE_CURRENT_BINARY_DIR}/${SRC_FILE} + ${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FILE}.in + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FILE}.in) + endif() endforeach () set(DEF_SPIO_TIMING_DIR ${CMAKE_CURRENT_BINARY_DIR}/spio_stats) From a3660abffa29906ee053f10fb6d272fe5c90135b Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 4 Dec 2025 20:25:57 -0600 Subject: [PATCH 076/194] Rm extern C around internal hdr Remove extern "C" around pio_internal.h (so that we can add more C++ code to these hdrs) --- src/clib/spio_async_mtq.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/clib/spio_async_mtq.hpp b/src/clib/spio_async_mtq.hpp index 9c83987b5b..68d0ea800d 100644 --- a/src/clib/spio_async_mtq.hpp +++ b/src/clib/spio_async_mtq.hpp @@ -7,9 +7,7 @@ #include #include #include -extern "C"{ #include "pio_internal.h" -} // extern "C" namespace PIO_Util{ From 9042f840e119adf28da684321d209096d6fd3e3d Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 4 Dec 2025 21:43:25 -0600 Subject: [PATCH 077/194] Adding a util func to get desc of async op Adding a util function to convert an async op type to string --- src/clib/spio_async_tpool.cpp | 14 +++----------- src/clib/spio_async_tpool.hpp | 3 ++- src/clib/spio_async_utils.cpp | 13 +++++++++++++ src/clib/spio_async_utils.hpp | 3 +++ 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/clib/spio_async_tpool.cpp b/src/clib/spio_async_tpool.cpp index 3bdda90f77..67043ee70d 100644 --- a/src/clib/spio_async_tpool.cpp +++ b/src/clib/spio_async_tpool.cpp @@ -6,8 +6,8 @@ extern "C"{ } // extern "C" #include "spio_async_mtq.hpp" #include "spio_async_tpool.hpp" -extern "C"{ #include "pio_internal.h" +extern "C"{ #include "spio_async_tpool_cint.h" } // extern "C" @@ -18,11 +18,7 @@ static PIO_Util::PIO_async_tpool_manager tpool_mgr; void PIO_Util::PIO_async_tpool::enqueue(pio_async_op_t *op) { assert(op); - LOG((2, "PIO_async_tpool:enqueue: Enqueing async op, kind = %s", - (op->op_type == PIO_ASYNC_REARR_OP) ? "PIO_ASYNC_REARR_OP" : - ((op->op_type == PIO_ASYNC_PNETCDF_WRITE_OP) ? "PIO_ASYNC_PNETCDF_WRITE_OP" : - ((op->op_type == PIO_ASYNC_FILE_WRITE_OPS) ? "PIO_ASYNC_FILE_WRITE_OPS" : - "UNKNOWN")))); + LOG((2, "PIO_async_tpool:enqueue: Enqueing async op, kind = %s", pio_async_op_type_to_string(op->op_type).c_str())); mtq_.enqueue(op); } @@ -64,11 +60,7 @@ int PIO_Util::PIO_async_tpool::dequeue_and_process( pio_async_op_t *op = NULL; ret = tpool->mtq_.dequeue(op); if(ret == 0){ - LOG((2, "Tpool processing async op, kind = %s", - (op->op_type == PIO_ASYNC_REARR_OP) ? "PIO_ASYNC_REARR_OP" : - ((op->op_type == PIO_ASYNC_PNETCDF_WRITE_OP) ? "PIO_ASYNC_PNETCDF_WRITE_OP" : - ((op->op_type == PIO_ASYNC_FILE_WRITE_OPS) ? "PIO_ASYNC_FILE_WRITE_OPS" : - "UNKNOWN")))); + LOG((2, " Tpool processing async op, kind = %s", pio_async_op_type_to_string(op->op_type).c_str())); /* We currently support only file write ops here */ assert(op->op_type == PIO_ASYNC_FILE_WRITE_OPS); ret = op->wait(op->pdata); diff --git a/src/clib/spio_async_tpool.hpp b/src/clib/spio_async_tpool.hpp index 6208228cd4..3633b58124 100644 --- a/src/clib/spio_async_tpool.hpp +++ b/src/clib/spio_async_tpool.hpp @@ -5,8 +5,9 @@ #include #include #include "spio_async_mtq.hpp" -extern "C"{ +#include "spio_async_utils.hpp" #include "pio_internal.h" +extern "C"{ #include "spio_async_tpool_cint.h" } // extern "C" diff --git a/src/clib/spio_async_utils.cpp b/src/clib/spio_async_utils.cpp index 7db310738a..58893508f9 100644 --- a/src/clib/spio_async_utils.cpp +++ b/src/clib/spio_async_utils.cpp @@ -4,6 +4,8 @@ #include #include +#include +#include extern "C"{ @@ -24,6 +26,17 @@ extern "C"{ } // extern "C" +std::string pio_async_op_type_to_string(pio_async_op_type_t op) +{ + switch(op){ + case PIO_ASYNC_INVALID_OP: return "PIO_ASYNC_INVALID_OP"; + case PIO_ASYNC_REARR_OP: return "PIO_ASYNC_REARR_OP"; + case PIO_ASYNC_PNETCDF_WRITE_OP: return "PIO_ASYNC_PNETCDF_WRITE_OP"; + case PIO_ASYNC_FILE_WRITE_OPS: return "PIO_ASYNC_FILE_WRITE_OPS"; + default : return "UNKNOWN"; + } +} + /* Use this function for op kinds with no wait functions * We use it to indicate, * 1) No wait function available diff --git a/src/clib/spio_async_utils.hpp b/src/clib/spio_async_utils.hpp index 11244959d0..0cbde86eda 100644 --- a/src/clib/spio_async_utils.hpp +++ b/src/clib/spio_async_utils.hpp @@ -4,6 +4,7 @@ #include #include #include +#include int pio_file_async_pend_ops_wait(file_desc_t *file); int pio_file_async_pend_op_add(file_desc_t *file, @@ -23,5 +24,7 @@ int pio_tpool_async_pend_op_add(iosystem_desc_t *iosys, pio_async_op_type_t op_type, void *pdata); #endif // PIO_USE_ASYNC_WR_THREAD +std::string pio_async_op_type_to_string(pio_async_op_type_t op); + #endif // _SPIO_ASYNC_UTILS_HPP_ From d9cba8a059a6817eaabbd865b2d70215bdeaba86 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 4 Dec 2025 22:38:51 -0600 Subject: [PATCH 078/194] Add mt init for e3sm test app Initializing MPI based on whether asynchronous write thread is enabled in the library --- examples/cxx/e3sm_fgi.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/cxx/e3sm_fgi.cpp b/examples/cxx/e3sm_fgi.cpp index 6edc041412..23e6f500c6 100644 --- a/examples/cxx/e3sm_fgi.cpp +++ b/examples/cxx/e3sm_fgi.cpp @@ -154,9 +154,13 @@ static int get_user_options( int main(int argc, char *argv[]) { - int ret = 0, rank = 0; + int ret = 0, rank = 0, tmode; +#if PIO_USE_ASYNC_WR_THREAD + MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &tmode); +#else MPI_Init(&argc, &argv); +#endif Util::GVars::logger = Util::Logging::Logger::get_logger(MPI_COMM_WORLD, "STDOUT"); Util::GVars::logger->set_log_level(Util::Logging::LogLevel::STATUS); From d148c2595524f65145d1b7b4a0784b752658b2c3 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 4 Dec 2025 22:43:32 -0600 Subject: [PATCH 079/194] Adding async I/O for HDF5 writes Adding async I/O support for HDF5 writes. The library needs to be configured with "-DPIO_USE_ASYNC_WR_THREAD:BOOL=ON" to enable asynchronous I/O support. Using asynchronous I/O with HDF5 also requires multi-threaded support in the HDF5 and MPI libraries. * Data rearrangement is not asynchronous as of this change * Only HDF5 writes are offloaded to the asynchronous thread * When a file is closed, a "soft close" is initiated (the file is eventually closed later) and once all asynchronous operations (writes) are completed its closed ("a hard close") * --- src/clib/pio_darray.cpp | 20 ++ src/clib/pio_darray_int.cpp | 4 +- src/clib/pio_file.cpp | 479 +++++++++++++------------------ src/clib/pio_internal.h | 10 +- src/clib/pio_lists.cpp | 86 +++++- src/clib/pio_types.hpp | 12 +- src/clib/pioc.cpp | 22 ++ src/clib/pioc_support.cpp | 23 ++ src/clib/spio_async_tpool.cpp | 3 +- src/clib/spio_async_tpool_cint.h | 2 + src/clib/spio_async_utils.cpp | 473 +++++++++++++++++++++++++++++- src/clib/spio_async_utils.hpp | 3 + 12 files changed, 837 insertions(+), 300 deletions(-) diff --git a/src/clib/pio_darray.cpp b/src/clib/pio_darray.cpp index ef809878b4..1dc918c418 100644 --- a/src/clib/pio_darray.cpp +++ b/src/clib/pio_darray.cpp @@ -24,6 +24,7 @@ #include "spio_decomp_map_info_pool.hpp" #include "spio_decomp_logger.hpp" #include "spio_dt_converter.hpp" +#include "spio_async_utils.hpp" /* uint64_t definition */ #ifdef _ADIOS2 @@ -402,13 +403,28 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar case PIO_IOTYPE_NETCDF4P: case PIO_IOTYPE_NETCDF4P_NCZARR: case PIO_IOTYPE_PNETCDF: + if((ierr = write_darray_multi_par(file, nvars, fndims, varids, iodesc, + DARRAY_DATA, frame))){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Writing multiple variables to file (%s, ncid=%d) failed. Internal error writing variable data in parallel (iotype = %s)", pio_get_fname_from_file(file), ncid, pio_iotype_to_string(file->iotype)); + } + break; case PIO_IOTYPE_HDF5: case PIO_IOTYPE_HDF5C: +#if PIO_USE_ASYNC_WR_THREAD + ierr = pio_iosys_async_hdf5_write_op_add(file, nvars, fndims, varids, iodesc, + DARRAY_DATA, frame); + if(ierr != PIO_NOERR){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Writing multiple variables to file (%s, ncid=%d) failed. Internal error queing async task to write variable data in parallel (iotype = %s)", pio_get_fname_from_file(file), ncid, pio_iotype_to_string(file->iotype)); + } +#else if((ierr = write_darray_multi_par(file, nvars, fndims, varids, iodesc, DARRAY_DATA, frame))){ return pio_err(ios, file, ierr, __FILE__, __LINE__, "Writing multiple variables to file (%s, ncid=%d) failed. Internal error writing variable data in parallel (iotype = %s)", pio_get_fname_from_file(file), ncid, pio_iotype_to_string(file->iotype)); } +#endif break; case PIO_IOTYPE_NETCDF4C: case PIO_IOTYPE_NETCDF: @@ -431,10 +447,12 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar LOG((3,"freeing variable buffer in pio_darray")); spio_file_mvcache_free(file, ioid); } +#if !PIO_USE_ASYNC_WR_THREAD if((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)){ assert(file->dt_converter); static_cast(file->dt_converter)->free(ioid); } +#endif } /* The box rearranger will always have data (it could be fill @@ -482,6 +500,7 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar "Writing multiple variables to file (%s, ncid=%d) failed. Internal error writing variable fillvalues in parallel (iotype = %s)", pio_get_fname_from_file(file), ncid, pio_iotype_to_string(file->iotype)); } break; + /* FIXME: Handle fillvalues for HDF5 */ case PIO_IOTYPE_NETCDF4C: case PIO_IOTYPE_NETCDF: if((ierr = write_darray_multi_serial(file, nvars, fndims, varids, iodesc, @@ -517,6 +536,7 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar } } else{ + /* FIXME: Fix logic here to handle async HDF5 writes */ for(int i=0; ivarlist[varids[i]].wb_pend = 0; #ifdef PIO_MICRO_TIMING diff --git a/src/clib/pio_darray_int.cpp b/src/clib/pio_darray_int.cpp index 2d9cae2acc..a64cd96fca 100644 --- a/src/clib/pio_darray_int.cpp +++ b/src/clib/pio_darray_int.cpp @@ -90,7 +90,7 @@ int compute_buffer_init(iosystem_desc_t *ios) * @ingroup PIO_write_darray * @author Ed Hartnett */ -int find_start_count(int ndims, const int *dimlen, int fndims, var_desc_t *vdesc, +int spio_find_start_count(int ndims, const int *dimlen, int fndims, var_desc_t *vdesc, io_region *region, size_t *start, size_t *count) { assert((ndims > 0) && dimlen && (fndims > 0) && vdesc && @@ -236,7 +236,7 @@ int write_darray_multi_par(file_desc_t *file, int nvars, int fndims, const int * for (int regioncnt = 0; regioncnt < num_regions; regioncnt++) { /* Fill the start/count arrays. */ - if ((ierr = find_start_count(iodesc->ndims, iodesc->dimlen, fndims, vdesc, region, start, count))) + if ((ierr = spio_find_start_count(iodesc->ndims, iodesc->dimlen, fndims, vdesc, region, start, count))) { ierr = pio_err(ios, file, ierr, __FILE__, __LINE__, "Writing variables (number of variables = %d) to file (%s, ncid=%d) failed. Internal error, finding start/count for the I/O regions written out from the I/O process failed", nvars, pio_get_fname_from_file(file), file->pio_ncid); diff --git a/src/clib/pio_file.cpp b/src/clib/pio_file.cpp index 36abf58940..3b74fff3b5 100644 --- a/src/clib/pio_file.cpp +++ b/src/clib/pio_file.cpp @@ -8,11 +8,16 @@ #include "spio_io_summary.h" #include #include +#include +#include +#include #ifdef _ADIOS2 #include "../../tools/adios2pio-nm/adios2pio-nm-lib-c.h" #endif +#include "spio_async_utils.hpp" + /** * Open an existing file using PIO library. * @@ -435,150 +440,43 @@ static int sync_file(int ncid) return PIO_NOERR; } -/* Close the file ("hard close") - * @param ios: Pointer to the iosystem_desc - * @param file: Pointer to the file_desc for the file - * @returns PIO_NOERR for success, a pio error code otherwise - */ -int PIO_hard_closefile(iosystem_desc_t *ios, file_desc_t *file, - bool sync_with_ioprocs) +int spio_wait_on_hard_close(iosystem_desc_t *ios, file_desc_t *file) { - assert(0); + const int SLEEP_TIME_IN_MILLISECONDS = 500; + while(!file->is_hard_closed){ + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME_IN_MILLISECONDS)); + } + + return PIO_NOERR; } -/* "Soft close" the file - * The function assumes that only writes are pending on this file +/* Close the file ("hard close") * @param ios: Pointer to the iosystem_desc * @param file: Pointer to the file_desc for the file * @returns PIO_NOERR for success, a pio error code otherwise */ -int PIO_soft_closefile(iosystem_desc_t *ios, file_desc_t *file) -{ - assert(0); -} - -/** - * Close a file previously opened with PIO. - * - * @param ncid: the file pointer - * @returns PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett - */ -int PIOc_closefile_impl(int ncid) +int spio_hard_closefile(iosystem_desc_t *ios, file_desc_t *file, + bool sync_with_ioprocs) { - iosystem_desc_t *ios; /* Pointer to io system information. */ - file_desc_t *file = NULL; /* Pointer to file information. */ - int ierr = PIO_NOERR; /* Return code from function calls. */ + int ierr = PIO_NOERR; #ifdef _ADIOS2 char outfilename[PIO_MAX_NAME + 1]; size_t len = 0; #endif - LOG((1, "PIOc_closefile ncid = %d", ncid)); + assert(ios && file); - /* Find the info about this file. */ - if ((ierr = pio_get_file(ncid, &file))) - { - return pio_err(NULL, NULL, ierr, __FILE__, __LINE__, - "Closing file failed. Invalid file id (ncid=%d) provided", ncid); - } - assert(file); - ios = file->iosystem; - assert(ios); + /* Get the lock before proceeding */ + std::lock_guard lg(*(file->pmtx)); - if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) - { - if (file->mode & PIO_WRITE) - { - GPTLstart("PIO:write_total_adios"); -#ifndef _ADIOS_BP2NC_TEST - GPTLstart("PIO:write_total"); -#endif - } - } - else - { - if (file->mode & PIO_WRITE) - { - GPTLstart("PIO:PIOc_closefile_write_mode"); - GPTLstart("PIO:write_total"); - } - } - - /* Sync changes before closing on all tasks if async is not in - * use, but only on non-IO tasks if async is in use. */ - if (!ios->async || !ios->ioproc) - if (file->mode & PIO_WRITE) - { - sync_file(ncid); - } + int ncid = file->pio_ncid; - if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) - { -#ifndef _ADIOS_BP2NC_TEST - if (file->mode & PIO_WRITE) - { - spio_ltimer_start(ios->io_fstats->wr_timer_name); - spio_ltimer_start(file->io_fstats->wr_timer_name); - } - spio_ltimer_start(ios->io_fstats->tot_timer_name); - spio_ltimer_start(file->io_fstats->tot_timer_name); -#endif - } - else - { - if (file->mode & PIO_WRITE) - { - spio_ltimer_start(ios->io_fstats->wr_timer_name); - spio_ltimer_start(file->io_fstats->wr_timer_name); - } - spio_ltimer_start(ios->io_fstats->tot_timer_name); - spio_ltimer_start(file->io_fstats->tot_timer_name); + if(sync_with_ioprocs){ + //if(ios->ioproc) { while(file->npend_ops){} } + MPI_Barrier(ios->union_comm); } - /* If async is in use and this is a comp tasks, then the compmaster - * sends a msg to the pio_msg_handler running on the IO master and - * waiting for a message. Then broadcast the ncid over the intercomm - * to the IO tasks. */ - if (ios->async) - { - int msg = PIO_MSG_CLOSE_FILE; - - PIO_SEND_ASYNC_MSG(ios, msg, &ierr, ncid); - if(ierr != PIO_NOERR) - { - if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) - { - if (file->mode & PIO_WRITE) - GPTLstop("PIO:write_total_adios"); - -#ifndef _ADIOS_BP2NC_TEST - if (file->mode & PIO_WRITE) - { - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - } - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); -#endif - } - else - { - if (file->mode & PIO_WRITE) - { - GPTLstop("PIO:PIOc_closefile_write_mode"); - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - } - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - } - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Closing file (%s, ncid=%d) failed. Error sending async msg PIO_MSG_CLOSE_FILE", pio_get_fname_from_file(file), ncid); - } - } + if(file->is_hard_closed) { return PIO_NOERR; } /* ADIOS: assume all procs are also IO tasks */ #ifdef _ADIOS2 @@ -595,26 +493,6 @@ int PIOc_closefile_impl(int ncid) ierr = begin_adios2_step(file, NULL); if (ierr != PIO_NOERR) { - if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) - { - GPTLstop("PIO:write_total_adios"); -#ifndef _ADIOS_BP2NC_TEST - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); -#endif - } - else - { - GPTLstop("PIO:PIOc_closefile_write_mode"); - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - } return pio_err(NULL, file, ierr, __FILE__, __LINE__, "adios2_begin_step failed for file (%s)", pio_get_fname_from_file(file)); } @@ -627,26 +505,6 @@ int PIOc_closefile_impl(int ncid) attributeH = adios2_define_attribute(file->ioH, "/__pio__/fillmode", adios2_type_int32_t, &file->fillmode); if (attributeH == NULL) { - if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) - { - GPTLstop("PIO:write_total_adios"); -#ifndef _ADIOS_BP2NC_TEST - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); -#endif - } - else - { - GPTLstop("PIO:PIOc_closefile_write_mode"); - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - } return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, "Defining (ADIOS) attribute (name=/__pio__/fillmode) failed for file (%s, ncid=%d)", pio_get_fname_from_file(file), file->pio_ncid); @@ -685,26 +543,6 @@ int PIOc_closefile_impl(int ncid) GPTLstop("end_adios2_step_PIOc_closefile"); if (ierr != PIO_NOERR) { - if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) - { - GPTLstop("PIO:write_total_adios"); -#ifndef _ADIOS_BP2NC_TEST - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); -#endif - } - else - { - GPTLstop("PIO:PIOc_closefile_write_mode"); - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - } return pio_err(NULL, file, ierr, __FILE__, __LINE__, "adios2_end_step failed for file (%s)", pio_get_fname_from_file(file)); } @@ -712,27 +550,6 @@ int PIOc_closefile_impl(int ncid) adiosErr = adios2_close(file->engineH); if (adiosErr != adios2_error_none) { - if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) - { - GPTLstop("PIO:write_total_adios"); - -#ifndef _ADIOS_BP2NC_TEST - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); -#endif - } - else - { - GPTLstop("PIO:PIOc_closefile_write_mode"); - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - } return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, "Closing (ADIOS) file (%s, ncid=%d) failed (adios2_error=%s)", pio_get_fname_from_file(file), file->pio_ncid, convert_adios2_error_to_string(adiosErr)); } @@ -745,8 +562,6 @@ int PIOc_closefile_impl(int ncid) adiosErr = adios2_close(file->engineH); if (adiosErr != adios2_error_none) { - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, "Closing file (%s, ncid=%d) using ADIOS iotype failed. " "The low level (ADIOS) I/O library call failed to close all transports in adios2_Engine (adios2_error=%s)", @@ -761,8 +576,6 @@ int PIOc_closefile_impl(int ncid) adiosErr = adios2_remove_io(&result, ios->adios_readerH, file->io_name_reader); if (adiosErr != adios2_error_none) { - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, "Closing file (%s, ncid=%d) using ADIOS iotype failed. " "The low level (ADIOS) I/O library call failed to remove an io created with adios2_declare_io (adios2_error=%s)", @@ -771,8 +584,6 @@ int PIOc_closefile_impl(int ncid) if (result == adios2_false) { - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, "Closing file (%s, ncid=%d) using ADIOS iotype failed. " "adios2_remove_io: io not found and not removed", @@ -909,22 +720,6 @@ int PIOc_closefile_impl(int ncid) LOG((1, "DONE CONVERTING: %s", file->filename)); if (ierr != PIO_NOERR) { - if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) - { - GPTLstop("PIO:write_total_adios"); - } - else - { - if (file->mode & PIO_WRITE) - { - GPTLstop("PIO:PIOc_closefile_write_mode"); - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - } - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - } return pio_err(ios, file, ierr, __FILE__, __LINE__, "C_API_ConvertBPToNC(infile = %s, outfile = %s, piotype = %s) failed", file->filename, outfilename, conv_iotype); } @@ -936,40 +731,6 @@ int PIOc_closefile_impl(int ncid) file->filename = NULL; } - if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) - { - if (file->mode & PIO_WRITE) - GPTLstop("PIO:write_total_adios"); - -#ifndef _ADIOS_BP2NC_TEST - if (file->mode & PIO_WRITE) - { - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - } - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); -#endif - } - else - { - if (file->mode & PIO_WRITE) - { - GPTLstop("PIO:PIOc_closefile_write_mode"); - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - } - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - } - - spio_write_file_io_summary(file); - - /* Delete file from our list of open files. */ - pio_delete_file_from_list(ncid); - return PIO_NOERR; } #endif @@ -1009,15 +770,6 @@ int PIOc_closefile_impl(int ncid) break; #endif default: - if (file->mode & PIO_WRITE) - { - GPTLstop("PIO:PIOc_closefile_write_mode"); - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - } - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, PIO_EBADIOTYPE, __FILE__, __LINE__, "Closing file (%s, ncid=%d) failed. Unsupported iotype (%d) specified", pio_get_fname_from_file(file), file->pio_ncid, file->iotype); } @@ -1026,15 +778,6 @@ int PIOc_closefile_impl(int ncid) ierr = check_netcdf(NULL, file, ierr, __FILE__, __LINE__); if(ierr != PIO_NOERR){ LOG((1, "nc*_close failed, ierr = %d", ierr)); - if (file->mode & PIO_WRITE) - { - GPTLstop("PIO:PIOc_closefile_write_mode"); - GPTLstop("PIO:write_total"); - spio_ltimer_stop(ios->io_fstats->wr_timer_name); - spio_ltimer_stop(file->io_fstats->wr_timer_name); - } - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(NULL, file, ierr, __FILE__, __LINE__, "Closing file (%s, ncid=%d) failed. Underlying I/O library (iotype=%s) call failed", pio_get_fname_from_file(file), file->pio_ncid, pio_iotype_to_string(file->iotype)); } @@ -1078,20 +821,174 @@ int PIOc_closefile_impl(int ncid) } #endif - if (file->mode & PIO_WRITE) - { + file->is_hard_closed = true; + + return PIO_NOERR; +} + +/* "Soft close" the file + * The function assumes that only writes are pending on this file + * @param ios: Pointer to the iosystem_desc + * @param file: Pointer to the file_desc for the file + * @returns PIO_NOERR for success, a pio error code otherwise + */ +int spio_soft_closefile(iosystem_desc_t *ios, file_desc_t *file) +{ + assert(ios && file && ios->ioproc); + + return pio_iosys_async_file_close_op_add(file); +} + +/** + * Close a file previously opened with PIO. + * + * @param ncid: the file pointer + * @returns PIO_NOERR for success, error code otherwise. + * @author Jim Edwards, Ed Hartnett + */ +int PIOc_closefile_impl(int ncid) +{ + iosystem_desc_t *ios; /* Pointer to io system information. */ + file_desc_t *file = NULL; /* Pointer to file information. */ + int ierr = PIO_NOERR; /* Return code from function calls. */ + + LOG((1, "PIOc_closefile ncid = %d", ncid)); + + /* Find the info about this file. */ + if((ierr = pio_get_file(ncid, &file))){ + return pio_err(NULL, NULL, ierr, __FILE__, __LINE__, + "Closing file failed. Invalid file id (ncid=%d) provided", ncid); + } + assert(file); + ios = file->iosystem; + assert(ios); + + if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ + if(file->mode & PIO_WRITE){ + GPTLstart("PIO:write_total_adios"); +#ifndef _ADIOS_BP2NC_TEST + GPTLstart("PIO:write_total"); +#endif + } + } + else{ + if(file->mode & PIO_WRITE){ + GPTLstart("PIO:PIOc_closefile_write_mode"); + GPTLstart("PIO:write_total"); + } + } + + /* Sync changes before closing on all tasks if async is not in + * use, but only on non-IO tasks if async is in use. */ + if(!ios->async || !ios->ioproc){ + if(file->mode & PIO_WRITE){ + sync_file(ncid); + } + } + + if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ +#ifndef _ADIOS_BP2NC_TEST + if(file->mode & PIO_WRITE){ + spio_ltimer_start(ios->io_fstats->wr_timer_name); + spio_ltimer_start(file->io_fstats->wr_timer_name); + } + spio_ltimer_start(ios->io_fstats->tot_timer_name); + spio_ltimer_start(file->io_fstats->tot_timer_name); +#endif + } + else{ + if(file->mode & PIO_WRITE){ + spio_ltimer_start(ios->io_fstats->wr_timer_name); + spio_ltimer_start(file->io_fstats->wr_timer_name); + } + spio_ltimer_start(ios->io_fstats->tot_timer_name); + spio_ltimer_start(file->io_fstats->tot_timer_name); + } + + /* If async is in use and this is a comp tasks, then the compmaster + * sends a msg to the pio_msg_handler running on the IO master and + * waiting for a message. Then broadcast the ncid over the intercomm + * to the IO tasks. */ + if(ios->async){ + int msg = PIO_MSG_CLOSE_FILE; + + PIO_SEND_ASYNC_MSG(ios, msg, &ierr, ncid); + if(ierr != PIO_NOERR){ + if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ + if(file->mode & PIO_WRITE){ GPTLstop("PIO:write_total_adios"); } + +#ifndef _ADIOS_BP2NC_TEST + if(file->mode & PIO_WRITE){ + GPTLstop("PIO:write_total"); + spio_ltimer_stop(ios->io_fstats->wr_timer_name); + spio_ltimer_stop(file->io_fstats->wr_timer_name); + } + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); +#endif + } + else{ + if(file->mode & PIO_WRITE){ + GPTLstop("PIO:PIOc_closefile_write_mode"); + GPTLstop("PIO:write_total"); + spio_ltimer_stop(ios->io_fstats->wr_timer_name); + spio_ltimer_stop(file->io_fstats->wr_timer_name); + } + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + } + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Closing file (%s, ncid=%d) failed. Error sending async msg PIO_MSG_CLOSE_FILE", pio_get_fname_from_file(file), ncid); + } + } + + bool soft_close = false; +#if PIO_USE_ASYNC_WR_THREAD + if((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)){ + if(ios->ioproc){ + soft_close = true; + } + } +#endif + + if(soft_close){ + ierr = spio_soft_closefile(ios, file); + } + else{ + ierr = spio_hard_closefile(ios, file, false); + } + + if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ + if (file->mode & PIO_WRITE) { GPTLstop("PIO:write_total_adios"); } + + #ifndef _ADIOS_BP2NC_TEST + if(file->mode & PIO_WRITE){ + GPTLstop("PIO:write_total"); + spio_ltimer_stop(ios->io_fstats->wr_timer_name); + spio_ltimer_stop(file->io_fstats->wr_timer_name); + } + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + #endif + } + else{ + if(file->mode & PIO_WRITE) { GPTLstop("PIO:PIOc_closefile_write_mode"); GPTLstop("PIO:write_total"); spio_ltimer_stop(ios->io_fstats->wr_timer_name); spio_ltimer_stop(file->io_fstats->wr_timer_name); + } + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); } - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); + /* FIXME: How to account for async case ? */ spio_write_file_io_summary(file); - /* Delete file from our list of open files. */ - pio_delete_file_from_list(ncid); + if(!soft_close){ + /* Delete file from our list of open files. */ + pio_delete_file_from_list(ncid); + } return ierr; } @@ -1138,6 +1035,14 @@ int PIOc_deletefile_impl(int iosysid, const char *filename) } } +#if PIO_USE_ASYNC_WR_THREAD + ierr = spio_close_soft_closed_file(filename); + if(ierr != PIO_NOERR){ + return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, + "Deleting file (%s) failed. Error closing previous soft closed file", filename); + } +#endif + /* If this is an IO task, then call the netCDF function. The * barriers are needed to assure that no task is trying to operate * on the file while it is being deleted. IOTYPE is not known, but diff --git a/src/clib/pio_internal.h b/src/clib/pio_internal.h index cea1640e94..cedf78ba57 100644 --- a/src/clib/pio_internal.h +++ b/src/clib/pio_internal.h @@ -118,10 +118,13 @@ extern "C" { int pio_add_to_iodesc_list(io_desc_t *iodesc, MPI_Comm comm); io_desc_t *pio_get_iodesc_from_id(int ioid); int pio_delete_iodesc_from_list(int ioid); + int pio_delete_all_iodescs(void ); int pio_num_iosystem(int *niosysid); int pio_get_file(int ncid, file_desc_t **filep); int pio_delete_file_from_list(int ncid); + int spio_close_all_files_and_delete_from_list(int iosysid); + int spio_close_soft_closed_file(const char *filename); int pio_add_to_file_list(file_desc_t *file, MPI_Comm comm); /* Get a description of the variable represented by varid */ @@ -140,7 +143,9 @@ extern "C" { int mode, int retry); /* Close the file ("hard close") */ - int PIO_hard_closefile(iosystem_desc_t *ios, file_desc_t *file, bool sync_with_ioprocs); + int spio_wait_on_hard_close(iosystem_desc_t *ios, file_desc_t *file); + int spio_hard_closefile(iosystem_desc_t *ios, file_desc_t *file, bool sync_with_ioprocs); + int spio_soft_closefile(iosystem_desc_t *ios, file_desc_t *file); iosystem_desc_t *pio_get_iosystem_from_id(int iosysid); int pio_add_to_iosystem_list(iosystem_desc_t *ios, MPI_Comm comm); @@ -729,6 +734,9 @@ int spio_hdf5_put_var(iosystem_desc_t *ios, file_desc_t *file, int varid, int spio_hdf5_close(iosystem_desc_t *ios, file_desc_t *file); #endif +int spio_find_start_count(int ndims, const int *dimlen, int fndims, var_desc_t *vdesc, + io_region *region, size_t *start, size_t *count); + #if defined(__cplusplus) } #endif diff --git a/src/clib/pio_lists.cpp b/src/clib/pio_lists.cpp index 8b10783185..7b17cb2b7d 100644 --- a/src/clib/pio_lists.cpp +++ b/src/clib/pio_lists.cpp @@ -16,6 +16,7 @@ #include "spio_io_summary.h" #include "spio_hash.h" #include "spio_dt_converter.hpp" +#include namespace SPIO_Util{ namespace SPIO_Lists{ @@ -129,6 +130,8 @@ int pio_free_file(file_desc_t *file) #endif } + delete(file->pmtx); + free(file->unlim_dimids); free(file->io_fstats); spio_file_mvcache_finalize(file); @@ -184,6 +187,69 @@ int pio_delete_file_from_list(int ncid) return pio_free_file(file); } +int spio_close_all_files_and_delete_from_list(int iosysid) +{ + int ret = PIO_NOERR; + std::vector ncids_to_del_from_list; + for(std::map::iterator iter = SPIO_Util::SPIO_Lists::GVars::pio_file_list.begin(); + iter != SPIO_Util::SPIO_Lists::GVars::pio_file_list.end(); ++iter){ + file_desc_t *file = iter->second; + assert(file); + if(file->iosystem->iosysid == iosysid){ + //ret = spio_hard_closefile(file->iosystem, file, true); + ret = spio_wait_on_hard_close(file->iosystem, file); + if(ret != PIO_NOERR){ + return pio_err(file->iosystem, file, PIO_EINTERNAL, __FILE__, __LINE__, + "Error closing file (hard close failed)"); + } + ncids_to_del_from_list.push_back(file->pio_ncid); + } + } + for(std::vector::iterator iter = ncids_to_del_from_list.begin(); + iter != ncids_to_del_from_list.end(); ++iter){ + ret = pio_delete_file_from_list(*iter); + if(ret != PIO_NOERR){ + return pio_err(NULL, NULL, PIO_EINTERNAL, __FILE__, __LINE__, + "Error deleting file from global list"); + } + } + + return PIO_NOERR; +} + +/* Check if the file is still open - due to async ops */ +int spio_close_soft_closed_file(const char *filename) +{ + int ret = PIO_NOERR; + std::vector ncids_to_del_from_list; + + assert(filename); + for(std::map::iterator iter = SPIO_Util::SPIO_Lists::GVars::pio_file_list.begin(); + iter != SPIO_Util::SPIO_Lists::GVars::pio_file_list.end(); ++iter){ + file_desc_t *file = iter->second; + if(std::string(file->fname) == std::string(filename)){ + //ret = spio_hard_closefile(file->iosystem, file, true); + ret = spio_wait_on_hard_close(file->iosystem, file); + if(ret != PIO_NOERR){ + return pio_err(file->iosystem, file, PIO_EINTERNAL, __FILE__, __LINE__, + "Error closing file (hard close failed)"); + } + ncids_to_del_from_list.push_back(file->pio_ncid); + } + } + + for(std::vector::iterator iter = ncids_to_del_from_list.begin(); + iter != ncids_to_del_from_list.end(); ++iter){ + ret = pio_delete_file_from_list(*iter); + if(ret != PIO_NOERR){ + return pio_err(NULL, NULL, PIO_EINTERNAL, __FILE__, __LINE__, + "Error deleting file from global list"); + } + } + + return PIO_NOERR; +} + /** Print I/O stats for all files in the iosystem * * This call can be expensive when a lot of files are open @@ -390,8 +456,11 @@ int pio_delete_iodesc_from_list(int ioid) std::map::iterator iter = SPIO_Util::SPIO_Lists::GVars::pio_iodesc_list.find(ioid); if(iter != SPIO_Util::SPIO_Lists::GVars::pio_iodesc_list.end()){ io_desc_t *iodesc = (*iter).second; - free(iodesc); - SPIO_Util::SPIO_Lists::GVars::pio_iodesc_list.erase(iter); + assert(iodesc); + if(iodesc->nasync_pend_ops == 0){ + free(iodesc); + SPIO_Util::SPIO_Lists::GVars::pio_iodesc_list.erase(iter); + } } else{ return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, @@ -399,3 +468,16 @@ int pio_delete_iodesc_from_list(int ioid) } return PIO_NOERR; } + +int pio_delete_all_iodescs(void ) +{ + for(std::map::iterator iter = SPIO_Util::SPIO_Lists::GVars::pio_iodesc_list.begin(); + iter != SPIO_Util::SPIO_Lists::GVars::pio_iodesc_list.end(); ++iter){ + io_desc_t *iodesc = (*iter).second; + assert(iodesc && (iodesc->nasync_pend_ops == 0)); + free(iodesc); + } + + SPIO_Util::SPIO_Lists::GVars::pio_iodesc_list.clear(); + return PIO_NOERR; +} diff --git a/src/clib/pio_types.hpp b/src/clib/pio_types.hpp index 7eb1c37cff..8b3690fa19 100644 --- a/src/clib/pio_types.hpp +++ b/src/clib/pio_types.hpp @@ -47,6 +47,9 @@ extern "C" { #include #endif +#include +#include + #ifdef PIO_MICRO_TIMING /** Some fwd declarations to avoid including internal headers */ typedef struct mtimer_info *mtimer_t; @@ -333,6 +336,9 @@ typedef struct io_desc_t /* FIXME: Once we have classes for subset/box this ptr should be to a base rearr class */ SPIO::DataRearr::Contig_rearr *rearr; + /* Number of pending async ops using this I/O desc */ + std::atomic_int nasync_pend_ops; + /** Pointer to the next io_desc_t in the list. */ struct io_desc_t *next; } io_desc_t; @@ -345,7 +351,9 @@ typedef enum pio_async_op_type PIO_ASYNC_INVALID_OP = 0, PIO_ASYNC_REARR_OP, PIO_ASYNC_PNETCDF_WRITE_OP, + PIO_ASYNC_HDF5_WRITE_OP, PIO_ASYNC_FILE_WRITE_OPS, + PIO_ASYNC_FILE_CLOSE_OP, PIO_ASYNC_NUM_OP_TYPES } pio_async_op_type_t; @@ -941,7 +949,9 @@ typedef struct file_desc_t * npend_ops shows any other pending ops (e.g. non-blocking * write done of rearranged data, still need to wait * on it) */ - int npend_ops; + std::atomic npend_ops; + std::atomic is_hard_closed; + std::mutex *pmtx; /** Pointer to the next file_desc_t in the list of open files. */ struct file_desc_t *next; diff --git a/src/clib/pioc.cpp b/src/clib/pioc.cpp index 4050cebd59..69a5d7b631 100644 --- a/src/clib/pioc.cpp +++ b/src/clib/pioc.cpp @@ -1808,6 +1808,10 @@ int PIOc_set_hint_impl(int iosysid, const char *hint, const char *hintval) return PIO_NOERR; } +int spio_close_soft_closed_files(iosystem_desc_t *iosys) +{ +} + /** * Clean up internal data structures, free MPI resources, and exit the * pio library. @@ -1857,6 +1861,14 @@ int PIOc_finalize_impl(int iosysid) } } +#if PIO_USE_ASYNC_WR_THREAD + ierr = spio_close_all_files_and_delete_from_list(iosysid); + if(ierr != PIO_NOERR){ + return pio_err(ios, NULL, ierr, __FILE__, __LINE__, + "PIO Finalize failed on iosytem (%d). Error closing files on this I/O system", iosysid); + } +#endif + #if PIO_SAVE_DECOMPS SPIO_Util::Decomp_Util::serialize_decomp_map_info_pool(ios); #endif @@ -1896,6 +1908,16 @@ int PIOc_finalize_impl(int iosysid) "PIO Finalize failed on iosystem (%d). Unable to get the number of open I/O systems", iosysid); } +#if PIO_USE_ASYNC_WR_THREAD + if(niosysid == 1){ + ierr = pio_delete_all_iodescs(); + if(ierr != PIO_NOERR){ + return pio_err(ios, NULL, ierr, __FILE__, __LINE__, + "PIO Finalize failed on iosytem (%d). Error deleting I/O decomps on this I/O system", iosysid); + } + } +#endif + LOG((2, "%d iosystems are still open.", niosysid)); /* Free the MPI groups. */ diff --git a/src/clib/pioc_support.cpp b/src/clib/pioc_support.cpp index 74668131fc..eff6a8d4ae 100644 --- a/src/clib/pioc_support.cpp +++ b/src/clib/pioc_support.cpp @@ -32,6 +32,7 @@ #include #include #include +#include /* Include headers for HDF5 compression filters */ #if PIO_USE_HDF5 @@ -3103,6 +3104,14 @@ int spio_createfile_int(int iosysid, int *ncidp, const int *iotype, const char * LOG((1, "PIOc_createfile iosysid = %d iotype = %d filename = %s mode = %d", iosysid, *iotype, filename, mode)); +#if PIO_USE_ASYNC_WR_THREAD + ierr = spio_close_soft_closed_file(filename); + if(ierr != PIO_NOERR){ + return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, + "Creating file (%s) failed. Error closing previous soft closed file", filename); + } +#endif + /* Allocate space for the file info. */ if (!(file = (file_desc_t *) calloc(sizeof(file_desc_t), 1))) { @@ -3110,6 +3119,9 @@ int spio_createfile_int(int iosysid, int *ncidp, const int *iotype, const char * "Creating file (%s) failed. Out of memory allocating %lld bytes for the file descriptor", filename, (unsigned long long) (sizeof(file_desc_t))); } + file->pmtx = new std::mutex(); + assert(file->pmtx); + file->io_fstats = (spio_io_fstats_summary_t *) calloc(sizeof(spio_io_fstats_summary_t), 1); if(!(file->io_fstats)) { @@ -4799,6 +4811,14 @@ int PIOc_openfile_retry_impl(int iosysid, int *ncidp, int *iotype, const char *f LOG((2, "PIOc_openfile_retry iosysid = %d iotype = %d filename = %s mode = %d retry = %d", iosysid, *iotype, filename, mode, retry)); +#if PIO_USE_ASYNC_WR_THREAD + ierr = spio_close_soft_closed_file(filename); + if(ierr != PIO_NOERR){ + return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, + "Creating file (%s) failed. Error closing previous soft closed file", filename); + } +#endif + /* Allocate space for the file info. */ if (!(file = (file_desc_t *) calloc(sizeof(file_desc_t), 1))) { @@ -4808,6 +4828,9 @@ int PIOc_openfile_retry_impl(int iosysid, int *ncidp, int *iotype, const char *f "Opening file (%s) failed. Out of memory allocating %lld bytes for the file structure", filename, (unsigned long long) (sizeof(*file))); } + file->pmtx = new std::mutex(); + assert(file->pmtx); + file->io_fstats = (spio_io_fstats_summary_t *) calloc(sizeof(spio_io_fstats_summary_t), 1); if(!(file->io_fstats)) { diff --git a/src/clib/spio_async_tpool.cpp b/src/clib/spio_async_tpool.cpp index 67043ee70d..232cc322a2 100644 --- a/src/clib/spio_async_tpool.cpp +++ b/src/clib/spio_async_tpool.cpp @@ -62,7 +62,8 @@ int PIO_Util::PIO_async_tpool::dequeue_and_process( if(ret == 0){ LOG((2, " Tpool processing async op, kind = %s", pio_async_op_type_to_string(op->op_type).c_str())); /* We currently support only file write ops here */ - assert(op->op_type == PIO_ASYNC_FILE_WRITE_OPS); + //assert(op->op_type == PIO_ASYNC_FILE_WRITE_OPS); + assert((op->op_type == PIO_ASYNC_HDF5_WRITE_OP) || (op->op_type == PIO_ASYNC_FILE_CLOSE_OP)); ret = op->wait(op->pdata); if(ret != PIO_NOERR){ return pio_err(NULL, NULL, PIO_EINTERNAL, __FILE__, __LINE__, diff --git a/src/clib/spio_async_tpool_cint.h b/src/clib/spio_async_tpool_cint.h index 0e1c70a1ed..5699bb4d70 100644 --- a/src/clib/spio_async_tpool_cint.h +++ b/src/clib/spio_async_tpool_cint.h @@ -4,9 +4,11 @@ #include "pio.h" #include "pio_internal.h" +extern "C"{ int pio_async_tpool_create(void ); int pio_async_tpool_op_add(pio_async_op_t *op); int pio_async_tpool_ops_wait(void ); int pio_async_tpool_finalize(void ); +} // extern "C" #endif // _PIO_ASYNC_THREAD_H_ diff --git a/src/clib/spio_async_utils.cpp b/src/clib/spio_async_utils.cpp index 58893508f9..eb5305f48a 100644 --- a/src/clib/spio_async_utils.cpp +++ b/src/clib/spio_async_utils.cpp @@ -17,14 +17,19 @@ extern "C"{ #include #endif /* PIO_ENABLE_LOGGING */ #include -#include -#include "pio_timer.h" +} // extern "C" #if PIO_USE_ASYNC_WR_THREAD #include "spio_async_tpool_cint.h" #endif +#include "pio_timer.h" +#include #include "spio_async_utils.hpp" +#include "spio_async_tpool.hpp" +#include "spio_file_mvcache.h" +#include "spio_dbg_utils.hpp" +#include "spio_dt_converter.hpp" +#include "spio_async_tpool_cint.h" -} // extern "C" std::string pio_async_op_type_to_string(pio_async_op_type_t op) { @@ -32,7 +37,9 @@ std::string pio_async_op_type_to_string(pio_async_op_type_t op) case PIO_ASYNC_INVALID_OP: return "PIO_ASYNC_INVALID_OP"; case PIO_ASYNC_REARR_OP: return "PIO_ASYNC_REARR_OP"; case PIO_ASYNC_PNETCDF_WRITE_OP: return "PIO_ASYNC_PNETCDF_WRITE_OP"; + case PIO_ASYNC_HDF5_WRITE_OP: return "PIO_ASYNC_HDF5_WRITE_OP"; case PIO_ASYNC_FILE_WRITE_OPS: return "PIO_ASYNC_FILE_WRITE_OPS"; + case PIO_ASYNC_FILE_CLOSE_OP: return "PIO_ASYNC_FILE_CLOSE_OP"; default : return "UNKNOWN"; } } @@ -51,7 +58,7 @@ int pio_async_wait_func_unavail(void *pdata) /* Use this function for op kinds with no poke function * Some asynchronous operations have no poke/test functions - * so any generic code that uses the poke function must + *pio_iosys_async_op_hdf5_write so any generic code that uses the poke function must * check the existence of this function before using it */ int pio_async_poke_func_unavail(void *pdata, int *flag) @@ -463,6 +470,11 @@ int pio_async_rearr_kwait(void *f) return PIO_NOERR; } +int pio_async_hdf5_write_kwait(void *file) +{ + assert(0); +} + /* Optimized wait functions for different async op kinds/types on a file */ typedef int (*file_async_pend_ops_kwait_func_t) (void *file); static file_async_pend_ops_kwait_func_t @@ -472,7 +484,13 @@ static file_async_pend_ops_kwait_func_t /* PIO_ASYNC_REARR_OP */ pio_async_rearr_kwait, /* PIO_ASYNC_PNETCDF_WRITE_OP */ - pio_async_pnetcdf_write_kwait + pio_async_pnetcdf_write_kwait, + /* PIO_ASYNC_HDF5_WRITE_OP */ + pio_async_hdf5_write_kwait, + /* PIO_ASYNC_FILE_WRITE_OPS */ + pio_async_wait_func_unavail, + /* PIO_ASYNC_FILE_CLOSE_OP */ + pio_async_wait_func_unavail }; /* Wait for pending asynchronous operations of kind, op_kind, on this file @@ -857,7 +875,7 @@ void pio_file_close_and_free(void *pdata) file_desc_t *file = (file_desc_t *)pdata; bool sync_with_ioprocs = false; - ret = PIO_hard_closefile(file->iosystem, file, sync_with_ioprocs); + ret = spio_hard_closefile(file->iosystem, file, sync_with_ioprocs); if(ret != PIO_NOERR){ LOG((1, "Closing file (id=%d) failed (ignoring the error)", file->pio_ncid)); } @@ -943,3 +961,446 @@ int pio_tpool_async_pend_op_add(iosystem_desc_t *iosys, return PIO_NOERR; } #endif // PIO_USE_ASYNC_WR_THREAD + +struct Hdf5_wcache{ + file_desc_t *file; + int nvars; + int fndims; + std::vector varids; + io_desc_t *iodesc; + std::vector frame; + + bool wr_fillbuf; + void *iobuf; + std::size_t iobuf_sz; + void *fillbuf; + std::size_t fillbuf_sz; +}; + +int spio_alloc_starts_counts_for_all_regions(iosystem_desc_t *ios, PIO_Offset **&startlist, PIO_Offset **&countlist, int num_regions, int fndims) +{ + int ret = PIO_NOERR; + + startlist = (PIO_Offset**)calloc(num_regions, sizeof(PIO_Offset*)); + if(startlist == NULL){ + return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, + "Unable to allocate memory (%lld bytes) for storing starts/counts when writing data", static_cast(num_regions * sizeof(PIO_Offset *))); + } + + countlist = (PIO_Offset**)calloc(num_regions, sizeof(PIO_Offset*)); + if(countlist == NULL){ + return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, + "Unable to allocate memory (%lld bytes) for storing starts/counts when writing data", static_cast(num_regions * sizeof(PIO_Offset *))); + } + + /* Allocate storage for start/count arrays for each region. */ + for(int iregion = 0; iregion < num_regions; iregion++){ + startlist[iregion] = (PIO_Offset *) calloc(fndims, sizeof(PIO_Offset)); + if(!startlist[iregion]){ + return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, + "Unable to allocate memory (%lld bytes) for storing starts/counts when writing data", static_cast(fndims * sizeof(PIO_Offset))); + } + countlist[iregion] = (PIO_Offset *) calloc(fndims, sizeof(PIO_Offset)); + if(!countlist[iregion]){ + return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, + "Unable to allocate memory (%lld bytes) for storing starts/counts when writing data", static_cast(fndims * sizeof(PIO_Offset))); + } + } + + return ret; +} + +int spio_free_starts_counts_for_all_regions(iosystem_desc_t *ios, PIO_Offset **&startlist, PIO_Offset **&countlist, int num_regions) +{ + for(int iregion=0; iregion < num_regions; iregion++){ + free(startlist[iregion]); + free(countlist[iregion]); + } + free(startlist); + free(countlist); + + startlist = NULL; + countlist = NULL; + + return PIO_NOERR; +} + +int pio_iosys_async_op_hdf5_write(void *pdata) +{ + /* FIXME: Add futures */ + int ret = PIO_NOERR; + Hdf5_wcache *wcache = static_cast(pdata); + assert(wcache); + + file_desc_t *file = wcache->file; + int nvars = wcache->nvars; + int fndims = wcache->fndims; + io_desc_t *iodesc = wcache->iodesc; + + assert(file && (nvars > 0) && (fndims >= 0) && iodesc); + assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); + + iosystem_desc_t *ios = file->iosystem; + var_desc_t *v1desc = file->varlist + wcache->varids[0]; + + assert(ios && v1desc && ios->ioproc); + + bool wr_fillbuf = wcache->wr_fillbuf; + + int num_regions = (wr_fillbuf) ? iodesc->maxfillregions : iodesc->maxregions; + io_region *region = (wr_fillbuf) ? iodesc->fillregion : iodesc->firstregion; + PIO_Offset llen = (wr_fillbuf) ? iodesc->holegridsize : iodesc->llen; + void *iobuf = (wr_fillbuf) ? (wcache->fillbuf) : (wcache->iobuf); + std::size_t iobuf_sz = (wr_fillbuf) ? (wcache->fillbuf_sz) : (wcache->iobuf_sz); + + assert((num_regions > 0) && region && (nvars * llen * iodesc->mpitype_size == static_cast(iobuf_sz)) && iobuf); + + /* Collect starts/counts for all regions to write */ + PIO_Offset **startlist = NULL, **countlist = NULL; + ret = spio_alloc_starts_counts_for_all_regions(ios, startlist, countlist, num_regions, fndims); + if(ret != PIO_NOERR){ + return pio_err(ios, file, ret, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) failed. Internal error, allocating memory for start/count for the I/O regions written out from the I/O process", nvars, pio_get_fname_from_file(file), file->pio_ncid); + } + + std::size_t dsize = 0, dsize_all = 0; + for(int iregion = 0; iregion < num_regions; iregion++){ + std::size_t start[fndims], count[fndims]; + + ret = spio_find_start_count(iodesc->ndims, iodesc->dimlen, fndims, v1desc, region, start, count); + if(ret != PIO_NOERR){ + return pio_err(ios, file, ret, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) failed. Internal error, finding start/count for the I/O regions written out from the I/O process failed", nvars, pio_get_fname_from_file(file), file->pio_ncid); + } + + /* Get the total number of data elements we are + * writing for this region. */ + dsize = 1; + for(int i = 0; i < fndims; i++) { dsize *= count[i]; } + LOG((3, "dsize = %d", dsize)); + + if(dsize > 0){ + dsize_all += dsize; + + /* Copy the start/count arrays for this region. */ + for(int i = 0; i < fndims; i++){ + startlist[iregion][i] = start[i]; + countlist[iregion][i] = count[i]; + LOG((3, "startlist[%d][%d] = %d countlist[%d][%d] = %d", iregion, i, + startlist[iregion][i], iregion, i, countlist[iregion][i])); + } + } + + /* Go to next region. */ + if(region){ region = region->next; } + } + + /* Write data - one variable at a time (all regions for a variable written out in a single call) */ + var_desc_t *vdesc = NULL; + void *bufptr = NULL; + for(int nv = 0; nv < nvars; nv++){ + hid_t file_space_id = H5Dget_space(file->hdf5_vars[wcache->varids[nv]].hdf5_dataset_id); + if(file_space_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to make a copy of the dataspace of the dataset associated with variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[nv]), wcache->varids[nv]); + } + + hid_t mem_space_id = H5I_INVALID_HID; + if(dsize_all > 0){ + /* Get the var info. */ + vdesc = file->varlist + wcache->varids[nv]; + + /* If this is a record (or quasi-record) var, set the start for + * the record dimension. */ + if(vdesc->record >= 0 && fndims > 1){ + for(int rc = 0; rc < num_regions; rc++){ startlist[rc][0] = wcache->frame[nv]; } + } + + H5S_seloper_t op = H5S_SELECT_SET; + for(int i = 0; i < num_regions; i++){ + /* Union hyperslabs of all regions */ + if(H5Sselect_hyperslab(file_space_id, op, (hsize_t*)startlist[i], NULL, (hsize_t*)countlist[i], NULL) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to select a hyperslab region for a dataspace copied from the dataset associated with variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[nv]), wcache->varids[nv]); + } + + op = H5S_SELECT_OR; + } + + mem_space_id = H5Screate_simple(1, &dsize_all, NULL); + if(mem_space_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new simple dataspace for variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[nv]), wcache->varids[nv]); + } + + /* Get a pointer to the data. */ + bufptr = (void *)((char *)iobuf + nv * iodesc->mpitype_size * llen); + } + else{ + /* No data to write on this IO task. */ + if(H5Sselect_none(file_space_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to reset the selection region for a dataspace copied from the dataset associated with variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[nv]), wcache->varids[nv]); + } + + mem_space_id = H5Screate(H5S_NULL); + if(mem_space_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new NULL dataspace for variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[nv]), wcache->varids[nv]); + } + + bufptr = NULL; + } + + /* Collective write */ + hid_t mem_type_id = spio_nc_type_to_hdf5_type(iodesc->piotype); + if(mem_type_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "Unsupported memory type (type=%x) for variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, iodesc->piotype, pio_get_vname_from_file(file, wcache->varids[nv]), wcache->varids[nv]); + } + + hid_t file_var_type_id = H5Dget_type(file->hdf5_vars[wcache->varids[nv]].hdf5_dataset_id); + if(file_var_type_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "Unable to query the type of variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[nv]), wcache->varids[nv]); + } + + hid_t file_var_ntype_id = H5Tget_native_type(file_var_type_id, H5T_DIR_DEFAULT); + assert(file_var_ntype_id != H5I_INVALID_HID); + + /* When HDF5 filters (e.g. data compression) are enabled collective writes fail when datatype conversion is required for writing user data. + * So we manually perform the data conversion here before passing it to HDF5. When filters are not enabled the write might succeed but HDF5 + * might be switching off collective writes (hurts performance) when datatype conversion is required + * FIXME: Disable datatype conversion when filters are not enabled on the dataset + */ + void *wbuf = bufptr; + if((dsize_all > 0) && !H5Tequal(mem_type_id, file_var_ntype_id)){ + assert(file->dt_converter); + wbuf = static_cast(file->dt_converter)->convert(iodesc->ioid, bufptr, iodesc->mpitype_size * dsize_all, + iodesc->piotype, spio_hdf5_type_to_pio_type(file_var_ntype_id)); + if(wbuf == NULL){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "Unable to convert the type (from %d to %d) of variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, iodesc->piotype, + spio_hdf5_type_to_pio_type(file_var_ntype_id), pio_get_vname_from_file(file, wcache->varids[nv]), wcache->varids[nv]); + } + } + + if(H5Dwrite(file->hdf5_vars[wcache->varids[nv]].hdf5_dataset_id, file_var_ntype_id, mem_space_id, file_space_id, + file->dxplid_coll, wbuf) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to write the dataset associated with variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[nv]), wcache->varids[nv]); + } + +#if SPIO_HDF5_FLUSH_AFTER_COLL_WR + if(H5Fflush(file->hdf5_file_id, H5F_SCOPE_LOCAL) < 0){ + H5Eprint2(H5E_DEFAULT, stderr); + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to flush the dataset associated with variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[nv]), wcache->varids[nv]); + } +#endif + + if(H5Sclose(file_space_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a dataspace copied from the dataset associated with variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[nv]), wcache->varids[nv]); + } + + if(H5Sclose(mem_space_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a simple (or NULL) dataspace for variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[nv]), wcache->varids[nv]); + } + } + + /* FIXME: Ignoring error for now - use futures */ + ret = spio_free_starts_counts_for_all_regions(ios, startlist, countlist, num_regions); + + MPI_Barrier(ios->io_comm); + + iodesc->nasync_pend_ops--; + file->npend_ops--; + + return PIO_NOERR; +} + +void pio_iosys_async_op_hdf5_free(void *pdata) +{ + Hdf5_wcache *wcache = static_cast(pdata); + assert(wcache); + + //wcache->varids.clear(); + std::vector().swap(wcache->varids); + //wcache->frame.clear(); + std::vector().swap(wcache->frame); + if(wcache->iobuf){ brel(wcache->iobuf); } + if(wcache->fillbuf){ brel(wcache->fillbuf); } + + free(wcache); +} + +int pio_iosys_async_hdf5_write_op_add(file_desc_t *file, int nvars, int fndims, + const int *varids, io_desc_t *iodesc, int fill, const int *frame) +{ + int ret = PIO_NOERR; + + assert(file && (nvars > 0) && (fndims > 0) && varids && iodesc); + + iosystem_desc_t *ios = file->iosystem; + assert(ios); + + if(!ios->ioproc){ + return PIO_NOERR; + } + + std::vector vids(varids, varids + nvars); + std::vector frms; + if(frame){ + frms.resize(nvars); + std::copy(frame, frame + nvars, frms.begin()); + } + + Hdf5_wcache *wcache = static_cast(calloc(1, sizeof(Hdf5_wcache))); + *wcache = {file, nvars, fndims, vids, iodesc, frms, (fill) ? true : false, NULL, 0, NULL, 0}; + + /* We need to copy the iobuf/fillbuf since the mvcache gets reused for future writes */ + /* Copy iobuf/fillvalue */ + var_desc_t *v1desc = file->varlist + varids[0]; + //PIO_Offset llen = fill ? iodesc->holegridsize : iodesc->llen; + if(fill){ + std::size_t fillbuf_sz = iodesc->holegridsize * iodesc->mpitype_size; + wcache->fillbuf = bget(fillbuf_sz); + if(!wcache->fillbuf){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Queuing asynchronous op/task for writing fillvalue for variables (number of variables = %d) to file (%s, ncid=%d) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for caching variable fillvalue", nvars, pio_get_fname_from_file(file), file->pio_ncid, static_cast(fillbuf_sz)); + } + + std::memcpy(wcache->fillbuf, v1desc->fillbuf, fillbuf_sz); + wcache->fillbuf_sz = fillbuf_sz; + } + else{ + /* Copy buffer, with rearranged data, for nvars */ + std::size_t iobuf_sz = nvars * iodesc->llen * iodesc->mpitype_size; + wcache->iobuf = bget(iobuf_sz); + if(!wcache->iobuf){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Queuing asynchronous op/task for writing fillvalue for variables (number of variables = %d) to file (%s, ncid=%d) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for caching variable data for all the variables", nvars, pio_get_fname_from_file(file), file->pio_ncid, static_cast(iobuf_sz)); + } + + void *iobuf = spio_file_mvcache_get(file, iodesc->ioid); + assert(iobuf); + std::memcpy(wcache->iobuf, iobuf, iobuf_sz); + wcache->iobuf_sz = iobuf_sz; + } + + /* Create async task */ + pio_async_op_t *pnew = static_cast(calloc(1, sizeof(pio_async_op_t))); + if(pnew == NULL){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Queuing asynchronous op/task for writing fillvalue for variables (number of variables = %d) to file (%s, ncid=%d) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for async task internal struct", nvars, pio_get_fname_from_file(file), file->pio_ncid, static_cast(sizeof(pio_async_op_t))); + } + + pnew->op_type = PIO_ASYNC_HDF5_WRITE_OP; + pnew->pdata = static_cast(wcache); + pnew->wait = pio_iosys_async_op_hdf5_write; + pnew->poke = pio_async_poke_func_unavail; + pnew->free = pio_iosys_async_op_hdf5_free; + + /* Get the mt queue and queue the async task */ + ret = pio_async_tpool_op_add(pnew); + if(ret != PIO_NOERR){ + LOG((1, "Adding file pending ops to tpool failed, ret = %d", ret)); + return pio_err(ios, NULL, ret, __FILE__, __LINE__, + "Internal error while adding asynchronous pending operation to the thread pool (iosystem = %d). Adding the asynchronous operation failed", ios->iosysid); + } + + /* One more pending op using this iodesc & file */ + iodesc->nasync_pend_ops++; + file->npend_ops++; + + return PIO_NOERR; +} + +int pio_iosys_async_file_close_op_wait(void *pdata) +{ + int ret = PIO_NOERR; + file_desc_t *file = static_cast(pdata); + assert(file); + + if(file->npend_ops == 0){ + ret = spio_hard_closefile(file->iosystem, file, false); + if(ret != PIO_NOERR){ + return pio_err(file->iosystem, file, ret, __FILE__, __LINE__, + "Closing file (%s, ncid=%d) asynchronously failed", + pio_get_fname_from_file(file), file->pio_ncid); + } + } + else{ + ret = pio_iosys_async_file_close_op_add(file); + if(ret != PIO_NOERR){ + return pio_err(file->iosystem, file, ret, __FILE__, __LINE__, + "Requeuing async op to close file (%s, ncid=%d) asynchronously failed", + pio_get_fname_from_file(file), file->pio_ncid); + } + } + + return PIO_NOERR; +} + +void pio_iosys_async_file_close_op_free_no_op(void *pdata) +{ + /* The file and associated structures should be freed during a "hard close" + * in the wait function + * Nothing to do here + */ + return; +} + +int pio_iosys_async_file_close_op_add(file_desc_t *file) +{ + int ret = PIO_NOERR; + + /* Create async task */ + pio_async_op_t *pnew = static_cast(calloc(1, sizeof(pio_async_op_t))); + if(pnew == NULL){ + return pio_err(file->iosystem, file, PIO_ENOMEM, __FILE__, __LINE__, + "Queuing asynchronous op/task for closing file (%s, ncid=%d) using PIO_IOTYPE_HDF5x failed. Allocating memory for async op task (%zu bytes)", pio_get_fname_from_file(file), file->pio_ncid, sizeof(pio_async_op_t)); + } + + pnew->op_type = PIO_ASYNC_FILE_CLOSE_OP; + pnew->pdata = static_cast(file); + pnew->wait = pio_iosys_async_file_close_op_wait; + pnew->poke = pio_async_poke_func_unavail; + pnew->free = pio_iosys_async_file_close_op_free_no_op; + + /* Get the mt queue and queue the async task */ + ret = pio_async_tpool_op_add(pnew); + if(ret != PIO_NOERR){ + LOG((1, "Adding file pending ops to tpool failed, ret = %d", ret)); + return pio_err(file->iosystem, file, PIO_ENOMEM, __FILE__, __LINE__, + "Queuing asynchronous op/task for closing file (%s, ncid=%d) using PIO_IOTYPE_HDF5x failed. Adding async op to thread pool failed", pio_get_fname_from_file(file), file->pio_ncid); + } + + return PIO_NOERR; +} diff --git a/src/clib/spio_async_utils.hpp b/src/clib/spio_async_utils.hpp index 0cbde86eda..803eced34f 100644 --- a/src/clib/spio_async_utils.hpp +++ b/src/clib/spio_async_utils.hpp @@ -23,6 +23,9 @@ int pio_iosys_async_pend_op_add(iosystem_desc_t *iosys, int pio_tpool_async_pend_op_add(iosystem_desc_t *iosys, pio_async_op_type_t op_type, void *pdata); #endif // PIO_USE_ASYNC_WR_THREAD +int pio_iosys_async_hdf5_write_op_add(file_desc_t *file, int nvars, int fndims, + const int *varids, io_desc_t *iodesc, int fill, const int *frame); +int pio_iosys_async_file_close_op_add(file_desc_t *file); std::string pio_async_op_type_to_string(pio_async_op_type_t op); From b35c93b46f6647983d8d58d6cf4fe352082ed8d1 Mon Sep 17 00:00:00 2001 From: Jayesh Krishna Date: Fri, 5 Dec 2025 10:13:12 -0500 Subject: [PATCH 080/194] Rm const qualifier for queue size Removing the const qualifier since some compilers complain about the local mutex value changing during locking. --- src/clib/spio_async_mtq.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/clib/spio_async_mtq.hpp b/src/clib/spio_async_mtq.hpp index 68d0ea800d..aab7228380 100644 --- a/src/clib/spio_async_mtq.hpp +++ b/src/clib/spio_async_mtq.hpp @@ -25,7 +25,7 @@ class PIO_mtq{ void enqueue(const T& val); int dequeue(T &val); void signal(SigTypes_t sig); - int size(void ) const; + int size(void ); template friend std::ostream & operator<<(std::ostream &ostr, PIO_mtq &mtq); @@ -122,7 +122,7 @@ void PIO_mtq::signal(PIO_mtq::SigTypes_t sig) } template -int PIO_mtq::size(void ) const +int PIO_mtq::size(void ) { int sz = 0; std::unique_lock lk(mtx_); From e39c65f79b5fe9412be42f92cee9097346a01a19 Mon Sep 17 00:00:00 2001 From: Jayesh Krishna Date: Fri, 5 Dec 2025 14:58:40 -0500 Subject: [PATCH 081/194] Fix ADIOS zfp comp rate typo Fix ADIOS zfp compression rate to match the name in config.h --- src/clib/pioc_support.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/clib/pioc_support.cpp b/src/clib/pioc_support.cpp index eff6a8d4ae..d9318a34ab 100644 --- a/src/clib/pioc_support.cpp +++ b/src/clib/pioc_support.cpp @@ -802,11 +802,11 @@ adios2_variable* spio_define_adios2_variable(iosystem_desc_t *ios, file_desc_t * } else if(SPIO_ADIOS2_ZFP_COMPRESSION_MODE == "ADIOS2_ZFP_MODE_RATE"){ /* Fixed Rate Mode : User specifies the number of bits to use for each value of the compressed data */ - adiosErr = adios2_add_operation(&operation_index, variable, ios->lossy_compression_operator, "rate", SPIO_ADIOS2_ZFP_RATE); + adiosErr = adios2_add_operation(&operation_index, variable, ios->lossy_compression_operator, "rate", SPIO_ADIOS2_ZFP_COMPRESSION_RATE); if(adiosErr != adios2_error_none){ pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, "Failed to add ZFP compression operation (rate=%s bits) to variable %s (adios2_error=%s)", - SPIO_ADIOS2_ZFP_RATE, name, convert_adios2_error_to_string(adiosErr)); + SPIO_ADIOS2_ZFP_COMPRESSION_RATE, name, convert_adios2_error_to_string(adiosErr)); } } else if(SPIO_ADIOS2_ZFP_COMPRESSION_MODE == "ADIOS2_ZFP_MODE_REVERSIBLE"){ @@ -821,7 +821,7 @@ adios2_variable* spio_define_adios2_variable(iosystem_desc_t *ios, file_desc_t * else{ pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, "Failed to add ZFP compression operation to variable %s (adios2_error=%s). Invalid compression mode (%s)", - SPIO_ADIOS2_ZFP_RATE, name, convert_adios2_error_to_string(adiosErr), SPIO_ADIOS2_ZFP_COMPRESSION_MODE); + SPIO_ADIOS2_ZFP_COMPRESSION_RATE, name, convert_adios2_error_to_string(adiosErr), SPIO_ADIOS2_ZFP_COMPRESSION_MODE); } } } From 4a6ab1b44e6ac12420e0baa1bdc115b33c125308 Mon Sep 17 00:00:00 2001 From: Jayesh Krishna Date: Fri, 5 Dec 2025 17:52:45 -0500 Subject: [PATCH 082/194] Rm conditionals on async sources We no longer conditionally build the async code. The code is built independent of whether async option is turned on. --- src/clib/CMakeLists.txt | 7 ++----- src/clib/spio_async_utils.cpp | 2 -- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/clib/CMakeLists.txt b/src/clib/CMakeLists.txt index e78d79f0a7..6c32e6845b 100644 --- a/src/clib/CMakeLists.txt +++ b/src/clib/CMakeLists.txt @@ -45,11 +45,8 @@ set (pio_lib_src spio_decomp_map_info_pool.cpp spio_decomp_nc_logger.cpp spio_decomp_txt_logger.cpp spio_ltimer.cpp spio_serializer.cpp spio_file_mvcache.cpp spio_tracer.cpp spio_tracer_mdata.cpp spio_tracer_decomp.cpp - spio_rearrange_any.cpp spio_dt_converter.cpp) - -if(PIO_USE_ASYNC_WR_THREAD) - list(APPEND pio_lib_src spio_async_tpool.cpp spio_async_utils.cpp) -endif() + spio_rearrange_any.cpp spio_dt_converter.cpp + spio_async_tpool.cpp spio_async_utils.cpp) # Add sources for libpioc.a add_library (pioc ${pio_api_src} ${pio_lib_src}) diff --git a/src/clib/spio_async_utils.cpp b/src/clib/spio_async_utils.cpp index eb5305f48a..a7fe5a8ca6 100644 --- a/src/clib/spio_async_utils.cpp +++ b/src/clib/spio_async_utils.cpp @@ -919,7 +919,6 @@ int pio_iosys_async_pend_op_add(iosystem_desc_t *iosys, return PIO_NOERR; } -#if PIO_USE_ASYNC_WR_THREAD /* Add an async op to the list of pending ops in the thread pool * @param iosys Pointer to the iosystem_desc * @param op_type Type of asynchronous operation added @@ -960,7 +959,6 @@ int pio_tpool_async_pend_op_add(iosystem_desc_t *iosys, return PIO_NOERR; } -#endif // PIO_USE_ASYNC_WR_THREAD struct Hdf5_wcache{ file_desc_t *file; From 6873db5c437074f9b3c42fb33bd1566681a40f4a Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 8 Dec 2025 13:37:20 -0600 Subject: [PATCH 083/194] Disable ZFP for HDF5 vars with only unlimited dims When using HDF5 for lossy data compression skip variables with only unlimited dimensions (HDF5 filters fail when chunking these variables and these variables tend to be really small 1D variables for E3SM runs) --- src/clib/pioc_support.cpp | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/clib/pioc_support.cpp b/src/clib/pioc_support.cpp index d9318a34ab..f4c145e49b 100644 --- a/src/clib/pioc_support.cpp +++ b/src/clib/pioc_support.cpp @@ -6856,19 +6856,36 @@ int spio_hdf5_create(iosystem_desc_t *ios, file_desc_t *file, const char *filena } /* Create HDF5 dataset property ID */ -static hid_t spio_create_hdf5_dataset_pid(iosystem_desc_t *ios, file_desc_t *file, const char *var_name, int var_ndims, nc_type var_type) +static hid_t spio_create_hdf5_dataset_pid(iosystem_desc_t *ios, file_desc_t *file, const char *var_name, const std::vector &max_dim_sz, nc_type var_type) { herr_t ret; hid_t dpid = H5I_INVALID_HID; + std::size_t var_ndims = max_dim_sz.size(); + assert((ios != NULL) && (file != NULL) && (var_ndims >= 0)); + bool var_has_only_unlimited_dims = true; + for(std::vector::const_iterator citer = max_dim_sz.cbegin(); citer != max_dim_sz.cend(); ++citer){ + if(*citer != H5S_UNLIMITED){ + var_has_only_unlimited_dims = false; + break; + } + } + /* Initialize the compression filter property list */ dpid = H5Pcreate(H5P_DATASET_CREATE); assert(dpid != H5I_INVALID_HID); /* We currently support compression for non-scalar data */ - if((var_ndims < 1) || (var_type == NC_CHAR) || (file->iotype != PIO_IOTYPE_HDF5C)) return dpid; + if(file->iotype != PIO_IOTYPE_HDF5C) return dpid; + if((var_ndims < 1) || (var_type == NC_CHAR)){ + std::string msg("Disabling HDF5 compression for variable"); + msg += std::string("(name=") + std::string(var_name) + std::string(", file=") + std::string(pio_get_fname_from_file(file)) + std::string(")"); + msg += (var_ndims < 1) ? std::string(" since its a scalar variable") : std::string(" since its a string/char variable"); + PIOc_warn(ios->iosysid, file->fh, __FILE__, __LINE__, msg.c_str()); + return dpid; + } /* Check if any variables have compression disabled by the user */ /* FIXME: Variables written out in a chunk size different from the one defined can cause hangs @@ -6892,6 +6909,15 @@ static hid_t spio_create_hdf5_dataset_pid(iosystem_desc_t *ios, file_desc_t *fil #ifdef _SPIO_HDF5_USE_LOSSY_COMPRESSION #ifdef _SPIO_HAS_H5Z_ZFP + /* Avoid ZFP compression for vars with only unlimited dims */ + if(var_has_only_unlimited_dims){ + std::string msg("Disabling HDF5 compression for variable"); + msg += std::string("(name=") + std::string(var_name) + std::string(", file=") + std::string(pio_get_fname_from_file(file)) + std::string(")"); + msg += std::string(" since it only has unlimited dims"); + PIOc_warn(ios->iosysid, file->fh, __FILE__, __LINE__, msg.c_str()); + return dpid; + } + if(SPIO_HDF5_ZFP_COMPRESSION_MODE == "H5Z_ZFP_MODE_RATE"){ /* Lossy compression : Fixed bit rate : Number of bits used for compressed values is fixed, e.g. 16 */ ret = H5Pset_zfp_rate(dpid, SPIO_HDF5_ZFP_COMPRESSION_RATE); @@ -7096,7 +7122,7 @@ int spio_hdf5_def_var(iosystem_desc_t *ios, file_desc_t *file, const char *name, } /* Create HDF5 dataset (and optionally add filters as needed) */ - hid_t dcpl_id = spio_create_hdf5_dataset_pid(ios, file, name, ndims, xtype); + hid_t dcpl_id = spio_create_hdf5_dataset_pid(ios, file, name, max_dim_sz, xtype); if(dcpl_id == H5I_INVALID_HID){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " From 27feaabc4c6b864a1400e89deefd515c715b01a6 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 8 Dec 2025 13:39:45 -0600 Subject: [PATCH 084/194] Adding a 1D put/get test for var with unlim dims Adding a put/get test for a 1D variable with only unlimited dimensions --- tests/general/pio_decomp_frame_tests.F90.in | 93 +++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/tests/general/pio_decomp_frame_tests.F90.in b/tests/general/pio_decomp_frame_tests.F90.in index 6db7964a27..090fecb122 100644 --- a/tests/general/pio_decomp_frame_tests.F90.in +++ b/tests/general/pio_decomp_frame_tests.F90.in @@ -1,3 +1,96 @@ +! Write multiple frames of a 1d variable with an unlimited dimension +PIO_TF_TEMPLATE +PIO_TF_AUTO_TEST_SUB_BEGIN nc_wr_rd_1d_unlim_dim + implicit none + integer, parameter :: NDIMS = 1 + integer, parameter :: NFRAMES = 6 + integer, parameter :: VEC_LOCAL_SZ = 7 + type(var_desc_t) :: pio_var + type(file_desc_t) :: pio_file + character(len=PIO_TF_MAX_STR_LEN) :: filename + character(len=*), parameter :: PIO_VAR_NAME = 'PIO_TF_test_var_1d_unlim' + PIO_TF_FC_DATA_TYPE, dimension(:), allocatable :: rbuf, wbuf, exp_val + integer, dimension(NDIMS) :: start, count + integer, dimension(NDIMS) :: pio_dims + integer :: i, ierr + integer(kind=pio_offset_kind) :: f + ! iotypes = valid io types + integer, dimension(:), allocatable :: iotypes + character(len=PIO_TF_MAX_STR_LEN), dimension(:), allocatable :: iotype_descs + integer :: num_iotypes + + start = 0 + count = 1 + + allocate(wbuf(1)) + allocate(rbuf(1)) + wbuf = 0 + rbuf = 0 + allocate(exp_val(NFRAMES)) + do f=1,NFRAMES + exp_val(f) = int(f) + end do + + num_iotypes = 0 + call PIO_TF_Get_nc_iotypes(iotypes, iotype_descs, num_iotypes) + filename = "test_pio_decomp_frame_tests.testfile" + do i=1,num_iotypes + PIO_TF_LOG(0,*) "Testing : PIO_TF_DATA_TYPE : ", iotype_descs(i) + ierr = PIO_createfile(pio_tf_iosystem_, pio_file, iotypes(i), filename, PIO_CLOBBER) + PIO_TF_CHECK_ERR(ierr, "Could not create file " // trim(filename)) + + ierr = PIO_def_dim(pio_file, 'PIO_TF_test_dim_time', pio_unlimited, pio_dims(1)) + PIO_TF_CHECK_ERR(ierr, "Failed to define a dim : " // trim(filename)) + + ierr = PIO_def_var(pio_file, PIO_VAR_NAME, PIO_TF_DATA_TYPE, pio_dims, pio_var) + PIO_TF_CHECK_ERR(ierr, "Failed to define a var : " // trim(filename)) + + ierr = PIO_enddef(pio_file) + PIO_TF_CHECK_ERR(ierr, "Failed to end redef mode : " // trim(filename)) + + do f=1,NFRAMES + start = int(f) + wbuf = int(f) + ! Write the current frame + ierr = PIO_put_var(pio_file, pio_var, start, count, wbuf) + PIO_TF_CHECK_ERR(ierr, "Failed to write darray : " // trim(filename)) + end do + +#ifdef PIO_TEST_CLOSE_OPEN_FOR_SYNC + call PIO_closefile(pio_file) + + ierr = PIO_openfile(pio_tf_iosystem_, pio_file, iotypes(i), filename, PIO_nowrite) + PIO_TF_CHECK_ERR(ierr, "Could not reopen file " // trim(filename)) + + ierr = PIO_inq_varid(pio_file, PIO_VAR_NAME, pio_var) + PIO_TF_CHECK_ERR(ierr, "Could not inq var : " // trim(filename)) +#else + call PIO_syncfile(pio_file) +#endif + + do f=1,NFRAMES + start = int(f) + rbuf = 0 + ierr = PIO_get_var(pio_file, pio_var, start, count, rbuf) + PIO_TF_CHECK_ERR(ierr, "Failed to read darray : " // trim(filename)) + PIO_TF_CHECK_VAL((rbuf, exp_val(f)), "Got wrong val, frame = ", f) + end do + + call PIO_closefile(pio_file) + + call PIO_deletefile(pio_tf_iosystem_, filename); + end do + + if(allocated(iotypes)) then + deallocate(iotypes) + deallocate(iotype_descs) + end if + + deallocate(exp_val) + deallocate(rbuf) + deallocate(wbuf) +PIO_TF_AUTO_TEST_SUB_END nc_wr_rd_1d_unlim_dim + ! Write multiple frames of a 2d variable with an unlimited dimension PIO_TF_TEMPLATE PIO_TF_AUTO_TEST_SUB_BEGIN nc_wr_rd_2d_unlim_dim From 1685fcfa20cdfb25d03eeaa1a4238cdc114f9948 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 10 Dec 2025 16:59:56 -0600 Subject: [PATCH 085/194] Rewrite the async hdf5 write func Reimplementing the asynchronous HDF5[C] write functions. * Using C++ ds to simplify code * Separating logic out into util funcs * Adding more data structures and renaming variables to make the intent of the code clear * Ensure that we only process valid regions when writing data out --- src/clib/spio_async_utils.cpp | 200 ++++++++++++++++------------------ 1 file changed, 93 insertions(+), 107 deletions(-) diff --git a/src/clib/spio_async_utils.cpp b/src/clib/spio_async_utils.cpp index a7fe5a8ca6..efe838de2d 100644 --- a/src/clib/spio_async_utils.cpp +++ b/src/clib/spio_async_utils.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include extern "C"{ @@ -975,52 +977,33 @@ struct Hdf5_wcache{ std::size_t fillbuf_sz; }; -int spio_alloc_starts_counts_for_all_regions(iosystem_desc_t *ios, PIO_Offset **&startlist, PIO_Offset **&countlist, int num_regions, int fndims) -{ - int ret = PIO_NOERR; - - startlist = (PIO_Offset**)calloc(num_regions, sizeof(PIO_Offset*)); - if(startlist == NULL){ - return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, - "Unable to allocate memory (%lld bytes) for storing starts/counts when writing data", static_cast(num_regions * sizeof(PIO_Offset *))); - } - - countlist = (PIO_Offset**)calloc(num_regions, sizeof(PIO_Offset*)); - if(countlist == NULL){ - return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, - "Unable to allocate memory (%lld bytes) for storing starts/counts when writing data", static_cast(num_regions * sizeof(PIO_Offset *))); - } +namespace Util{ + /* Each variable writes out one or more regions of data. However all variables have the + * same I/O decomposition and write the same regions (within the variable) of data. The + * region info is the same across all variables + * Note: Different variables (among nvars variables) could be writing out different + * timesteps/records (while still writing the same region - within the record) + */ + struct RInfo{ + /* The starts(:) for this region - local to this process */ + std::vector starts; + /* The counts(:) for this region - local to this process */ + std::vector counts; + /* Total number of elements written out, locally, for this region */ + std::size_t nelems; + }; +} // namespace Util - /* Allocate storage for start/count arrays for each region. */ - for(int iregion = 0; iregion < num_regions; iregion++){ - startlist[iregion] = (PIO_Offset *) calloc(fndims, sizeof(PIO_Offset)); - if(!startlist[iregion]){ - return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, - "Unable to allocate memory (%lld bytes) for storing starts/counts when writing data", static_cast(fndims * sizeof(PIO_Offset))); - } - countlist[iregion] = (PIO_Offset *) calloc(fndims, sizeof(PIO_Offset)); - if(!countlist[iregion]){ - return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, - "Unable to allocate memory (%lld bytes) for storing starts/counts when writing data", static_cast(fndims * sizeof(PIO_Offset))); +/* Update the the start frame for all regions in reg_infos, based on the variable's current frame */ +static inline void update_reg_infos_start_frame(std::vector ®_infos, const var_desc_t *vdesc, const int frame) +{ + /* If the variable has records/frames then update the starts(:) to the provided frame/record number */ + if(vdesc->record >= 0){ + for(std::vector::iterator iter = reg_infos.begin(); iter != reg_infos.end(); ++iter){ + assert(iter->starts.size() > 0); + iter->starts[0] = frame; } } - - return ret; -} - -int spio_free_starts_counts_for_all_regions(iosystem_desc_t *ios, PIO_Offset **&startlist, PIO_Offset **&countlist, int num_regions) -{ - for(int iregion=0; iregion < num_regions; iregion++){ - free(startlist[iregion]); - free(countlist[iregion]); - } - free(startlist); - free(countlist); - - startlist = NULL; - countlist = NULL; - - return PIO_NOERR; } int pio_iosys_async_op_hdf5_write(void *pdata) @@ -1035,7 +1018,7 @@ int pio_iosys_async_op_hdf5_write(void *pdata) int fndims = wcache->fndims; io_desc_t *iodesc = wcache->iodesc; - assert(file && (nvars > 0) && (fndims >= 0) && iodesc); + assert(file && (nvars > 0) && (fndims > 0) && iodesc); assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); iosystem_desc_t *ios = file->iosystem; @@ -1045,108 +1028,109 @@ int pio_iosys_async_op_hdf5_write(void *pdata) bool wr_fillbuf = wcache->wr_fillbuf; - int num_regions = (wr_fillbuf) ? iodesc->maxfillregions : iodesc->maxregions; + //int num_regions = (wr_fillbuf) ? iodesc->maxfillregions : iodesc->maxregions; io_region *region = (wr_fillbuf) ? iodesc->fillregion : iodesc->firstregion; PIO_Offset llen = (wr_fillbuf) ? iodesc->holegridsize : iodesc->llen; void *iobuf = (wr_fillbuf) ? (wcache->fillbuf) : (wcache->iobuf); std::size_t iobuf_sz = (wr_fillbuf) ? (wcache->fillbuf_sz) : (wcache->iobuf_sz); - assert((num_regions > 0) && region && (nvars * llen * iodesc->mpitype_size == static_cast(iobuf_sz)) && iobuf); + assert(region && (nvars * llen * iodesc->mpitype_size == static_cast(iobuf_sz)) && iobuf); - /* Collect starts/counts for all regions to write */ - PIO_Offset **startlist = NULL, **countlist = NULL; - ret = spio_alloc_starts_counts_for_all_regions(ios, startlist, countlist, num_regions, fndims); - if(ret != PIO_NOERR){ - return pio_err(ios, file, ret, __FILE__, __LINE__, - "Writing variables (number of variables = %d) to file (%s, ncid=%d) failed. Internal error, allocating memory for start/count for the I/O regions written out from the I/O process", nvars, pio_get_fname_from_file(file), file->pio_ncid); - } + /* Info on all regions */ + std::vector vreg_infos; + /* Total number of elements written out for all the regions. Since all variables write + * out the same regions - since they use the same I/O decomposition - the total number + * of elements written out for each variable will be the same (reg_nelems) + */ + hsize_t reg_nelems = 0; - std::size_t dsize = 0, dsize_all = 0; - for(int iregion = 0; iregion < num_regions; iregion++){ + /* Collect region info, starts/counts etc, for all regions */ + while(region){ std::size_t start[fndims], count[fndims]; ret = spio_find_start_count(iodesc->ndims, iodesc->dimlen, fndims, v1desc, region, start, count); if(ret != PIO_NOERR){ return pio_err(ios, file, ret, __FILE__, __LINE__, - "Writing variables (number of variables = %d) to file (%s, ncid=%d) failed. Internal error, finding start/count for the I/O regions written out from the I/O process failed", nvars, pio_get_fname_from_file(file), file->pio_ncid); + "Writing variables (number of variables = %d) to file (%s, ncid=%d) failed. Internal error finding start/count for the I/O regions written out from the I/O process", nvars, pio_get_fname_from_file(file), file->pio_ncid); } - /* Get the total number of data elements we are - * writing for this region. */ - dsize = 1; - for(int i = 0; i < fndims; i++) { dsize *= count[i]; } - LOG((3, "dsize = %d", dsize)); - - if(dsize > 0){ - dsize_all += dsize; - - /* Copy the start/count arrays for this region. */ - for(int i = 0; i < fndims; i++){ - startlist[iregion][i] = start[i]; - countlist[iregion][i] = count[i]; - LOG((3, "startlist[%d][%d] = %d countlist[%d][%d] = %d", iregion, i, - startlist[iregion][i], iregion, i, countlist[iregion][i])); - } - } + std::size_t nelems = std::accumulate(count, count + fndims, 1, std::multiplies()); - /* Go to next region. */ - if(region){ region = region->next; } + /* Note: The region info is tied to the first variable, we need to update the variable specific + * sections, start(:) based on the record/frame being written out, later + */ + if(nelems > 0){ + std::vector tmp_start(start, start + fndims); + std::vector tmp_count(count, count + fndims); + vreg_infos.push_back({tmp_start, tmp_count, nelems}); + reg_nelems += static_cast(nelems); + } + region = region->next; } + std::size_t num_regions = vreg_infos.size(); + /* Write data - one variable at a time (all regions for a variable written out in a single call) */ var_desc_t *vdesc = NULL; void *bufptr = NULL; - for(int nv = 0; nv < nvars; nv++){ - hid_t file_space_id = H5Dget_space(file->hdf5_vars[wcache->varids[nv]].hdf5_dataset_id); + for(int vidx = 0; vidx < nvars; vidx++){ + hid_t file_space_id = H5Dget_space(file->hdf5_vars[wcache->varids[vidx]].hdf5_dataset_id); if(file_space_id == H5I_INVALID_HID){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to make a copy of the dataspace of the dataset associated with variable (%s, varid=%d)", - nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[nv]), wcache->varids[nv]); + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); } hid_t mem_space_id = H5I_INVALID_HID; - if(dsize_all > 0){ + if(reg_nelems > 0){ /* Get the var info. */ - vdesc = file->varlist + wcache->varids[nv]; + vdesc = file->varlist + wcache->varids[vidx]; + /* Update the generic region info with variable-specific info */ /* If this is a record (or quasi-record) var, set the start for * the record dimension. */ - if(vdesc->record >= 0 && fndims > 1){ - for(int rc = 0; rc < num_regions; rc++){ startlist[rc][0] = wcache->frame[nv]; } + if((fndims > 1) && (vdesc->record > 0)){ + assert(static_cast(wcache->frame.size()) == nvars); + update_reg_infos_start_frame(vreg_infos, vdesc, wcache->frame[vidx]); } + + /* Create a hyperslab of all the regions written out for a variable */ H5S_seloper_t op = H5S_SELECT_SET; - for(int i = 0; i < num_regions; i++){ + for(std::size_t ireg = 0; ireg < num_regions; ireg++){ /* Union hyperslabs of all regions */ - if(H5Sselect_hyperslab(file_space_id, op, (hsize_t*)startlist[i], NULL, (hsize_t*)countlist[i], NULL) < 0){ + if(H5Sselect_hyperslab(file_space_id, op, static_cast(vreg_infos[ireg].starts.data()), NULL, static_cast(vreg_infos[ireg].counts.data()), NULL) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to select a hyperslab region for a dataspace copied from the dataset associated with variable (%s, varid=%d)", - nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[nv]), wcache->varids[nv]); + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); } op = H5S_SELECT_OR; } - mem_space_id = H5Screate_simple(1, &dsize_all, NULL); + /* Total number of elements across all regions = + * total number of elements written out with this hyperslab = reg_nelems + */ + mem_space_id = H5Screate_simple(1, ®_nelems, NULL); if(mem_space_id == H5I_INVALID_HID){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to create a new simple dataspace for variable (%s, varid=%d)", - nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[nv]), wcache->varids[nv]); + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); } - /* Get a pointer to the data. */ - bufptr = (void *)((char *)iobuf + nv * iodesc->mpitype_size * llen); + /* Get a pointer to the data. This buffer points to data from all the regions written out for this variable */ + bufptr = (void *)((char *)iobuf + vidx * iodesc->mpitype_size * llen); } else{ - /* No data to write on this IO task. */ + /* No data, across all regions, to write on this IO task */ if(H5Sselect_none(file_space_id) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to reset the selection region for a dataspace copied from the dataset associated with variable (%s, varid=%d)", - nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[nv]), wcache->varids[nv]); + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); } mem_space_id = H5Screate(H5S_NULL); @@ -1154,27 +1138,27 @@ int pio_iosys_async_op_hdf5_write(void *pdata) return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to create a new NULL dataspace for variable (%s, varid=%d)", - nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[nv]), wcache->varids[nv]); + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); } bufptr = NULL; } - /* Collective write */ + /* Collective write - for all regions in a single variable */ hid_t mem_type_id = spio_nc_type_to_hdf5_type(iodesc->piotype); if(mem_type_id == H5I_INVALID_HID){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " "Unsupported memory type (type=%x) for variable (%s, varid=%d)", - nvars, pio_get_fname_from_file(file), file->pio_ncid, iodesc->piotype, pio_get_vname_from_file(file, wcache->varids[nv]), wcache->varids[nv]); + nvars, pio_get_fname_from_file(file), file->pio_ncid, iodesc->piotype, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); } - hid_t file_var_type_id = H5Dget_type(file->hdf5_vars[wcache->varids[nv]].hdf5_dataset_id); + hid_t file_var_type_id = H5Dget_type(file->hdf5_vars[wcache->varids[vidx]].hdf5_dataset_id); if(file_var_type_id == H5I_INVALID_HID){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " "Unable to query the type of variable (%s, varid=%d)", - nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[nv]), wcache->varids[nv]); + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); } hid_t file_var_ntype_id = H5Tget_native_type(file_var_type_id, H5T_DIR_DEFAULT); @@ -1186,25 +1170,25 @@ int pio_iosys_async_op_hdf5_write(void *pdata) * FIXME: Disable datatype conversion when filters are not enabled on the dataset */ void *wbuf = bufptr; - if((dsize_all > 0) && !H5Tequal(mem_type_id, file_var_ntype_id)){ + if((reg_nelems > 0) && !H5Tequal(mem_type_id, file_var_ntype_id)){ assert(file->dt_converter); - wbuf = static_cast(file->dt_converter)->convert(iodesc->ioid, bufptr, iodesc->mpitype_size * dsize_all, + wbuf = static_cast(file->dt_converter)->convert(iodesc->ioid, bufptr, iodesc->mpitype_size * reg_nelems, iodesc->piotype, spio_hdf5_type_to_pio_type(file_var_ntype_id)); if(wbuf == NULL){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " "Unable to convert the type (from %d to %d) of variable (%s, varid=%d)", nvars, pio_get_fname_from_file(file), file->pio_ncid, iodesc->piotype, - spio_hdf5_type_to_pio_type(file_var_ntype_id), pio_get_vname_from_file(file, wcache->varids[nv]), wcache->varids[nv]); + spio_hdf5_type_to_pio_type(file_var_ntype_id), pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); } } - if(H5Dwrite(file->hdf5_vars[wcache->varids[nv]].hdf5_dataset_id, file_var_ntype_id, mem_space_id, file_space_id, + if(H5Dwrite(file->hdf5_vars[wcache->varids[vidx]].hdf5_dataset_id, file_var_ntype_id, mem_space_id, file_space_id, file->dxplid_coll, wbuf) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to write the dataset associated with variable (%s, varid=%d)", - nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[nv]), wcache->varids[nv]); + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); } #if SPIO_HDF5_FLUSH_AFTER_COLL_WR @@ -1213,7 +1197,7 @@ int pio_iosys_async_op_hdf5_write(void *pdata) return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to flush the dataset associated with variable (%s, varid=%d)", - nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[nv]), wcache->varids[nv]); + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); } #endif @@ -1221,20 +1205,18 @@ int pio_iosys_async_op_hdf5_write(void *pdata) return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to release a dataspace copied from the dataset associated with variable (%s, varid=%d)", - nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[nv]), wcache->varids[nv]); + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); } if(H5Sclose(mem_space_id) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to release a simple (or NULL) dataspace for variable (%s, varid=%d)", - nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[nv]), wcache->varids[nv]); + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); } } - /* FIXME: Ignoring error for now - use futures */ - ret = spio_free_starts_counts_for_all_regions(ios, startlist, countlist, num_regions); - + /* FIXME: Is this barrier needed ? */ MPI_Barrier(ios->io_comm); iodesc->nasync_pend_ops--; @@ -1248,10 +1230,14 @@ void pio_iosys_async_op_hdf5_free(void *pdata) Hdf5_wcache *wcache = static_cast(pdata); assert(wcache); + /* Using swap trick to free vectors + * - swap vector with an empty local/temp vector that gets deallocated when func exits + */ //wcache->varids.clear(); std::vector().swap(wcache->varids); //wcache->frame.clear(); std::vector().swap(wcache->frame); + if(wcache->iobuf){ brel(wcache->iobuf); } if(wcache->fillbuf){ brel(wcache->fillbuf); } From 431d84f1c98d8933fa90177f39c3a37f9cde14bb Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 10 Dec 2025 19:02:04 -0600 Subject: [PATCH 086/194] Handle async I/O procs with 0 bytes to write Handling async writes on I/O processes with 0 bytes to write --- src/clib/spio_async_utils.cpp | 41 ++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/src/clib/spio_async_utils.cpp b/src/clib/spio_async_utils.cpp index efe838de2d..67202c56c2 100644 --- a/src/clib/spio_async_utils.cpp +++ b/src/clib/spio_async_utils.cpp @@ -1034,7 +1034,8 @@ int pio_iosys_async_op_hdf5_write(void *pdata) void *iobuf = (wr_fillbuf) ? (wcache->fillbuf) : (wcache->iobuf); std::size_t iobuf_sz = (wr_fillbuf) ? (wcache->fillbuf_sz) : (wcache->iobuf_sz); - assert(region && (nvars * llen * iodesc->mpitype_size == static_cast(iobuf_sz)) && iobuf); + assert(region && (nvars * llen * iodesc->mpitype_size == static_cast(iobuf_sz))); + assert(((iobuf_sz == 0) && !iobuf) || ((iobuf_sz != 0) && iobuf)); /* Info on all regions */ std::vector vreg_infos; @@ -1274,28 +1275,34 @@ int pio_iosys_async_hdf5_write_op_add(file_desc_t *file, int nvars, int fndims, //PIO_Offset llen = fill ? iodesc->holegridsize : iodesc->llen; if(fill){ std::size_t fillbuf_sz = iodesc->holegridsize * iodesc->mpitype_size; - wcache->fillbuf = bget(fillbuf_sz); - if(!wcache->fillbuf){ - return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, - "Queuing asynchronous op/task for writing fillvalue for variables (number of variables = %d) to file (%s, ncid=%d) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for caching variable fillvalue", nvars, pio_get_fname_from_file(file), file->pio_ncid, static_cast(fillbuf_sz)); - } + /* On I/O processes with no data (after rearrangement) to write the fillbuf_sz will be 0 */ + if(fillbuf_sz > 0){ + wcache->fillbuf = bget(fillbuf_sz); + if(!wcache->fillbuf){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Queuing asynchronous op/task for writing fillvalue for variables (number of variables = %d) to file (%s, ncid=%d) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for caching variable fillvalue", nvars, pio_get_fname_from_file(file), file->pio_ncid, static_cast(fillbuf_sz)); + } - std::memcpy(wcache->fillbuf, v1desc->fillbuf, fillbuf_sz); - wcache->fillbuf_sz = fillbuf_sz; + std::memcpy(wcache->fillbuf, v1desc->fillbuf, fillbuf_sz); + wcache->fillbuf_sz = fillbuf_sz; + } } else{ /* Copy buffer, with rearranged data, for nvars */ std::size_t iobuf_sz = nvars * iodesc->llen * iodesc->mpitype_size; - wcache->iobuf = bget(iobuf_sz); - if(!wcache->iobuf){ - return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, - "Queuing asynchronous op/task for writing fillvalue for variables (number of variables = %d) to file (%s, ncid=%d) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for caching variable data for all the variables", nvars, pio_get_fname_from_file(file), file->pio_ncid, static_cast(iobuf_sz)); - } + /* On I/O processes with no data (after rearrangement) to write the iobuf_sz will be 0 */ + if(iobuf_sz > 0){ + wcache->iobuf = bget(iobuf_sz); + if(!wcache->iobuf){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Queuing asynchronous op/task for writing fillvalue for variables (number of variables = %d) to file (%s, ncid=%d) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for caching variable data for all the variables", nvars, pio_get_fname_from_file(file), file->pio_ncid, static_cast(iobuf_sz)); + } - void *iobuf = spio_file_mvcache_get(file, iodesc->ioid); - assert(iobuf); - std::memcpy(wcache->iobuf, iobuf, iobuf_sz); - wcache->iobuf_sz = iobuf_sz; + void *iobuf = spio_file_mvcache_get(file, iodesc->ioid); + assert(iobuf); + std::memcpy(wcache->iobuf, iobuf, iobuf_sz); + wcache->iobuf_sz = iobuf_sz; + } } /* Create async task */ From 3dfab2365f7578a0e52a8dc0156ac21aa3767577 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 10 Dec 2025 20:58:45 -0600 Subject: [PATCH 087/194] Avoid freeing I/O desc with pending ops Ensure that I/O descriptor is freed only after all async ops on the I/O descriptor is finished --- src/clib/pio_internal.h | 2 +- src/clib/pio_lists.cpp | 27 ++++++++++++++++++++++++--- src/clib/pioc.cpp | 2 +- src/clib/pioc_support.cpp | 5 +++++ 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/clib/pio_internal.h b/src/clib/pio_internal.h index cedf78ba57..491d55db9e 100644 --- a/src/clib/pio_internal.h +++ b/src/clib/pio_internal.h @@ -118,7 +118,7 @@ extern "C" { int pio_add_to_iodesc_list(io_desc_t *iodesc, MPI_Comm comm); io_desc_t *pio_get_iodesc_from_id(int ioid); int pio_delete_iodesc_from_list(int ioid); - int pio_delete_all_iodescs(void ); + int pio_delete_all_iodescs(int iosysid); int pio_num_iosystem(int *niosysid); int pio_get_file(int ncid, file_desc_t **filep); diff --git a/src/clib/pio_lists.cpp b/src/clib/pio_lists.cpp index 7b17cb2b7d..27223a6c08 100644 --- a/src/clib/pio_lists.cpp +++ b/src/clib/pio_lists.cpp @@ -17,6 +17,8 @@ #include "spio_hash.h" #include "spio_dt_converter.hpp" #include +#include +#include namespace SPIO_Util{ namespace SPIO_Lists{ @@ -469,13 +471,32 @@ int pio_delete_iodesc_from_list(int ioid) return PIO_NOERR; } -int pio_delete_all_iodescs(void ) +static int spio_wait_async_iodesc_ops(io_desc_t *iodesc) { + const int SLEEP_TIME_IN_MILLISECONDS = 500; + while(iodesc->nasync_pend_ops > 0){ + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME_IN_MILLISECONDS)); + } + + return PIO_NOERR; +} + +int pio_delete_all_iodescs(int iosysid) +{ + int ret = PIO_NOERR; for(std::map::iterator iter = SPIO_Util::SPIO_Lists::GVars::pio_iodesc_list.begin(); iter != SPIO_Util::SPIO_Lists::GVars::pio_iodesc_list.end(); ++iter){ io_desc_t *iodesc = (*iter).second; - assert(iodesc && (iodesc->nasync_pend_ops == 0)); - free(iodesc); + ret = spio_wait_async_iodesc_ops(iodesc); + if(ret != PIO_NOERR){ + return pio_err(NULL, NULL, ret, __FILE__, __LINE__, + "Deleting I/O descriptor (ioid = %d) failed. Error while waiting for async ops on I/O descriptor", iodesc->ioid); + } + ret = PIOc_freedecomp_impl(iosysid, iodesc->ioid); + if(ret != PIO_NOERR){ + return pio_err(NULL, NULL, ret, __FILE__, __LINE__, + "Deleting I/O descriptor (ioid = %d) failed. Error when freeing I/O decomp after waiting for async ops on I/O descriptor", iodesc->ioid); + } } SPIO_Util::SPIO_Lists::GVars::pio_iodesc_list.clear(); diff --git a/src/clib/pioc.cpp b/src/clib/pioc.cpp index 69a5d7b631..27bbeb200a 100644 --- a/src/clib/pioc.cpp +++ b/src/clib/pioc.cpp @@ -1910,7 +1910,7 @@ int PIOc_finalize_impl(int iosysid) #if PIO_USE_ASYNC_WR_THREAD if(niosysid == 1){ - ierr = pio_delete_all_iodescs(); + ierr = pio_delete_all_iodescs(iosysid); if(ierr != PIO_NOERR){ return pio_err(ios, NULL, ierr, __FILE__, __LINE__, "PIO Finalize failed on iosytem (%d). Error deleting I/O decomps on this I/O system", iosysid); diff --git a/src/clib/pioc_support.cpp b/src/clib/pioc_support.cpp index f4c145e49b..98baa09acb 100644 --- a/src/clib/pioc_support.cpp +++ b/src/clib/pioc_support.cpp @@ -1805,6 +1805,11 @@ int PIOc_freedecomp_impl(int iosysid, int ioid) } } + if(iodesc->nasync_pend_ops > 0){ + /* Let I/O desc be freed during finalize */ + return PIO_NOERR; + } + /* Free the map. */ free(iodesc->map); From b18b70511a0289992f17788050ba782667b8e74b Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 11 Dec 2025 11:42:52 -0600 Subject: [PATCH 088/194] Adding stringify for HDF5[C] types Adding ability to stringify HDF5/HDF5C types (useful for error messages related to HDF5[C]) --- src/clib/pio_print.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/clib/pio_print.cpp b/src/clib/pio_print.cpp index c768b7ee9c..b8c53b58e4 100644 --- a/src/clib/pio_print.cpp +++ b/src/clib/pio_print.cpp @@ -19,6 +19,10 @@ const char *pio_iotype_to_string(int iotype) return "PIO_IOTYPE_ADIOS"; case PIO_IOTYPE_ADIOSC: return "PIO_IOTYPE_ADIOSC"; + case PIO_IOTYPE_HDF5: + return "PIO_IOTYPE_HDF5"; + case PIO_IOTYPE_HDF5C: + return "PIO_IOTYPE_HDF5C"; default: return "UNKNOWN"; } From d697bcc0880a9af84dfdba06724cec614b2f1206 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 11 Dec 2025 20:20:50 -0600 Subject: [PATCH 089/194] Adding timeout for soft close wait Adding a maximum timeout when waiting on "soft closed" files. (The application might skip the close on a file) --- src/clib/pio_file.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/clib/pio_file.cpp b/src/clib/pio_file.cpp index 3b74fff3b5..eb9cdf817d 100644 --- a/src/clib/pio_file.cpp +++ b/src/clib/pio_file.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #ifdef _ADIOS2 #include "../../tools/adios2pio-nm/adios2pio-nm-lib-c.h" @@ -442,11 +443,30 @@ static int sync_file(int ncid) int spio_wait_on_hard_close(iosystem_desc_t *ios, file_desc_t *file) { + /* FIXME: Make the max time configurable */ + const int MAX_SLEEP_TIME_IN_MILLISECONDS = 5000; const int SLEEP_TIME_IN_MILLISECONDS = 500; - while(!file->is_hard_closed){ + + /* For files that will never be closed, due to user error for ex, we cannot wait + * indefenitely. On the other hand we do want to have enough time to finish async ops + */ + const int max_tries = (MAX_SLEEP_TIME_IN_MILLISECONDS > SLEEP_TIME_IN_MILLISECONDS) ? + (MAX_SLEEP_TIME_IN_MILLISECONDS/SLEEP_TIME_IN_MILLISECONDS) : 1; + int i = 0; + while(!file->is_hard_closed && (i++ < max_tries)){ std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME_IN_MILLISECONDS)); } + if(!file->is_hard_closed && (i > max_tries)){ + std::string msg = std::string("Waiting on a close on file aborted due to exceeding max timelimit") + + std::string(" (") + + std::string("ncid = ") + std::to_string(file->pio_ncid) + + std::string(", file = ") + std::string(file->fname) + + std::string(", max timeout limit(milli secs) = ") + std::to_string(MAX_SLEEP_TIME_IN_MILLISECONDS) + + std::string(")"); + PIOc_warn(ios->iosysid, file->pio_ncid, __FILE__, __LINE__, msg.c_str()); + } + return PIO_NOERR; } From abc684a380d4fcc0e206abaf4c51a854e3245992 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 11 Dec 2025 21:29:51 -0600 Subject: [PATCH 090/194] Free hdf5 struct names when freeing file Since we no longer hard close all files, adding code to free hdf5 struct names when freeing the file --- src/clib/pio_lists.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/clib/pio_lists.cpp b/src/clib/pio_lists.cpp index 27223a6c08..c777a767fe 100644 --- a/src/clib/pio_lists.cpp +++ b/src/clib/pio_lists.cpp @@ -142,6 +142,26 @@ int pio_free_file(file_desc_t *file) if(file->dt_converter != NULL){ delete(static_cast(file->dt_converter)); } + + if((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)){ + for(int i = 0; i < file->hdf5_num_dims; i++){ + if(file->hdf5_dims[i].name) { free(file->hdf5_dims[i].name); } + } + file->hdf5_num_dims = 0; + + for(int i = 0; i < file->hdf5_num_vars; i++){ + if(file->hdf5_vars[i].name) { free(file->hdf5_vars[i].name); } + if(file->hdf5_vars[i].alt_name) { free(file->hdf5_vars[i].alt_name); } + if(file->hdf5_vars[i].hdf5_dimids) { free(file->hdf5_vars[i].hdf5_dimids); } + } + file->hdf5_num_vars = 0; + + for(int i = 0; i < file->hdf5_num_attrs; i++) { + if(file->hdf5_attrs[i].att_name) { free(file->hdf5_attrs[i].att_name); } + } + file->hdf5_num_attrs = 0; + file->hdf5_num_gattrs = 0; + } #endif #ifdef _ADIOS2 From 7c3a5ba81da2f171c7e306dc1cdde278721de9c8 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 12 Dec 2025 11:32:15 -0600 Subject: [PATCH 091/194] Expose datatype converter for all I/O types Exposing the datatype converter for all I/O types. However the converter is currently only used by the HDF5 I/O type. --- src/clib/pio_types.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clib/pio_types.hpp b/src/clib/pio_types.hpp index 8b3690fa19..89c095a5bb 100644 --- a/src/clib/pio_types.hpp +++ b/src/clib/pio_types.hpp @@ -894,9 +894,9 @@ typedef struct file_desc_t /** Number of global attrs defined */ int hdf5_num_gattrs; +#endif /* _HDF5 */ /** A datatype converter for user buffers */ void *dt_converter; -#endif /* _HDF5 */ /* File name - cached */ char fname[PIO_MAX_NAME + 1]; From aeea2465ab36f70519014cd83d029fb5972a628b Mon Sep 17 00:00:00 2001 From: Jayesh Krishna Date: Mon, 15 Dec 2025 11:23:36 -0500 Subject: [PATCH 092/194] Disabling waiting on close for read-only files Disable waiting on close (soft close) for read-only files --- src/clib/pio_lists.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/clib/pio_lists.cpp b/src/clib/pio_lists.cpp index c777a767fe..2def371c48 100644 --- a/src/clib/pio_lists.cpp +++ b/src/clib/pio_lists.cpp @@ -249,7 +249,8 @@ int spio_close_soft_closed_file(const char *filename) for(std::map::iterator iter = SPIO_Util::SPIO_Lists::GVars::pio_file_list.begin(); iter != SPIO_Util::SPIO_Lists::GVars::pio_file_list.end(); ++iter){ file_desc_t *file = iter->second; - if(std::string(file->fname) == std::string(filename)){ + /* No need to worry about "read only" files */ + if((std::string(file->fname) == std::string(filename)) && (file->mode & PIO_WRITE)){ //ret = spio_hard_closefile(file->iosystem, file, true); ret = spio_wait_on_hard_close(file->iosystem, file); if(ret != PIO_NOERR){ From ccd289c26adbcdf8a714b27bbf5f6b65e2a2490b Mon Sep 17 00:00:00 2001 From: Jayesh Krishna Date: Mon, 15 Dec 2025 11:24:32 -0500 Subject: [PATCH 093/194] Disable zfp compression for scalar vars Disable zfp compression for essentially scalar vars (variable with multiple dimensions by all dimensions are of size 1) --- src/clib/pioc_support.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/clib/pioc_support.cpp b/src/clib/pioc_support.cpp index 98baa09acb..722ec1c495 100644 --- a/src/clib/pioc_support.cpp +++ b/src/clib/pioc_support.cpp @@ -6871,10 +6871,11 @@ static hid_t spio_create_hdf5_dataset_pid(iosystem_desc_t *ios, file_desc_t *fil assert((ios != NULL) && (file != NULL) && (var_ndims >= 0)); bool var_has_only_unlimited_dims = true; + bool var_is_scalar = true; for(std::vector::const_iterator citer = max_dim_sz.cbegin(); citer != max_dim_sz.cend(); ++citer){ if(*citer != H5S_UNLIMITED){ var_has_only_unlimited_dims = false; - break; + if(*citer != 1) { var_is_scalar = false; } } } @@ -6915,10 +6916,10 @@ static hid_t spio_create_hdf5_dataset_pid(iosystem_desc_t *ios, file_desc_t *fil #ifdef _SPIO_HAS_H5Z_ZFP /* Avoid ZFP compression for vars with only unlimited dims */ - if(var_has_only_unlimited_dims){ + if(var_has_only_unlimited_dims || var_is_scalar){ std::string msg("Disabling HDF5 compression for variable"); msg += std::string("(name=") + std::string(var_name) + std::string(", file=") + std::string(pio_get_fname_from_file(file)) + std::string(")"); - msg += std::string(" since it only has unlimited dims"); + msg += (var_has_only_unlimited_dims) ? std::string(" since it only has unlimited dims") : std::string(" since it is essentially a scalar variable"); PIOc_warn(ios->iosysid, file->fh, __FILE__, __LINE__, msg.c_str()); return dpid; } From b2acf6f4c39aa89268c9ee0d41800c8e92602384 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 15 Dec 2025 14:33:35 -0600 Subject: [PATCH 094/194] Disable HDF5+ZFP compression for >4D vars Disable HDF5 + ZFP compression for 5D+ variables for now --- src/clib/pioc_support.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/clib/pioc_support.cpp b/src/clib/pioc_support.cpp index 722ec1c495..d18ea193cc 100644 --- a/src/clib/pioc_support.cpp +++ b/src/clib/pioc_support.cpp @@ -6870,6 +6870,7 @@ static hid_t spio_create_hdf5_dataset_pid(iosystem_desc_t *ios, file_desc_t *fil assert((ios != NULL) && (file != NULL) && (var_ndims >= 0)); + bool var_has_more_than_four_dims = (max_dim_sz.size() > 4) ? true : false; bool var_has_only_unlimited_dims = true; bool var_is_scalar = true; for(std::vector::const_iterator citer = max_dim_sz.cbegin(); citer != max_dim_sz.cend(); ++citer){ @@ -6916,10 +6917,11 @@ static hid_t spio_create_hdf5_dataset_pid(iosystem_desc_t *ios, file_desc_t *fil #ifdef _SPIO_HAS_H5Z_ZFP /* Avoid ZFP compression for vars with only unlimited dims */ - if(var_has_only_unlimited_dims || var_is_scalar){ - std::string msg("Disabling HDF5 compression for variable"); + if(var_has_only_unlimited_dims || var_is_scalar || var_has_more_than_four_dims){ + std::string msg("Disabling HDF5 ZFP compression for variable"); msg += std::string("(name=") + std::string(var_name) + std::string(", file=") + std::string(pio_get_fname_from_file(file)) + std::string(")"); - msg += (var_has_only_unlimited_dims) ? std::string(" since it only has unlimited dims") : std::string(" since it is essentially a scalar variable"); + msg += (var_has_only_unlimited_dims) ? std::string(" since it only has unlimited dims") : + ((var_is_scalar) ? std::string(" since it is essentially a scalar variable") : std::string(" since variable has more than 4 dimensions")); PIOc_warn(ios->iosysid, file->fh, __FILE__, __LINE__, msg.c_str()); return dpid; } From e0d4efdae7336e55f547cca993c75956dd94b38a Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 15 Dec 2025 14:35:17 -0600 Subject: [PATCH 095/194] Adding test for writing a 6d var Adding a test for writing a non-distributed 6D var, one slice at a time --- tests/general/ncdf_get_put.F90.in | 152 ++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) diff --git a/tests/general/ncdf_get_put.F90.in b/tests/general/ncdf_get_put.F90.in index 6444316199..13f04083b1 100644 --- a/tests/general/ncdf_get_put.F90.in +++ b/tests/general/ncdf_get_put.F90.in @@ -844,6 +844,158 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_md2mdplus1_var PIO_TF_AUTO_TEST_SUB_END test_put_get_md2mdplus1_var +! Write out a 6d var, one time slice at a time +! (ne4pg2 + EAMXX writes out similar 6d vars) +PIO_TF_TEMPLATE +PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_6d_var + Implicit none + type(file_desc_t) :: pio_file + character(len=PIO_TF_MAX_STR_LEN) :: filename + character(len=*), parameter :: PIO_6DVAR_NAME = '6d_val' + ! There are 6 dims in the variable, but only 5 unique dims + integer, parameter :: MAX_DIMS = 6 + integer, parameter :: MAX_LEVS = 9 + integer, parameter :: MAX_GP = 4 + integer, parameter :: MAX_DIM2 = 2 + integer, parameter :: MAX_ELEMS = 6 + integer, parameter :: MAX_TIMES = 3 + integer, dimension(MAX_DIMS) :: pio_dims + type(var_desc_t) :: pio_6dvar + PIO_TF_FC_DATA_TYPE, dimension(MAX_LEVS, MAX_GP, MAX_GP, MAX_DIM2, MAX_ELEMS, MAX_TIMES) ::& + gval_6d, exp_val_6d + integer, dimension(:) :: start(MAX_DIMS), count(MAX_DIMS) + integer, dimension(:), allocatable :: iotypes + character(len=PIO_TF_MAX_STR_LEN), dimension(:), allocatable :: iotype_descs + integer :: num_iotypes + integer :: i, j, k, l, m, tstep, iotype_idx, ret + + num_iotypes = 0 + call PIO_TF_Get_nc_iotypes(iotypes, iotype_descs, num_iotypes) + filename = "test_pio_ncdf_get_put_6d_slice.testfile" + do iotype_idx=1,num_iotypes + PIO_TF_LOG(0,*) "Testing type :", iotype_descs(iotype_idx) + ret = PIO_createfile(pio_tf_iosystem_, pio_file, iotypes(iotype_idx), filename, PIO_CLOBBER) + PIO_TF_CHECK_ERR(ret, "Failed to open:" // trim(filename)) + + ! Since file is just created no need to enter redef + ret = PIO_def_dim(pio_file, 'nlevs', MAX_LEVS, pio_dims(1)) + PIO_TF_CHECK_ERR(ret, "Failed to define nlevs dim:" // trim(filename)) + + ret = PIO_def_dim(pio_file, 'gp', MAX_GP, pio_dims(2)) + PIO_TF_CHECK_ERR(ret, "Failed to define gp dim:" // trim(filename)) + + pio_dims(3) = pio_dims(2) + + ret = PIO_def_dim(pio_file, 'dim2', MAX_DIM2, pio_dims(4)) + PIO_TF_CHECK_ERR(ret, "Failed to define dim2 dim:" // trim(filename)) + + ret = PIO_def_dim(pio_file, 'elems', MAX_ELEMS, pio_dims(5)) + PIO_TF_CHECK_ERR(ret, "Failed to define elems dim:" // trim(filename)) + + ret = PIO_def_dim(pio_file, 'time', PIO_UNLIMITED, pio_dims(6)) + PIO_TF_CHECK_ERR(ret, "Failed to define time dim:" // trim(filename)) + + ret = PIO_def_var(pio_file, PIO_6DVAR_NAME, PIO_TF_DATA_TYPE,& + pio_dims, pio_6dvar) + PIO_TF_CHECK_ERR(ret, "Failed to define 6d var:" // trim(filename)) + + ret = PIO_enddef(pio_file) + PIO_TF_CHECK_ERR(ret, "Failed to enddef:" // trim(filename)) + + ! Put vals are for each timestep & + ! expected vals are combined for all timesteps + do tstep=1,MAX_TIMES + do m=1,MAX_ELEMS + do l=1,MAX_DIM2 + do k=1,MAX_GP + do j=1,MAX_GP + do i=1,MAX_LEVS + exp_val_6d(:,:,:,:,:,tstep) = i + j * MAX_LEVS + k * (MAX_GP * MAX_LEVS) +& + l * (MAX_GP * MAX_GP * MAX_LEVS) + m * (MAX_DIM2 * MAX_GP * MAX_GP * MAX_LEVS) +& + tstep * (MAX_ELEMS * MAX_DIM2 * MAX_GP * MAX_GP * MAX_LEVS) + end do + end do + end do + end do + end do + end do + + ! Put 6d val, one timestep at a time + do tstep=1,MAX_TIMES + start = 0 + count = 0 + + start(1) = 1 + count(1) = MAX_LEVS + start(2) = 1 + count(2) = MAX_GP + start(3) = 1 + count(3) = MAX_GP + start(4) = 1 + count(4) = MAX_DIM2 + start(5) = 1 + count(5) = MAX_ELEMS + start(6) = tstep + count(6) = 1 + ret = PIO_put_var(pio_file, pio_6dvar, start, count,& + exp_val_6d(:,:,:,:,:,tstep)) + PIO_TF_CHECK_ERR(ret, "Failed to put 6d var:" // trim(filename)) + end do + +#ifdef PIO_TEST_CLOSE_OPEN_FOR_SYNC + call PIO_closefile(pio_file) + + ret = PIO_openfile(pio_tf_iosystem_, pio_file, iotypes(iotype_idx), filename, PIO_nowrite) + PIO_TF_CHECK_ERR(ret, "Failed to reopen:" // trim(filename)) + + ret = PIO_inq_varid(pio_file, PIO_6DVAR_NAME, pio_6dvar) + PIO_TF_CHECK_ERR(ret, "Failed to inq 6d var" // trim(filename)) +#else + call PIO_syncfile(pio_file) +#endif + + gval_6d = 0 + do tstep=1,MAX_TIMES + start = 0 + count = 0 + + start(1) = 1 + count(1) = MAX_LEVS + start(2) = 1 + count(2) = MAX_GP + start(3) = 1 + count(3) = MAX_GP + start(4) = 1 + count(4) = MAX_DIM2 + start(5) = 1 + count(5) = MAX_ELEMS + start(6) = tstep + count(6) = 1 + ret = PIO_get_var(pio_file, pio_6dvar, start, count, gval_6d(:,:,:,:,:,tstep)) + PIO_TF_CHECK_ERR(ret, "Failed to get 6d var time slice:" // trim(filename)) + end do + + ! Special code to handle 6d vals is required since the framework + ! currently does not support comparing 6d arrays + do tstep=1,MAX_TIMES + do m=1,MAX_ELEMS + do l=1,MAX_DIM2 + PIO_TF_CHECK_VAL((gval_6d(:,:,:,l,m,tstep), exp_val_6d(:,:,:,l,m,tstep)), "Got wrong value (6d var)") + end do + end do + end do + + call PIO_closefile(pio_file) + call PIO_deletefile(pio_tf_iosystem_, filename); + end do + + if(allocated(iotypes)) then + deallocate(iotypes) + deallocate(iotype_descs) + end if + +PIO_TF_AUTO_TEST_SUB_END test_put_get_6d_var + ! Similar to test_put_get_md2mdplus1_var, but uses an unlimited time dimension instead PIO_TF_TEMPLATE PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_md2mdplus1_rec From 526352ada539256a10fbb25e086aca3cec54f200 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 17 Dec 2025 18:25:50 -0600 Subject: [PATCH 096/194] Free I/O desc list one at a time Since I/O desc list gets modified when finalizing the I/O desc, we now free the list one element (head) at a time --- src/clib/pio_lists.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/clib/pio_lists.cpp b/src/clib/pio_lists.cpp index 2def371c48..9fa5515537 100644 --- a/src/clib/pio_lists.cpp +++ b/src/clib/pio_lists.cpp @@ -505,8 +505,9 @@ static int spio_wait_async_iodesc_ops(io_desc_t *iodesc) int pio_delete_all_iodescs(int iosysid) { int ret = PIO_NOERR; - for(std::map::iterator iter = SPIO_Util::SPIO_Lists::GVars::pio_iodesc_list.begin(); - iter != SPIO_Util::SPIO_Lists::GVars::pio_iodesc_list.end(); ++iter){ + /* Delete the head of the list, one at a time - to delete all I/O descs */ + std::map::iterator iter = SPIO_Util::SPIO_Lists::GVars::pio_iodesc_list.begin(); + while(iter != SPIO_Util::SPIO_Lists::GVars::pio_iodesc_list.end()){ io_desc_t *iodesc = (*iter).second; ret = spio_wait_async_iodesc_ops(iodesc); if(ret != PIO_NOERR){ @@ -518,6 +519,9 @@ int pio_delete_all_iodescs(int iosysid) return pio_err(NULL, NULL, ret, __FILE__, __LINE__, "Deleting I/O descriptor (ioid = %d) failed. Error when freeing I/O decomp after waiting for async ops on I/O descriptor", iodesc->ioid); } + + /* Get the latest head */ + iter = SPIO_Util::SPIO_Lists::GVars::pio_iodesc_list.begin(); } SPIO_Util::SPIO_Lists::GVars::pio_iodesc_list.clear(); From 310ea95477f05717f70f0849057c07a4eb0495db Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 19 Dec 2025 11:29:48 -0600 Subject: [PATCH 097/194] Wait for async hdf5 ops before sync ops Ensure that we wait for async HDF5 ops to complete before proceeding with sync HDF5 ops --- src/clib/pio_file.cpp | 16 ++++++++ src/clib/pioc_support.cpp | 70 +++++++++++++++++++++++++++++++++-- src/clib/spio_async_utils.cpp | 35 ++++++++++++++++-- src/clib/spio_async_utils.hpp | 1 + 4 files changed, 114 insertions(+), 8 deletions(-) diff --git a/src/clib/pio_file.cpp b/src/clib/pio_file.cpp index eb9cdf817d..6262dd4008 100644 --- a/src/clib/pio_file.cpp +++ b/src/clib/pio_file.cpp @@ -968,6 +968,22 @@ int PIOc_closefile_impl(int ncid) if(ios->ioproc){ soft_close = true; } + else{ + /* Wait on all hdf5 async ops before a "hard close" */ + ierr = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ierr != PIO_NOERR){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Closing file (%s, ncid=%d) failed. Error sending async msg PIO_MSG_CLOSE_FILE", pio_get_fname_from_file(file), ncid); + } + } + } + else{ + /* Wait on all hdf5 async ops before a "hard close" */ + ierr = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ierr != PIO_NOERR){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Closing file (%s, ncid=%d) failed. Error sending async msg PIO_MSG_CLOSE_FILE", pio_get_fname_from_file(file), ncid); + } } #endif diff --git a/src/clib/pioc_support.cpp b/src/clib/pioc_support.cpp index d18ea193cc..05d52b48f6 100644 --- a/src/clib/pioc_support.cpp +++ b/src/clib/pioc_support.cpp @@ -28,6 +28,7 @@ #include "spio_hash.h" #include "pio_rearr_contig.hpp" #include "spio_decomp_logger.hpp" +#include "spio_async_utils.hpp" #include #include #include @@ -3115,6 +3116,7 @@ int spio_createfile_int(int iosysid, int *ncidp, const int *iotype, const char * return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, "Creating file (%s) failed. Error closing previous soft closed file", filename); } + #endif /* Allocate space for the file info. */ @@ -4819,9 +4821,17 @@ int PIOc_openfile_retry_impl(int iosysid, int *ncidp, int *iotype, const char *f #if PIO_USE_ASYNC_WR_THREAD ierr = spio_close_soft_closed_file(filename); if(ierr != PIO_NOERR){ - return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, + return pio_err(ios, NULL, ierr, __FILE__, __LINE__, "Creating file (%s) failed. Error closing previous soft closed file", filename); } + + if((*iotype == PIO_IOTYPE_HDF5) || (*iotype == PIO_IOTYPE_HDF5C)){ + ierr = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ierr != PIO_NOERR){ + return pio_err(ios, NULL, ierr, __FILE__, __LINE__, + "Creating file (%s) failed. Error waiting on all pending asynchronous HDF5 ops", filename); + } + } #endif /* Allocate space for the file info. */ @@ -6575,12 +6585,19 @@ int spio_hdf5_type_to_pio_type(hid_t ntype) int spio_hdf5_create(iosystem_desc_t *ios, file_desc_t *file, const char *filename) { - int mpierr = MPI_SUCCESS; + int mpierr = MPI_SUCCESS, ret = PIO_NOERR; assert(ios && file && filename); assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); assert(ios->ioproc); + /* FIXME: Relax this wait */ + ret = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ret != PIO_NOERR){ + return pio_err(ios, NULL, ret, __FILE__, __LINE__, + "Creating file (%s) failed. Error waiting on all pending asynchronous HDF5 ops", filename); + } + if (file->mode & PIO_NOCLOBBER) /* Check whether HDF5 file exists */ { struct stat sd; @@ -7112,11 +7129,22 @@ static inline int spio_add_nc_hidden_coord(iosystem_desc_t *ios, file_desc_t *fi int spio_hdf5_def_var(iosystem_desc_t *ios, file_desc_t *file, const char *name, nc_type xtype, int ndims, const int *dimidsp, int varid) { + int ret = PIO_NOERR; + assert(ios && file && name && ndims >= 0 && varid >= 0); assert((ndims == 0) || dimidsp); assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); assert(ios->ioproc); + /* FIXME: Relax this wait */ + ret = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ret != PIO_NOERR){ + return pio_err(ios, file, ret, __FILE__, __LINE__, + "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " + "Error waiting on all pending asynchronous HDF5 ops", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + /* Cache the dim sizes for HDF5 calls */ std::vector dim_sz(ndims), max_dim_sz(ndims); for(int i = 0; i < ndims; i++){ @@ -7198,12 +7226,21 @@ int spio_hdf5_def_var(iosystem_desc_t *ios, file_desc_t *file, const char *name, int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) { - int i; + int i = 0, ret = PIO_NOERR; assert(ios && file); assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); assert(ios->ioproc); + /* FIXME: Relax this wait */ + ret = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ret != PIO_NOERR){ + return pio_err(ios, file, ret, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Error waiting on all pending asynchronous HDF5 ops", + pio_get_fname_from_file(file), file->pio_ncid); + } + for (i = 0; i < file->hdf5_num_dims; i++) { /* For dimensions without an associated coordinate var, define them here. However since the @@ -7478,6 +7515,7 @@ int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) int spio_hdf5_put_att(iosystem_desc_t *ios, file_desc_t *file, int varid, const char *name, nc_type atttype, PIO_Offset len, const void *op) { + int ret = PIO_NOERR; hid_t attr_id; hid_t space_id; hsize_t asize = len; @@ -7489,6 +7527,15 @@ int spio_hdf5_put_att(iosystem_desc_t *ios, file_desc_t *file, int varid, const assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); assert(ios->ioproc); + /* FIXME: Relax this wait */ + ret = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ret != PIO_NOERR){ + return pio_err(ios, file, ret, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "Error waiting on all pending asynchronous HDF5 ops", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + if (varid == PIO_GLOBAL) loc_id = file->hdf5_file_id; else @@ -7641,6 +7688,7 @@ int spio_hdf5_put_var(iosystem_desc_t *ios, file_desc_t *file, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, nc_type xtype, const void *buf) { + int ret = PIO_NOERR; hsize_t dims[H5S_MAX_RANK]; hsize_t mdims[H5S_MAX_RANK]; @@ -7648,6 +7696,15 @@ int spio_hdf5_put_var(iosystem_desc_t *ios, file_desc_t *file, int varid, assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); assert(ios->ioproc); + /* FIXME: Relax this wait */ + ret = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ret != PIO_NOERR){ + return pio_err(ios, file, ret, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "Error waiting on all pending asynchronous HDF5 ops", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + hid_t file_space_id = H5Dget_space(file->hdf5_vars[varid].hdf5_dataset_id); if (file_space_id == H5I_INVALID_HID) { @@ -7844,12 +7901,17 @@ int spio_hdf5_put_var(iosystem_desc_t *ios, file_desc_t *file, int varid, int spio_hdf5_close(iosystem_desc_t *ios, file_desc_t *file) { - int i; + int i = 0; assert(ios && file); assert((file->iotype == PIO_IOTYPE_HDF5) || ((file->iotype == PIO_IOTYPE_HDF5C))); assert(ios->ioproc); + /* Since close is always an async op, when async thread is used, we do not need + * to explicitly wait for async ops to complete + * i.e., we don't need spio_wait_all_hdf5_async_ops() here + */ + if (H5Pclose(file->dxplid_coll) < 0) { return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, diff --git a/src/clib/spio_async_utils.cpp b/src/clib/spio_async_utils.cpp index 67202c56c2..619d65d6b7 100644 --- a/src/clib/spio_async_utils.cpp +++ b/src/clib/spio_async_utils.cpp @@ -1006,6 +1006,25 @@ static inline void update_reg_infos_start_frame(std::vector ®_in } } +namespace SPIO_Util{ + namespace GVars{ + std::atomic npend_hdf5_async_ops; + } // namespace GVars +} // namespace SPIO_Util + +int spio_wait_all_hdf5_async_ops(int iosysid) +{ + const int SLEEP_TIME_IN_MILLISECONDS = 500; + while(SPIO_Util::GVars::npend_hdf5_async_ops > 0){ + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME_IN_MILLISECONDS)); + if(SPIO_Util::GVars::npend_hdf5_async_ops > 0){ + PIOc_warn(iosysid, PIO_DEFAULT, __FILE__, __LINE__, "Continuing to wait on all HDF5 async ops..."); + } + } + + return PIO_NOERR; +} + int pio_iosys_async_op_hdf5_write(void *pdata) { /* FIXME: Add futures */ @@ -1222,6 +1241,7 @@ int pio_iosys_async_op_hdf5_write(void *pdata) iodesc->nasync_pend_ops--; file->npend_ops--; + SPIO_Util::GVars::npend_hdf5_async_ops--; return PIO_NOERR; } @@ -1318,6 +1338,11 @@ int pio_iosys_async_hdf5_write_op_add(file_desc_t *file, int nvars, int fndims, pnew->poke = pio_async_poke_func_unavail; pnew->free = pio_iosys_async_op_hdf5_free; + /* One more pending op using this iodesc & file */ + iodesc->nasync_pend_ops++; + file->npend_ops++; + SPIO_Util::GVars::npend_hdf5_async_ops++; + /* Get the mt queue and queue the async task */ ret = pio_async_tpool_op_add(pnew); if(ret != PIO_NOERR){ @@ -1326,10 +1351,6 @@ int pio_iosys_async_hdf5_write_op_add(file_desc_t *file, int nvars, int fndims, "Internal error while adding asynchronous pending operation to the thread pool (iosystem = %d). Adding the asynchronous operation failed", ios->iosysid); } - /* One more pending op using this iodesc & file */ - iodesc->nasync_pend_ops++; - file->npend_ops++; - return PIO_NOERR; } @@ -1339,6 +1360,7 @@ int pio_iosys_async_file_close_op_wait(void *pdata) file_desc_t *file = static_cast(pdata); assert(file); + //file->npend_ops--; if(file->npend_ops == 0){ ret = spio_hard_closefile(file->iosystem, file, false); if(ret != PIO_NOERR){ @@ -1356,6 +1378,8 @@ int pio_iosys_async_file_close_op_wait(void *pdata) } } + SPIO_Util::GVars::npend_hdf5_async_ops--; + return PIO_NOERR; } @@ -1385,6 +1409,9 @@ int pio_iosys_async_file_close_op_add(file_desc_t *file) pnew->poke = pio_async_poke_func_unavail; pnew->free = pio_iosys_async_file_close_op_free_no_op; + //file->npend_ops++; + SPIO_Util::GVars::npend_hdf5_async_ops++; + /* Get the mt queue and queue the async task */ ret = pio_async_tpool_op_add(pnew); if(ret != PIO_NOERR){ diff --git a/src/clib/spio_async_utils.hpp b/src/clib/spio_async_utils.hpp index 803eced34f..d79d95f896 100644 --- a/src/clib/spio_async_utils.hpp +++ b/src/clib/spio_async_utils.hpp @@ -29,5 +29,6 @@ int pio_iosys_async_file_close_op_add(file_desc_t *file); std::string pio_async_op_type_to_string(pio_async_op_type_t op); +int spio_wait_all_hdf5_async_ops(int iosysid); #endif // _SPIO_ASYNC_UTILS_HPP_ From abaadcf9aef127b430b6b748ea7a3e98f8f01f53 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 19 Dec 2025 11:31:03 -0600 Subject: [PATCH 098/194] Adding a sanity check for timer level Adding a util member function to do a sanity check on the timer level (useful for debugging) --- src/clib/spio_ltimer.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/clib/spio_ltimer.hpp b/src/clib/spio_ltimer.hpp index dc7786fbab..ae34ebe845 100644 --- a/src/clib/spio_ltimer.hpp +++ b/src/clib/spio_ltimer.hpp @@ -1,6 +1,8 @@ #ifndef __SPIO_LTIMER_HPP__ #define __SPIO_LTIMER_HPP__ +#include + namespace PIO_Util{ namespace SPIO_Ltimer_Utils{ /* A simple timer class */ @@ -17,6 +19,12 @@ namespace PIO_Util{ inline double get_stop_time(void ) const { return stop_; } /* Get elapsed wallclock time */ double get_wtime(void ) const; + + void sanity_check(const std::string &msg) const { + if(lvl_ != 0){ + std::cerr << "WARNING: Sanity check failed, trying to get timer before its stopped, level = " << lvl_ << "(" << msg.c_str() << ")\n"; + } + } private: /* Start time for the most recent start() call */ double start_; From 51e95eb8d5bfd3331941d293fcb5bd77d6217bd7 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 19 Dec 2025 13:40:18 -0600 Subject: [PATCH 099/194] ifdef HDF5 async code out Conditionally compile (ifdef _HDF5) HDF5-specific async util code based on whether HDF5 support is enabled --- src/clib/spio_async_utils.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/clib/spio_async_utils.cpp b/src/clib/spio_async_utils.cpp index 619d65d6b7..833ebf367f 100644 --- a/src/clib/spio_async_utils.cpp +++ b/src/clib/spio_async_utils.cpp @@ -977,6 +977,7 @@ struct Hdf5_wcache{ std::size_t fillbuf_sz; }; +#ifdef _HDF5 namespace Util{ /* Each variable writes out one or more regions of data. However all variables have the * same I/O decomposition and write the same regions (within the variable) of data. The @@ -1005,6 +1006,7 @@ static inline void update_reg_infos_start_frame(std::vector ®_in } } } +#endif // _HDF5 namespace SPIO_Util{ namespace GVars{ @@ -1027,6 +1029,7 @@ int spio_wait_all_hdf5_async_ops(int iosysid) int pio_iosys_async_op_hdf5_write(void *pdata) { +#ifdef _HDF5 /* FIXME: Add futures */ int ret = PIO_NOERR; Hdf5_wcache *wcache = static_cast(pdata); @@ -1244,10 +1247,15 @@ int pio_iosys_async_op_hdf5_write(void *pdata) SPIO_Util::GVars::npend_hdf5_async_ops--; return PIO_NOERR; +#else // _HDF5 + assert(0); + return PIO_EINTERNAL; +#endif // _HDF5 } void pio_iosys_async_op_hdf5_free(void *pdata) { +#ifdef _HDF5 Hdf5_wcache *wcache = static_cast(pdata); assert(wcache); @@ -1263,11 +1271,15 @@ void pio_iosys_async_op_hdf5_free(void *pdata) if(wcache->fillbuf){ brel(wcache->fillbuf); } free(wcache); +#else // _HDF5 + assert(0); +#endif // _HDF5 } int pio_iosys_async_hdf5_write_op_add(file_desc_t *file, int nvars, int fndims, const int *varids, io_desc_t *iodesc, int fill, const int *frame) { +#ifdef _HDF5 int ret = PIO_NOERR; assert(file && (nvars > 0) && (fndims > 0) && varids && iodesc); @@ -1352,6 +1364,10 @@ int pio_iosys_async_hdf5_write_op_add(file_desc_t *file, int nvars, int fndims, } return PIO_NOERR; +#else // _HDF5 + assert(0); + return PIO_EINTERNAL; +#endif // _HDF5 } int pio_iosys_async_file_close_op_wait(void *pdata) From 22e88de91fa0e1f0ee7d85af208e738c24410068 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 19 Dec 2025 14:16:16 -0600 Subject: [PATCH 100/194] Move freeing iodescs before iostats are freed Moving freeing I/O decomps before the file I/O stats are freed (since we update the I/O stats when I/O decomps are freed) --- src/clib/pioc.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/clib/pioc.cpp b/src/clib/pioc.cpp index 27bbeb200a..15021a4b4a 100644 --- a/src/clib/pioc.cpp +++ b/src/clib/pioc.cpp @@ -1891,17 +1891,7 @@ int PIOc_finalize_impl(int iosysid) #endif /* ifdef _HDF5 */ - free(ios->io_fstats); - - /* Free this memory that was allocated in init_intracomm. */ - if (ios->ioranks) - free(ios->ioranks); - LOG((3, "Freed ioranks.")); - if (ios->compranks) - free(ios->compranks); - LOG((3, "Freed compranks.")); - - /* Learn the number of open IO systems. */ + /* Find the number of open IO systems. */ if ((ierr = pio_num_iosystem(&niosysid))) { return pio_err(ios, NULL, ierr, __FILE__, __LINE__, @@ -1919,6 +1909,16 @@ int PIOc_finalize_impl(int iosysid) #endif LOG((2, "%d iosystems are still open.", niosysid)); + free(ios->io_fstats); + + /* Free this memory that was allocated in init_intracomm. */ + if (ios->ioranks) + free(ios->ioranks); + LOG((3, "Freed ioranks.")); + if (ios->compranks) + free(ios->compranks); + LOG((3, "Freed compranks.")); + /* Free the MPI groups. */ if (ios->compgroup != MPI_GROUP_NULL) From cd6311812f52ff312be4679da3a467330de1e10f Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 19 Dec 2025 19:06:34 -0600 Subject: [PATCH 101/194] Adding util to capture backtrace Adding a util function to capture and stringify stack trace --- src/clib/spio_dbg_ds.cpp | 24 ++++++++++++++++++++++++ src/clib/spio_dbg_utils.hpp | 3 +++ 2 files changed, 27 insertions(+) diff --git a/src/clib/spio_dbg_ds.cpp b/src/clib/spio_dbg_ds.cpp index cac0d766da..fae0cd1824 100644 --- a/src/clib/spio_dbg_ds.cpp +++ b/src/clib/spio_dbg_ds.cpp @@ -3,8 +3,10 @@ #include "pio_internal.h" #include "pio_types.hpp" #include "spio_dbg_utils.hpp" +#include "execinfo.h" #include +#include #include #include #include @@ -50,3 +52,25 @@ std::string SPIO_Util::Dbg_Util::get_iodesc_info(io_desc_t *iodesc) return ostr.str(); } + +void SPIO_Util::Dbg_Util::get_stack_trace(std::vector &st) +{ + const std::size_t MAX_STACK_DEPTH = 20; + std::array st_addrs; + + std::size_t st_sz = backtrace(st_addrs.data(), st_addrs.size()); + char **st_syms = backtrace_symbols(st_addrs.data(), st_sz); + + if(!st_syms){ return; } + + std::for_each(st_syms, st_syms + st_sz, [&st](char *sname) { st.push_back(sname); }); + + free(st_syms); +} + +std::string SPIO_Util::Dbg_Util::stack_trace_to_string(const std::vector &st) +{ + std::ostringstream ostr; + std::for_each(st.cbegin(), st.cend(), [&ostr](const std::string &str) { ostr << str << "\n"; }); + return ostr.str(); +} diff --git a/src/clib/spio_dbg_utils.hpp b/src/clib/spio_dbg_utils.hpp index e19ac151f6..749afb120d 100644 --- a/src/clib/spio_dbg_utils.hpp +++ b/src/clib/spio_dbg_utils.hpp @@ -65,6 +65,9 @@ namespace SPIO_Util{ } std::string get_iodesc_info(io_desc_t *ios); + + void get_stack_trace(std::vector &st); + std::string stack_trace_to_string(const std::vector &st); } // namespace Dbg_Util } // namespace SPIO_Util From a06a4ddf40082467abed0e55596f1b4da05a944a Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 19 Dec 2025 19:07:20 -0600 Subject: [PATCH 102/194] Stop timer when exiting freedecomp Adding missing stop for timer when exiting freedecomp function --- src/clib/pioc_support.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/clib/pioc_support.cpp b/src/clib/pioc_support.cpp index 05d52b48f6..bb8202d7d1 100644 --- a/src/clib/pioc_support.cpp +++ b/src/clib/pioc_support.cpp @@ -1808,6 +1808,7 @@ int PIOc_freedecomp_impl(int iosysid, int ioid) if(iodesc->nasync_pend_ops > 0){ /* Let I/O desc be freed during finalize */ + spio_ltimer_stop(ios->io_fstats->tot_timer_name); return PIO_NOERR; } From 37456111d1c7cb123874bcdaee5da78af43d1eb4 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 19 Dec 2025 19:09:44 -0600 Subject: [PATCH 103/194] Adding opt to capture stack trace for timers Adding util functions to capture and display stack trace during sanity checks for timers The assert for checking if the timer is stopped before querying the time is now re-enabled. (the code to capture stack trace is commented out by default) --- src/clib/spio_ltimer.cpp | 5 +++++ src/clib/spio_ltimer.hpp | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/clib/spio_ltimer.cpp b/src/clib/spio_ltimer.cpp index 1f87349471..c31a396d2e 100644 --- a/src/clib/spio_ltimer.cpp +++ b/src/clib/spio_ltimer.cpp @@ -8,6 +8,7 @@ #include "pio_internal.h" #include "spio_ltimer.h" #include "spio_ltimer.hpp" +#include "spio_dbg_utils.hpp" /* Global timer cache */ static std::map gtimers; @@ -19,6 +20,7 @@ void PIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer::start(void ) start_ = MPI_Wtime(); } lvl_++; + // push_stack_trace(); } void PIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer::stop(void ) @@ -34,6 +36,7 @@ void PIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer::stop(void ) stop_ = MPI_Wtime(); wtime_ += stop_ - start_; //start_ = 0.0; + // pop_stack_trace(); } double PIO_Util::SPIO_Ltimer_Utils::SPIO_ltimer::get_wtime(void ) const @@ -57,5 +60,7 @@ void spio_ltimer_stop(const char *timer_name) double spio_ltimer_get_wtime(const char *timer_name) { /* Note : If the timer is not present we return 0 */ + // gtimers[timer_name].sanity_check(timer_name); + return gtimers[timer_name].get_wtime(); } diff --git a/src/clib/spio_ltimer.hpp b/src/clib/spio_ltimer.hpp index ae34ebe845..0d6f4dddaf 100644 --- a/src/clib/spio_ltimer.hpp +++ b/src/clib/spio_ltimer.hpp @@ -2,6 +2,9 @@ #define __SPIO_LTIMER_HPP__ #include +#include +#include +#include "spio_dbg_utils.hpp" namespace PIO_Util{ namespace SPIO_Ltimer_Utils{ @@ -23,6 +26,10 @@ namespace PIO_Util{ void sanity_check(const std::string &msg) const { if(lvl_ != 0){ std::cerr << "WARNING: Sanity check failed, trying to get timer before its stopped, level = " << lvl_ << "(" << msg.c_str() << ")\n"; + if(st_.size() > 0){ + std::cerr << "Printing first (of " << st_.size() << ") stack traces:\n"; + std::cerr << SPIO_Util::Dbg_Util::stack_trace_to_string(st_[0]).c_str() << "\n"; + } } } private: @@ -36,6 +43,20 @@ namespace PIO_Util{ * recursive calls to this timer */ int lvl_; + + /* Stack traces of calls to timer - for debugging */ + std::vector > st_; + + void push_stack_trace(void ){ + std::vector st; + SPIO_Util::Dbg_Util::get_stack_trace(st); + st_.push_back(st); + } + + void pop_stack_trace(void ){ + assert(st_.size() > 0); + st_.pop_back(); + } }; } // namespace SPIO_Ltimer_Utils } // namespace PIO_Util From 04031d9a26d6bf31574117e32d9491fb11e777af Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 9 Jan 2026 11:44:56 -0600 Subject: [PATCH 104/194] Moving HDF5 utils to a separate file Moving all HDF5 util functions from pioc_support.cpp to a separate file. No code change, just moving code around --- src/clib/CMakeLists.txt | 2 +- src/clib/pio_darray_int.cpp | 1 + src/clib/pio_file.cpp | 1 + src/clib/pio_getput_int.cpp | 1 + src/clib/pio_internal.h | 27 - src/clib/pio_nc.cpp | 1 + src/clib/pioc_support.cpp | 1447 +------------------------------- src/clib/spio_async_utils.cpp | 1 + src/clib/spio_hdf5_utils.cpp | 1479 +++++++++++++++++++++++++++++++++ src/clib/spio_hdf5_utils.hpp | 33 + 10 files changed, 1519 insertions(+), 1474 deletions(-) create mode 100644 src/clib/spio_hdf5_utils.cpp create mode 100644 src/clib/spio_hdf5_utils.hpp diff --git a/src/clib/CMakeLists.txt b/src/clib/CMakeLists.txt index 6c32e6845b..0d2e0f979e 100644 --- a/src/clib/CMakeLists.txt +++ b/src/clib/CMakeLists.txt @@ -46,7 +46,7 @@ set (pio_lib_src spio_ltimer.cpp spio_serializer.cpp spio_file_mvcache.cpp spio_tracer.cpp spio_tracer_mdata.cpp spio_tracer_decomp.cpp spio_rearrange_any.cpp spio_dt_converter.cpp - spio_async_tpool.cpp spio_async_utils.cpp) + spio_async_tpool.cpp spio_async_utils.cpp spio_hdf5_utils.cpp) # Add sources for libpioc.a add_library (pioc ${pio_api_src} ${pio_lib_src}) diff --git a/src/clib/pio_darray_int.cpp b/src/clib/pio_darray_int.cpp index a64cd96fca..7621af7e91 100644 --- a/src/clib/pio_darray_int.cpp +++ b/src/clib/pio_darray_int.cpp @@ -21,6 +21,7 @@ #include "spio_file_mvcache.h" #include "spio_dbg_utils.hpp" #include "spio_dt_converter.hpp" +#include "spio_hdf5_utils.hpp" /* 10MB default limit. */ extern PIO_Offset pio_buffer_size_limit; diff --git a/src/clib/pio_file.cpp b/src/clib/pio_file.cpp index 6262dd4008..ab8bb4075f 100644 --- a/src/clib/pio_file.cpp +++ b/src/clib/pio_file.cpp @@ -12,6 +12,7 @@ #include #include #include +#include "spio_hdf5_utils.hpp" #ifdef _ADIOS2 #include "../../tools/adios2pio-nm/adios2pio-nm-lib-c.h" diff --git a/src/clib/pio_getput_int.cpp b/src/clib/pio_getput_int.cpp index adb93acfb7..3ebacd0e3f 100644 --- a/src/clib/pio_getput_int.cpp +++ b/src/clib/pio_getput_int.cpp @@ -14,6 +14,7 @@ #include #include "spio_io_summary.h" #include "spio_hash.h" +#include "spio_hdf5_utils.hpp" /** * Write a netCDF attribute of any type, converting to any type. diff --git a/src/clib/pio_internal.h b/src/clib/pio_internal.h index 491d55db9e..967f6fe8cb 100644 --- a/src/clib/pio_internal.h +++ b/src/clib/pio_internal.h @@ -433,12 +433,6 @@ extern "C" { const adios2_constant_dims constant_dims); #endif -#ifdef _HDF5 - hid_t nc_type_to_hdf5_type(nc_type xtype); - int spio_hdf5_type_to_pio_type(hid_t xtype); - PIO_Offset hdf5_get_nc_type_size(nc_type xtype); -#endif - /* Asynchronous I/O services start with the following seq num */ static const int PIO_MSG_START_SEQ_NUM = 1024; /** These are the messages that can be sent over the intercomm when @@ -713,27 +707,6 @@ const char *pio_get_vnames_from_file_id(int pio_file_id, const char *pio_async_msg_to_string(int msg); #define PIO_IS_NULL(p) ((p) ? "not NULL" : "NULL") -/* Some helper functions internally used by HDF5 IO type */ -#ifdef _HDF5 -hid_t spio_nc_type_to_hdf5_type(nc_type xtype); - -int spio_hdf5_create(iosystem_desc_t *ios, file_desc_t *file, const char *filename); - -int spio_hdf5_def_var(iosystem_desc_t *ios, file_desc_t *file, const char *name, - nc_type xtype, int ndims, const int *dimidsp, int varid); - -int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file); - -int spio_hdf5_put_att(iosystem_desc_t *ios, file_desc_t *file, int varid, const char *name, - nc_type atttype, PIO_Offset len, const void *op); - -int spio_hdf5_put_var(iosystem_desc_t *ios, file_desc_t *file, int varid, - const PIO_Offset *start, const PIO_Offset *count, - const PIO_Offset *stride, nc_type xtype, const void *buf); - -int spio_hdf5_close(iosystem_desc_t *ios, file_desc_t *file); -#endif - int spio_find_start_count(int ndims, const int *dimlen, int fndims, var_desc_t *vdesc, io_region *region, size_t *start, size_t *count); diff --git a/src/clib/pio_nc.cpp b/src/clib/pio_nc.cpp index a218276ce3..58f2899e9e 100644 --- a/src/clib/pio_nc.cpp +++ b/src/clib/pio_nc.cpp @@ -21,6 +21,7 @@ #include "pio_timer.h" #endif #include "spio_io_summary.h" +#include "spio_hdf5_utils.hpp" const char spio_nc_fillvalue_aname[] = "_FillValue"; diff --git a/src/clib/pioc_support.cpp b/src/clib/pioc_support.cpp index bb8202d7d1..84dc98e2b8 100644 --- a/src/clib/pioc_support.cpp +++ b/src/clib/pioc_support.cpp @@ -29,22 +29,15 @@ #include "pio_rearr_contig.hpp" #include "spio_decomp_logger.hpp" #include "spio_async_utils.hpp" +#include "spio_hdf5_utils.hpp" #include #include #include #include #include -/* Include headers for HDF5 compression filters */ #if PIO_USE_HDF5 #include -#ifdef _SPIO_HAS_H5Z_ZFP -#include "H5Zzfp_lib.h" -#include "H5Zzfp_props.h" -#endif -#ifdef _SPIO_HAS_H5Z_BLOSC2 -#include "blosc2_filter.h" -#endif #endif #define VERSNO 2001 @@ -6538,1441 +6531,3 @@ PIO_Offset spio_get_nc_type_size(nc_type xtype) return -1; } - -#ifdef _HDF5 -hid_t spio_nc_type_to_hdf5_type(nc_type xtype) -{ - switch (xtype) - { - case NC_BYTE: return H5T_NATIVE_UINT8; - case NC_UBYTE: return H5T_NATIVE_UCHAR; - case NC_CHAR: return H5T_NATIVE_CHAR; - case NC_SHORT: return H5T_NATIVE_SHORT; - case NC_USHORT: return H5T_NATIVE_USHORT; - case NC_INT: return H5T_NATIVE_INT; - case NC_UINT: return H5T_NATIVE_UINT; - case NC_FLOAT : return H5T_NATIVE_FLOAT; - case NC_DOUBLE: return H5T_NATIVE_DOUBLE; - case NC_INT64: return H5T_NATIVE_INT64; - case NC_UINT64: return H5T_NATIVE_UINT64; - default: return H5I_INVALID_HID; - } - - return H5I_INVALID_HID; -} - -int spio_hdf5_type_to_pio_type(hid_t ntype) -{ -// hid_t ntype = H5Tget_native_type(xtype, H5T_DIR_DEFAULT); - - /* switch() does not work with HDF5 "types" */ - if(H5Tequal(ntype, H5T_NATIVE_UINT8)) { return PIO_BYTE; } - else if(H5Tequal(ntype, H5T_NATIVE_UCHAR)) { return PIO_UBYTE; } - else if(H5Tequal(ntype, H5T_NATIVE_CHAR)) { return PIO_CHAR; } - else if(H5Tequal(ntype, H5T_NATIVE_SHORT)) { return PIO_SHORT; } - else if(H5Tequal(ntype, H5T_NATIVE_USHORT)) { return PIO_USHORT; } - else if(H5Tequal(ntype, H5T_NATIVE_INT)) { return PIO_INT; } - else if(H5Tequal(ntype, H5T_NATIVE_UINT)) { return PIO_UINT; } - else if(H5Tequal(ntype, H5T_NATIVE_FLOAT)) { return PIO_FLOAT; } - else if(H5Tequal(ntype, H5T_NATIVE_DOUBLE)) { return PIO_DOUBLE; } - else if(H5Tequal(ntype, H5T_NATIVE_INT64)) { return PIO_INT64; } - else if(H5Tequal(ntype, H5T_NATIVE_UINT64)) { return PIO_UINT64; } - else{ - assert(0); - } - - return PIO_NAT; -} - -int spio_hdf5_create(iosystem_desc_t *ios, file_desc_t *file, const char *filename) -{ - int mpierr = MPI_SUCCESS, ret = PIO_NOERR; - - assert(ios && file && filename); - assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); - assert(ios->ioproc); - - /* FIXME: Relax this wait */ - ret = spio_wait_all_hdf5_async_ops(ios->iosysid); - if(ret != PIO_NOERR){ - return pio_err(ios, NULL, ret, __FILE__, __LINE__, - "Creating file (%s) failed. Error waiting on all pending asynchronous HDF5 ops", filename); - } - - if (file->mode & PIO_NOCLOBBER) /* Check whether HDF5 file exists */ - { - struct stat sd; - if (0 == stat(filename, &sd)) - { - return pio_err(ios, NULL, PIO_EEXIST, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The HDF5 file already exists and PIO_NOCLOBBER mode is specified", - filename); - } - } - else - { - /* Delete HDF5 file if it exists */ - if (ios->io_rank == 0) - { - struct stat sd; - if (0 == stat(filename, &sd)) - unlink(filename); - } - - /* Make sure that no task is trying to operate on the - * HDF5 file while it is being deleted */ - if ((mpierr = MPI_Barrier(ios->io_comm))) - { - return check_mpi(ios, file, mpierr, __FILE__, __LINE__); - } - } - - if (ios->info == MPI_INFO_NULL) - { - if ((mpierr = MPI_Info_create(&ios->info))) - { - return check_mpi(ios, file, mpierr, __FILE__, __LINE__); - } - } - - hid_t fcpl_id = H5Pcreate(H5P_FILE_CREATE); - if (fcpl_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new file creation property list", - filename); - } - - if (H5Pset_link_creation_order(fcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set tracking and indexing of link creation order", - filename); - } - - /* H5DSattach_scale calls (even with MPI_Barrier) might fail or hang if attribute creation - * order is tracked or indexed. Before we have a better workaround, temporarily disable - * tracking and indexing of attribute creation order. */ -#if 0 - if (H5Pset_attr_creation_order(fcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set tracking and indexing of attribute creation order", - filename); - } -#endif - - hid_t fapl_id = H5Pcreate(H5P_FILE_ACCESS); - if (fapl_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new file access property list", - filename); - } - - if (H5Pset_fapl_mpio(fapl_id, ios->io_comm, ios->info) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to store the user-supplied MPI IO parameters", - filename); - } - - file->hdf5_file_id = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl_id, fapl_id); - if (file->hdf5_file_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new HDF5 file", - filename); - } - - if (H5Pclose(fcpl_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to close a file creation property list", - filename); - } - - if (H5Pclose(fapl_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to close a file access property list", - filename); - } - - /* Set up collective dataset transfer property list */ - file->dxplid_coll = H5Pcreate(H5P_DATASET_XFER); - if (file->dxplid_coll == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new dataset transfer property list (collective data transfer)", - filename); - } - - if (H5Pset_dxpl_mpio(file->dxplid_coll, H5FD_MPIO_COLLECTIVE) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set data transfer mode to collective", - filename); - } - - /* Set up independent dataset transfer property list */ - file->dxplid_indep = H5Pcreate(H5P_DATASET_XFER); - if (file->dxplid_indep == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new dataset transfer property list (independent data transfer)", - filename); - } - - if (H5Pset_dxpl_mpio(file->dxplid_indep, H5FD_MPIO_COLLECTIVE) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set data transfer mode to collective", - filename); - } - - if (H5Pset_dxpl_mpio_collective_opt(file->dxplid_indep, H5FD_MPIO_INDIVIDUAL_IO) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set data transfer mode to individual I/O", - filename); - } - /* Writing _NCProperties attribute */ - const char* attr_name = "_NCProperties"; - char nc_properties[PIO_MAX_NAME]; - unsigned int major, minor, release; - - if (H5get_libversion(&major, &minor, &release) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to retrieve the the version of the HDF5 library", - filename); - } - - snprintf(nc_properties, PIO_MAX_NAME, - "version=2,scorpio=%d.%d.%d,hdf5=%1u.%1u.%1u", - PIO_VERSION_MAJOR, PIO_VERSION_MINOR, PIO_VERSION_PATCH, - major, minor, release); - - hid_t attr_id; - hsize_t asize = strlen(nc_properties); - hid_t loc_id = file->hdf5_file_id; - - hid_t space_id = H5Screate(H5S_SCALAR); - if (space_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new scalar dataspace", - filename); - } - - hid_t h5_string_type = H5Tcopy(H5T_C_S1); - if (h5_string_type == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to make a copy of the predefined string datatype in C", - filename); - } - - assert(asize > 0); - if (H5Tset_size(h5_string_type, asize) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set the total size (%ld bytes) for a derived C-style string datatype", - filename, asize); - } - - if (H5Tset_strpad(h5_string_type, H5T_STR_NULLTERM) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to define the type of padding (NULL-terminated) used for a derived C-style string datatype", - filename); - } - - if (H5Tset_cset(h5_string_type, H5T_CSET_ASCII) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set the character set (US ASCII) to be used in a derived C-style string datatype", - filename); - } - - /* H5Aexists() returns zero (false), a positive (true) or a negative (failure) value */ - htri_t att_exists = H5Aexists(loc_id, attr_name); - if (att_exists > 0) - { - assert(0); - } - else if (att_exists == 0) - { - attr_id = H5Acreate2(loc_id, attr_name, h5_string_type, space_id, H5P_DEFAULT, H5P_DEFAULT); - if (attr_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new attribute (%s) attached to the file", - filename, attr_name); - } - } - else - { - /* Error determining whether an attribute with a given name exists on an object */ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to determine whether an attribute (%s) exists on the file", - filename, attr_name); - } - - if (H5Awrite(attr_id, h5_string_type, nc_properties) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to write an attribute (%s) attached to the file", - filename, attr_name); - } - - if (H5Sclose(space_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a scalar dataspace", - filename); - } - - if (H5Aclose(attr_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to close an attribute (%s) attached to the file", - filename, attr_name); - } - - if (H5Tclose(h5_string_type) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a derived C-style string datatype " - "used by an attribute (%s) attached to the file", - filename, attr_name); - } - - return PIO_NOERR; -} - -/* Create HDF5 dataset property ID */ -static hid_t spio_create_hdf5_dataset_pid(iosystem_desc_t *ios, file_desc_t *file, const char *var_name, const std::vector &max_dim_sz, nc_type var_type) -{ - herr_t ret; - hid_t dpid = H5I_INVALID_HID; - - std::size_t var_ndims = max_dim_sz.size(); - - assert((ios != NULL) && (file != NULL) && (var_ndims >= 0)); - - bool var_has_more_than_four_dims = (max_dim_sz.size() > 4) ? true : false; - bool var_has_only_unlimited_dims = true; - bool var_is_scalar = true; - for(std::vector::const_iterator citer = max_dim_sz.cbegin(); citer != max_dim_sz.cend(); ++citer){ - if(*citer != H5S_UNLIMITED){ - var_has_only_unlimited_dims = false; - if(*citer != 1) { var_is_scalar = false; } - } - } - - /* Initialize the compression filter property list */ - dpid = H5Pcreate(H5P_DATASET_CREATE); - assert(dpid != H5I_INVALID_HID); - - /* We currently support compression for non-scalar data */ - if(file->iotype != PIO_IOTYPE_HDF5C) return dpid; - if((var_ndims < 1) || (var_type == NC_CHAR)){ - std::string msg("Disabling HDF5 compression for variable"); - msg += std::string("(name=") + std::string(var_name) + std::string(", file=") + std::string(pio_get_fname_from_file(file)) + std::string(")"); - msg += (var_ndims < 1) ? std::string(" since its a scalar variable") : std::string(" since its a string/char variable"); - PIOc_warn(ios->iosysid, file->fh, __FILE__, __LINE__, msg.c_str()); - return dpid; - } - - /* Check if any variables have compression disabled by the user */ - /* FIXME: Variables written out in a chunk size different from the one defined can cause hangs - * e.g. E3SM variables : decomp_type, numlev, hwrt_prec, avgflag, fillvalue, - * meridional_complement, zonal_complement - */ -#ifndef SPIO_NO_CXX_REGEX - std::regex vname_override_rgx(SPIO_OVERRIDE_HDF5_COMPRESSION_VNAME_REGEX); - if(var_name && std::regex_match(std::string(var_name), vname_override_rgx)){ - std::string msg("Disabling HDF5 compression for variable"); - msg += std::string("(name=") + std::string(var_name) + std::string(", file=") + std::string(pio_get_fname_from_file(file)) + std::string(")"); - msg += std::string(" since it matches the user specified regex"); - msg += std::string(" (SPIO_OVERRIDE_HDF5_COMPRESSION_VNAME_REGEX=\"") + std::string(SPIO_OVERRIDE_HDF5_COMPRESSION_VNAME_REGEX) + std::string("\")"); - PIOc_warn(ios->iosysid, file->fh, __FILE__, __LINE__, msg.c_str()); - return dpid; - } -#endif - -#ifdef _SPIO_HDF5_USE_COMPRESSION - -#ifdef _SPIO_HDF5_USE_LOSSY_COMPRESSION - -#ifdef _SPIO_HAS_H5Z_ZFP - /* Avoid ZFP compression for vars with only unlimited dims */ - if(var_has_only_unlimited_dims || var_is_scalar || var_has_more_than_four_dims){ - std::string msg("Disabling HDF5 ZFP compression for variable"); - msg += std::string("(name=") + std::string(var_name) + std::string(", file=") + std::string(pio_get_fname_from_file(file)) + std::string(")"); - msg += (var_has_only_unlimited_dims) ? std::string(" since it only has unlimited dims") : - ((var_is_scalar) ? std::string(" since it is essentially a scalar variable") : std::string(" since variable has more than 4 dimensions")); - PIOc_warn(ios->iosysid, file->fh, __FILE__, __LINE__, msg.c_str()); - return dpid; - } - - if(SPIO_HDF5_ZFP_COMPRESSION_MODE == "H5Z_ZFP_MODE_RATE"){ - /* Lossy compression : Fixed bit rate : Number of bits used for compressed values is fixed, e.g. 16 */ - ret = H5Pset_zfp_rate(dpid, SPIO_HDF5_ZFP_COMPRESSION_RATE); - if(ret < 0){ - PIOc_warn(ios->iosysid, file->fh, __FILE__, __LINE__, "Setting HDF5 ZFP filter compression rate failed (ignoring specific compression bit rate)"); - } - } - else if(SPIO_HDF5_ZFP_COMPRESSION_MODE == "H5Z_ZFP_MODE_PRECISION"){ - /* Lossy compression : Fixed precision Variable bit rate : Number of bits used for original value is fixed. e.g. 16 */ - ret = H5Pset_zfp_precision(dpid, SPIO_HDF5_ZFP_PRECISION); - if(ret < 0){ - PIOc_warn(ios->iosysid, file->fh, __FILE__, __LINE__, "Setting HDF5 ZFP filter relative error bound failed (continuing with the default error bounds)"); - } - } - else if(SPIO_HDF5_ZFP_COMPRESSION_MODE == "H5Z_ZFP_MODE_ACCURACY"){ - /* Lossy compression : Fixed accuracy Variable bit rate : Absolute error between original and compressed values is bound e.g. 0.001 */ - ret = H5Pset_zfp_accuracy(dpid, SPIO_HDF5_ZFP_ACCURACY); - if(ret < 0){ - PIOc_warn(ios->iosysid, file->fh, __FILE__, __LINE__, "Setting HDF5 ZFP filter absolute error bound failed (continuing with the default error bounds)"); - } - } - else if(SPIO_HDF5_ZFP_COMPRESSION_MODE == "H5Z_ZFP_MODE_REVERSIBLE"){ - /* Lossless compression */ - ret = H5Pset_zfp_reversible(dpid); - if(ret < 0){ - PIOc_warn(ios->iosysid, file->fh, __FILE__, __LINE__, "Setting HDF5 ZFP filter for lossless compression failed (ignoring compression option)"); - } - } -#endif - -#else /* lossless compression, ifdef _SPIO_HDF5_USE_LOSSY_COMPRESSION */ - -#ifdef _SPIO_HAS_H5Z_BLOSC2 - /* Lossless compression : Default Blosc2 + ZSTD */ - unsigned int cd_values[7]; - cd_values[4] = SPIO_HDF5_BLOSC2_COMPRESSION_LEVEL; // compression level - cd_values[5] = SPIO_HDF5_BLOSC2_SHUFFLE_METHOD; // shuffle option - cd_values[6] = SPIO_HDF5_BLOSC2_COMPRESSION_LIBRARY; // Use ZSTD for compression - ret = H5Pset_filter(dpid, FILTER_BLOSC2, H5Z_FLAG_OPTIONAL, 7, cd_values); - if(ret < 0){ - PIOc_warn(ios->iosysid, file->fh, __FILE__, __LINE__, "User requested lossless compression, but setting HDF5 Blosc2 filter failed. Writing data without compression"); - } -#endif - -#endif /* ifdef _SPIO_HDF5_USE_LOSSY_COMPRESSION */ - -#endif /* ifdef _SPIO_HDF5_USE_COMPRESSION */ - - /* By default HDF5 does not track the order of creation of the attributes. So the attributes - * appear based on the alphanumeric order, of the attribute name, in the file. However, - * H5DSattach_scale calls (even with MPI_Barrier) might fail or hang if attribute creation - * order is tracked or indexed. Before we have a better workaround, temporarily disable - * tracking and indexing of attribute creation order. - */ -#if 0 - if(H5Pset_attr_creation_order(dcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set tracking and indexing of attribute creation order", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } -#endif - - return dpid; -} - -/* Get default chunk size (no of elems) - across each dimension - for variable data. The - * max chunk size (across all dimensions) is specified via PIO_CHUNK_SIZE (in bytes) - */ -static inline std::vector spio_get_dim_chunk_sz(const std::vector &dim_sz, nc_type xtype) -{ - std::size_t ndims = dim_sz.size(); - std::vector dim_chunk_sz = dim_sz; - - /* Unlimited dimensions have a chunk size of 1 */ - std::transform(dim_chunk_sz.begin(), dim_chunk_sz.end(), dim_chunk_sz.begin(), - [](hsize_t i) { return (i != H5S_UNLIMITED) ? i : 1; }); - - /* No chunking for scalars and 1D vars */ - if(ndims <= 1){ - return dim_chunk_sz; - } - - /* Number of elements corresponding to PIO_CHUNK_SIZE */ - double chunk_nelems = static_cast(PIO_CHUNK_SIZE)/static_cast(spio_get_nc_type_size(xtype)); - /* Assuming that elements are evenly distributed across all non-unlimited dimensions, - * Total (across all dimensions) chunked elements = (d * d * ...(n -1) times), where d is the size of each - * dimension - */ - hsize_t chunk_per_dim_nelems = static_cast(pow(chunk_nelems, 1.0/(ndims - 1) )); - - for(std::size_t i = 0; i < ndims; i++){ - /* Chunk size across UNLIMITED dimension is 1 */ - dim_chunk_sz[i] = (dim_sz[i] != H5S_UNLIMITED) ? (std::min(chunk_per_dim_nelems, dim_sz[i])) : 1; - } - - return dim_chunk_sz; -} - -/* Create an HDF5 string type - ASCII + null terminated */ -static inline hid_t spio_create_hdf5_str_type(void ) -{ - hid_t st = H5Tcopy(H5T_C_S1); - if(st != H5I_INVALID_HID){ - if(H5Tset_strpad(st, H5T_STR_NULLTERM) < 0){ - H5Tclose(st); - return H5I_INVALID_HID; - } - if(H5Tset_cset(st, H5T_CSET_ASCII) < 0){ - H5Tclose(st); - return H5I_INVALID_HID; - } - } - - return st; -} - -/* Write a hidden coordinates attribute (_Netcdf4Coordinates), which lists the dimids of the variable. */ -static inline int spio_add_nc_hidden_coord(iosystem_desc_t *ios, file_desc_t *file, int varid, - int ndims, const int *dimidsp) -{ - assert(ios && file && (varid >= 0) && (ndims >= 0)); - - /* No coordinate atttribute for scalars */ - if(ndims == 0) return PIO_NOERR; - - assert(dimidsp); - - /* Writing "_Netcdf4Coordinates" hidden attribute. This attribute stores the dimension ids of the - * variable dimensions in an integer array. - * This attribute is required for NetCDF to read HDF5 output - */ - const char* attr_name = "_Netcdf4Coordinates"; - - /* Sanity check : Ensure that "_Netcdf4Coordinates" attribute does not exist */ - htri_t attr_exists = H5Aexists(file->hdf5_vars[varid].hdf5_dataset_id, attr_name); - assert(attr_exists == 0); - - /* Create dataspace for the attribute i.e., space for integer array to store the dimension ids */ - std::array coords_len = {static_cast(ndims)}; - hid_t coords_space_id = H5Screate_simple(1, coords_len.data(), NULL); - if(coords_space_id == H5I_INVALID_HID){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new simple dataspace", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - /* Create the hidden attribute */ - hid_t coords_att_id = H5Acreate2(file->hdf5_vars[varid].hdf5_dataset_id, attr_name, - H5T_NATIVE_INT, coords_space_id, H5P_DEFAULT, H5P_DEFAULT); - if(coords_att_id == H5I_INVALID_HID){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new attribute (%s) attached to the variable", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, attr_name); - } - - /* Write the dimension ids */ - if(H5Awrite(coords_att_id, H5T_NATIVE_INT, dimidsp) < 0){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to write an attribute (%s) attached to the variable", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, attr_name); - } - - if(H5Aclose(coords_att_id) < 0){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to close an attribute (%s) attached to the variable", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, attr_name); - } - - if(H5Sclose(coords_space_id) < 0){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a simple dataspace", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - return PIO_NOERR; -} - -int spio_hdf5_def_var(iosystem_desc_t *ios, file_desc_t *file, const char *name, - nc_type xtype, int ndims, const int *dimidsp, int varid) -{ - int ret = PIO_NOERR; - - assert(ios && file && name && ndims >= 0 && varid >= 0); - assert((ndims == 0) || dimidsp); - assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); - assert(ios->ioproc); - - /* FIXME: Relax this wait */ - ret = spio_wait_all_hdf5_async_ops(ios->iosysid); - if(ret != PIO_NOERR){ - return pio_err(ios, file, ret, __FILE__, __LINE__, - "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " - "Error waiting on all pending asynchronous HDF5 ops", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - /* Cache the dim sizes for HDF5 calls */ - std::vector dim_sz(ndims), max_dim_sz(ndims); - for(int i = 0; i < ndims; i++){ - if(file->hdf5_dims[dimidsp[i]].len != PIO_UNLIMITED){ - dim_sz[i] = max_dim_sz[i] = file->hdf5_dims[dimidsp[i]].len; - } - else{ - dim_sz[i] = 1; - max_dim_sz[i] = H5S_UNLIMITED; - } - } - - /* Create HDF5 dataset (and optionally add filters as needed) */ - hid_t dcpl_id = spio_create_hdf5_dataset_pid(ios, file, name, max_dim_sz, xtype); - if(dcpl_id == H5I_INVALID_HID){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new dataset creation property list", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - file->hdf5_vars[varid].hdf5_type = (xtype == NC_CHAR) ? spio_create_hdf5_str_type() : spio_nc_type_to_hdf5_type(xtype); - assert(file->hdf5_vars[varid].hdf5_type != H5I_INVALID_HID); - - /* Set default chunk size for variable data */ - if(ndims > 0){ - if(H5Pset_chunk(dcpl_id, ndims, spio_get_dim_chunk_sz(max_dim_sz, xtype).data()) < 0){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set the size of the chunks used to store a chunked layout dataset", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } - } - - /* Create a simple dataspace to define the global variable dimensions */ - hid_t sid = H5Screate_simple(ndims, dim_sz.data(), max_dim_sz.data()); - if(sid == H5I_INVALID_HID){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new simple dataspace", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - /* Define the variable */ - const char* dataset_name = (file->hdf5_vars[varid].alt_name == NULL)? name : file->hdf5_vars[varid].alt_name; - file->hdf5_vars[varid].hdf5_dataset_id = H5Dcreate2(file->hdf5_file_id, dataset_name, file->hdf5_vars[varid].hdf5_type, - sid, H5P_DEFAULT, dcpl_id, H5P_DEFAULT); - if(file->hdf5_vars[varid].hdf5_dataset_id < 0){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new dataset (%s) for the variable", - name, varid, pio_get_fname_from_file(file), file->pio_ncid, dataset_name); - } - - if(H5Sclose(sid) < 0){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a simple dataspace", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - if(H5Pclose(dcpl_id) < 0){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to close a dataset creation property list", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - /* Add a hidden attribute, "_Netcdf4Coordinates", to store var dimension ids so that NetCDF can read the var */ - if(spio_add_nc_hidden_coord(ios, file, varid, ndims, dimidsp) != PIO_NOERR){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " - "Adding NetCDF hidden coordinate attribute failed", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - return PIO_NOERR; -} - -int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) -{ - int i = 0, ret = PIO_NOERR; - - assert(ios && file); - assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); - assert(ios->ioproc); - - /* FIXME: Relax this wait */ - ret = spio_wait_all_hdf5_async_ops(ios->iosysid); - if(ret != PIO_NOERR){ - return pio_err(ios, file, ret, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "Error waiting on all pending asynchronous HDF5 ops", - pio_get_fname_from_file(file), file->pio_ncid); - } - - for (i = 0; i < file->hdf5_num_dims; i++) - { - /* For dimensions without an associated coordinate var, define them here. However since the - * the user can call redef() multiple times define it only its not already defined/valid - */ - if (!file->hdf5_dims[i].has_coord_var && (file->hdf5_dims[i].hdf5_dataset_id == H5I_INVALID_HID)) - { - hid_t space_id, dcpl_id = H5I_INVALID_HID, dimscale_id; - hsize_t dims[1], max_dims[1], chunk_dims[1] = {1}; - - dcpl_id = H5Pcreate(H5P_DATASET_CREATE); - if (dcpl_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new dataset creation property list", - pio_get_fname_from_file(file), file->pio_ncid); - } - - /* H5DSattach_scale calls (even with MPI_Barrier) might fail or hang if attribute creation - * order is tracked or indexed. Before we have a better workaround, temporarily disable - * tracking and indexing of attribute creation order. */ -#if 0 - if (H5Pset_attr_creation_order(dcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set tracking and indexing of attribute creation order", - pio_get_fname_from_file(file), file->pio_ncid); - } -#endif - - /* Set size of dataset to size of dimension. */ - max_dims[0] = dims[0] = file->hdf5_dims[i].len; - - /* If this dimension scale is unlimited, set up chunking with a chunksize of 1. */ - if (max_dims[0] == PIO_UNLIMITED) - { - max_dims[0] = H5S_UNLIMITED; - - if (H5Pset_chunk(dcpl_id, 1, chunk_dims) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set the size of the chunks used to store a chunked layout dataset", - pio_get_fname_from_file(file), file->pio_ncid); - } - } - - space_id = H5Screate_simple(1, dims, max_dims); - if (space_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new simple dataspace", - pio_get_fname_from_file(file), file->pio_ncid); - } - - /* Create a dataset that will be converted to a dimension scale. */ - dimscale_id = H5Dcreate2(file->hdf5_file_id, file->hdf5_dims[i].name, H5T_IEEE_F32BE, - space_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT); - if (dimscale_id < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new dataset (%s) that will be converted to a dimension scale", - pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_dims[i].name); - } - - char dimscale_name[PIO_MAX_NAME]; - snprintf(dimscale_name, PIO_MAX_NAME, "%s%10d", "This is a netCDF dimension but not a netCDF variable.", (int)dims[0]); - - if (H5DSset_scale(dimscale_id, dimscale_name) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to convert a dataset (for dimension %s) to a dimension scale", - pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_dims[i].name); - } - - file->hdf5_dims[i].hdf5_dataset_id = dimscale_id; - - /* Write a special attribute (_Netcdf4Dimid) for the netCDF-4 dimension ID. */ - hid_t dimid_att_id; - htri_t attr_exists; - - hid_t dimid_space_id = H5Screate(H5S_SCALAR); - if (dimid_space_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new scalar dataspace", - pio_get_fname_from_file(file), file->pio_ncid); - } - - /* Writing _Netcdf4Dimid attribute */ - const char* attr_name = "_Netcdf4Dimid"; - - /* H5Aexists() returns zero (false), a positive (true) or a negative (failure) value */ - attr_exists = H5Aexists(dimscale_id, attr_name); - if (attr_exists > 0) - { - assert(0); - } - else if (attr_exists == 0) - { - dimid_att_id = H5Acreate2(dimscale_id, attr_name, - H5T_NATIVE_INT, dimid_space_id, H5P_DEFAULT, H5P_DEFAULT); - if (dimid_att_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new attribute (%s) attached to a dimension scale (%s)", - pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_dims[i].name); - } - } - else - { - /* Error determining whether an attribute with a given name exists on an object */ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to determine whether an attribute (%s) exists on a dimension scale (%s)", - pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_dims[i].name); - } - - if (H5Awrite(dimid_att_id, H5T_NATIVE_INT, &i) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to write an attribute (%s) attached to a dimension scale (%s)", - pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_dims[i].name); - } - - if (H5Sclose(dimid_space_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a scalar dataspace", - pio_get_fname_from_file(file), file->pio_ncid); - } - - if (H5Aclose(dimid_att_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to close an attribute (%s) attached to a dimension scale (%s)", - pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_dims[i].name); - } - - if (H5Sclose(space_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a simple dataspace", - pio_get_fname_from_file(file), file->pio_ncid); - } - - if (H5Pclose(dcpl_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to close a dataset creation property list", - pio_get_fname_from_file(file), file->pio_ncid); - } - - } - } - - for(i = 0; i < file->hdf5_num_vars; i++){ - /* Upgrade the dataset of a coordinate variable to a dimension scale */ - if(file->hdf5_vars[i].is_coord_var){ - /* Write a special attribute (_Netcdf4Dimid) for the netCDF-4 dimension ID. */ - hid_t dimscale_id = file->hdf5_vars[i].hdf5_dataset_id; - hid_t dimid_att_id; - htri_t attr_exists; - - /* Writing _Netcdf4Dimid attribute */ - const char* attr_name = "_Netcdf4Dimid"; - - attr_exists = H5Aexists(dimscale_id, attr_name); - if(attr_exists < 0){ - /* Error determining whether an attribute with a given name exists on an object */ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to determine whether an attribute (%s) exists on a dimension scale (%s)", - pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); - } - - if(attr_exists > 0){ - /* If redef/enddef is called, potentially multiple times, - * this attribute might already have been created - */ - continue; - } - - if(H5DSset_scale(file->hdf5_vars[i].hdf5_dataset_id, file->hdf5_vars[i].name) < 0){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to convert a dataset (for coordinate variable %s) to a dimension scale", - pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_vars[i].name); - } - - assert(file->hdf5_vars[i].ndims > 0); - int dimid = file->hdf5_vars[i].hdf5_dimids[0]; - file->hdf5_dims[dimid].hdf5_dataset_id = file->hdf5_vars[i].hdf5_dataset_id; - - hid_t dimid_space_id = H5Screate(H5S_SCALAR); - if(dimid_space_id == H5I_INVALID_HID){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new scalar dataspace", - pio_get_fname_from_file(file), file->pio_ncid); - } - - dimid_att_id = H5Acreate2(dimscale_id, attr_name, - H5T_NATIVE_INT, dimid_space_id, H5P_DEFAULT, H5P_DEFAULT); - if(dimid_att_id == H5I_INVALID_HID){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new attribute (%s) attached to a dimension scale (%s)", - pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); - } - - if(H5Awrite(dimid_att_id, H5T_NATIVE_INT, &dimid) < 0){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to write an attribute (%s) attached to a dimension scale (%s)", - pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); - } - - if(H5Aclose(dimid_att_id) < 0){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to close an attribute (%s) attached to a dimension scale (%s)", - pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); - } - - if(H5Sclose(dimid_space_id) < 0){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a scalar dataspace", - pio_get_fname_from_file(file), file->pio_ncid); - } - } - else{ - /* Not a coordinate var */ - int ndims = file->hdf5_vars[i].ndims; - if(ndims > 0){ - int* dimids = file->hdf5_vars[i].hdf5_dimids; - for(int j = 0; j < ndims; j++){ - if(H5DSattach_scale(file->hdf5_vars[i].hdf5_dataset_id, file->hdf5_dims[dimids[j]].hdf5_dataset_id, j) < 0){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to attach a dimension scale (for dimension %s) to %dth dimension of a dataset (for variable %s)", - pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_dims[dimids[j]].name, j, file->hdf5_vars[i].name); - } - - /* According to HDF5 developers, the H5DS routines are not parallel, so all the ranks are going to be - * doing the same operations. At some point, with enough iterations of the loop, HDF5 might get out of - * step between the ranks. - * Workaround: place a barrier to sync H5DSattach_scale calls. - */ - MPI_Barrier(ios->io_comm); - } - } - } - } - - return PIO_NOERR; -} - -int spio_hdf5_put_att(iosystem_desc_t *ios, file_desc_t *file, int varid, const char *name, - nc_type atttype, PIO_Offset len, const void *op) -{ - int ret = PIO_NOERR; - hid_t attr_id; - hid_t space_id; - hsize_t asize = len; - htri_t att_exists; - hid_t loc_id; - hid_t h5_xtype; - - assert(ios && file && name && op); - assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); - assert(ios->ioproc); - - /* FIXME: Relax this wait */ - ret = spio_wait_all_hdf5_async_ops(ios->iosysid); - if(ret != PIO_NOERR){ - return pio_err(ios, file, ret, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "Error waiting on all pending asynchronous HDF5 ops", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - if (varid == PIO_GLOBAL) - loc_id = file->hdf5_file_id; - else - loc_id = file->hdf5_vars[varid].hdf5_dataset_id; - - if (atttype == NC_CHAR) - { - /* String type */ - if (asize == 0) - space_id = H5Screate(H5S_NULL); - else - space_id = H5Screate(H5S_SCALAR); - - if (space_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new scalar dataspace", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - h5_xtype = H5Tcopy(H5T_C_S1); - if (h5_xtype == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to make a copy of the predefined string datatype in C", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - /* For empty strings, asize is 0, while H5Tset_size() requires that size must be positive */ - if (H5Tset_size(h5_xtype, (asize == 0 ? 1 : asize)) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set the total size (%ld bytes) for a derived C-style string datatype", - name, varid, pio_get_fname_from_file(file), file->pio_ncid, (asize == 0 ? 1 : asize)); - } - - if (H5Tset_strpad(h5_xtype, H5T_STR_NULLTERM) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to define the type of padding (NULL-terminated) used for a derived C-style string datatype", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - if (H5Tset_cset(h5_xtype, H5T_CSET_ASCII) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set the character set (US ASCII) to be used in a derived C-style string datatype", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } - } - else - { - space_id = H5Screate_simple(1, &asize, &asize); - if (space_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new simple dataspace", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - h5_xtype = spio_nc_type_to_hdf5_type(atttype); - if (h5_xtype == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "Unsupported variable type (type=%x)", - name, varid, pio_get_fname_from_file(file), file->pio_ncid, atttype); - } - } - - /* H5Aexists() returns zero (false), a positive (true) or a negative (failure) value */ - att_exists = H5Aexists(loc_id, name); - if (att_exists > 0) - { - attr_id = H5Aopen(loc_id, name, H5P_DEFAULT); - if (attr_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) with HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to open this existing attribute", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } - } - else if (att_exists == 0) - { - attr_id = H5Acreate2(loc_id, name, h5_xtype, space_id, H5P_DEFAULT, H5P_DEFAULT); - if (attr_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new attribute", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } - } - else - { - /* Error determining whether an attribute with a given name exists on an object */ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to determine whether this attribute exists", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - if (H5Awrite(attr_id, h5_xtype, op) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to write this attribute", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - if (H5Sclose(space_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a simple dataspace", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - if (H5Aclose(attr_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to close this attribute", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - /* String attribute */ - if (atttype == NC_CHAR) - { - if (H5Tclose(h5_xtype) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a derived C-style string datatype used by this attribute", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } - } - - return PIO_NOERR; -} - -int spio_hdf5_put_var(iosystem_desc_t *ios, file_desc_t *file, int varid, - const PIO_Offset *start, const PIO_Offset *count, - const PIO_Offset *stride, nc_type xtype, const void *buf) -{ - int ret = PIO_NOERR; - hsize_t dims[H5S_MAX_RANK]; - hsize_t mdims[H5S_MAX_RANK]; - - assert(ios && file && varid >= 0 && buf); - assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); - assert(ios->ioproc); - - /* FIXME: Relax this wait */ - ret = spio_wait_all_hdf5_async_ops(ios->iosysid); - if(ret != PIO_NOERR){ - return pio_err(ios, file, ret, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "Error waiting on all pending asynchronous HDF5 ops", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - hid_t file_space_id = H5Dget_space(file->hdf5_vars[varid].hdf5_dataset_id); - if (file_space_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to make a copy of the dataspace of the dataset associated with this variable", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - if (H5Sget_simple_extent_dims(file_space_id, dims, mdims) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to retrieve dimension size and maximum size of a dataspace copied from the dataset associated with this variable", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - int ndims = file->hdf5_vars[varid].ndims; - - /* Extend record dimension if needed */ - if (ndims > 0 && start != NULL && count != NULL && mdims[0] == H5S_UNLIMITED && dims[0] < (hsize_t)(start[0] + count[0])) - { - dims[0] = (hsize_t) (start[0] + count[0]); - - if (H5Sclose(file_space_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a dataspace copied from the dataset associated with this variable", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - if (H5Dextend(file->hdf5_vars[varid].hdf5_dataset_id, dims) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to extend the dataset associated with this variable", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - file_space_id = H5Dget_space(file->hdf5_vars[varid].hdf5_dataset_id); - if (file_space_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to make a copy of the dataspace of the dataset (extended) associated with this variable", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - } - - hsize_t hstart[(ndims > 0) ? ndims : 1]; - hsize_t hcount[(ndims > 0) ? ndims : 1]; - hsize_t hstride[(ndims > 0) ? ndims : 1]; - hsize_t nelems = 0; - - for(int i = 0; i < ndims; i++){ - if(start){ - hstart[i] = (hsize_t) start[i]; - } - else{ - hstart[i] = 0; - } - hcount[i] = 0; - hstride[i] = 1; - } - - /* Only the IO master does the IO */ - if(ios->iomaster == MPI_ROOT){ - if(count){ - for(int i = 0; i < ndims; i++){ - hcount[i] = (hsize_t)count[i]; - } - } - else{ - for(int i = 0; i < ndims; i++){ - hcount[i] = dims[i]; - } - } - - nelems = (ndims > 0) ? 1 : 0; - for(int i = 0; i < ndims; i++){ - nelems *= hcount[i]; - } - - if(stride){ - for(int i = 0; i < ndims; i++){ - hstride[i] = (stride[i] > 0) ? ((hsize_t)stride[i]) : 1 ; - } - } - } - - hid_t mem_space_id = H5Screate_simple(ndims, hcount, hcount); - if (mem_space_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new simple dataspace", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - if (ndims > 0) - { - if (H5Sselect_hyperslab(file_space_id, H5S_SELECT_SET, hstart, hstride, hcount, NULL) < 0) - { - H5Eprint2(H5E_DEFAULT, stderr); - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to select a hyperslab region for a dataspace copied from the dataset associated with this variable", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - } - - hid_t mem_type_id; - if (xtype == NC_CHAR) - { - /* String type */ - mem_type_id = H5Tcopy(H5T_C_S1); - if (mem_type_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to make a copy of the predefined string datatype in C", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - if (H5Tset_strpad(mem_type_id, H5T_STR_NULLTERM) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to define the type of padding (NULL-terminated) used for a derived C-style string datatype", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - if (H5Tset_cset(mem_type_id, H5T_CSET_ASCII) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set the character set (US ASCII) to be used in a derived C-style string datatype", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - } - else - { - mem_type_id = spio_nc_type_to_hdf5_type(xtype); - if (mem_type_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "Unsupported memory type (type=%x)", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, xtype); - } - } - - /* Independent write */ - if (H5Dwrite(file->hdf5_vars[varid].hdf5_dataset_id, mem_type_id, mem_space_id, - file_space_id, file->dxplid_indep, buf) < 0) - { - H5Eprint2(H5E_DEFAULT, stderr); - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to write the dataset associated with this variable", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - if (H5Sclose(mem_space_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a simple dataspace", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - if (xtype == NC_CHAR) - { - if (H5Tclose(mem_type_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a derived C-style string datatype used by this variable", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - } - - if (H5Sclose(file_space_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a dataspace copied from the dataset associated with this variable", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - return PIO_NOERR; -} - -int spio_hdf5_close(iosystem_desc_t *ios, file_desc_t *file) -{ - int i = 0; - - assert(ios && file); - assert((file->iotype == PIO_IOTYPE_HDF5) || ((file->iotype == PIO_IOTYPE_HDF5C))); - assert(ios->ioproc); - - /* Since close is always an async op, when async thread is used, we do not need - * to explicitly wait for async ops to complete - * i.e., we don't need spio_wait_all_hdf5_async_ops() here - */ - - if (H5Pclose(file->dxplid_coll) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Closing file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to close a dataset transfer property list (collective data transfer)", - pio_get_fname_from_file(file), file->pio_ncid); - } - - if (H5Pclose(file->dxplid_indep) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Closing file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to close a dataset transfer property list (independent data transfer)", - pio_get_fname_from_file(file), file->pio_ncid); - } - - for (i = 0; i < file->hdf5_num_dims; i++) - { - if (!file->hdf5_dims[i].has_coord_var) - { - if (H5Dclose(file->hdf5_dims[i].hdf5_dataset_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Closing file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to close a dataset created for a dimension (%s, dimid = %d)", - pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_dims[i].name, i); - } - } - } - - for (i = 0; i < file->hdf5_num_vars; i++) - { - if (H5Dclose(file->hdf5_vars[i].hdf5_dataset_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Closing file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to close a dataset created for a variable (%s, varid = %d)", - pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_vars[i].name, i); - } - - if (file->hdf5_vars[i].nc_type == NC_CHAR) - { - if (H5Tclose(file->hdf5_vars[i].hdf5_type) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Closing file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a derived C-style string datatype created for a variable (%s, varid = %d)", - pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_dims[i].name, i); - } - } - } - - if (H5Fclose(file->hdf5_file_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Closing file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to terminate access to an HDF5 file", - pio_get_fname_from_file(file), file->pio_ncid); - } - - return PIO_NOERR; -} -#endif diff --git a/src/clib/spio_async_utils.cpp b/src/clib/spio_async_utils.cpp index 833ebf367f..0d6cc36697 100644 --- a/src/clib/spio_async_utils.cpp +++ b/src/clib/spio_async_utils.cpp @@ -30,6 +30,7 @@ extern "C"{ #include "spio_file_mvcache.h" #include "spio_dbg_utils.hpp" #include "spio_dt_converter.hpp" +#include "spio_hdf5_utils.hpp" #include "spio_async_tpool_cint.h" diff --git a/src/clib/spio_hdf5_utils.cpp b/src/clib/spio_hdf5_utils.cpp new file mode 100644 index 0000000000..f92bf5d178 --- /dev/null +++ b/src/clib/spio_hdf5_utils.cpp @@ -0,0 +1,1479 @@ +/** @file + * Utility functions for using the HDF5 library + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include "spio_io_summary.h" +#include "spio_file_mvcache.h" +#include "spio_dt_converter.hpp" +//#include "spio_hash.h" +//#include "pio_rearr_contig.hpp" +//#include "spio_decomp_logger.hpp" +#include "spio_async_utils.hpp" +#include +#include +#include +#include +#include + +/* Include headers for HDF5 compression filters */ +#if PIO_USE_HDF5 +#include +#ifdef _SPIO_HAS_H5Z_ZFP +#include "H5Zzfp_lib.h" +#include "H5Zzfp_props.h" +#endif +#ifdef _SPIO_HAS_H5Z_BLOSC2 +#include "blosc2_filter.h" +#endif +#endif + +#ifdef _HDF5 +hid_t spio_nc_type_to_hdf5_type(nc_type xtype) +{ + switch (xtype) + { + case NC_BYTE: return H5T_NATIVE_UINT8; + case NC_UBYTE: return H5T_NATIVE_UCHAR; + case NC_CHAR: return H5T_NATIVE_CHAR; + case NC_SHORT: return H5T_NATIVE_SHORT; + case NC_USHORT: return H5T_NATIVE_USHORT; + case NC_INT: return H5T_NATIVE_INT; + case NC_UINT: return H5T_NATIVE_UINT; + case NC_FLOAT : return H5T_NATIVE_FLOAT; + case NC_DOUBLE: return H5T_NATIVE_DOUBLE; + case NC_INT64: return H5T_NATIVE_INT64; + case NC_UINT64: return H5T_NATIVE_UINT64; + default: return H5I_INVALID_HID; + } + + return H5I_INVALID_HID; +} + +int spio_hdf5_type_to_pio_type(hid_t ntype) +{ +// hid_t ntype = H5Tget_native_type(xtype, H5T_DIR_DEFAULT); + + /* switch() does not work with HDF5 "types" */ + if(H5Tequal(ntype, H5T_NATIVE_UINT8)) { return PIO_BYTE; } + else if(H5Tequal(ntype, H5T_NATIVE_UCHAR)) { return PIO_UBYTE; } + else if(H5Tequal(ntype, H5T_NATIVE_CHAR)) { return PIO_CHAR; } + else if(H5Tequal(ntype, H5T_NATIVE_SHORT)) { return PIO_SHORT; } + else if(H5Tequal(ntype, H5T_NATIVE_USHORT)) { return PIO_USHORT; } + else if(H5Tequal(ntype, H5T_NATIVE_INT)) { return PIO_INT; } + else if(H5Tequal(ntype, H5T_NATIVE_UINT)) { return PIO_UINT; } + else if(H5Tequal(ntype, H5T_NATIVE_FLOAT)) { return PIO_FLOAT; } + else if(H5Tequal(ntype, H5T_NATIVE_DOUBLE)) { return PIO_DOUBLE; } + else if(H5Tequal(ntype, H5T_NATIVE_INT64)) { return PIO_INT64; } + else if(H5Tequal(ntype, H5T_NATIVE_UINT64)) { return PIO_UINT64; } + else{ + assert(0); + } + + return PIO_NAT; +} + +int spio_hdf5_create(iosystem_desc_t *ios, file_desc_t *file, const char *filename) +{ + int mpierr = MPI_SUCCESS, ret = PIO_NOERR; + + assert(ios && file && filename); + assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); + assert(ios->ioproc); + + /* FIXME: Relax this wait */ + ret = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ret != PIO_NOERR){ + return pio_err(ios, NULL, ret, __FILE__, __LINE__, + "Creating file (%s) failed. Error waiting on all pending asynchronous HDF5 ops", filename); + } + + if (file->mode & PIO_NOCLOBBER) /* Check whether HDF5 file exists */ + { + struct stat sd; + if (0 == stat(filename, &sd)) + { + return pio_err(ios, NULL, PIO_EEXIST, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The HDF5 file already exists and PIO_NOCLOBBER mode is specified", + filename); + } + } + else + { + /* Delete HDF5 file if it exists */ + if (ios->io_rank == 0) + { + struct stat sd; + if (0 == stat(filename, &sd)) + unlink(filename); + } + + /* Make sure that no task is trying to operate on the + * HDF5 file while it is being deleted */ + if ((mpierr = MPI_Barrier(ios->io_comm))) + { + return check_mpi(ios, file, mpierr, __FILE__, __LINE__); + } + } + + if (ios->info == MPI_INFO_NULL) + { + if ((mpierr = MPI_Info_create(&ios->info))) + { + return check_mpi(ios, file, mpierr, __FILE__, __LINE__); + } + } + + hid_t fcpl_id = H5Pcreate(H5P_FILE_CREATE); + if (fcpl_id == H5I_INVALID_HID) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new file creation property list", + filename); + } + + if (H5Pset_link_creation_order(fcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to set tracking and indexing of link creation order", + filename); + } + + /* H5DSattach_scale calls (even with MPI_Barrier) might fail or hang if attribute creation + * order is tracked or indexed. Before we have a better workaround, temporarily disable + * tracking and indexing of attribute creation order. */ +#if 0 + if (H5Pset_attr_creation_order(fcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to set tracking and indexing of attribute creation order", + filename); + } +#endif + + hid_t fapl_id = H5Pcreate(H5P_FILE_ACCESS); + if (fapl_id == H5I_INVALID_HID) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new file access property list", + filename); + } + + if (H5Pset_fapl_mpio(fapl_id, ios->io_comm, ios->info) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to store the user-supplied MPI IO parameters", + filename); + } + + file->hdf5_file_id = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl_id, fapl_id); + if (file->hdf5_file_id == H5I_INVALID_HID) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new HDF5 file", + filename); + } + + if (H5Pclose(fcpl_id) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to close a file creation property list", + filename); + } + + if (H5Pclose(fapl_id) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to close a file access property list", + filename); + } + + /* Set up collective dataset transfer property list */ + file->dxplid_coll = H5Pcreate(H5P_DATASET_XFER); + if (file->dxplid_coll == H5I_INVALID_HID) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new dataset transfer property list (collective data transfer)", + filename); + } + + if (H5Pset_dxpl_mpio(file->dxplid_coll, H5FD_MPIO_COLLECTIVE) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to set data transfer mode to collective", + filename); + } + + /* Set up independent dataset transfer property list */ + file->dxplid_indep = H5Pcreate(H5P_DATASET_XFER); + if (file->dxplid_indep == H5I_INVALID_HID) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new dataset transfer property list (independent data transfer)", + filename); + } + + if (H5Pset_dxpl_mpio(file->dxplid_indep, H5FD_MPIO_COLLECTIVE) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to set data transfer mode to collective", + filename); + } + + if (H5Pset_dxpl_mpio_collective_opt(file->dxplid_indep, H5FD_MPIO_INDIVIDUAL_IO) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to set data transfer mode to individual I/O", + filename); + } + /* Writing _NCProperties attribute */ + const char* attr_name = "_NCProperties"; + char nc_properties[PIO_MAX_NAME]; + unsigned int major, minor, release; + + if (H5get_libversion(&major, &minor, &release) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to retrieve the the version of the HDF5 library", + filename); + } + + snprintf(nc_properties, PIO_MAX_NAME, + "version=2,scorpio=%d.%d.%d,hdf5=%1u.%1u.%1u", + PIO_VERSION_MAJOR, PIO_VERSION_MINOR, PIO_VERSION_PATCH, + major, minor, release); + + hid_t attr_id; + hsize_t asize = strlen(nc_properties); + hid_t loc_id = file->hdf5_file_id; + + hid_t space_id = H5Screate(H5S_SCALAR); + if (space_id == H5I_INVALID_HID) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new scalar dataspace", + filename); + } + + hid_t h5_string_type = H5Tcopy(H5T_C_S1); + if (h5_string_type == H5I_INVALID_HID) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to make a copy of the predefined string datatype in C", + filename); + } + + assert(asize > 0); + if (H5Tset_size(h5_string_type, asize) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to set the total size (%ld bytes) for a derived C-style string datatype", + filename, asize); + } + + if (H5Tset_strpad(h5_string_type, H5T_STR_NULLTERM) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to define the type of padding (NULL-terminated) used for a derived C-style string datatype", + filename); + } + + if (H5Tset_cset(h5_string_type, H5T_CSET_ASCII) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to set the character set (US ASCII) to be used in a derived C-style string datatype", + filename); + } + + /* H5Aexists() returns zero (false), a positive (true) or a negative (failure) value */ + htri_t att_exists = H5Aexists(loc_id, attr_name); + if (att_exists > 0) + { + assert(0); + } + else if (att_exists == 0) + { + attr_id = H5Acreate2(loc_id, attr_name, h5_string_type, space_id, H5P_DEFAULT, H5P_DEFAULT); + if (attr_id == H5I_INVALID_HID) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new attribute (%s) attached to the file", + filename, attr_name); + } + } + else + { + /* Error determining whether an attribute with a given name exists on an object */ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to determine whether an attribute (%s) exists on the file", + filename, attr_name); + } + + if (H5Awrite(attr_id, h5_string_type, nc_properties) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to write an attribute (%s) attached to the file", + filename, attr_name); + } + + if (H5Sclose(space_id) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a scalar dataspace", + filename); + } + + if (H5Aclose(attr_id) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to close an attribute (%s) attached to the file", + filename, attr_name); + } + + if (H5Tclose(h5_string_type) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a derived C-style string datatype " + "used by an attribute (%s) attached to the file", + filename, attr_name); + } + + return PIO_NOERR; +} + +/* Create HDF5 dataset property ID */ +static hid_t spio_create_hdf5_dataset_pid(iosystem_desc_t *ios, file_desc_t *file, const char *var_name, const std::vector &max_dim_sz, nc_type var_type) +{ + herr_t ret; + hid_t dpid = H5I_INVALID_HID; + + std::size_t var_ndims = max_dim_sz.size(); + + assert((ios != NULL) && (file != NULL) && (var_ndims >= 0)); + + bool var_has_more_than_four_dims = (max_dim_sz.size() > 4) ? true : false; + bool var_has_only_unlimited_dims = true; + bool var_is_scalar = true; + for(std::vector::const_iterator citer = max_dim_sz.cbegin(); citer != max_dim_sz.cend(); ++citer){ + if(*citer != H5S_UNLIMITED){ + var_has_only_unlimited_dims = false; + if(*citer != 1) { var_is_scalar = false; } + } + } + + /* Initialize the compression filter property list */ + dpid = H5Pcreate(H5P_DATASET_CREATE); + assert(dpid != H5I_INVALID_HID); + + /* We currently support compression for non-scalar data */ + if(file->iotype != PIO_IOTYPE_HDF5C) return dpid; + if((var_ndims < 1) || (var_type == NC_CHAR)){ + std::string msg("Disabling HDF5 compression for variable"); + msg += std::string("(name=") + std::string(var_name) + std::string(", file=") + std::string(pio_get_fname_from_file(file)) + std::string(")"); + msg += (var_ndims < 1) ? std::string(" since its a scalar variable") : std::string(" since its a string/char variable"); + PIOc_warn(ios->iosysid, file->fh, __FILE__, __LINE__, msg.c_str()); + return dpid; + } + + /* Check if any variables have compression disabled by the user */ + /* FIXME: Variables written out in a chunk size different from the one defined can cause hangs + * e.g. E3SM variables : decomp_type, numlev, hwrt_prec, avgflag, fillvalue, + * meridional_complement, zonal_complement + */ +#ifndef SPIO_NO_CXX_REGEX + std::regex vname_override_rgx(SPIO_OVERRIDE_HDF5_COMPRESSION_VNAME_REGEX); + if(var_name && std::regex_match(std::string(var_name), vname_override_rgx)){ + std::string msg("Disabling HDF5 compression for variable"); + msg += std::string("(name=") + std::string(var_name) + std::string(", file=") + std::string(pio_get_fname_from_file(file)) + std::string(")"); + msg += std::string(" since it matches the user specified regex"); + msg += std::string(" (SPIO_OVERRIDE_HDF5_COMPRESSION_VNAME_REGEX=\"") + std::string(SPIO_OVERRIDE_HDF5_COMPRESSION_VNAME_REGEX) + std::string("\")"); + PIOc_warn(ios->iosysid, file->fh, __FILE__, __LINE__, msg.c_str()); + return dpid; + } +#endif + +#ifdef _SPIO_HDF5_USE_COMPRESSION + +#ifdef _SPIO_HDF5_USE_LOSSY_COMPRESSION + +#ifdef _SPIO_HAS_H5Z_ZFP + /* Avoid ZFP compression for vars with only unlimited dims */ + if(var_has_only_unlimited_dims || var_is_scalar || var_has_more_than_four_dims){ + std::string msg("Disabling HDF5 ZFP compression for variable"); + msg += std::string("(name=") + std::string(var_name) + std::string(", file=") + std::string(pio_get_fname_from_file(file)) + std::string(")"); + msg += (var_has_only_unlimited_dims) ? std::string(" since it only has unlimited dims") : + ((var_is_scalar) ? std::string(" since it is essentially a scalar variable") : std::string(" since variable has more than 4 dimensions")); + PIOc_warn(ios->iosysid, file->fh, __FILE__, __LINE__, msg.c_str()); + return dpid; + } + + if(SPIO_HDF5_ZFP_COMPRESSION_MODE == "H5Z_ZFP_MODE_RATE"){ + /* Lossy compression : Fixed bit rate : Number of bits used for compressed values is fixed, e.g. 16 */ + ret = H5Pset_zfp_rate(dpid, SPIO_HDF5_ZFP_COMPRESSION_RATE); + if(ret < 0){ + PIOc_warn(ios->iosysid, file->fh, __FILE__, __LINE__, "Setting HDF5 ZFP filter compression rate failed (ignoring specific compression bit rate)"); + } + } + else if(SPIO_HDF5_ZFP_COMPRESSION_MODE == "H5Z_ZFP_MODE_PRECISION"){ + /* Lossy compression : Fixed precision Variable bit rate : Number of bits used for original value is fixed. e.g. 16 */ + ret = H5Pset_zfp_precision(dpid, SPIO_HDF5_ZFP_PRECISION); + if(ret < 0){ + PIOc_warn(ios->iosysid, file->fh, __FILE__, __LINE__, "Setting HDF5 ZFP filter relative error bound failed (continuing with the default error bounds)"); + } + } + else if(SPIO_HDF5_ZFP_COMPRESSION_MODE == "H5Z_ZFP_MODE_ACCURACY"){ + /* Lossy compression : Fixed accuracy Variable bit rate : Absolute error between original and compressed values is bound e.g. 0.001 */ + ret = H5Pset_zfp_accuracy(dpid, SPIO_HDF5_ZFP_ACCURACY); + if(ret < 0){ + PIOc_warn(ios->iosysid, file->fh, __FILE__, __LINE__, "Setting HDF5 ZFP filter absolute error bound failed (continuing with the default error bounds)"); + } + } + else if(SPIO_HDF5_ZFP_COMPRESSION_MODE == "H5Z_ZFP_MODE_REVERSIBLE"){ + /* Lossless compression */ + ret = H5Pset_zfp_reversible(dpid); + if(ret < 0){ + PIOc_warn(ios->iosysid, file->fh, __FILE__, __LINE__, "Setting HDF5 ZFP filter for lossless compression failed (ignoring compression option)"); + } + } +#endif + +#else /* lossless compression, ifdef _SPIO_HDF5_USE_LOSSY_COMPRESSION */ + +#ifdef _SPIO_HAS_H5Z_BLOSC2 + /* Lossless compression : Default Blosc2 + ZSTD */ + unsigned int cd_values[7]; + cd_values[4] = SPIO_HDF5_BLOSC2_COMPRESSION_LEVEL; // compression level + cd_values[5] = SPIO_HDF5_BLOSC2_SHUFFLE_METHOD; // shuffle option + cd_values[6] = SPIO_HDF5_BLOSC2_COMPRESSION_LIBRARY; // Use ZSTD for compression + ret = H5Pset_filter(dpid, FILTER_BLOSC2, H5Z_FLAG_OPTIONAL, 7, cd_values); + if(ret < 0){ + PIOc_warn(ios->iosysid, file->fh, __FILE__, __LINE__, "User requested lossless compression, but setting HDF5 Blosc2 filter failed. Writing data without compression"); + } +#endif + +#endif /* ifdef _SPIO_HDF5_USE_LOSSY_COMPRESSION */ + +#endif /* ifdef _SPIO_HDF5_USE_COMPRESSION */ + + /* By default HDF5 does not track the order of creation of the attributes. So the attributes + * appear based on the alphanumeric order, of the attribute name, in the file. However, + * H5DSattach_scale calls (even with MPI_Barrier) might fail or hang if attribute creation + * order is tracked or indexed. Before we have a better workaround, temporarily disable + * tracking and indexing of attribute creation order. + */ +#if 0 + if(H5Pset_attr_creation_order(dcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to set tracking and indexing of attribute creation order", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } +#endif + + return dpid; +} + +/* Get default chunk size (no of elems) - across each dimension - for variable data. The + * max chunk size (across all dimensions) is specified via PIO_CHUNK_SIZE (in bytes) + */ +static inline std::vector spio_get_dim_chunk_sz(const std::vector &dim_sz, nc_type xtype) +{ + std::size_t ndims = dim_sz.size(); + std::vector dim_chunk_sz = dim_sz; + + /* Unlimited dimensions have a chunk size of 1 */ + std::transform(dim_chunk_sz.begin(), dim_chunk_sz.end(), dim_chunk_sz.begin(), + [](hsize_t i) { return (i != H5S_UNLIMITED) ? i : 1; }); + + /* No chunking for scalars and 1D vars */ + if(ndims <= 1){ + return dim_chunk_sz; + } + + /* Number of elements corresponding to PIO_CHUNK_SIZE */ + double chunk_nelems = static_cast(PIO_CHUNK_SIZE)/static_cast(spio_get_nc_type_size(xtype)); + /* Assuming that elements are evenly distributed across all non-unlimited dimensions, + * Total (across all dimensions) chunked elements = (d * d * ...(n -1) times), where d is the size of each + * dimension + */ + hsize_t chunk_per_dim_nelems = static_cast(pow(chunk_nelems, 1.0/(ndims - 1) )); + + for(std::size_t i = 0; i < ndims; i++){ + /* Chunk size across UNLIMITED dimension is 1 */ + dim_chunk_sz[i] = (dim_sz[i] != H5S_UNLIMITED) ? (std::min(chunk_per_dim_nelems, dim_sz[i])) : 1; + } + + return dim_chunk_sz; +} + +/* Create an HDF5 string type - ASCII + null terminated */ +static inline hid_t spio_create_hdf5_str_type(void ) +{ + hid_t st = H5Tcopy(H5T_C_S1); + if(st != H5I_INVALID_HID){ + if(H5Tset_strpad(st, H5T_STR_NULLTERM) < 0){ + H5Tclose(st); + return H5I_INVALID_HID; + } + if(H5Tset_cset(st, H5T_CSET_ASCII) < 0){ + H5Tclose(st); + return H5I_INVALID_HID; + } + } + + return st; +} + +/* Write a hidden coordinates attribute (_Netcdf4Coordinates), which lists the dimids of the variable. */ +static inline int spio_add_nc_hidden_coord(iosystem_desc_t *ios, file_desc_t *file, int varid, + int ndims, const int *dimidsp) +{ + assert(ios && file && (varid >= 0) && (ndims >= 0)); + + /* No coordinate atttribute for scalars */ + if(ndims == 0) return PIO_NOERR; + + assert(dimidsp); + + /* Writing "_Netcdf4Coordinates" hidden attribute. This attribute stores the dimension ids of the + * variable dimensions in an integer array. + * This attribute is required for NetCDF to read HDF5 output + */ + const char* attr_name = "_Netcdf4Coordinates"; + + /* Sanity check : Ensure that "_Netcdf4Coordinates" attribute does not exist */ + htri_t attr_exists = H5Aexists(file->hdf5_vars[varid].hdf5_dataset_id, attr_name); + assert(attr_exists == 0); + + /* Create dataspace for the attribute i.e., space for integer array to store the dimension ids */ + std::array coords_len = {static_cast(ndims)}; + hid_t coords_space_id = H5Screate_simple(1, coords_len.data(), NULL); + if(coords_space_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new simple dataspace", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + /* Create the hidden attribute */ + hid_t coords_att_id = H5Acreate2(file->hdf5_vars[varid].hdf5_dataset_id, attr_name, + H5T_NATIVE_INT, coords_space_id, H5P_DEFAULT, H5P_DEFAULT); + if(coords_att_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new attribute (%s) attached to the variable", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, attr_name); + } + + /* Write the dimension ids */ + if(H5Awrite(coords_att_id, H5T_NATIVE_INT, dimidsp) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to write an attribute (%s) attached to the variable", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, attr_name); + } + + if(H5Aclose(coords_att_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to close an attribute (%s) attached to the variable", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, attr_name); + } + + if(H5Sclose(coords_space_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a simple dataspace", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + return PIO_NOERR; +} + +int spio_hdf5_def_var(iosystem_desc_t *ios, file_desc_t *file, const char *name, + nc_type xtype, int ndims, const int *dimidsp, int varid) +{ + int ret = PIO_NOERR; + + assert(ios && file && name && ndims >= 0 && varid >= 0); + assert((ndims == 0) || dimidsp); + assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); + assert(ios->ioproc); + + /* FIXME: Relax this wait */ + ret = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ret != PIO_NOERR){ + return pio_err(ios, file, ret, __FILE__, __LINE__, + "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " + "Error waiting on all pending asynchronous HDF5 ops", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + /* Cache the dim sizes for HDF5 calls */ + std::vector dim_sz(ndims), max_dim_sz(ndims); + for(int i = 0; i < ndims; i++){ + if(file->hdf5_dims[dimidsp[i]].len != PIO_UNLIMITED){ + dim_sz[i] = max_dim_sz[i] = file->hdf5_dims[dimidsp[i]].len; + } + else{ + dim_sz[i] = 1; + max_dim_sz[i] = H5S_UNLIMITED; + } + } + + /* Create HDF5 dataset (and optionally add filters as needed) */ + hid_t dcpl_id = spio_create_hdf5_dataset_pid(ios, file, name, max_dim_sz, xtype); + if(dcpl_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new dataset creation property list", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + file->hdf5_vars[varid].hdf5_type = (xtype == NC_CHAR) ? spio_create_hdf5_str_type() : spio_nc_type_to_hdf5_type(xtype); + assert(file->hdf5_vars[varid].hdf5_type != H5I_INVALID_HID); + + /* Set default chunk size for variable data */ + if(ndims > 0){ + if(H5Pset_chunk(dcpl_id, ndims, spio_get_dim_chunk_sz(max_dim_sz, xtype).data()) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to set the size of the chunks used to store a chunked layout dataset", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + } + + /* Create a simple dataspace to define the global variable dimensions */ + hid_t sid = H5Screate_simple(ndims, dim_sz.data(), max_dim_sz.data()); + if(sid == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new simple dataspace", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + /* Define the variable */ + const char* dataset_name = (file->hdf5_vars[varid].alt_name == NULL)? name : file->hdf5_vars[varid].alt_name; + file->hdf5_vars[varid].hdf5_dataset_id = H5Dcreate2(file->hdf5_file_id, dataset_name, file->hdf5_vars[varid].hdf5_type, + sid, H5P_DEFAULT, dcpl_id, H5P_DEFAULT); + if(file->hdf5_vars[varid].hdf5_dataset_id < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new dataset (%s) for the variable", + name, varid, pio_get_fname_from_file(file), file->pio_ncid, dataset_name); + } + + if(H5Sclose(sid) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a simple dataspace", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + if(H5Pclose(dcpl_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to close a dataset creation property list", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + /* Add a hidden attribute, "_Netcdf4Coordinates", to store var dimension ids so that NetCDF can read the var */ + if(spio_add_nc_hidden_coord(ios, file, varid, ndims, dimidsp) != PIO_NOERR){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " + "Adding NetCDF hidden coordinate attribute failed", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + return PIO_NOERR; +} + +int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) +{ + int i = 0, ret = PIO_NOERR; + + assert(ios && file); + assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); + assert(ios->ioproc); + + /* FIXME: Relax this wait */ + ret = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ret != PIO_NOERR){ + return pio_err(ios, file, ret, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Error waiting on all pending asynchronous HDF5 ops", + pio_get_fname_from_file(file), file->pio_ncid); + } + + for (i = 0; i < file->hdf5_num_dims; i++) + { + /* For dimensions without an associated coordinate var, define them here. However since the + * the user can call redef() multiple times define it only its not already defined/valid + */ + if (!file->hdf5_dims[i].has_coord_var && (file->hdf5_dims[i].hdf5_dataset_id == H5I_INVALID_HID)) + { + hid_t space_id, dcpl_id = H5I_INVALID_HID, dimscale_id; + hsize_t dims[1], max_dims[1], chunk_dims[1] = {1}; + + dcpl_id = H5Pcreate(H5P_DATASET_CREATE); + if (dcpl_id == H5I_INVALID_HID) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new dataset creation property list", + pio_get_fname_from_file(file), file->pio_ncid); + } + + /* H5DSattach_scale calls (even with MPI_Barrier) might fail or hang if attribute creation + * order is tracked or indexed. Before we have a better workaround, temporarily disable + * tracking and indexing of attribute creation order. */ +#if 0 + if (H5Pset_attr_creation_order(dcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to set tracking and indexing of attribute creation order", + pio_get_fname_from_file(file), file->pio_ncid); + } +#endif + + /* Set size of dataset to size of dimension. */ + max_dims[0] = dims[0] = file->hdf5_dims[i].len; + + /* If this dimension scale is unlimited, set up chunking with a chunksize of 1. */ + if (max_dims[0] == PIO_UNLIMITED) + { + max_dims[0] = H5S_UNLIMITED; + + if (H5Pset_chunk(dcpl_id, 1, chunk_dims) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to set the size of the chunks used to store a chunked layout dataset", + pio_get_fname_from_file(file), file->pio_ncid); + } + } + + space_id = H5Screate_simple(1, dims, max_dims); + if (space_id == H5I_INVALID_HID) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new simple dataspace", + pio_get_fname_from_file(file), file->pio_ncid); + } + + /* Create a dataset that will be converted to a dimension scale. */ + dimscale_id = H5Dcreate2(file->hdf5_file_id, file->hdf5_dims[i].name, H5T_IEEE_F32BE, + space_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT); + if (dimscale_id < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new dataset (%s) that will be converted to a dimension scale", + pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_dims[i].name); + } + + char dimscale_name[PIO_MAX_NAME]; + snprintf(dimscale_name, PIO_MAX_NAME, "%s%10d", "This is a netCDF dimension but not a netCDF variable.", (int)dims[0]); + + if (H5DSset_scale(dimscale_id, dimscale_name) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to convert a dataset (for dimension %s) to a dimension scale", + pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_dims[i].name); + } + + file->hdf5_dims[i].hdf5_dataset_id = dimscale_id; + + /* Write a special attribute (_Netcdf4Dimid) for the netCDF-4 dimension ID. */ + hid_t dimid_att_id; + htri_t attr_exists; + + hid_t dimid_space_id = H5Screate(H5S_SCALAR); + if (dimid_space_id == H5I_INVALID_HID) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new scalar dataspace", + pio_get_fname_from_file(file), file->pio_ncid); + } + + /* Writing _Netcdf4Dimid attribute */ + const char* attr_name = "_Netcdf4Dimid"; + + /* H5Aexists() returns zero (false), a positive (true) or a negative (failure) value */ + attr_exists = H5Aexists(dimscale_id, attr_name); + if (attr_exists > 0) + { + assert(0); + } + else if (attr_exists == 0) + { + dimid_att_id = H5Acreate2(dimscale_id, attr_name, + H5T_NATIVE_INT, dimid_space_id, H5P_DEFAULT, H5P_DEFAULT); + if (dimid_att_id == H5I_INVALID_HID) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new attribute (%s) attached to a dimension scale (%s)", + pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_dims[i].name); + } + } + else + { + /* Error determining whether an attribute with a given name exists on an object */ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to determine whether an attribute (%s) exists on a dimension scale (%s)", + pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_dims[i].name); + } + + if (H5Awrite(dimid_att_id, H5T_NATIVE_INT, &i) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to write an attribute (%s) attached to a dimension scale (%s)", + pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_dims[i].name); + } + + if (H5Sclose(dimid_space_id) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a scalar dataspace", + pio_get_fname_from_file(file), file->pio_ncid); + } + + if (H5Aclose(dimid_att_id) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to close an attribute (%s) attached to a dimension scale (%s)", + pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_dims[i].name); + } + + if (H5Sclose(space_id) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a simple dataspace", + pio_get_fname_from_file(file), file->pio_ncid); + } + + if (H5Pclose(dcpl_id) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to close a dataset creation property list", + pio_get_fname_from_file(file), file->pio_ncid); + } + + } + } + + for(i = 0; i < file->hdf5_num_vars; i++){ + /* Upgrade the dataset of a coordinate variable to a dimension scale */ + if(file->hdf5_vars[i].is_coord_var){ + /* Write a special attribute (_Netcdf4Dimid) for the netCDF-4 dimension ID. */ + hid_t dimscale_id = file->hdf5_vars[i].hdf5_dataset_id; + hid_t dimid_att_id; + htri_t attr_exists; + + /* Writing _Netcdf4Dimid attribute */ + const char* attr_name = "_Netcdf4Dimid"; + + attr_exists = H5Aexists(dimscale_id, attr_name); + if(attr_exists < 0){ + /* Error determining whether an attribute with a given name exists on an object */ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to determine whether an attribute (%s) exists on a dimension scale (%s)", + pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); + } + + if(attr_exists > 0){ + /* If redef/enddef is called, potentially multiple times, + * this attribute might already have been created + */ + continue; + } + + if(H5DSset_scale(file->hdf5_vars[i].hdf5_dataset_id, file->hdf5_vars[i].name) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to convert a dataset (for coordinate variable %s) to a dimension scale", + pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_vars[i].name); + } + + assert(file->hdf5_vars[i].ndims > 0); + int dimid = file->hdf5_vars[i].hdf5_dimids[0]; + file->hdf5_dims[dimid].hdf5_dataset_id = file->hdf5_vars[i].hdf5_dataset_id; + + hid_t dimid_space_id = H5Screate(H5S_SCALAR); + if(dimid_space_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new scalar dataspace", + pio_get_fname_from_file(file), file->pio_ncid); + } + + dimid_att_id = H5Acreate2(dimscale_id, attr_name, + H5T_NATIVE_INT, dimid_space_id, H5P_DEFAULT, H5P_DEFAULT); + if(dimid_att_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new attribute (%s) attached to a dimension scale (%s)", + pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); + } + + if(H5Awrite(dimid_att_id, H5T_NATIVE_INT, &dimid) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to write an attribute (%s) attached to a dimension scale (%s)", + pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); + } + + if(H5Aclose(dimid_att_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to close an attribute (%s) attached to a dimension scale (%s)", + pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); + } + + if(H5Sclose(dimid_space_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a scalar dataspace", + pio_get_fname_from_file(file), file->pio_ncid); + } + } + else{ + /* Not a coordinate var */ + int ndims = file->hdf5_vars[i].ndims; + if(ndims > 0){ + int* dimids = file->hdf5_vars[i].hdf5_dimids; + for(int j = 0; j < ndims; j++){ + if(H5DSattach_scale(file->hdf5_vars[i].hdf5_dataset_id, file->hdf5_dims[dimids[j]].hdf5_dataset_id, j) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to attach a dimension scale (for dimension %s) to %dth dimension of a dataset (for variable %s)", + pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_dims[dimids[j]].name, j, file->hdf5_vars[i].name); + } + + /* According to HDF5 developers, the H5DS routines are not parallel, so all the ranks are going to be + * doing the same operations. At some point, with enough iterations of the loop, HDF5 might get out of + * step between the ranks. + * Workaround: place a barrier to sync H5DSattach_scale calls. + */ + MPI_Barrier(ios->io_comm); + } + } + } + } + + return PIO_NOERR; +} + +int spio_hdf5_put_att(iosystem_desc_t *ios, file_desc_t *file, int varid, const char *name, + nc_type atttype, PIO_Offset len, const void *op) +{ + int ret = PIO_NOERR; + hid_t attr_id; + hid_t space_id; + hsize_t asize = len; + htri_t att_exists; + hid_t loc_id; + hid_t h5_xtype; + + assert(ios && file && name && op); + assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); + assert(ios->ioproc); + + /* FIXME: Relax this wait */ + ret = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ret != PIO_NOERR){ + return pio_err(ios, file, ret, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "Error waiting on all pending asynchronous HDF5 ops", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + if (varid == PIO_GLOBAL) + loc_id = file->hdf5_file_id; + else + loc_id = file->hdf5_vars[varid].hdf5_dataset_id; + + if (atttype == NC_CHAR) + { + /* String type */ + if (asize == 0) + space_id = H5Screate(H5S_NULL); + else + space_id = H5Screate(H5S_SCALAR); + + if (space_id == H5I_INVALID_HID) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new scalar dataspace", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + h5_xtype = H5Tcopy(H5T_C_S1); + if (h5_xtype == H5I_INVALID_HID) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to make a copy of the predefined string datatype in C", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + /* For empty strings, asize is 0, while H5Tset_size() requires that size must be positive */ + if (H5Tset_size(h5_xtype, (asize == 0 ? 1 : asize)) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to set the total size (%ld bytes) for a derived C-style string datatype", + name, varid, pio_get_fname_from_file(file), file->pio_ncid, (asize == 0 ? 1 : asize)); + } + + if (H5Tset_strpad(h5_xtype, H5T_STR_NULLTERM) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to define the type of padding (NULL-terminated) used for a derived C-style string datatype", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + if (H5Tset_cset(h5_xtype, H5T_CSET_ASCII) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to set the character set (US ASCII) to be used in a derived C-style string datatype", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + } + else + { + space_id = H5Screate_simple(1, &asize, &asize); + if (space_id == H5I_INVALID_HID) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new simple dataspace", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + h5_xtype = spio_nc_type_to_hdf5_type(atttype); + if (h5_xtype == H5I_INVALID_HID) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "Unsupported variable type (type=%x)", + name, varid, pio_get_fname_from_file(file), file->pio_ncid, atttype); + } + } + + /* H5Aexists() returns zero (false), a positive (true) or a negative (failure) value */ + att_exists = H5Aexists(loc_id, name); + if (att_exists > 0) + { + attr_id = H5Aopen(loc_id, name, H5P_DEFAULT); + if (attr_id == H5I_INVALID_HID) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) with HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to open this existing attribute", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + } + else if (att_exists == 0) + { + attr_id = H5Acreate2(loc_id, name, h5_xtype, space_id, H5P_DEFAULT, H5P_DEFAULT); + if (attr_id == H5I_INVALID_HID) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new attribute", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + } + else + { + /* Error determining whether an attribute with a given name exists on an object */ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to determine whether this attribute exists", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + if (H5Awrite(attr_id, h5_xtype, op) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to write this attribute", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + if (H5Sclose(space_id) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a simple dataspace", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + if (H5Aclose(attr_id) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to close this attribute", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + /* String attribute */ + if (atttype == NC_CHAR) + { + if (H5Tclose(h5_xtype) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a derived C-style string datatype used by this attribute", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + } + + return PIO_NOERR; +} + +int spio_hdf5_put_var(iosystem_desc_t *ios, file_desc_t *file, int varid, + const PIO_Offset *start, const PIO_Offset *count, + const PIO_Offset *stride, nc_type xtype, const void *buf) +{ + int ret = PIO_NOERR; + hsize_t dims[H5S_MAX_RANK]; + hsize_t mdims[H5S_MAX_RANK]; + + assert(ios && file && varid >= 0 && buf); + assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); + assert(ios->ioproc); + + /* FIXME: Relax this wait */ + ret = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ret != PIO_NOERR){ + return pio_err(ios, file, ret, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "Error waiting on all pending asynchronous HDF5 ops", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + hid_t file_space_id = H5Dget_space(file->hdf5_vars[varid].hdf5_dataset_id); + if (file_space_id == H5I_INVALID_HID) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to make a copy of the dataspace of the dataset associated with this variable", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + if (H5Sget_simple_extent_dims(file_space_id, dims, mdims) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to retrieve dimension size and maximum size of a dataspace copied from the dataset associated with this variable", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + int ndims = file->hdf5_vars[varid].ndims; + + /* Extend record dimension if needed */ + if (ndims > 0 && start != NULL && count != NULL && mdims[0] == H5S_UNLIMITED && dims[0] < (hsize_t)(start[0] + count[0])) + { + dims[0] = (hsize_t) (start[0] + count[0]); + + if (H5Sclose(file_space_id) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a dataspace copied from the dataset associated with this variable", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + if (H5Dextend(file->hdf5_vars[varid].hdf5_dataset_id, dims) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to extend the dataset associated with this variable", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + file_space_id = H5Dget_space(file->hdf5_vars[varid].hdf5_dataset_id); + if (file_space_id == H5I_INVALID_HID) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to make a copy of the dataspace of the dataset (extended) associated with this variable", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + } + + hsize_t hstart[(ndims > 0) ? ndims : 1]; + hsize_t hcount[(ndims > 0) ? ndims : 1]; + hsize_t hstride[(ndims > 0) ? ndims : 1]; + hsize_t nelems = 0; + + for(int i = 0; i < ndims; i++){ + if(start){ + hstart[i] = (hsize_t) start[i]; + } + else{ + hstart[i] = 0; + } + hcount[i] = 0; + hstride[i] = 1; + } + + /* Only the IO master does the IO */ + if(ios->iomaster == MPI_ROOT){ + if(count){ + for(int i = 0; i < ndims; i++){ + hcount[i] = (hsize_t)count[i]; + } + } + else{ + for(int i = 0; i < ndims; i++){ + hcount[i] = dims[i]; + } + } + + nelems = (ndims > 0) ? 1 : 0; + for(int i = 0; i < ndims; i++){ + nelems *= hcount[i]; + } + + if(stride){ + for(int i = 0; i < ndims; i++){ + hstride[i] = (stride[i] > 0) ? ((hsize_t)stride[i]) : 1 ; + } + } + } + + hid_t mem_space_id = H5Screate_simple(ndims, hcount, hcount); + if (mem_space_id == H5I_INVALID_HID) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new simple dataspace", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + if (ndims > 0) + { + if (H5Sselect_hyperslab(file_space_id, H5S_SELECT_SET, hstart, hstride, hcount, NULL) < 0) + { + H5Eprint2(H5E_DEFAULT, stderr); + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to select a hyperslab region for a dataspace copied from the dataset associated with this variable", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + } + + hid_t mem_type_id; + if (xtype == NC_CHAR) + { + /* String type */ + mem_type_id = H5Tcopy(H5T_C_S1); + if (mem_type_id == H5I_INVALID_HID) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to make a copy of the predefined string datatype in C", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + if (H5Tset_strpad(mem_type_id, H5T_STR_NULLTERM) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to define the type of padding (NULL-terminated) used for a derived C-style string datatype", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + if (H5Tset_cset(mem_type_id, H5T_CSET_ASCII) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to set the character set (US ASCII) to be used in a derived C-style string datatype", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + } + else + { + mem_type_id = spio_nc_type_to_hdf5_type(xtype); + if (mem_type_id == H5I_INVALID_HID) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "Unsupported memory type (type=%x)", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, xtype); + } + } + + /* Independent write */ + if (H5Dwrite(file->hdf5_vars[varid].hdf5_dataset_id, mem_type_id, mem_space_id, + file_space_id, file->dxplid_indep, buf) < 0) + { + H5Eprint2(H5E_DEFAULT, stderr); + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to write the dataset associated with this variable", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + if (H5Sclose(mem_space_id) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a simple dataspace", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + if (xtype == NC_CHAR) + { + if (H5Tclose(mem_type_id) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a derived C-style string datatype used by this variable", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + } + + if (H5Sclose(file_space_id) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a dataspace copied from the dataset associated with this variable", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + return PIO_NOERR; +} + +int spio_hdf5_close(iosystem_desc_t *ios, file_desc_t *file) +{ + int i = 0; + + assert(ios && file); + assert((file->iotype == PIO_IOTYPE_HDF5) || ((file->iotype == PIO_IOTYPE_HDF5C))); + assert(ios->ioproc); + + /* Since close is always an async op, when async thread is used, we do not need + * to explicitly wait for async ops to complete + * i.e., we don't need spio_wait_all_hdf5_async_ops() here + */ + + if (H5Pclose(file->dxplid_coll) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Closing file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to close a dataset transfer property list (collective data transfer)", + pio_get_fname_from_file(file), file->pio_ncid); + } + + if (H5Pclose(file->dxplid_indep) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Closing file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to close a dataset transfer property list (independent data transfer)", + pio_get_fname_from_file(file), file->pio_ncid); + } + + for (i = 0; i < file->hdf5_num_dims; i++) + { + if (!file->hdf5_dims[i].has_coord_var) + { + if (H5Dclose(file->hdf5_dims[i].hdf5_dataset_id) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Closing file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to close a dataset created for a dimension (%s, dimid = %d)", + pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_dims[i].name, i); + } + } + } + + for (i = 0; i < file->hdf5_num_vars; i++) + { + if (H5Dclose(file->hdf5_vars[i].hdf5_dataset_id) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Closing file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to close a dataset created for a variable (%s, varid = %d)", + pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_vars[i].name, i); + } + + if (file->hdf5_vars[i].nc_type == NC_CHAR) + { + if (H5Tclose(file->hdf5_vars[i].hdf5_type) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Closing file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a derived C-style string datatype created for a variable (%s, varid = %d)", + pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_dims[i].name, i); + } + } + } + + if (H5Fclose(file->hdf5_file_id) < 0) + { + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Closing file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to terminate access to an HDF5 file", + pio_get_fname_from_file(file), file->pio_ncid); + } + + return PIO_NOERR; +} +#endif diff --git a/src/clib/spio_hdf5_utils.hpp b/src/clib/spio_hdf5_utils.hpp new file mode 100644 index 0000000000..20271681b2 --- /dev/null +++ b/src/clib/spio_hdf5_utils.hpp @@ -0,0 +1,33 @@ +#ifndef __SPIO_HDF5_UTILS_HPP__ +#define __SPIO_HDF5_UTILS_HPP__ + +#include +#include +#include +#if PIO_USE_HDF5 +#include +#endif // PIO_USE_HDF5 + +#ifdef _HDF5 +hid_t spio_nc_type_to_hdf5_type(nc_type xtype); +int spio_hdf5_type_to_pio_type(hid_t xtype); +PIO_Offset hdf5_get_nc_type_size(nc_type xtype); + +int spio_hdf5_create(iosystem_desc_t *ios, file_desc_t *file, const char *filename); + +int spio_hdf5_def_var(iosystem_desc_t *ios, file_desc_t *file, const char *name, + nc_type xtype, int ndims, const int *dimidsp, int varid); + +int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file); + +int spio_hdf5_put_att(iosystem_desc_t *ios, file_desc_t *file, int varid, const char *name, + nc_type atttype, PIO_Offset len, const void *op); + +int spio_hdf5_put_var(iosystem_desc_t *ios, file_desc_t *file, int varid, + const PIO_Offset *start, const PIO_Offset *count, + const PIO_Offset *stride, nc_type xtype, const void *buf); + +int spio_hdf5_close(iosystem_desc_t *ios, file_desc_t *file); +#endif + +#endif // __SPIO_HDF5_UTILS_HPP__ From c0bf4ea9ec1603f573f244dfb47748c7bf43d68b Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 9 Jan 2026 18:06:53 -0600 Subject: [PATCH 105/194] Code refactoring - hdf5 utils Code refactoring hdf5 util functions. No major code changes. * Two functions moved to header (inlined) * Code reformatting of all HDF5 util functions --- src/clib/spio_hdf5_utils.cpp | 1739 ++++++++++++++++------------------ src/clib/spio_hdf5_utils.hpp | 50 +- 2 files changed, 842 insertions(+), 947 deletions(-) diff --git a/src/clib/spio_hdf5_utils.cpp b/src/clib/spio_hdf5_utils.cpp index f92bf5d178..8028fdf542 100644 --- a/src/clib/spio_hdf5_utils.cpp +++ b/src/clib/spio_hdf5_utils.cpp @@ -28,6 +28,7 @@ #include #include +#include "spio_hdf5_utils.hpp" /* Include headers for HDF5 compression filters */ #if PIO_USE_HDF5 #include @@ -41,342 +42,262 @@ #endif #ifdef _HDF5 -hid_t spio_nc_type_to_hdf5_type(nc_type xtype) +int spio_hdf5_create(iosystem_desc_t *ios, file_desc_t *file, const char *filename) { - switch (xtype) - { - case NC_BYTE: return H5T_NATIVE_UINT8; - case NC_UBYTE: return H5T_NATIVE_UCHAR; - case NC_CHAR: return H5T_NATIVE_CHAR; - case NC_SHORT: return H5T_NATIVE_SHORT; - case NC_USHORT: return H5T_NATIVE_USHORT; - case NC_INT: return H5T_NATIVE_INT; - case NC_UINT: return H5T_NATIVE_UINT; - case NC_FLOAT : return H5T_NATIVE_FLOAT; - case NC_DOUBLE: return H5T_NATIVE_DOUBLE; - case NC_INT64: return H5T_NATIVE_INT64; - case NC_UINT64: return H5T_NATIVE_UINT64; - default: return H5I_INVALID_HID; - } + int mpierr = MPI_SUCCESS, ret = PIO_NOERR; - return H5I_INVALID_HID; -} + assert(ios && file && filename); + assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); + assert(ios->ioproc); -int spio_hdf5_type_to_pio_type(hid_t ntype) -{ -// hid_t ntype = H5Tget_native_type(xtype, H5T_DIR_DEFAULT); - - /* switch() does not work with HDF5 "types" */ - if(H5Tequal(ntype, H5T_NATIVE_UINT8)) { return PIO_BYTE; } - else if(H5Tequal(ntype, H5T_NATIVE_UCHAR)) { return PIO_UBYTE; } - else if(H5Tequal(ntype, H5T_NATIVE_CHAR)) { return PIO_CHAR; } - else if(H5Tequal(ntype, H5T_NATIVE_SHORT)) { return PIO_SHORT; } - else if(H5Tequal(ntype, H5T_NATIVE_USHORT)) { return PIO_USHORT; } - else if(H5Tequal(ntype, H5T_NATIVE_INT)) { return PIO_INT; } - else if(H5Tequal(ntype, H5T_NATIVE_UINT)) { return PIO_UINT; } - else if(H5Tequal(ntype, H5T_NATIVE_FLOAT)) { return PIO_FLOAT; } - else if(H5Tequal(ntype, H5T_NATIVE_DOUBLE)) { return PIO_DOUBLE; } - else if(H5Tequal(ntype, H5T_NATIVE_INT64)) { return PIO_INT64; } - else if(H5Tequal(ntype, H5T_NATIVE_UINT64)) { return PIO_UINT64; } - else{ - assert(0); + /* FIXME: Relax this wait */ + ret = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ret != PIO_NOERR){ + return pio_err(ios, NULL, ret, __FILE__, __LINE__, + "Creating file (%s) failed. Error waiting on all pending asynchronous HDF5 ops", filename); } - return PIO_NAT; -} - -int spio_hdf5_create(iosystem_desc_t *ios, file_desc_t *file, const char *filename) -{ - int mpierr = MPI_SUCCESS, ret = PIO_NOERR; - - assert(ios && file && filename); - assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); - assert(ios->ioproc); - - /* FIXME: Relax this wait */ - ret = spio_wait_all_hdf5_async_ops(ios->iosysid); - if(ret != PIO_NOERR){ - return pio_err(ios, NULL, ret, __FILE__, __LINE__, - "Creating file (%s) failed. Error waiting on all pending asynchronous HDF5 ops", filename); + if(file->mode & PIO_NOCLOBBER){ + /* No clobber : Check if file exists from all processes */ + struct stat sd; + if(0 == stat(filename, &sd)){ + return pio_err(ios, NULL, PIO_EEXIST, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The HDF5 file already exists and PIO_NOCLOBBER mode is specified", + filename); } - - if (file->mode & PIO_NOCLOBBER) /* Check whether HDF5 file exists */ - { - struct stat sd; - if (0 == stat(filename, &sd)) - { - return pio_err(ios, NULL, PIO_EEXIST, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The HDF5 file already exists and PIO_NOCLOBBER mode is specified", - filename); - } + } + else{ + /* Clobber mode : Delete HDF5 file (from root I/O proc) if it exists */ + if(ios->io_rank == 0){ + struct stat sd; + if(0 == stat(filename, &sd)) { unlink(filename); } } - else - { - /* Delete HDF5 file if it exists */ - if (ios->io_rank == 0) - { - struct stat sd; - if (0 == stat(filename, &sd)) - unlink(filename); - } - /* Make sure that no task is trying to operate on the - * HDF5 file while it is being deleted */ - if ((mpierr = MPI_Barrier(ios->io_comm))) - { - return check_mpi(ios, file, mpierr, __FILE__, __LINE__); - } + /* Wait for root process (that might delete an existing file) */ + if((mpierr = MPI_Barrier(ios->io_comm))){ + return check_mpi(ios, file, mpierr, __FILE__, __LINE__); } + } - if (ios->info == MPI_INFO_NULL) - { - if ((mpierr = MPI_Info_create(&ios->info))) - { - return check_mpi(ios, file, mpierr, __FILE__, __LINE__); - } + if(ios->info == MPI_INFO_NULL){ + if((mpierr = MPI_Info_create(&ios->info))){ + return check_mpi(ios, file, mpierr, __FILE__, __LINE__); } + } - hid_t fcpl_id = H5Pcreate(H5P_FILE_CREATE); - if (fcpl_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new file creation property list", - filename); - } + hid_t fcpl_id = H5Pcreate(H5P_FILE_CREATE); + if(fcpl_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new file creation property list", + filename); + } - if (H5Pset_link_creation_order(fcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set tracking and indexing of link creation order", - filename); - } + if(H5Pset_link_creation_order(fcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to set tracking and indexing of link creation order", + filename); + } - /* H5DSattach_scale calls (even with MPI_Barrier) might fail or hang if attribute creation - * order is tracked or indexed. Before we have a better workaround, temporarily disable - * tracking and indexing of attribute creation order. */ + /* H5DSattach_scale calls (even with MPI_Barrier) might fail or hang if attribute creation + * order is tracked or indexed. Before we have a better workaround, temporarily disable + * tracking and indexing of attribute creation order. */ #if 0 - if (H5Pset_attr_creation_order(fcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set tracking and indexing of attribute creation order", - filename); - } + if(H5Pset_attr_creation_order(fcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to set tracking and indexing of attribute creation order", + filename); + } #endif - hid_t fapl_id = H5Pcreate(H5P_FILE_ACCESS); - if (fapl_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new file access property list", - filename); - } + hid_t fapl_id = H5Pcreate(H5P_FILE_ACCESS); + if(fapl_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new file access property list", + filename); + } - if (H5Pset_fapl_mpio(fapl_id, ios->io_comm, ios->info) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to store the user-supplied MPI IO parameters", - filename); - } + if(H5Pset_fapl_mpio(fapl_id, ios->io_comm, ios->info) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to store the user-supplied MPI IO parameters", + filename); + } - file->hdf5_file_id = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl_id, fapl_id); - if (file->hdf5_file_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new HDF5 file", - filename); - } + file->hdf5_file_id = H5Fcreate(filename, H5F_ACC_TRUNC, fcpl_id, fapl_id); + if(file->hdf5_file_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new HDF5 file", + filename); + } - if (H5Pclose(fcpl_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to close a file creation property list", - filename); - } + if(H5Pclose(fcpl_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to close a file creation property list", + filename); + } - if (H5Pclose(fapl_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to close a file access property list", - filename); - } + if(H5Pclose(fapl_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to close a file access property list", + filename); + } - /* Set up collective dataset transfer property list */ - file->dxplid_coll = H5Pcreate(H5P_DATASET_XFER); - if (file->dxplid_coll == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new dataset transfer property list (collective data transfer)", - filename); - } + /* Set up collective dataset transfer property list */ + file->dxplid_coll = H5Pcreate(H5P_DATASET_XFER); + if(file->dxplid_coll == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new dataset transfer property list (collective data transfer)", + filename); + } - if (H5Pset_dxpl_mpio(file->dxplid_coll, H5FD_MPIO_COLLECTIVE) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set data transfer mode to collective", - filename); - } + if(H5Pset_dxpl_mpio(file->dxplid_coll, H5FD_MPIO_COLLECTIVE) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to set data transfer mode to collective", + filename); + } - /* Set up independent dataset transfer property list */ - file->dxplid_indep = H5Pcreate(H5P_DATASET_XFER); - if (file->dxplid_indep == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new dataset transfer property list (independent data transfer)", - filename); - } + /* Set up independent dataset transfer property list */ + file->dxplid_indep = H5Pcreate(H5P_DATASET_XFER); + if(file->dxplid_indep == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new dataset transfer property list (independent data transfer)", + filename); + } - if (H5Pset_dxpl_mpio(file->dxplid_indep, H5FD_MPIO_COLLECTIVE) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set data transfer mode to collective", - filename); - } + if(H5Pset_dxpl_mpio(file->dxplid_indep, H5FD_MPIO_COLLECTIVE) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to set data transfer mode to collective", + filename); + } - if (H5Pset_dxpl_mpio_collective_opt(file->dxplid_indep, H5FD_MPIO_INDIVIDUAL_IO) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set data transfer mode to individual I/O", - filename); - } - /* Writing _NCProperties attribute */ - const char* attr_name = "_NCProperties"; - char nc_properties[PIO_MAX_NAME]; - unsigned int major, minor, release; + if(H5Pset_dxpl_mpio_collective_opt(file->dxplid_indep, H5FD_MPIO_INDIVIDUAL_IO) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to set data transfer mode to individual I/O", + filename); + } - if (H5get_libversion(&major, &minor, &release) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to retrieve the the version of the HDF5 library", - filename); - } + /* Writing _NCProperties attribute */ + const char* attr_name = "_NCProperties"; + char nc_properties[PIO_MAX_NAME]; + unsigned int major, minor, release; - snprintf(nc_properties, PIO_MAX_NAME, - "version=2,scorpio=%d.%d.%d,hdf5=%1u.%1u.%1u", - PIO_VERSION_MAJOR, PIO_VERSION_MINOR, PIO_VERSION_PATCH, - major, minor, release); + if(H5get_libversion(&major, &minor, &release) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to retrieve the the version of the HDF5 library", + filename); + } - hid_t attr_id; - hsize_t asize = strlen(nc_properties); - hid_t loc_id = file->hdf5_file_id; + snprintf(nc_properties, PIO_MAX_NAME, + "version=2,scorpio=%d.%d.%d,hdf5=%1u.%1u.%1u", + PIO_VERSION_MAJOR, PIO_VERSION_MINOR, PIO_VERSION_PATCH, + major, minor, release); - hid_t space_id = H5Screate(H5S_SCALAR); - if (space_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new scalar dataspace", - filename); - } + hid_t attr_id; + hsize_t asize = strlen(nc_properties); + hid_t loc_id = file->hdf5_file_id; - hid_t h5_string_type = H5Tcopy(H5T_C_S1); - if (h5_string_type == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to make a copy of the predefined string datatype in C", - filename); - } + hid_t space_id = H5Screate(H5S_SCALAR); + if(space_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new scalar dataspace", + filename); + } - assert(asize > 0); - if (H5Tset_size(h5_string_type, asize) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set the total size (%ld bytes) for a derived C-style string datatype", - filename, asize); - } + hid_t h5_string_type = H5Tcopy(H5T_C_S1); + if(h5_string_type == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to make a copy of the predefined string datatype in C", + filename); + } - if (H5Tset_strpad(h5_string_type, H5T_STR_NULLTERM) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to define the type of padding (NULL-terminated) used for a derived C-style string datatype", - filename); - } + assert(asize > 0); + if(H5Tset_size(h5_string_type, asize) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to set the total size (%ld bytes) for a derived C-style string datatype", + filename, asize); + } - if (H5Tset_cset(h5_string_type, H5T_CSET_ASCII) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set the character set (US ASCII) to be used in a derived C-style string datatype", - filename); - } + if(H5Tset_strpad(h5_string_type, H5T_STR_NULLTERM) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to define the type of padding (NULL-terminated) used for a derived C-style string datatype", + filename); + } - /* H5Aexists() returns zero (false), a positive (true) or a negative (failure) value */ - htri_t att_exists = H5Aexists(loc_id, attr_name); - if (att_exists > 0) - { - assert(0); - } - else if (att_exists == 0) - { - attr_id = H5Acreate2(loc_id, attr_name, h5_string_type, space_id, H5P_DEFAULT, H5P_DEFAULT); - if (attr_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new attribute (%s) attached to the file", - filename, attr_name); - } - } - else - { - /* Error determining whether an attribute with a given name exists on an object */ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to determine whether an attribute (%s) exists on the file", - filename, attr_name); - } + if(H5Tset_cset(h5_string_type, H5T_CSET_ASCII) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to set the character set (US ASCII) to be used in a derived C-style string datatype", + filename); + } - if (H5Awrite(attr_id, h5_string_type, nc_properties) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to write an attribute (%s) attached to the file", - filename, attr_name); + /* H5Aexists() returns zero (false), a positive (true) or a negative (failure) value */ + htri_t att_exists = H5Aexists(loc_id, attr_name); + if(att_exists > 0) { assert(0); } + else if(att_exists == 0){ + attr_id = H5Acreate2(loc_id, attr_name, h5_string_type, space_id, H5P_DEFAULT, H5P_DEFAULT); + if(attr_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new attribute (%s) attached to the file", + filename, attr_name); } + } + else{ + /* Error determining whether an attribute with a given name exists on an object */ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to determine whether an attribute (%s) exists on the file", + filename, attr_name); + } - if (H5Sclose(space_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a scalar dataspace", - filename); - } + if(H5Awrite(attr_id, h5_string_type, nc_properties) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to write an attribute (%s) attached to the file", + filename, attr_name); + } - if (H5Aclose(attr_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to close an attribute (%s) attached to the file", - filename, attr_name); - } + if(H5Sclose(space_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a scalar dataspace", + filename); + } - if (H5Tclose(h5_string_type) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Creating file (%s) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a derived C-style string datatype " - "used by an attribute (%s) attached to the file", - filename, attr_name); - } + if(H5Aclose(attr_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to close an attribute (%s) attached to the file", + filename, attr_name); + } + + if(H5Tclose(h5_string_type) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a derived C-style string datatype " + "used by an attribute (%s) attached to the file", + filename, attr_name); + } - return PIO_NOERR; + return PIO_NOERR; } /* Create HDF5 dataset property ID */ @@ -524,9 +445,7 @@ static inline std::vector spio_get_dim_chunk_sz(const std::vector(PIO_CHUNK_SIZE)/static_cast(spio_get_nc_type_size(xtype)); @@ -569,7 +488,7 @@ static inline int spio_add_nc_hidden_coord(iosystem_desc_t *ios, file_desc_t *fi assert(ios && file && (varid >= 0) && (ndims >= 0)); /* No coordinate atttribute for scalars */ - if(ndims == 0) return PIO_NOERR; + if(ndims == 0) { return PIO_NOERR; } assert(dimidsp); @@ -728,752 +647,684 @@ int spio_hdf5_def_var(iosystem_desc_t *ios, file_desc_t *file, const char *name, int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) { - int i = 0, ret = PIO_NOERR; - - assert(ios && file); - assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); - assert(ios->ioproc); - - /* FIXME: Relax this wait */ - ret = spio_wait_all_hdf5_async_ops(ios->iosysid); - if(ret != PIO_NOERR){ - return pio_err(ios, file, ret, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "Error waiting on all pending asynchronous HDF5 ops", - pio_get_fname_from_file(file), file->pio_ncid); - } + int i = 0, ret = PIO_NOERR; - for (i = 0; i < file->hdf5_num_dims; i++) - { - /* For dimensions without an associated coordinate var, define them here. However since the - * the user can call redef() multiple times define it only its not already defined/valid - */ - if (!file->hdf5_dims[i].has_coord_var && (file->hdf5_dims[i].hdf5_dataset_id == H5I_INVALID_HID)) - { - hid_t space_id, dcpl_id = H5I_INVALID_HID, dimscale_id; - hsize_t dims[1], max_dims[1], chunk_dims[1] = {1}; - - dcpl_id = H5Pcreate(H5P_DATASET_CREATE); - if (dcpl_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new dataset creation property list", - pio_get_fname_from_file(file), file->pio_ncid); - } - - /* H5DSattach_scale calls (even with MPI_Barrier) might fail or hang if attribute creation - * order is tracked or indexed. Before we have a better workaround, temporarily disable - * tracking and indexing of attribute creation order. */ -#if 0 - if (H5Pset_attr_creation_order(dcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set tracking and indexing of attribute creation order", - pio_get_fname_from_file(file), file->pio_ncid); - } -#endif + assert(ios && file); + assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); + assert(ios->ioproc); + + /* FIXME: Relax this wait */ + ret = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ret != PIO_NOERR){ + return pio_err(ios, file, ret, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Error waiting on all pending asynchronous HDF5 ops", + pio_get_fname_from_file(file), file->pio_ncid); + } - /* Set size of dataset to size of dimension. */ - max_dims[0] = dims[0] = file->hdf5_dims[i].len; - - /* If this dimension scale is unlimited, set up chunking with a chunksize of 1. */ - if (max_dims[0] == PIO_UNLIMITED) - { - max_dims[0] = H5S_UNLIMITED; - - if (H5Pset_chunk(dcpl_id, 1, chunk_dims) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set the size of the chunks used to store a chunked layout dataset", - pio_get_fname_from_file(file), file->pio_ncid); - } - } - - space_id = H5Screate_simple(1, dims, max_dims); - if (space_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new simple dataspace", - pio_get_fname_from_file(file), file->pio_ncid); - } - - /* Create a dataset that will be converted to a dimension scale. */ - dimscale_id = H5Dcreate2(file->hdf5_file_id, file->hdf5_dims[i].name, H5T_IEEE_F32BE, - space_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT); - if (dimscale_id < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new dataset (%s) that will be converted to a dimension scale", - pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_dims[i].name); - } - - char dimscale_name[PIO_MAX_NAME]; - snprintf(dimscale_name, PIO_MAX_NAME, "%s%10d", "This is a netCDF dimension but not a netCDF variable.", (int)dims[0]); - - if (H5DSset_scale(dimscale_id, dimscale_name) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to convert a dataset (for dimension %s) to a dimension scale", - pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_dims[i].name); - } - - file->hdf5_dims[i].hdf5_dataset_id = dimscale_id; - - /* Write a special attribute (_Netcdf4Dimid) for the netCDF-4 dimension ID. */ - hid_t dimid_att_id; - htri_t attr_exists; - - hid_t dimid_space_id = H5Screate(H5S_SCALAR); - if (dimid_space_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new scalar dataspace", - pio_get_fname_from_file(file), file->pio_ncid); - } - - /* Writing _Netcdf4Dimid attribute */ - const char* attr_name = "_Netcdf4Dimid"; - - /* H5Aexists() returns zero (false), a positive (true) or a negative (failure) value */ - attr_exists = H5Aexists(dimscale_id, attr_name); - if (attr_exists > 0) - { - assert(0); - } - else if (attr_exists == 0) - { - dimid_att_id = H5Acreate2(dimscale_id, attr_name, - H5T_NATIVE_INT, dimid_space_id, H5P_DEFAULT, H5P_DEFAULT); - if (dimid_att_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new attribute (%s) attached to a dimension scale (%s)", - pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_dims[i].name); - } - } - else - { - /* Error determining whether an attribute with a given name exists on an object */ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to determine whether an attribute (%s) exists on a dimension scale (%s)", - pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_dims[i].name); - } - - if (H5Awrite(dimid_att_id, H5T_NATIVE_INT, &i) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to write an attribute (%s) attached to a dimension scale (%s)", - pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_dims[i].name); - } - - if (H5Sclose(dimid_space_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a scalar dataspace", - pio_get_fname_from_file(file), file->pio_ncid); - } - - if (H5Aclose(dimid_att_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to close an attribute (%s) attached to a dimension scale (%s)", - pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_dims[i].name); - } - - if (H5Sclose(space_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a simple dataspace", - pio_get_fname_from_file(file), file->pio_ncid); - } - - if (H5Pclose(dcpl_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to close a dataset creation property list", - pio_get_fname_from_file(file), file->pio_ncid); - } + for(i = 0; i < file->hdf5_num_dims; i++){ + /* For dimensions without an associated coordinate var, define them here. However since the + * the user can call redef() multiple times define it only its not already defined/valid + */ + if(!file->hdf5_dims[i].has_coord_var && (file->hdf5_dims[i].hdf5_dataset_id == H5I_INVALID_HID)){ + hid_t space_id, dcpl_id = H5I_INVALID_HID, dimscale_id; + hsize_t dims[1], max_dims[1], chunk_dims[1] = {1}; - } - } + dcpl_id = H5Pcreate(H5P_DATASET_CREATE); + if(dcpl_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new dataset creation property list", + pio_get_fname_from_file(file), file->pio_ncid); + } + + /* H5DSattach_scale calls (even with MPI_Barrier) might fail or hang if attribute creation + * order is tracked or indexed. Before we have a better workaround, temporarily disable + * tracking and indexing of attribute creation order. */ +#if 0 + if(H5Pset_attr_creation_order(dcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to set tracking and indexing of attribute creation order", + pio_get_fname_from_file(file), file->pio_ncid); + } +#endif - for(i = 0; i < file->hdf5_num_vars; i++){ - /* Upgrade the dataset of a coordinate variable to a dimension scale */ - if(file->hdf5_vars[i].is_coord_var){ - /* Write a special attribute (_Netcdf4Dimid) for the netCDF-4 dimension ID. */ - hid_t dimscale_id = file->hdf5_vars[i].hdf5_dataset_id; - hid_t dimid_att_id; - htri_t attr_exists; + /* Set size of dataset to size of dimension. */ + max_dims[0] = dims[0] = file->hdf5_dims[i].len; - /* Writing _Netcdf4Dimid attribute */ - const char* attr_name = "_Netcdf4Dimid"; + /* If this dimension scale is unlimited, set up chunking with a chunksize of 1. */ + if(max_dims[0] == PIO_UNLIMITED){ + max_dims[0] = H5S_UNLIMITED; - attr_exists = H5Aexists(dimscale_id, attr_name); - if(attr_exists < 0){ - /* Error determining whether an attribute with a given name exists on an object */ + if(H5Pset_chunk(dcpl_id, 1, chunk_dims) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to determine whether an attribute (%s) exists on a dimension scale (%s)", - pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); + "The low level (HDF5) I/O library call failed to set the size of the chunks used to store a chunked layout dataset", + pio_get_fname_from_file(file), file->pio_ncid); } + } - if(attr_exists > 0){ - /* If redef/enddef is called, potentially multiple times, - * this attribute might already have been created - */ - continue; - } + space_id = H5Screate_simple(1, dims, max_dims); + if(space_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new simple dataspace", + pio_get_fname_from_file(file), file->pio_ncid); + } - if(H5DSset_scale(file->hdf5_vars[i].hdf5_dataset_id, file->hdf5_vars[i].name) < 0){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to convert a dataset (for coordinate variable %s) to a dimension scale", - pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_vars[i].name); - } + /* Create a dataset that will be converted to a dimension scale. */ + dimscale_id = H5Dcreate2(file->hdf5_file_id, file->hdf5_dims[i].name, H5T_IEEE_F32BE, + space_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT); + if(dimscale_id < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new dataset (%s) that will be converted to a dimension scale", + pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_dims[i].name); + } - assert(file->hdf5_vars[i].ndims > 0); - int dimid = file->hdf5_vars[i].hdf5_dimids[0]; - file->hdf5_dims[dimid].hdf5_dataset_id = file->hdf5_vars[i].hdf5_dataset_id; + char dimscale_name[PIO_MAX_NAME]; + snprintf(dimscale_name, PIO_MAX_NAME, "%s%10d", "This is a netCDF dimension but not a netCDF variable.", (int)dims[0]); - hid_t dimid_space_id = H5Screate(H5S_SCALAR); - if(dimid_space_id == H5I_INVALID_HID){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new scalar dataspace", - pio_get_fname_from_file(file), file->pio_ncid); - } + if(H5DSset_scale(dimscale_id, dimscale_name) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to convert a dataset (for dimension %s) to a dimension scale", + pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_dims[i].name); + } + + file->hdf5_dims[i].hdf5_dataset_id = dimscale_id; + + /* Write a special attribute (_Netcdf4Dimid) for the netCDF-4 dimension ID. */ + hid_t dimid_att_id; + htri_t attr_exists; + + hid_t dimid_space_id = H5Screate(H5S_SCALAR); + if(dimid_space_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new scalar dataspace", + pio_get_fname_from_file(file), file->pio_ncid); + } + /* Writing _Netcdf4Dimid attribute */ + const char* attr_name = "_Netcdf4Dimid"; + + /* H5Aexists() returns zero (false), a positive (true) or a negative (failure) value */ + attr_exists = H5Aexists(dimscale_id, attr_name); + if(attr_exists > 0) { assert(0); } + else if(attr_exists == 0){ dimid_att_id = H5Acreate2(dimscale_id, attr_name, H5T_NATIVE_INT, dimid_space_id, H5P_DEFAULT, H5P_DEFAULT); if(dimid_att_id == H5I_INVALID_HID){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to create a new attribute (%s) attached to a dimension scale (%s)", - pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); - } - - if(H5Awrite(dimid_att_id, H5T_NATIVE_INT, &dimid) < 0){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to write an attribute (%s) attached to a dimension scale (%s)", - pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); - } - - if(H5Aclose(dimid_att_id) < 0){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to close an attribute (%s) attached to a dimension scale (%s)", - pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); - } - - if(H5Sclose(dimid_space_id) < 0){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a scalar dataspace", - pio_get_fname_from_file(file), file->pio_ncid); + pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_dims[i].name); } } else{ - /* Not a coordinate var */ - int ndims = file->hdf5_vars[i].ndims; - if(ndims > 0){ - int* dimids = file->hdf5_vars[i].hdf5_dimids; - for(int j = 0; j < ndims; j++){ - if(H5DSattach_scale(file->hdf5_vars[i].hdf5_dataset_id, file->hdf5_dims[dimids[j]].hdf5_dataset_id, j) < 0){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to attach a dimension scale (for dimension %s) to %dth dimension of a dataset (for variable %s)", - pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_dims[dimids[j]].name, j, file->hdf5_vars[i].name); - } - - /* According to HDF5 developers, the H5DS routines are not parallel, so all the ranks are going to be - * doing the same operations. At some point, with enough iterations of the loop, HDF5 might get out of - * step between the ranks. - * Workaround: place a barrier to sync H5DSattach_scale calls. - */ - MPI_Barrier(ios->io_comm); - } - } + /* Error determining whether an attribute with a given name exists on an object */ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to determine whether an attribute (%s) exists on a dimension scale (%s)", + pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_dims[i].name); } - } - - return PIO_NOERR; -} - -int spio_hdf5_put_att(iosystem_desc_t *ios, file_desc_t *file, int varid, const char *name, - nc_type atttype, PIO_Offset len, const void *op) -{ - int ret = PIO_NOERR; - hid_t attr_id; - hid_t space_id; - hsize_t asize = len; - htri_t att_exists; - hid_t loc_id; - hid_t h5_xtype; - - assert(ios && file && name && op); - assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); - assert(ios->ioproc); - - /* FIXME: Relax this wait */ - ret = spio_wait_all_hdf5_async_ops(ios->iosysid); - if(ret != PIO_NOERR){ - return pio_err(ios, file, ret, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "Error waiting on all pending asynchronous HDF5 ops", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } - if (varid == PIO_GLOBAL) - loc_id = file->hdf5_file_id; - else - loc_id = file->hdf5_vars[varid].hdf5_dataset_id; - - if (atttype == NC_CHAR) - { - /* String type */ - if (asize == 0) - space_id = H5Screate(H5S_NULL); - else - space_id = H5Screate(H5S_SCALAR); - - if (space_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new scalar dataspace", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } + if(H5Awrite(dimid_att_id, H5T_NATIVE_INT, &i) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to write an attribute (%s) attached to a dimension scale (%s)", + pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_dims[i].name); + } - h5_xtype = H5Tcopy(H5T_C_S1); - if (h5_xtype == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to make a copy of the predefined string datatype in C", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } + if(H5Sclose(dimid_space_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a scalar dataspace", + pio_get_fname_from_file(file), file->pio_ncid); + } - /* For empty strings, asize is 0, while H5Tset_size() requires that size must be positive */ - if (H5Tset_size(h5_xtype, (asize == 0 ? 1 : asize)) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set the total size (%ld bytes) for a derived C-style string datatype", - name, varid, pio_get_fname_from_file(file), file->pio_ncid, (asize == 0 ? 1 : asize)); - } + if(H5Aclose(dimid_att_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to close an attribute (%s) attached to a dimension scale (%s)", + pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_dims[i].name); + } - if (H5Tset_strpad(h5_xtype, H5T_STR_NULLTERM) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to define the type of padding (NULL-terminated) used for a derived C-style string datatype", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } + if(H5Sclose(space_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a simple dataspace", + pio_get_fname_from_file(file), file->pio_ncid); + } - if (H5Tset_cset(h5_xtype, H5T_CSET_ASCII) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set the character set (US ASCII) to be used in a derived C-style string datatype", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } + if(H5Pclose(dcpl_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to close a dataset creation property list", + pio_get_fname_from_file(file), file->pio_ncid); + } } - else - { - space_id = H5Screate_simple(1, &asize, &asize); - if (space_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new simple dataspace", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } + } - h5_xtype = spio_nc_type_to_hdf5_type(atttype); - if (h5_xtype == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "Unsupported variable type (type=%x)", - name, varid, pio_get_fname_from_file(file), file->pio_ncid, atttype); - } - } + for(i = 0; i < file->hdf5_num_vars; i++){ + /* Upgrade the dataset of a coordinate variable to a dimension scale */ + if(file->hdf5_vars[i].is_coord_var){ + /* Write a special attribute (_Netcdf4Dimid) for the netCDF-4 dimension ID. */ + hid_t dimscale_id = file->hdf5_vars[i].hdf5_dataset_id; + hid_t dimid_att_id; + htri_t attr_exists; - /* H5Aexists() returns zero (false), a positive (true) or a negative (failure) value */ - att_exists = H5Aexists(loc_id, name); - if (att_exists > 0) - { - attr_id = H5Aopen(loc_id, name, H5P_DEFAULT); - if (attr_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) with HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to open this existing attribute", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } - } - else if (att_exists == 0) - { - attr_id = H5Acreate2(loc_id, name, h5_xtype, space_id, H5P_DEFAULT, H5P_DEFAULT); - if (attr_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new attribute", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } - } - else - { + /* Writing _Netcdf4Dimid attribute */ + const char* attr_name = "_Netcdf4Dimid"; + + attr_exists = H5Aexists(dimscale_id, attr_name); + if(attr_exists < 0){ /* Error determining whether an attribute with a given name exists on an object */ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to determine whether this attribute exists", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to determine whether an attribute (%s) exists on a dimension scale (%s)", + pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); + } - if (H5Awrite(attr_id, h5_xtype, op) < 0) - { + if(attr_exists > 0){ + /* If redef/enddef is called, potentially multiple times, + * this attribute might already have been created + */ + continue; + } + + if(H5DSset_scale(file->hdf5_vars[i].hdf5_dataset_id, file->hdf5_vars[i].name) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to write this attribute", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to convert a dataset (for coordinate variable %s) to a dimension scale", + pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_vars[i].name); + } - if (H5Sclose(space_id) < 0) - { + assert(file->hdf5_vars[i].ndims > 0); + int dimid = file->hdf5_vars[i].hdf5_dimids[0]; + file->hdf5_dims[dimid].hdf5_dataset_id = file->hdf5_vars[i].hdf5_dataset_id; + + hid_t dimid_space_id = H5Screate(H5S_SCALAR); + if(dimid_space_id == H5I_INVALID_HID){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a simple dataspace", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new scalar dataspace", + pio_get_fname_from_file(file), file->pio_ncid); + } - if (H5Aclose(attr_id) < 0) - { + dimid_att_id = H5Acreate2(dimscale_id, attr_name, + H5T_NATIVE_INT, dimid_space_id, H5P_DEFAULT, H5P_DEFAULT); + if(dimid_att_id == H5I_INVALID_HID){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to close this attribute", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new attribute (%s) attached to a dimension scale (%s)", + pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); + } - /* String attribute */ - if (atttype == NC_CHAR) - { - if (H5Tclose(h5_xtype) < 0) - { + if(H5Awrite(dimid_att_id, H5T_NATIVE_INT, &dimid) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to write an attribute (%s) attached to a dimension scale (%s)", + pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); + } + + if(H5Aclose(dimid_att_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to close an attribute (%s) attached to a dimension scale (%s)", + pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); + } + + if(H5Sclose(dimid_space_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a scalar dataspace", + pio_get_fname_from_file(file), file->pio_ncid); + } + } + else{ + /* Not a coordinate var */ + int ndims = file->hdf5_vars[i].ndims; + if(ndims > 0){ + int* dimids = file->hdf5_vars[i].hdf5_dimids; + for(int j = 0; j < ndims; j++){ + if(H5DSattach_scale(file->hdf5_vars[i].hdf5_dataset_id, file->hdf5_dims[dimids[j]].hdf5_dataset_id, j) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a derived C-style string datatype used by this attribute", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to attach a dimension scale (for dimension %s) to %dth dimension of a dataset (for variable %s)", + pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_dims[dimids[j]].name, j, file->hdf5_vars[i].name); + } + + /* According to HDF5 developers, the H5DS routines are not parallel, so all the ranks are going to be + * doing the same operations. At some point, with enough iterations of the loop, HDF5 might get out of + * step between the ranks. + * Workaround: place a barrier to sync H5DSattach_scale calls. + */ + MPI_Barrier(ios->io_comm); } + } } + } - return PIO_NOERR; + return PIO_NOERR; } -int spio_hdf5_put_var(iosystem_desc_t *ios, file_desc_t *file, int varid, - const PIO_Offset *start, const PIO_Offset *count, - const PIO_Offset *stride, nc_type xtype, const void *buf) +int spio_hdf5_put_att(iosystem_desc_t *ios, file_desc_t *file, int varid, const char *name, + nc_type atttype, PIO_Offset len, const void *op) { - int ret = PIO_NOERR; - hsize_t dims[H5S_MAX_RANK]; - hsize_t mdims[H5S_MAX_RANK]; - - assert(ios && file && varid >= 0 && buf); - assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); - assert(ios->ioproc); - - /* FIXME: Relax this wait */ - ret = spio_wait_all_hdf5_async_ops(ios->iosysid); - if(ret != PIO_NOERR){ - return pio_err(ios, file, ret, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "Error waiting on all pending asynchronous HDF5 ops", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + int ret = PIO_NOERR; + hid_t attr_id; + hid_t space_id; + hsize_t asize = len; + htri_t att_exists; + hid_t loc_id; + hid_t h5_xtype; + + assert(ios && file && name && op); + assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); + assert(ios->ioproc); + + /* FIXME: Relax this wait */ + ret = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ret != PIO_NOERR){ + return pio_err(ios, file, ret, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "Error waiting on all pending asynchronous HDF5 ops", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + if(varid == PIO_GLOBAL){ + loc_id = file->hdf5_file_id; + } + else{ + loc_id = file->hdf5_vars[varid].hdf5_dataset_id; + } + + if(atttype == NC_CHAR){ + /* String type */ + if(asize == 0){ + space_id = H5Screate(H5S_NULL); + } + else{ + space_id = H5Screate(H5S_SCALAR); } - hid_t file_space_id = H5Dget_space(file->hdf5_vars[varid].hdf5_dataset_id); - if (file_space_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to make a copy of the dataspace of the dataset associated with this variable", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + if(space_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new scalar dataspace", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); } - if (H5Sget_simple_extent_dims(file_space_id, dims, mdims) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to retrieve dimension size and maximum size of a dataspace copied from the dataset associated with this variable", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + h5_xtype = H5Tcopy(H5T_C_S1); + if(h5_xtype == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to make a copy of the predefined string datatype in C", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); } - int ndims = file->hdf5_vars[varid].ndims; + /* For empty strings, asize is 0, while H5Tset_size() requires that size must be positive */ + if(H5Tset_size(h5_xtype, (asize == 0 ? 1 : asize)) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to set the total size (%ld bytes) for a derived C-style string datatype", + name, varid, pio_get_fname_from_file(file), file->pio_ncid, (asize == 0 ? 1 : asize)); + } - /* Extend record dimension if needed */ - if (ndims > 0 && start != NULL && count != NULL && mdims[0] == H5S_UNLIMITED && dims[0] < (hsize_t)(start[0] + count[0])) - { - dims[0] = (hsize_t) (start[0] + count[0]); + if(H5Tset_strpad(h5_xtype, H5T_STR_NULLTERM) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to define the type of padding (NULL-terminated) used for a derived C-style string datatype", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } - if (H5Sclose(file_space_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a dataspace copied from the dataset associated with this variable", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } + if(H5Tset_cset(h5_xtype, H5T_CSET_ASCII) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to set the character set (US ASCII) to be used in a derived C-style string datatype", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + } + else{ + space_id = H5Screate_simple(1, &asize, &asize); + if(space_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new simple dataspace", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } - if (H5Dextend(file->hdf5_vars[varid].hdf5_dataset_id, dims) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to extend the dataset associated with this variable", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } + h5_xtype = spio_nc_type_to_hdf5_type(atttype); + if(h5_xtype == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "Unsupported variable type (type=%x)", + name, varid, pio_get_fname_from_file(file), file->pio_ncid, atttype); + } + } - file_space_id = H5Dget_space(file->hdf5_vars[varid].hdf5_dataset_id); - if (file_space_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to make a copy of the dataspace of the dataset (extended) associated with this variable", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } + /* H5Aexists() returns zero (false), a positive (true) or a negative (failure) value */ + att_exists = H5Aexists(loc_id, name); + if(att_exists > 0){ + attr_id = H5Aopen(loc_id, name, H5P_DEFAULT); + if(attr_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) with HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to open this existing attribute", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); } + } + else if(att_exists == 0){ + attr_id = H5Acreate2(loc_id, name, h5_xtype, space_id, H5P_DEFAULT, H5P_DEFAULT); + if(attr_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new attribute", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + } + else{ + /* Error determining whether an attribute with a given name exists on an object */ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to determine whether this attribute exists", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + if(H5Awrite(attr_id, h5_xtype, op) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to write this attribute", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } - hsize_t hstart[(ndims > 0) ? ndims : 1]; - hsize_t hcount[(ndims > 0) ? ndims : 1]; - hsize_t hstride[(ndims > 0) ? ndims : 1]; - hsize_t nelems = 0; + if(H5Sclose(space_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a simple dataspace", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } - for(int i = 0; i < ndims; i++){ - if(start){ - hstart[i] = (hsize_t) start[i]; - } - else{ - hstart[i] = 0; - } - hcount[i] = 0; - hstride[i] = 1; + if(H5Aclose(attr_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to close this attribute", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + /* String attribute */ + if(atttype == NC_CHAR){ + if(H5Tclose(h5_xtype) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a derived C-style string datatype used by this attribute", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); } + } - /* Only the IO master does the IO */ - if(ios->iomaster == MPI_ROOT){ - if(count){ - for(int i = 0; i < ndims; i++){ - hcount[i] = (hsize_t)count[i]; - } - } - else{ - for(int i = 0; i < ndims; i++){ - hcount[i] = dims[i]; - } - } + return PIO_NOERR; +} - nelems = (ndims > 0) ? 1 : 0; - for(int i = 0; i < ndims; i++){ - nelems *= hcount[i]; - } +int spio_hdf5_put_var(iosystem_desc_t *ios, file_desc_t *file, int varid, + const PIO_Offset *start, const PIO_Offset *count, + const PIO_Offset *stride, nc_type xtype, const void *buf) +{ + int ret = PIO_NOERR; + hsize_t dims[H5S_MAX_RANK]; + hsize_t mdims[H5S_MAX_RANK]; - if(stride){ - for(int i = 0; i < ndims; i++){ - hstride[i] = (stride[i] > 0) ? ((hsize_t)stride[i]) : 1 ; - } - } + assert(ios && file && varid >= 0 && buf); + assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); + assert(ios->ioproc); + + /* FIXME: Relax this wait */ + ret = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ret != PIO_NOERR){ + return pio_err(ios, file, ret, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "Error waiting on all pending asynchronous HDF5 ops", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + hid_t file_space_id = H5Dget_space(file->hdf5_vars[varid].hdf5_dataset_id); + if(file_space_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to make a copy of the dataspace of the dataset associated with this variable", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + if(H5Sget_simple_extent_dims(file_space_id, dims, mdims) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to retrieve dimension size and maximum size of a dataspace copied from the dataset associated with this variable", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + int ndims = file->hdf5_vars[varid].ndims; + + /* Extend record dimension if needed */ + if(ndims > 0 && start != NULL && count != NULL && mdims[0] == H5S_UNLIMITED && dims[0] < (hsize_t)(start[0] + count[0])){ + dims[0] = (hsize_t) (start[0] + count[0]); + + if(H5Sclose(file_space_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a dataspace copied from the dataset associated with this variable", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); } - hid_t mem_space_id = H5Screate_simple(ndims, hcount, hcount); - if (mem_space_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new simple dataspace", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + if(H5Dextend(file->hdf5_vars[varid].hdf5_dataset_id, dims) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to extend the dataset associated with this variable", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); } - if (ndims > 0) - { - if (H5Sselect_hyperslab(file_space_id, H5S_SELECT_SET, hstart, hstride, hcount, NULL) < 0) - { - H5Eprint2(H5E_DEFAULT, stderr); - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to select a hyperslab region for a dataspace copied from the dataset associated with this variable", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } + file_space_id = H5Dget_space(file->hdf5_vars[varid].hdf5_dataset_id); + if(file_space_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to make a copy of the dataspace of the dataset (extended) associated with this variable", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); } + } - hid_t mem_type_id; - if (xtype == NC_CHAR) - { - /* String type */ - mem_type_id = H5Tcopy(H5T_C_S1); - if (mem_type_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to make a copy of the predefined string datatype in C", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } + hsize_t hstart[(ndims > 0) ? ndims : 1]; + hsize_t hcount[(ndims > 0) ? ndims : 1]; + hsize_t hstride[(ndims > 0) ? ndims : 1]; + hsize_t nelems = 0; - if (H5Tset_strpad(mem_type_id, H5T_STR_NULLTERM) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to define the type of padding (NULL-terminated) used for a derived C-style string datatype", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } + for(int i = 0; i < ndims; i++){ + if(start){ + hstart[i] = (hsize_t) start[i]; + } + else{ + hstart[i] = 0; + } + hcount[i] = 0; + hstride[i] = 1; + } - if (H5Tset_cset(mem_type_id, H5T_CSET_ASCII) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to set the character set (US ASCII) to be used in a derived C-style string datatype", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } + /* Only the IO master does the IO */ + if(ios->iomaster == MPI_ROOT){ + if(count){ + for(int i = 0; i < ndims; i++){ + hcount[i] = (hsize_t)count[i]; + } } - else - { - mem_type_id = spio_nc_type_to_hdf5_type(xtype); - if (mem_type_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "Unsupported memory type (type=%x)", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, xtype); - } + else{ + for(int i = 0; i < ndims; i++){ + hcount[i] = dims[i]; + } } - /* Independent write */ - if (H5Dwrite(file->hdf5_vars[varid].hdf5_dataset_id, mem_type_id, mem_space_id, - file_space_id, file->dxplid_indep, buf) < 0) - { - H5Eprint2(H5E_DEFAULT, stderr); - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to write the dataset associated with this variable", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + nelems = (ndims > 0) ? 1 : 0; + for(int i = 0; i < ndims; i++){ + nelems *= hcount[i]; } - if (H5Sclose(mem_space_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a simple dataspace", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + if(stride){ + for(int i = 0; i < ndims; i++){ + hstride[i] = (stride[i] > 0) ? ((hsize_t)stride[i]) : 1 ; + } } + } - if (xtype == NC_CHAR) - { - if (H5Tclose(mem_type_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a derived C-style string datatype used by this variable", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } + hid_t mem_space_id = H5Screate_simple(ndims, hcount, hcount); + if(mem_space_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new simple dataspace", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + if(ndims > 0){ + if(H5Sselect_hyperslab(file_space_id, H5S_SELECT_SET, hstart, hstride, hcount, NULL) < 0){ + H5Eprint2(H5E_DEFAULT, stderr); + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to select a hyperslab region for a dataspace copied from the dataset associated with this variable", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); } + } - if (H5Sclose(file_space_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a dataspace copied from the dataset associated with this variable", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + hid_t mem_type_id; + if(xtype == NC_CHAR){ + /* String type */ + mem_type_id = H5Tcopy(H5T_C_S1); + if(mem_type_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to make a copy of the predefined string datatype in C", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + if(H5Tset_strpad(mem_type_id, H5T_STR_NULLTERM) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to define the type of padding (NULL-terminated) used for a derived C-style string datatype", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + if(H5Tset_cset(mem_type_id, H5T_CSET_ASCII) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to set the character set (US ASCII) to be used in a derived C-style string datatype", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + } + else{ + mem_type_id = spio_nc_type_to_hdf5_type(xtype); + if(mem_type_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "Unsupported memory type (type=%x)", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, xtype); + } + } + + /* Independent write */ + if(H5Dwrite(file->hdf5_vars[varid].hdf5_dataset_id, mem_type_id, mem_space_id, + file_space_id, file->dxplid_indep, buf) < 0){ + H5Eprint2(H5E_DEFAULT, stderr); + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to write the dataset associated with this variable", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + if(H5Sclose(mem_space_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a simple dataspace", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + if(xtype == NC_CHAR){ + if(H5Tclose(mem_type_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a derived C-style string datatype used by this variable", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); } + } + + if(H5Sclose(file_space_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a dataspace copied from the dataset associated with this variable", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } - return PIO_NOERR; + return PIO_NOERR; } int spio_hdf5_close(iosystem_desc_t *ios, file_desc_t *file) { - int i = 0; + int i = 0; - assert(ios && file); - assert((file->iotype == PIO_IOTYPE_HDF5) || ((file->iotype == PIO_IOTYPE_HDF5C))); - assert(ios->ioproc); + assert(ios && file); + assert((file->iotype == PIO_IOTYPE_HDF5) || ((file->iotype == PIO_IOTYPE_HDF5C))); + assert(ios->ioproc); - /* Since close is always an async op, when async thread is used, we do not need - * to explicitly wait for async ops to complete - * i.e., we don't need spio_wait_all_hdf5_async_ops() here - */ + /* Since close is always an async op, when async thread is used, we do not need + * to explicitly wait for async ops to complete + * i.e., we don't need spio_wait_all_hdf5_async_ops() here + */ + if(H5Pclose(file->dxplid_coll) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Closing file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to close a dataset transfer property list (collective data transfer)", + pio_get_fname_from_file(file), file->pio_ncid); + } - if (H5Pclose(file->dxplid_coll) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Closing file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to close a dataset transfer property list (collective data transfer)", - pio_get_fname_from_file(file), file->pio_ncid); - } + if(H5Pclose(file->dxplid_indep) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Closing file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to close a dataset transfer property list (independent data transfer)", + pio_get_fname_from_file(file), file->pio_ncid); + } - if (H5Pclose(file->dxplid_indep) < 0) - { + for(i = 0; i < file->hdf5_num_dims; i++){ + if(!file->hdf5_dims[i].has_coord_var){ + if(H5Dclose(file->hdf5_dims[i].hdf5_dataset_id) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, "Closing file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to close a dataset transfer property list (independent data transfer)", - pio_get_fname_from_file(file), file->pio_ncid); - } - - for (i = 0; i < file->hdf5_num_dims; i++) - { - if (!file->hdf5_dims[i].has_coord_var) - { - if (H5Dclose(file->hdf5_dims[i].hdf5_dataset_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Closing file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to close a dataset created for a dimension (%s, dimid = %d)", - pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_dims[i].name, i); - } - } + "The low level (HDF5) I/O library call failed to close a dataset created for a dimension (%s, dimid = %d)", + pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_dims[i].name, i); + } } + } - for (i = 0; i < file->hdf5_num_vars; i++) - { - if (H5Dclose(file->hdf5_vars[i].hdf5_dataset_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Closing file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to close a dataset created for a variable (%s, varid = %d)", - pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_vars[i].name, i); - } - - if (file->hdf5_vars[i].nc_type == NC_CHAR) - { - if (H5Tclose(file->hdf5_vars[i].hdf5_type) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Closing file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a derived C-style string datatype created for a variable (%s, varid = %d)", - pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_dims[i].name, i); - } - } + for(i = 0; i < file->hdf5_num_vars; i++){ + if(H5Dclose(file->hdf5_vars[i].hdf5_dataset_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Closing file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to close a dataset created for a variable (%s, varid = %d)", + pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_vars[i].name, i); } - if (H5Fclose(file->hdf5_file_id) < 0) - { + if(file->hdf5_vars[i].nc_type == NC_CHAR){ + if(H5Tclose(file->hdf5_vars[i].hdf5_type) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, "Closing file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to terminate access to an HDF5 file", - pio_get_fname_from_file(file), file->pio_ncid); + "The low level (HDF5) I/O library call failed to release a derived C-style string datatype created for a variable (%s, varid = %d)", + pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_dims[i].name, i); + } } + } - return PIO_NOERR; + if(H5Fclose(file->hdf5_file_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Closing file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to terminate access to an HDF5 file", + pio_get_fname_from_file(file), file->pio_ncid); + } + + return PIO_NOERR; } #endif diff --git a/src/clib/spio_hdf5_utils.hpp b/src/clib/spio_hdf5_utils.hpp index 20271681b2..2ede67942b 100644 --- a/src/clib/spio_hdf5_utils.hpp +++ b/src/clib/spio_hdf5_utils.hpp @@ -9,10 +9,8 @@ #endif // PIO_USE_HDF5 #ifdef _HDF5 -hid_t spio_nc_type_to_hdf5_type(nc_type xtype); -int spio_hdf5_type_to_pio_type(hid_t xtype); -PIO_Offset hdf5_get_nc_type_size(nc_type xtype); +/* Function declarations */ int spio_hdf5_create(iosystem_desc_t *ios, file_desc_t *file, const char *filename); int spio_hdf5_def_var(iosystem_desc_t *ios, file_desc_t *file, const char *name, @@ -28,6 +26,52 @@ int spio_hdf5_put_var(iosystem_desc_t *ios, file_desc_t *file, int varid, const PIO_Offset *stride, nc_type xtype, const void *buf); int spio_hdf5_close(iosystem_desc_t *ios, file_desc_t *file); + +/* Inline functions */ +inline hid_t spio_nc_type_to_hdf5_type(nc_type xtype) +{ + switch(xtype){ + case NC_BYTE: return H5T_NATIVE_UINT8; + case NC_UBYTE: return H5T_NATIVE_UCHAR; + case NC_CHAR: return H5T_NATIVE_CHAR; + case NC_SHORT: return H5T_NATIVE_SHORT; + case NC_USHORT: return H5T_NATIVE_USHORT; + case NC_INT: return H5T_NATIVE_INT; + case NC_UINT: return H5T_NATIVE_UINT; + case NC_FLOAT : return H5T_NATIVE_FLOAT; + case NC_DOUBLE: return H5T_NATIVE_DOUBLE; + case NC_INT64: return H5T_NATIVE_INT64; + case NC_UINT64: return H5T_NATIVE_UINT64; + default: return H5I_INVALID_HID; + } + + return H5I_INVALID_HID; +} + +inline int spio_hdf5_type_to_pio_type(hid_t ntype) +{ + /* switch() does not work with HDF5 "types" since these types are macros + * (which include library initialization call, H5Open(), if needed) + */ + if(H5Tequal(ntype, H5T_NATIVE_UINT8)) { return PIO_BYTE; } + else if(H5Tequal(ntype, H5T_NATIVE_UCHAR)) { return PIO_UBYTE; } + else if(H5Tequal(ntype, H5T_NATIVE_CHAR)) { return PIO_CHAR; } + else if(H5Tequal(ntype, H5T_NATIVE_SHORT)) { return PIO_SHORT; } + else if(H5Tequal(ntype, H5T_NATIVE_USHORT)) { return PIO_USHORT; } + else if(H5Tequal(ntype, H5T_NATIVE_INT)) { return PIO_INT; } + else if(H5Tequal(ntype, H5T_NATIVE_UINT)) { return PIO_UINT; } + else if(H5Tequal(ntype, H5T_NATIVE_FLOAT)) { return PIO_FLOAT; } + else if(H5Tequal(ntype, H5T_NATIVE_DOUBLE)) { return PIO_DOUBLE; } + else if(H5Tequal(ntype, H5T_NATIVE_INT64)) { return PIO_INT64; } + else if(H5Tequal(ntype, H5T_NATIVE_UINT64)) { return PIO_UINT64; } + else{ + assert(0); + } + + return PIO_NAT; +} + + #endif #endif // __SPIO_HDF5_UTILS_HPP__ From dd438f4949a1d5d6d1f0b1a6b37a7607e8f692aa Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 13 Jan 2026 10:35:59 -0600 Subject: [PATCH 106/194] Moving async hdf5 utils to a separate file Moving all async HDF5-specific utilities to a separate source file No code change (Moving source code around) --- src/clib/CMakeLists.txt | 2 +- src/clib/spio_async_hdf5_utils.cpp | 440 +++++++++++++++++++++++++++++ src/clib/spio_async_hdf5_utils.hpp | 19 ++ src/clib/spio_async_utils.cpp | 409 --------------------------- src/clib/spio_async_utils.hpp | 5 +- 5 files changed, 462 insertions(+), 413 deletions(-) create mode 100644 src/clib/spio_async_hdf5_utils.cpp create mode 100644 src/clib/spio_async_hdf5_utils.hpp diff --git a/src/clib/CMakeLists.txt b/src/clib/CMakeLists.txt index 0d2e0f979e..32ddc18942 100644 --- a/src/clib/CMakeLists.txt +++ b/src/clib/CMakeLists.txt @@ -46,7 +46,7 @@ set (pio_lib_src spio_ltimer.cpp spio_serializer.cpp spio_file_mvcache.cpp spio_tracer.cpp spio_tracer_mdata.cpp spio_tracer_decomp.cpp spio_rearrange_any.cpp spio_dt_converter.cpp - spio_async_tpool.cpp spio_async_utils.cpp spio_hdf5_utils.cpp) + spio_async_tpool.cpp spio_async_utils.cpp spio_hdf5_utils.cpp spio_async_hdf5_utils.cpp) # Add sources for libpioc.a add_library (pioc ${pio_api_src} ${pio_lib_src}) diff --git a/src/clib/spio_async_hdf5_utils.cpp b/src/clib/spio_async_hdf5_utils.cpp new file mode 100644 index 0000000000..fa2c9e5020 --- /dev/null +++ b/src/clib/spio_async_hdf5_utils.cpp @@ -0,0 +1,440 @@ +/** @file + * Utility functions for Asynchronous I/O using HDF5 + */ + +#include +#include +#include +#include +#include +#include + +extern "C"{ + +#include +#include +#include +#include +#if PIO_ENABLE_LOGGING +#include +#endif /* PIO_ENABLE_LOGGING */ +#include +} // extern "C" +#if PIO_USE_ASYNC_WR_THREAD +#include "spio_async_tpool_cint.h" +#endif +#include "pio_timer.h" +#include +#include "spio_async_utils.hpp" +#include "spio_async_tpool.hpp" +#include "spio_file_mvcache.h" +#include "spio_dbg_utils.hpp" +#include "spio_dt_converter.hpp" +#include "spio_hdf5_utils.hpp" +#include "spio_async_tpool_cint.h" + +struct Hdf5_wcache{ + file_desc_t *file; + int nvars; + int fndims; + std::vector varids; + io_desc_t *iodesc; + std::vector frame; + + bool wr_fillbuf; + void *iobuf; + std::size_t iobuf_sz; + void *fillbuf; + std::size_t fillbuf_sz; +}; + +/* Global vars */ +std::atomic SPIO_Util::GVars::npend_hdf5_async_ops; + +#ifdef _HDF5 +namespace Util{ + /* Each variable writes out one or more regions of data. However all variables have the + * same I/O decomposition and write the same regions (within the variable) of data. The + * region info is the same across all variables + * Note: Different variables (among nvars variables) could be writing out different + * timesteps/records (while still writing the same region - within the record) + */ + struct RInfo{ + /* The starts(:) for this region - local to this process */ + std::vector starts; + /* The counts(:) for this region - local to this process */ + std::vector counts; + /* Total number of elements written out, locally, for this region */ + std::size_t nelems; + }; +} // namespace Util + +/* Update the the start frame for all regions in reg_infos, based on the variable's current frame */ +static inline void update_reg_infos_start_frame(std::vector ®_infos, const var_desc_t *vdesc, const int frame) +{ + /* If the variable has records/frames then update the starts(:) to the provided frame/record number */ + if(vdesc->record >= 0){ + for(std::vector::iterator iter = reg_infos.begin(); iter != reg_infos.end(); ++iter){ + assert(iter->starts.size() > 0); + iter->starts[0] = frame; + } + } +} +#endif // _HDF5 + +int spio_wait_all_hdf5_async_ops(int iosysid) +{ + const int SLEEP_TIME_IN_MILLISECONDS = 500; + while(SPIO_Util::GVars::npend_hdf5_async_ops > 0){ + std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME_IN_MILLISECONDS)); + if(SPIO_Util::GVars::npend_hdf5_async_ops > 0){ + PIOc_warn(iosysid, PIO_DEFAULT, __FILE__, __LINE__, "Continuing to wait on all HDF5 async ops..."); + } + } + + return PIO_NOERR; +} + +int pio_iosys_async_op_hdf5_write(void *pdata) +{ +#ifdef _HDF5 + /* FIXME: Add futures */ + int ret = PIO_NOERR; + Hdf5_wcache *wcache = static_cast(pdata); + assert(wcache); + + file_desc_t *file = wcache->file; + int nvars = wcache->nvars; + int fndims = wcache->fndims; + io_desc_t *iodesc = wcache->iodesc; + + assert(file && (nvars > 0) && (fndims > 0) && iodesc); + assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); + + iosystem_desc_t *ios = file->iosystem; + var_desc_t *v1desc = file->varlist + wcache->varids[0]; + + assert(ios && v1desc && ios->ioproc); + + bool wr_fillbuf = wcache->wr_fillbuf; + + //int num_regions = (wr_fillbuf) ? iodesc->maxfillregions : iodesc->maxregions; + io_region *region = (wr_fillbuf) ? iodesc->fillregion : iodesc->firstregion; + PIO_Offset llen = (wr_fillbuf) ? iodesc->holegridsize : iodesc->llen; + void *iobuf = (wr_fillbuf) ? (wcache->fillbuf) : (wcache->iobuf); + std::size_t iobuf_sz = (wr_fillbuf) ? (wcache->fillbuf_sz) : (wcache->iobuf_sz); + + assert(region && (nvars * llen * iodesc->mpitype_size == static_cast(iobuf_sz))); + assert(((iobuf_sz == 0) && !iobuf) || ((iobuf_sz != 0) && iobuf)); + + /* Info on all regions */ + std::vector vreg_infos; + /* Total number of elements written out for all the regions. Since all variables write + * out the same regions - since they use the same I/O decomposition - the total number + * of elements written out for each variable will be the same (reg_nelems) + */ + hsize_t reg_nelems = 0; + + /* Collect region info, starts/counts etc, for all regions */ + while(region){ + std::size_t start[fndims], count[fndims]; + + ret = spio_find_start_count(iodesc->ndims, iodesc->dimlen, fndims, v1desc, region, start, count); + if(ret != PIO_NOERR){ + return pio_err(ios, file, ret, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) failed. Internal error finding start/count for the I/O regions written out from the I/O process", nvars, pio_get_fname_from_file(file), file->pio_ncid); + } + + std::size_t nelems = std::accumulate(count, count + fndims, 1, std::multiplies()); + + /* Note: The region info is tied to the first variable, we need to update the variable specific + * sections, start(:) based on the record/frame being written out, later + */ + if(nelems > 0){ + std::vector tmp_start(start, start + fndims); + std::vector tmp_count(count, count + fndims); + vreg_infos.push_back({tmp_start, tmp_count, nelems}); + reg_nelems += static_cast(nelems); + } + region = region->next; + } + + std::size_t num_regions = vreg_infos.size(); + + /* Write data - one variable at a time (all regions for a variable written out in a single call) */ + var_desc_t *vdesc = NULL; + void *bufptr = NULL; + for(int vidx = 0; vidx < nvars; vidx++){ + hid_t file_space_id = H5Dget_space(file->hdf5_vars[wcache->varids[vidx]].hdf5_dataset_id); + if(file_space_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to make a copy of the dataspace of the dataset associated with variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); + } + + hid_t mem_space_id = H5I_INVALID_HID; + if(reg_nelems > 0){ + /* Get the var info. */ + vdesc = file->varlist + wcache->varids[vidx]; + + /* Update the generic region info with variable-specific info */ + /* If this is a record (or quasi-record) var, set the start for + * the record dimension. */ + if((fndims > 1) && (vdesc->record > 0)){ + assert(static_cast(wcache->frame.size()) == nvars); + update_reg_infos_start_frame(vreg_infos, vdesc, wcache->frame[vidx]); + } + + + /* Create a hyperslab of all the regions written out for a variable */ + H5S_seloper_t op = H5S_SELECT_SET; + for(std::size_t ireg = 0; ireg < num_regions; ireg++){ + /* Union hyperslabs of all regions */ + if(H5Sselect_hyperslab(file_space_id, op, static_cast(vreg_infos[ireg].starts.data()), NULL, static_cast(vreg_infos[ireg].counts.data()), NULL) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to select a hyperslab region for a dataspace copied from the dataset associated with variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); + } + + op = H5S_SELECT_OR; + } + + /* Total number of elements across all regions = + * total number of elements written out with this hyperslab = reg_nelems + */ + mem_space_id = H5Screate_simple(1, ®_nelems, NULL); + if(mem_space_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new simple dataspace for variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); + } + + /* Get a pointer to the data. This buffer points to data from all the regions written out for this variable */ + bufptr = (void *)((char *)iobuf + vidx * iodesc->mpitype_size * llen); + } + else{ + /* No data, across all regions, to write on this IO task */ + if(H5Sselect_none(file_space_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to reset the selection region for a dataspace copied from the dataset associated with variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); + } + + mem_space_id = H5Screate(H5S_NULL); + if(mem_space_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to create a new NULL dataspace for variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); + } + + bufptr = NULL; + } + + /* Collective write - for all regions in a single variable */ + hid_t mem_type_id = spio_nc_type_to_hdf5_type(iodesc->piotype); + if(mem_type_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "Unsupported memory type (type=%x) for variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, iodesc->piotype, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); + } + + hid_t file_var_type_id = H5Dget_type(file->hdf5_vars[wcache->varids[vidx]].hdf5_dataset_id); + if(file_var_type_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "Unable to query the type of variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); + } + + hid_t file_var_ntype_id = H5Tget_native_type(file_var_type_id, H5T_DIR_DEFAULT); + assert(file_var_ntype_id != H5I_INVALID_HID); + + /* When HDF5 filters (e.g. data compression) are enabled collective writes fail when datatype conversion is required for writing user data. + * So we manually perform the data conversion here before passing it to HDF5. When filters are not enabled the write might succeed but HDF5 + * might be switching off collective writes (hurts performance) when datatype conversion is required + * FIXME: Disable datatype conversion when filters are not enabled on the dataset + */ + void *wbuf = bufptr; + if((reg_nelems > 0) && !H5Tequal(mem_type_id, file_var_ntype_id)){ + assert(file->dt_converter); + wbuf = static_cast(file->dt_converter)->convert(iodesc->ioid, bufptr, iodesc->mpitype_size * reg_nelems, + iodesc->piotype, spio_hdf5_type_to_pio_type(file_var_ntype_id)); + if(wbuf == NULL){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "Unable to convert the type (from %d to %d) of variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, iodesc->piotype, + spio_hdf5_type_to_pio_type(file_var_ntype_id), pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); + } + } + + if(H5Dwrite(file->hdf5_vars[wcache->varids[vidx]].hdf5_dataset_id, file_var_ntype_id, mem_space_id, file_space_id, + file->dxplid_coll, wbuf) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to write the dataset associated with variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); + } + +#if SPIO_HDF5_FLUSH_AFTER_COLL_WR + if(H5Fflush(file->hdf5_file_id, H5F_SCOPE_LOCAL) < 0){ + H5Eprint2(H5E_DEFAULT, stderr); + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to flush the dataset associated with variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); + } +#endif + + if(H5Sclose(file_space_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a dataspace copied from the dataset associated with variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); + } + + if(H5Sclose(mem_space_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a simple (or NULL) dataspace for variable (%s, varid=%d)", + nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); + } + } + + /* FIXME: Is this barrier needed ? */ + MPI_Barrier(ios->io_comm); + + iodesc->nasync_pend_ops--; + file->npend_ops--; + SPIO_Util::GVars::npend_hdf5_async_ops--; + + return PIO_NOERR; +#else // _HDF5 + assert(0); + return PIO_EINTERNAL; +#endif // _HDF5 +} + +void pio_iosys_async_op_hdf5_free(void *pdata) +{ +#ifdef _HDF5 + Hdf5_wcache *wcache = static_cast(pdata); + assert(wcache); + + /* Using swap trick to free vectors + * - swap vector with an empty local/temp vector that gets deallocated when func exits + */ + //wcache->varids.clear(); + std::vector().swap(wcache->varids); + //wcache->frame.clear(); + std::vector().swap(wcache->frame); + + if(wcache->iobuf){ brel(wcache->iobuf); } + if(wcache->fillbuf){ brel(wcache->fillbuf); } + + free(wcache); +#else // _HDF5 + assert(0); +#endif // _HDF5 +} + +int pio_iosys_async_hdf5_write_op_add(file_desc_t *file, int nvars, int fndims, + const int *varids, io_desc_t *iodesc, int fill, const int *frame) +{ +#ifdef _HDF5 + int ret = PIO_NOERR; + + assert(file && (nvars > 0) && (fndims > 0) && varids && iodesc); + + iosystem_desc_t *ios = file->iosystem; + assert(ios); + + if(!ios->ioproc){ + return PIO_NOERR; + } + + std::vector vids(varids, varids + nvars); + std::vector frms; + if(frame){ + frms.resize(nvars); + std::copy(frame, frame + nvars, frms.begin()); + } + + Hdf5_wcache *wcache = static_cast(calloc(1, sizeof(Hdf5_wcache))); + *wcache = {file, nvars, fndims, vids, iodesc, frms, (fill) ? true : false, NULL, 0, NULL, 0}; + + /* We need to copy the iobuf/fillbuf since the mvcache gets reused for future writes */ + /* Copy iobuf/fillvalue */ + var_desc_t *v1desc = file->varlist + varids[0]; + //PIO_Offset llen = fill ? iodesc->holegridsize : iodesc->llen; + if(fill){ + std::size_t fillbuf_sz = iodesc->holegridsize * iodesc->mpitype_size; + /* On I/O processes with no data (after rearrangement) to write the fillbuf_sz will be 0 */ + if(fillbuf_sz > 0){ + wcache->fillbuf = bget(fillbuf_sz); + if(!wcache->fillbuf){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Queuing asynchronous op/task for writing fillvalue for variables (number of variables = %d) to file (%s, ncid=%d) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for caching variable fillvalue", nvars, pio_get_fname_from_file(file), file->pio_ncid, static_cast(fillbuf_sz)); + } + + std::memcpy(wcache->fillbuf, v1desc->fillbuf, fillbuf_sz); + wcache->fillbuf_sz = fillbuf_sz; + } + } + else{ + /* Copy buffer, with rearranged data, for nvars */ + std::size_t iobuf_sz = nvars * iodesc->llen * iodesc->mpitype_size; + /* On I/O processes with no data (after rearrangement) to write the iobuf_sz will be 0 */ + if(iobuf_sz > 0){ + wcache->iobuf = bget(iobuf_sz); + if(!wcache->iobuf){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Queuing asynchronous op/task for writing fillvalue for variables (number of variables = %d) to file (%s, ncid=%d) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for caching variable data for all the variables", nvars, pio_get_fname_from_file(file), file->pio_ncid, static_cast(iobuf_sz)); + } + + void *iobuf = spio_file_mvcache_get(file, iodesc->ioid); + assert(iobuf); + std::memcpy(wcache->iobuf, iobuf, iobuf_sz); + wcache->iobuf_sz = iobuf_sz; + } + } + + /* Create async task */ + pio_async_op_t *pnew = static_cast(calloc(1, sizeof(pio_async_op_t))); + if(pnew == NULL){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Queuing asynchronous op/task for writing fillvalue for variables (number of variables = %d) to file (%s, ncid=%d) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for async task internal struct", nvars, pio_get_fname_from_file(file), file->pio_ncid, static_cast(sizeof(pio_async_op_t))); + } + + pnew->op_type = PIO_ASYNC_HDF5_WRITE_OP; + pnew->pdata = static_cast(wcache); + pnew->wait = pio_iosys_async_op_hdf5_write; + pnew->poke = pio_async_poke_func_unavail; + pnew->free = pio_iosys_async_op_hdf5_free; + + /* One more pending op using this iodesc & file */ + iodesc->nasync_pend_ops++; + file->npend_ops++; + SPIO_Util::GVars::npend_hdf5_async_ops++; + + /* Get the mt queue and queue the async task */ + ret = pio_async_tpool_op_add(pnew); + if(ret != PIO_NOERR){ + LOG((1, "Adding file pending ops to tpool failed, ret = %d", ret)); + return pio_err(ios, NULL, ret, __FILE__, __LINE__, + "Internal error while adding asynchronous pending operation to the thread pool (iosystem = %d). Adding the asynchronous operation failed", ios->iosysid); + } + + return PIO_NOERR; +#else // _HDF5 + assert(0); + return PIO_EINTERNAL; +#endif // _HDF5 +} + diff --git a/src/clib/spio_async_hdf5_utils.hpp b/src/clib/spio_async_hdf5_utils.hpp new file mode 100644 index 0000000000..b31d8000ba --- /dev/null +++ b/src/clib/spio_async_hdf5_utils.hpp @@ -0,0 +1,19 @@ +#ifndef __SPIO_ASYNC_HDF5_UTILS_HPP__ +#include "pio_config.h" +#include "pio.h" +#include "pio_internal.h" + +namespace SPIO_Util{ + namespace GVars{ + extern std::atomic npend_hdf5_async_ops; + } // namespace GVars +} // namespace SPIO_Util + +int spio_wait_all_hdf5_async_ops(int iosysid); +int pio_iosys_async_op_hdf5_write(void *pdata); +void pio_iosys_async_op_hdf5_free(void *pdata); +int pio_iosys_async_hdf5_write_op_add(file_desc_t *file, int nvars, int fndims, + const int *varids, io_desc_t *iodesc, int fill, const int *frame); + +#define __SPIO_ASYNC_HDF5_UTILS_HPP__ +#endif // __SPIO_ASYNC_HDF5_UTILS_HPP__ diff --git a/src/clib/spio_async_utils.cpp b/src/clib/spio_async_utils.cpp index 0d6cc36697..279b085107 100644 --- a/src/clib/spio_async_utils.cpp +++ b/src/clib/spio_async_utils.cpp @@ -33,7 +33,6 @@ extern "C"{ #include "spio_hdf5_utils.hpp" #include "spio_async_tpool_cint.h" - std::string pio_async_op_type_to_string(pio_async_op_type_t op) { switch(op){ @@ -963,414 +962,6 @@ int pio_tpool_async_pend_op_add(iosystem_desc_t *iosys, return PIO_NOERR; } -struct Hdf5_wcache{ - file_desc_t *file; - int nvars; - int fndims; - std::vector varids; - io_desc_t *iodesc; - std::vector frame; - - bool wr_fillbuf; - void *iobuf; - std::size_t iobuf_sz; - void *fillbuf; - std::size_t fillbuf_sz; -}; - -#ifdef _HDF5 -namespace Util{ - /* Each variable writes out one or more regions of data. However all variables have the - * same I/O decomposition and write the same regions (within the variable) of data. The - * region info is the same across all variables - * Note: Different variables (among nvars variables) could be writing out different - * timesteps/records (while still writing the same region - within the record) - */ - struct RInfo{ - /* The starts(:) for this region - local to this process */ - std::vector starts; - /* The counts(:) for this region - local to this process */ - std::vector counts; - /* Total number of elements written out, locally, for this region */ - std::size_t nelems; - }; -} // namespace Util - -/* Update the the start frame for all regions in reg_infos, based on the variable's current frame */ -static inline void update_reg_infos_start_frame(std::vector ®_infos, const var_desc_t *vdesc, const int frame) -{ - /* If the variable has records/frames then update the starts(:) to the provided frame/record number */ - if(vdesc->record >= 0){ - for(std::vector::iterator iter = reg_infos.begin(); iter != reg_infos.end(); ++iter){ - assert(iter->starts.size() > 0); - iter->starts[0] = frame; - } - } -} -#endif // _HDF5 - -namespace SPIO_Util{ - namespace GVars{ - std::atomic npend_hdf5_async_ops; - } // namespace GVars -} // namespace SPIO_Util - -int spio_wait_all_hdf5_async_ops(int iosysid) -{ - const int SLEEP_TIME_IN_MILLISECONDS = 500; - while(SPIO_Util::GVars::npend_hdf5_async_ops > 0){ - std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME_IN_MILLISECONDS)); - if(SPIO_Util::GVars::npend_hdf5_async_ops > 0){ - PIOc_warn(iosysid, PIO_DEFAULT, __FILE__, __LINE__, "Continuing to wait on all HDF5 async ops..."); - } - } - - return PIO_NOERR; -} - -int pio_iosys_async_op_hdf5_write(void *pdata) -{ -#ifdef _HDF5 - /* FIXME: Add futures */ - int ret = PIO_NOERR; - Hdf5_wcache *wcache = static_cast(pdata); - assert(wcache); - - file_desc_t *file = wcache->file; - int nvars = wcache->nvars; - int fndims = wcache->fndims; - io_desc_t *iodesc = wcache->iodesc; - - assert(file && (nvars > 0) && (fndims > 0) && iodesc); - assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); - - iosystem_desc_t *ios = file->iosystem; - var_desc_t *v1desc = file->varlist + wcache->varids[0]; - - assert(ios && v1desc && ios->ioproc); - - bool wr_fillbuf = wcache->wr_fillbuf; - - //int num_regions = (wr_fillbuf) ? iodesc->maxfillregions : iodesc->maxregions; - io_region *region = (wr_fillbuf) ? iodesc->fillregion : iodesc->firstregion; - PIO_Offset llen = (wr_fillbuf) ? iodesc->holegridsize : iodesc->llen; - void *iobuf = (wr_fillbuf) ? (wcache->fillbuf) : (wcache->iobuf); - std::size_t iobuf_sz = (wr_fillbuf) ? (wcache->fillbuf_sz) : (wcache->iobuf_sz); - - assert(region && (nvars * llen * iodesc->mpitype_size == static_cast(iobuf_sz))); - assert(((iobuf_sz == 0) && !iobuf) || ((iobuf_sz != 0) && iobuf)); - - /* Info on all regions */ - std::vector vreg_infos; - /* Total number of elements written out for all the regions. Since all variables write - * out the same regions - since they use the same I/O decomposition - the total number - * of elements written out for each variable will be the same (reg_nelems) - */ - hsize_t reg_nelems = 0; - - /* Collect region info, starts/counts etc, for all regions */ - while(region){ - std::size_t start[fndims], count[fndims]; - - ret = spio_find_start_count(iodesc->ndims, iodesc->dimlen, fndims, v1desc, region, start, count); - if(ret != PIO_NOERR){ - return pio_err(ios, file, ret, __FILE__, __LINE__, - "Writing variables (number of variables = %d) to file (%s, ncid=%d) failed. Internal error finding start/count for the I/O regions written out from the I/O process", nvars, pio_get_fname_from_file(file), file->pio_ncid); - } - - std::size_t nelems = std::accumulate(count, count + fndims, 1, std::multiplies()); - - /* Note: The region info is tied to the first variable, we need to update the variable specific - * sections, start(:) based on the record/frame being written out, later - */ - if(nelems > 0){ - std::vector tmp_start(start, start + fndims); - std::vector tmp_count(count, count + fndims); - vreg_infos.push_back({tmp_start, tmp_count, nelems}); - reg_nelems += static_cast(nelems); - } - region = region->next; - } - - std::size_t num_regions = vreg_infos.size(); - - /* Write data - one variable at a time (all regions for a variable written out in a single call) */ - var_desc_t *vdesc = NULL; - void *bufptr = NULL; - for(int vidx = 0; vidx < nvars; vidx++){ - hid_t file_space_id = H5Dget_space(file->hdf5_vars[wcache->varids[vidx]].hdf5_dataset_id); - if(file_space_id == H5I_INVALID_HID){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to make a copy of the dataspace of the dataset associated with variable (%s, varid=%d)", - nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); - } - - hid_t mem_space_id = H5I_INVALID_HID; - if(reg_nelems > 0){ - /* Get the var info. */ - vdesc = file->varlist + wcache->varids[vidx]; - - /* Update the generic region info with variable-specific info */ - /* If this is a record (or quasi-record) var, set the start for - * the record dimension. */ - if((fndims > 1) && (vdesc->record > 0)){ - assert(static_cast(wcache->frame.size()) == nvars); - update_reg_infos_start_frame(vreg_infos, vdesc, wcache->frame[vidx]); - } - - - /* Create a hyperslab of all the regions written out for a variable */ - H5S_seloper_t op = H5S_SELECT_SET; - for(std::size_t ireg = 0; ireg < num_regions; ireg++){ - /* Union hyperslabs of all regions */ - if(H5Sselect_hyperslab(file_space_id, op, static_cast(vreg_infos[ireg].starts.data()), NULL, static_cast(vreg_infos[ireg].counts.data()), NULL) < 0){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to select a hyperslab region for a dataspace copied from the dataset associated with variable (%s, varid=%d)", - nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); - } - - op = H5S_SELECT_OR; - } - - /* Total number of elements across all regions = - * total number of elements written out with this hyperslab = reg_nelems - */ - mem_space_id = H5Screate_simple(1, ®_nelems, NULL); - if(mem_space_id == H5I_INVALID_HID){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new simple dataspace for variable (%s, varid=%d)", - nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); - } - - /* Get a pointer to the data. This buffer points to data from all the regions written out for this variable */ - bufptr = (void *)((char *)iobuf + vidx * iodesc->mpitype_size * llen); - } - else{ - /* No data, across all regions, to write on this IO task */ - if(H5Sselect_none(file_space_id) < 0){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to reset the selection region for a dataspace copied from the dataset associated with variable (%s, varid=%d)", - nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); - } - - mem_space_id = H5Screate(H5S_NULL); - if(mem_space_id == H5I_INVALID_HID){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to create a new NULL dataspace for variable (%s, varid=%d)", - nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); - } - - bufptr = NULL; - } - - /* Collective write - for all regions in a single variable */ - hid_t mem_type_id = spio_nc_type_to_hdf5_type(iodesc->piotype); - if(mem_type_id == H5I_INVALID_HID){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "Unsupported memory type (type=%x) for variable (%s, varid=%d)", - nvars, pio_get_fname_from_file(file), file->pio_ncid, iodesc->piotype, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); - } - - hid_t file_var_type_id = H5Dget_type(file->hdf5_vars[wcache->varids[vidx]].hdf5_dataset_id); - if(file_var_type_id == H5I_INVALID_HID){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "Unable to query the type of variable (%s, varid=%d)", - nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); - } - - hid_t file_var_ntype_id = H5Tget_native_type(file_var_type_id, H5T_DIR_DEFAULT); - assert(file_var_ntype_id != H5I_INVALID_HID); - - /* When HDF5 filters (e.g. data compression) are enabled collective writes fail when datatype conversion is required for writing user data. - * So we manually perform the data conversion here before passing it to HDF5. When filters are not enabled the write might succeed but HDF5 - * might be switching off collective writes (hurts performance) when datatype conversion is required - * FIXME: Disable datatype conversion when filters are not enabled on the dataset - */ - void *wbuf = bufptr; - if((reg_nelems > 0) && !H5Tequal(mem_type_id, file_var_ntype_id)){ - assert(file->dt_converter); - wbuf = static_cast(file->dt_converter)->convert(iodesc->ioid, bufptr, iodesc->mpitype_size * reg_nelems, - iodesc->piotype, spio_hdf5_type_to_pio_type(file_var_ntype_id)); - if(wbuf == NULL){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "Unable to convert the type (from %d to %d) of variable (%s, varid=%d)", - nvars, pio_get_fname_from_file(file), file->pio_ncid, iodesc->piotype, - spio_hdf5_type_to_pio_type(file_var_ntype_id), pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); - } - } - - if(H5Dwrite(file->hdf5_vars[wcache->varids[vidx]].hdf5_dataset_id, file_var_ntype_id, mem_space_id, file_space_id, - file->dxplid_coll, wbuf) < 0){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to write the dataset associated with variable (%s, varid=%d)", - nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); - } - -#if SPIO_HDF5_FLUSH_AFTER_COLL_WR - if(H5Fflush(file->hdf5_file_id, H5F_SCOPE_LOCAL) < 0){ - H5Eprint2(H5E_DEFAULT, stderr); - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to flush the dataset associated with variable (%s, varid=%d)", - nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); - } -#endif - - if(H5Sclose(file_space_id) < 0){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a dataspace copied from the dataset associated with variable (%s, varid=%d)", - nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); - } - - if(H5Sclose(mem_space_id) < 0){ - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Writing variables (number of variables = %d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a simple (or NULL) dataspace for variable (%s, varid=%d)", - nvars, pio_get_fname_from_file(file), file->pio_ncid, pio_get_vname_from_file(file, wcache->varids[vidx]), wcache->varids[vidx]); - } - } - - /* FIXME: Is this barrier needed ? */ - MPI_Barrier(ios->io_comm); - - iodesc->nasync_pend_ops--; - file->npend_ops--; - SPIO_Util::GVars::npend_hdf5_async_ops--; - - return PIO_NOERR; -#else // _HDF5 - assert(0); - return PIO_EINTERNAL; -#endif // _HDF5 -} - -void pio_iosys_async_op_hdf5_free(void *pdata) -{ -#ifdef _HDF5 - Hdf5_wcache *wcache = static_cast(pdata); - assert(wcache); - - /* Using swap trick to free vectors - * - swap vector with an empty local/temp vector that gets deallocated when func exits - */ - //wcache->varids.clear(); - std::vector().swap(wcache->varids); - //wcache->frame.clear(); - std::vector().swap(wcache->frame); - - if(wcache->iobuf){ brel(wcache->iobuf); } - if(wcache->fillbuf){ brel(wcache->fillbuf); } - - free(wcache); -#else // _HDF5 - assert(0); -#endif // _HDF5 -} - -int pio_iosys_async_hdf5_write_op_add(file_desc_t *file, int nvars, int fndims, - const int *varids, io_desc_t *iodesc, int fill, const int *frame) -{ -#ifdef _HDF5 - int ret = PIO_NOERR; - - assert(file && (nvars > 0) && (fndims > 0) && varids && iodesc); - - iosystem_desc_t *ios = file->iosystem; - assert(ios); - - if(!ios->ioproc){ - return PIO_NOERR; - } - - std::vector vids(varids, varids + nvars); - std::vector frms; - if(frame){ - frms.resize(nvars); - std::copy(frame, frame + nvars, frms.begin()); - } - - Hdf5_wcache *wcache = static_cast(calloc(1, sizeof(Hdf5_wcache))); - *wcache = {file, nvars, fndims, vids, iodesc, frms, (fill) ? true : false, NULL, 0, NULL, 0}; - - /* We need to copy the iobuf/fillbuf since the mvcache gets reused for future writes */ - /* Copy iobuf/fillvalue */ - var_desc_t *v1desc = file->varlist + varids[0]; - //PIO_Offset llen = fill ? iodesc->holegridsize : iodesc->llen; - if(fill){ - std::size_t fillbuf_sz = iodesc->holegridsize * iodesc->mpitype_size; - /* On I/O processes with no data (after rearrangement) to write the fillbuf_sz will be 0 */ - if(fillbuf_sz > 0){ - wcache->fillbuf = bget(fillbuf_sz); - if(!wcache->fillbuf){ - return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, - "Queuing asynchronous op/task for writing fillvalue for variables (number of variables = %d) to file (%s, ncid=%d) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for caching variable fillvalue", nvars, pio_get_fname_from_file(file), file->pio_ncid, static_cast(fillbuf_sz)); - } - - std::memcpy(wcache->fillbuf, v1desc->fillbuf, fillbuf_sz); - wcache->fillbuf_sz = fillbuf_sz; - } - } - else{ - /* Copy buffer, with rearranged data, for nvars */ - std::size_t iobuf_sz = nvars * iodesc->llen * iodesc->mpitype_size; - /* On I/O processes with no data (after rearrangement) to write the iobuf_sz will be 0 */ - if(iobuf_sz > 0){ - wcache->iobuf = bget(iobuf_sz); - if(!wcache->iobuf){ - return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, - "Queuing asynchronous op/task for writing fillvalue for variables (number of variables = %d) to file (%s, ncid=%d) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for caching variable data for all the variables", nvars, pio_get_fname_from_file(file), file->pio_ncid, static_cast(iobuf_sz)); - } - - void *iobuf = spio_file_mvcache_get(file, iodesc->ioid); - assert(iobuf); - std::memcpy(wcache->iobuf, iobuf, iobuf_sz); - wcache->iobuf_sz = iobuf_sz; - } - } - - /* Create async task */ - pio_async_op_t *pnew = static_cast(calloc(1, sizeof(pio_async_op_t))); - if(pnew == NULL){ - return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, - "Queuing asynchronous op/task for writing fillvalue for variables (number of variables = %d) to file (%s, ncid=%d) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for async task internal struct", nvars, pio_get_fname_from_file(file), file->pio_ncid, static_cast(sizeof(pio_async_op_t))); - } - - pnew->op_type = PIO_ASYNC_HDF5_WRITE_OP; - pnew->pdata = static_cast(wcache); - pnew->wait = pio_iosys_async_op_hdf5_write; - pnew->poke = pio_async_poke_func_unavail; - pnew->free = pio_iosys_async_op_hdf5_free; - - /* One more pending op using this iodesc & file */ - iodesc->nasync_pend_ops++; - file->npend_ops++; - SPIO_Util::GVars::npend_hdf5_async_ops++; - - /* Get the mt queue and queue the async task */ - ret = pio_async_tpool_op_add(pnew); - if(ret != PIO_NOERR){ - LOG((1, "Adding file pending ops to tpool failed, ret = %d", ret)); - return pio_err(ios, NULL, ret, __FILE__, __LINE__, - "Internal error while adding asynchronous pending operation to the thread pool (iosystem = %d). Adding the asynchronous operation failed", ios->iosysid); - } - - return PIO_NOERR; -#else // _HDF5 - assert(0); - return PIO_EINTERNAL; -#endif // _HDF5 -} - int pio_iosys_async_file_close_op_wait(void *pdata) { int ret = PIO_NOERR; diff --git a/src/clib/spio_async_utils.hpp b/src/clib/spio_async_utils.hpp index d79d95f896..258e973c7d 100644 --- a/src/clib/spio_async_utils.hpp +++ b/src/clib/spio_async_utils.hpp @@ -5,7 +5,9 @@ #include #include #include +#include "spio_async_hdf5_utils.hpp" +int pio_async_poke_func_unavail(void *pdata, int *flag); int pio_file_async_pend_ops_wait(file_desc_t *file); int pio_file_async_pend_op_add(file_desc_t *file, pio_async_op_type_t op_type, void *pdata); @@ -23,12 +25,9 @@ int pio_iosys_async_pend_op_add(iosystem_desc_t *iosys, int pio_tpool_async_pend_op_add(iosystem_desc_t *iosys, pio_async_op_type_t op_type, void *pdata); #endif // PIO_USE_ASYNC_WR_THREAD -int pio_iosys_async_hdf5_write_op_add(file_desc_t *file, int nvars, int fndims, - const int *varids, io_desc_t *iodesc, int fill, const int *frame); int pio_iosys_async_file_close_op_add(file_desc_t *file); std::string pio_async_op_type_to_string(pio_async_op_type_t op); -int spio_wait_all_hdf5_async_ops(int iosysid); #endif // _SPIO_ASYNC_UTILS_HPP_ From 5a8c547bb4934f707356b16cff3536ea97c9180c Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 13 Jan 2026 13:31:29 -0600 Subject: [PATCH 107/194] Async offload creating HDF5 files Offloading creating HDF5 files to the asynchronous I/O framework --- src/clib/pio_types.hpp | 1 + src/clib/pioc_support.cpp | 12 +++++ src/clib/spio_async_hdf5_utils.cpp | 74 +++++++++++++++++++++++++++++- src/clib/spio_async_hdf5_utils.hpp | 4 +- src/clib/spio_async_tpool.cpp | 2 +- src/clib/spio_async_utils.cpp | 3 ++ src/clib/spio_hdf5_utils.cpp | 7 --- 7 files changed, 92 insertions(+), 11 deletions(-) diff --git a/src/clib/pio_types.hpp b/src/clib/pio_types.hpp index 89c095a5bb..bf0a30c064 100644 --- a/src/clib/pio_types.hpp +++ b/src/clib/pio_types.hpp @@ -351,6 +351,7 @@ typedef enum pio_async_op_type PIO_ASYNC_INVALID_OP = 0, PIO_ASYNC_REARR_OP, PIO_ASYNC_PNETCDF_WRITE_OP, + PIO_ASYNC_HDF5_CREATE_OP, PIO_ASYNC_HDF5_WRITE_OP, PIO_ASYNC_FILE_WRITE_OPS, PIO_ASYNC_FILE_CLOSE_OP, diff --git a/src/clib/pioc_support.cpp b/src/clib/pioc_support.cpp index 84dc98e2b8..7217b5ea27 100644 --- a/src/clib/pioc_support.cpp +++ b/src/clib/pioc_support.cpp @@ -30,6 +30,7 @@ #include "spio_decomp_logger.hpp" #include "spio_async_utils.hpp" #include "spio_hdf5_utils.hpp" +#include "spio_async_hdf5_utils.hpp" #include #include #include @@ -3105,6 +3106,13 @@ int spio_createfile_int(int iosysid, int *ncidp, const int *iotype, const char * iosysid, *iotype, filename, mode)); #if PIO_USE_ASYNC_WR_THREAD + /* FIXME: Relax this wait */ + ierr = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ierr != PIO_NOERR){ + return pio_err(ios, NULL, ierr, __FILE__, __LINE__, + "Creating file (%s) failed. Error waiting on all pending asynchronous HDF5 ops", filename); + } + ierr = spio_close_soft_closed_file(filename); if(ierr != PIO_NOERR){ return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, @@ -3812,7 +3820,11 @@ int spio_createfile_int(int iosysid, int *ncidp, const int *iotype, const char * #ifdef _HDF5 case PIO_IOTYPE_HDF5: case PIO_IOTYPE_HDF5C: +#ifdef PIO_USE_ASYNC_WR_THREAD + ierr = spio_iosys_async_hdf5_create_op_add(file, filename); +#else ierr = spio_hdf5_create(ios, file, filename); +#endif break; #endif } diff --git a/src/clib/spio_async_hdf5_utils.cpp b/src/clib/spio_async_hdf5_utils.cpp index fa2c9e5020..491fdee6ea 100644 --- a/src/clib/spio_async_hdf5_utils.cpp +++ b/src/clib/spio_async_hdf5_utils.cpp @@ -33,6 +33,11 @@ extern "C"{ #include "spio_hdf5_utils.hpp" #include "spio_async_tpool_cint.h" +struct Hdf5_create_info{ + file_desc_t *file; + std::string fname; +}; + struct Hdf5_wcache{ file_desc_t *file; int nvars; @@ -80,6 +85,71 @@ static inline void update_reg_infos_start_frame(std::vector ®_in } } } + +void spio_iosys_async_op_hdf5_create_free(void *pdata) +{ + if(pdata){ + delete(static_cast(pdata)); + } +} + +int spio_iosys_async_op_hdf5_create(void *pdata) +{ + int ret = PIO_NOERR; + + Hdf5_create_info *cinfo = static_cast(pdata); + + assert(cinfo && cinfo->file && cinfo->file->iosystem); + + ret = spio_hdf5_create(cinfo->file->iosystem, cinfo->file, cinfo->fname.c_str()); + + cinfo->file->npend_ops--; + SPIO_Util::GVars::npend_hdf5_async_ops--; + + return ret; +} + +int spio_iosys_async_hdf5_create_op_add(file_desc_t *file, const char *filename) +{ + int ret = PIO_NOERR; + + assert(file && file->iosystem && filename); + + iosystem_desc_t *ios = file->iosystem; + + if(!ios->ioproc){ + return PIO_NOERR; + } + + Hdf5_create_info *cinfo = new Hdf5_create_info{file, filename}; + + /* Create async task */ + pio_async_op_t *pnew = static_cast(calloc(1, sizeof(pio_async_op_t))); + if(pnew == NULL){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Queuing asynchronous op/task for creating file (%s) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for async task internal struct", filename, static_cast(sizeof(pio_async_op_t))); + } + + pnew->op_type = PIO_ASYNC_HDF5_CREATE_OP; + pnew->pdata = static_cast(cinfo); + pnew->wait = spio_iosys_async_op_hdf5_create; + pnew->poke = pio_async_poke_func_unavail; + pnew->free = spio_iosys_async_op_hdf5_create_free; + + /* One more pending op using this iodesc & file */ + file->npend_ops++; + SPIO_Util::GVars::npend_hdf5_async_ops++; + + /* Get the mt queue and queue the async task */ + ret = pio_async_tpool_op_add(pnew); + if(ret != PIO_NOERR){ + LOG((1, "Adding file pending ops to tpool failed, ret = %d", ret)); + return pio_err(ios, NULL, ret, __FILE__, __LINE__, + "Internal error while adding asynchronous pending operation to the thread pool (iosystem = %d). Adding the asynchronous operation failed", ios->iosysid); + } + + return PIO_NOERR; +} #endif // _HDF5 int spio_wait_all_hdf5_async_ops(int iosysid) @@ -321,7 +391,7 @@ int pio_iosys_async_op_hdf5_write(void *pdata) #endif // _HDF5 } -void pio_iosys_async_op_hdf5_free(void *pdata) +void pio_iosys_async_op_hdf5_write_free(void *pdata) { #ifdef _HDF5 Hdf5_wcache *wcache = static_cast(pdata); @@ -416,7 +486,7 @@ int pio_iosys_async_hdf5_write_op_add(file_desc_t *file, int nvars, int fndims, pnew->pdata = static_cast(wcache); pnew->wait = pio_iosys_async_op_hdf5_write; pnew->poke = pio_async_poke_func_unavail; - pnew->free = pio_iosys_async_op_hdf5_free; + pnew->free = pio_iosys_async_op_hdf5_write_free; /* One more pending op using this iodesc & file */ iodesc->nasync_pend_ops++; diff --git a/src/clib/spio_async_hdf5_utils.hpp b/src/clib/spio_async_hdf5_utils.hpp index b31d8000ba..1114badd2e 100644 --- a/src/clib/spio_async_hdf5_utils.hpp +++ b/src/clib/spio_async_hdf5_utils.hpp @@ -9,9 +9,11 @@ namespace SPIO_Util{ } // namespace GVars } // namespace SPIO_Util +int spio_iosys_async_hdf5_create_op_add(file_desc_t *file, const char *filename); + int spio_wait_all_hdf5_async_ops(int iosysid); int pio_iosys_async_op_hdf5_write(void *pdata); -void pio_iosys_async_op_hdf5_free(void *pdata); +void pio_iosys_async_op_hdf5_write_free(void *pdata); int pio_iosys_async_hdf5_write_op_add(file_desc_t *file, int nvars, int fndims, const int *varids, io_desc_t *iodesc, int fill, const int *frame); diff --git a/src/clib/spio_async_tpool.cpp b/src/clib/spio_async_tpool.cpp index 232cc322a2..7e045e9d81 100644 --- a/src/clib/spio_async_tpool.cpp +++ b/src/clib/spio_async_tpool.cpp @@ -63,7 +63,7 @@ int PIO_Util::PIO_async_tpool::dequeue_and_process( LOG((2, " Tpool processing async op, kind = %s", pio_async_op_type_to_string(op->op_type).c_str())); /* We currently support only file write ops here */ //assert(op->op_type == PIO_ASYNC_FILE_WRITE_OPS); - assert((op->op_type == PIO_ASYNC_HDF5_WRITE_OP) || (op->op_type == PIO_ASYNC_FILE_CLOSE_OP)); + assert((op->op_type == PIO_ASYNC_HDF5_CREATE_OP) || (op->op_type == PIO_ASYNC_HDF5_WRITE_OP) || (op->op_type == PIO_ASYNC_FILE_CLOSE_OP)); ret = op->wait(op->pdata); if(ret != PIO_NOERR){ return pio_err(NULL, NULL, PIO_EINTERNAL, __FILE__, __LINE__, diff --git a/src/clib/spio_async_utils.cpp b/src/clib/spio_async_utils.cpp index 279b085107..0e73345edf 100644 --- a/src/clib/spio_async_utils.cpp +++ b/src/clib/spio_async_utils.cpp @@ -39,6 +39,7 @@ std::string pio_async_op_type_to_string(pio_async_op_type_t op) case PIO_ASYNC_INVALID_OP: return "PIO_ASYNC_INVALID_OP"; case PIO_ASYNC_REARR_OP: return "PIO_ASYNC_REARR_OP"; case PIO_ASYNC_PNETCDF_WRITE_OP: return "PIO_ASYNC_PNETCDF_WRITE_OP"; + case PIO_ASYNC_HDF5_CREATE_OP: return "PIO_ASYNC_HDF5_CREATE_OP"; case PIO_ASYNC_HDF5_WRITE_OP: return "PIO_ASYNC_HDF5_WRITE_OP"; case PIO_ASYNC_FILE_WRITE_OPS: return "PIO_ASYNC_FILE_WRITE_OPS"; case PIO_ASYNC_FILE_CLOSE_OP: return "PIO_ASYNC_FILE_CLOSE_OP"; @@ -487,6 +488,8 @@ static file_async_pend_ops_kwait_func_t pio_async_rearr_kwait, /* PIO_ASYNC_PNETCDF_WRITE_OP */ pio_async_pnetcdf_write_kwait, + /* PIO_ASYNC_HDF5_CREATE_OP */ + pio_async_wait_func_unavail, /* PIO_ASYNC_HDF5_WRITE_OP */ pio_async_hdf5_write_kwait, /* PIO_ASYNC_FILE_WRITE_OPS */ diff --git a/src/clib/spio_hdf5_utils.cpp b/src/clib/spio_hdf5_utils.cpp index 8028fdf542..a3c81b37c7 100644 --- a/src/clib/spio_hdf5_utils.cpp +++ b/src/clib/spio_hdf5_utils.cpp @@ -50,13 +50,6 @@ int spio_hdf5_create(iosystem_desc_t *ios, file_desc_t *file, const char *filena assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); assert(ios->ioproc); - /* FIXME: Relax this wait */ - ret = spio_wait_all_hdf5_async_ops(ios->iosysid); - if(ret != PIO_NOERR){ - return pio_err(ios, NULL, ret, __FILE__, __LINE__, - "Creating file (%s) failed. Error waiting on all pending asynchronous HDF5 ops", filename); - } - if(file->mode & PIO_NOCLOBBER){ /* No clobber : Check if file exists from all processes */ struct stat sd; From 62545a7f31caf4c6d7d729932b9cc1154b4ac5ab Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 13 Jan 2026 15:05:44 -0600 Subject: [PATCH 108/194] Async offload HDF5 def var Offloading defining HDF5 variables to asynchronous I/O framework --- src/clib/pio_nc.cpp | 14 ++++++ src/clib/pio_types.hpp | 1 + src/clib/spio_async_hdf5_utils.cpp | 78 ++++++++++++++++++++++++++++++ src/clib/spio_async_hdf5_utils.hpp | 2 + src/clib/spio_async_tpool.cpp | 3 +- src/clib/spio_async_utils.cpp | 3 ++ src/clib/spio_hdf5_utils.cpp | 9 ---- 7 files changed, 100 insertions(+), 10 deletions(-) diff --git a/src/clib/pio_nc.cpp b/src/clib/pio_nc.cpp index 58f2899e9e..bec15b93c2 100644 --- a/src/clib/pio_nc.cpp +++ b/src/clib/pio_nc.cpp @@ -22,6 +22,7 @@ #endif #include "spio_io_summary.h" #include "spio_hdf5_utils.hpp" +#include "spio_async_hdf5_utils.hpp" const char spio_nc_fillvalue_aname[] = "_FillValue"; @@ -3384,6 +3385,15 @@ int PIOc_def_var_impl(int ncid, const char *name, nc_type xtype, int ndims, return PIO_EINVAL; } + /* FIXME: Relax this wait */ + ierr = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ierr != PIO_NOERR){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Defining variable (%s) in file (%s, ncid=%d) using HDF5 iotype failed. " + "Error waiting on all pending asynchronous HDF5 ops", + name, pio_get_fname_from_file(file), file->pio_ncid); + } + /* ADIOS: assume all procs are also IO tasks */ #ifdef _ADIOS2 if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) @@ -3676,7 +3686,11 @@ int PIOc_def_var_impl(int ncid, const char *name, nc_type xtype, int ndims, #ifdef _HDF5 if ((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)) { +#ifdef PIO_USE_ASYNC_WR_THREAD + ierr = spio_iosys_async_hdf5_def_var_op_add(file, name, xtype, ndims, dimidsp, *varidp); +#else ierr = spio_hdf5_def_var(ios, file, name, xtype, ndims, dimidsp, *varidp); +#endif if (ierr != PIO_NOERR) { char errmsg[PIO_MAX_NAME]; diff --git a/src/clib/pio_types.hpp b/src/clib/pio_types.hpp index bf0a30c064..9c1ad498ff 100644 --- a/src/clib/pio_types.hpp +++ b/src/clib/pio_types.hpp @@ -352,6 +352,7 @@ typedef enum pio_async_op_type PIO_ASYNC_REARR_OP, PIO_ASYNC_PNETCDF_WRITE_OP, PIO_ASYNC_HDF5_CREATE_OP, + PIO_ASYNC_HDF5_DEF_VAR_OP, PIO_ASYNC_HDF5_WRITE_OP, PIO_ASYNC_FILE_WRITE_OPS, PIO_ASYNC_FILE_CLOSE_OP, diff --git a/src/clib/spio_async_hdf5_utils.cpp b/src/clib/spio_async_hdf5_utils.cpp index 491fdee6ea..e9c61906e1 100644 --- a/src/clib/spio_async_hdf5_utils.cpp +++ b/src/clib/spio_async_hdf5_utils.cpp @@ -38,6 +38,15 @@ struct Hdf5_create_info{ std::string fname; }; +struct Hdf5_def_var_info{ + file_desc_t *file; + std::string vname; + nc_type xtype; + int ndims; + std::vector dimids; + int varid; +}; + struct Hdf5_wcache{ file_desc_t *file; int nvars; @@ -150,6 +159,75 @@ int spio_iosys_async_hdf5_create_op_add(file_desc_t *file, const char *filename) return PIO_NOERR; } + +void spio_iosys_async_op_hdf5_def_var_free(void *pdata) +{ + if(pdata){ + delete(static_cast(pdata)); + } +} + +int spio_iosys_async_op_hdf5_def_var(void *pdata) +{ + int ret = PIO_NOERR; + + Hdf5_def_var_info *def_var_info = static_cast(pdata); + + assert(def_var_info && def_var_info->file && def_var_info->file->iosystem); + + ret = spio_hdf5_def_var(def_var_info->file->iosystem, def_var_info->file, + def_var_info->vname.c_str(), def_var_info->xtype, def_var_info->ndims, + def_var_info->dimids.data(), def_var_info->varid); + + def_var_info->file->npend_ops--; + SPIO_Util::GVars::npend_hdf5_async_ops--; + + return ret; +} + +int spio_iosys_async_hdf5_def_var_op_add(file_desc_t *file, const char *name, + nc_type xtype, int ndims, const int *dimidsp, int varid) +{ + int ret = PIO_NOERR; + + assert(file && file->iosystem && name); + + iosystem_desc_t *ios = file->iosystem; + + if(!ios->ioproc){ + return PIO_NOERR; + } + + Hdf5_def_var_info *def_var_info = new Hdf5_def_var_info{file, name, xtype, ndims, + {dimidsp, dimidsp + ndims}, varid}; + + /* Create async task */ + pio_async_op_t *pnew = static_cast(calloc(1, sizeof(pio_async_op_t))); + if(pnew == NULL){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Queuing asynchronous op/task for defining variable (%s, file=%s) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for async task internal struct", name, pio_get_fname_from_file(file), static_cast(sizeof(pio_async_op_t))); + } + + pnew->op_type = PIO_ASYNC_HDF5_DEF_VAR_OP; + pnew->pdata = static_cast(def_var_info); + pnew->wait = spio_iosys_async_op_hdf5_def_var; + pnew->poke = pio_async_poke_func_unavail; + pnew->free = spio_iosys_async_op_hdf5_def_var_free; + + /* One more pending op using this iodesc & file */ + file->npend_ops++; + SPIO_Util::GVars::npend_hdf5_async_ops++; + + /* Get the mt queue and queue the async task */ + ret = pio_async_tpool_op_add(pnew); + if(ret != PIO_NOERR){ + LOG((1, "Adding file pending ops to tpool failed, ret = %d", ret)); + return pio_err(ios, NULL, ret, __FILE__, __LINE__, + "Internal error while adding asynchronous pending operation to the thread pool (iosystem = %d). Adding the asynchronous operation failed", ios->iosysid); + } + + return PIO_NOERR; +} #endif // _HDF5 int spio_wait_all_hdf5_async_ops(int iosysid) diff --git a/src/clib/spio_async_hdf5_utils.hpp b/src/clib/spio_async_hdf5_utils.hpp index 1114badd2e..b6cd8db5cd 100644 --- a/src/clib/spio_async_hdf5_utils.hpp +++ b/src/clib/spio_async_hdf5_utils.hpp @@ -10,6 +10,8 @@ namespace SPIO_Util{ } // namespace SPIO_Util int spio_iosys_async_hdf5_create_op_add(file_desc_t *file, const char *filename); +int spio_iosys_async_hdf5_def_var_op_add(file_desc_t *file, const char *name, + nc_type xtype, int ndims, const int *dimidsp, int varid); int spio_wait_all_hdf5_async_ops(int iosysid); int pio_iosys_async_op_hdf5_write(void *pdata); diff --git a/src/clib/spio_async_tpool.cpp b/src/clib/spio_async_tpool.cpp index 7e045e9d81..89f136db9e 100644 --- a/src/clib/spio_async_tpool.cpp +++ b/src/clib/spio_async_tpool.cpp @@ -63,7 +63,8 @@ int PIO_Util::PIO_async_tpool::dequeue_and_process( LOG((2, " Tpool processing async op, kind = %s", pio_async_op_type_to_string(op->op_type).c_str())); /* We currently support only file write ops here */ //assert(op->op_type == PIO_ASYNC_FILE_WRITE_OPS); - assert((op->op_type == PIO_ASYNC_HDF5_CREATE_OP) || (op->op_type == PIO_ASYNC_HDF5_WRITE_OP) || (op->op_type == PIO_ASYNC_FILE_CLOSE_OP)); + assert((op->op_type == PIO_ASYNC_HDF5_CREATE_OP) || (op->op_type == PIO_ASYNC_HDF5_DEF_VAR_OP) || (op->op_type == PIO_ASYNC_HDF5_WRITE_OP) || + (op->op_type == PIO_ASYNC_FILE_CLOSE_OP)); ret = op->wait(op->pdata); if(ret != PIO_NOERR){ return pio_err(NULL, NULL, PIO_EINTERNAL, __FILE__, __LINE__, diff --git a/src/clib/spio_async_utils.cpp b/src/clib/spio_async_utils.cpp index 0e73345edf..51554f7ede 100644 --- a/src/clib/spio_async_utils.cpp +++ b/src/clib/spio_async_utils.cpp @@ -40,6 +40,7 @@ std::string pio_async_op_type_to_string(pio_async_op_type_t op) case PIO_ASYNC_REARR_OP: return "PIO_ASYNC_REARR_OP"; case PIO_ASYNC_PNETCDF_WRITE_OP: return "PIO_ASYNC_PNETCDF_WRITE_OP"; case PIO_ASYNC_HDF5_CREATE_OP: return "PIO_ASYNC_HDF5_CREATE_OP"; + case PIO_ASYNC_HDF5_DEF_VAR_OP: return "PIO_ASYNC_HDF5_DEF_VAR_OP"; case PIO_ASYNC_HDF5_WRITE_OP: return "PIO_ASYNC_HDF5_WRITE_OP"; case PIO_ASYNC_FILE_WRITE_OPS: return "PIO_ASYNC_FILE_WRITE_OPS"; case PIO_ASYNC_FILE_CLOSE_OP: return "PIO_ASYNC_FILE_CLOSE_OP"; @@ -490,6 +491,8 @@ static file_async_pend_ops_kwait_func_t pio_async_pnetcdf_write_kwait, /* PIO_ASYNC_HDF5_CREATE_OP */ pio_async_wait_func_unavail, + /* PIO_ASYNC_HDF5_DEF_VAR_OP */ + pio_async_wait_func_unavail, /* PIO_ASYNC_HDF5_WRITE_OP */ pio_async_hdf5_write_kwait, /* PIO_ASYNC_FILE_WRITE_OPS */ diff --git a/src/clib/spio_hdf5_utils.cpp b/src/clib/spio_hdf5_utils.cpp index a3c81b37c7..414027a551 100644 --- a/src/clib/spio_hdf5_utils.cpp +++ b/src/clib/spio_hdf5_utils.cpp @@ -550,15 +550,6 @@ int spio_hdf5_def_var(iosystem_desc_t *ios, file_desc_t *file, const char *name, assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); assert(ios->ioproc); - /* FIXME: Relax this wait */ - ret = spio_wait_all_hdf5_async_ops(ios->iosysid); - if(ret != PIO_NOERR){ - return pio_err(ios, file, ret, __FILE__, __LINE__, - "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " - "Error waiting on all pending asynchronous HDF5 ops", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } - /* Cache the dim sizes for HDF5 calls */ std::vector dim_sz(ndims), max_dim_sz(ndims); for(int i = 0; i < ndims; i++){ From 792013dc75db968d493583cae66f3817364c993f Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 14 Jan 2026 11:02:30 -0600 Subject: [PATCH 109/194] Adding chk for empty in dt converter Adding a function to check if a datatype converter has any cached buffers (useful for debugging) --- src/clib/spio_dt_converter.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/clib/spio_dt_converter.hpp b/src/clib/spio_dt_converter.hpp index 69d2fbd793..8fa23b8646 100644 --- a/src/clib/spio_dt_converter.hpp +++ b/src/clib/spio_dt_converter.hpp @@ -20,6 +20,8 @@ namespace SPIO_Util{ public: /* Convert buffer to requested type, buffer size, sz, is in bytes */ void *convert(int ncid, void *buf, std::size_t sz, int from_pio_type, int to_pio_type); + /* Check if the converter has any cached buffers - useful for debugging */ + bool empty(void ) const { return cbufs_.empty(); } /* Free the scratch/temp buffers associated with ncid/file */ void free(int ncid); /* Clear all scratch/temp buffers */ From cd2778e05ccfbc65a512d88b2f1c4b1e59ba8597 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 14 Jan 2026 11:03:49 -0600 Subject: [PATCH 110/194] Clear dt converter before deleting During async I/O processing there can be some cached buffers in the datatype converter. Ensure that we always clear it for deleting the converter --- src/clib/pio_lists.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/clib/pio_lists.cpp b/src/clib/pio_lists.cpp index 9fa5515537..4112d9e99d 100644 --- a/src/clib/pio_lists.cpp +++ b/src/clib/pio_lists.cpp @@ -140,7 +140,9 @@ int pio_free_file(file_desc_t *file) #ifdef _HDF5 if(file->dt_converter != NULL){ - delete(static_cast(file->dt_converter)); + SPIO_Util::File_Util::DTConverter *dt_conv = static_cast(file->dt_converter); + dt_conv->clear(); + delete(dt_conv); } if((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)){ From b7f098d52048d0403ee9813808ab5b1f77794553 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 14 Jan 2026 11:46:42 -0600 Subject: [PATCH 111/194] Async offload HDF5 enddef Offload enddefs on HDF5 files to the asynchronous I/O framework --- src/clib/pio_types.hpp | 1 + src/clib/pioc_support.cpp | 25 ++++++++--- src/clib/spio_async_hdf5_utils.cpp | 69 ++++++++++++++++++++++++++++++ src/clib/spio_async_hdf5_utils.hpp | 1 + src/clib/spio_async_tpool.cpp | 5 ++- src/clib/spio_async_utils.cpp | 3 ++ src/clib/spio_hdf5_utils.cpp | 9 ---- 7 files changed, 97 insertions(+), 16 deletions(-) diff --git a/src/clib/pio_types.hpp b/src/clib/pio_types.hpp index 9c1ad498ff..9a9610f480 100644 --- a/src/clib/pio_types.hpp +++ b/src/clib/pio_types.hpp @@ -353,6 +353,7 @@ typedef enum pio_async_op_type PIO_ASYNC_PNETCDF_WRITE_OP, PIO_ASYNC_HDF5_CREATE_OP, PIO_ASYNC_HDF5_DEF_VAR_OP, + PIO_ASYNC_HDF5_ENDDEF_OP, PIO_ASYNC_HDF5_WRITE_OP, PIO_ASYNC_FILE_WRITE_OPS, PIO_ASYNC_FILE_CLOSE_OP, diff --git a/src/clib/pioc_support.cpp b/src/clib/pioc_support.cpp index 7217b5ea27..a37985a59e 100644 --- a/src/clib/pioc_support.cpp +++ b/src/clib/pioc_support.cpp @@ -5798,6 +5798,17 @@ int spio_change_def(int ncid, int is_enddef) } } +#ifdef PIO_USE_ASYNC_WR_THREAD + /* FIXME: Relax this wait */ + ierr = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ierr != PIO_NOERR){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Error waiting on all pending asynchronous HDF5 ops", + pio_get_fname_from_file(file), file->pio_ncid); + } +#endif + /* If this is an IO task, then call the netCDF function. */ LOG((3, "spio_change_def ios->ioproc = %d", ios->ioproc)); if (ios->ioproc) @@ -5921,12 +5932,14 @@ int spio_change_def(int ncid, int is_enddef) } #endif /* _NETCDF */ #ifdef _HDF5 - if ((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)) - { - if (is_enddef) - { - ierr = spio_hdf5_enddef(ios, file); - } + if((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)){ + if(is_enddef){ +#ifdef PIO_USE_ASYNC_WR_THREAD + ierr = spio_iosys_async_hdf5_enddef_op_add(file); +#else + ierr = spio_hdf5_enddef(ios, file); +#endif + } } #endif /* _HDF5 */ } diff --git a/src/clib/spio_async_hdf5_utils.cpp b/src/clib/spio_async_hdf5_utils.cpp index e9c61906e1..a46a32ee52 100644 --- a/src/clib/spio_async_hdf5_utils.cpp +++ b/src/clib/spio_async_hdf5_utils.cpp @@ -47,6 +47,10 @@ struct Hdf5_def_var_info{ int varid; }; +struct Hdf5_enddef_info{ + file_desc_t *file; +}; + struct Hdf5_wcache{ file_desc_t *file; int nvars; @@ -228,6 +232,71 @@ int spio_iosys_async_hdf5_def_var_op_add(file_desc_t *file, const char *name, return PIO_NOERR; } + +void spio_iosys_async_op_hdf5_enddef_free(void *pdata) +{ + if(pdata){ + delete(static_cast(pdata)); + } +} + +int spio_iosys_async_op_hdf5_enddef(void *pdata) +{ + int ret = PIO_NOERR; + + Hdf5_enddef_info *info = static_cast(pdata); + + assert(info && info->file && info->file->iosystem); + + ret = spio_hdf5_enddef(info->file->iosystem, info->file); + + info->file->npend_ops--; + SPIO_Util::GVars::npend_hdf5_async_ops--; + + return ret; +} + +int spio_iosys_async_hdf5_enddef_op_add(file_desc_t *file) +{ + int ret = PIO_NOERR; + + assert(file && file->iosystem); + + iosystem_desc_t *ios = file->iosystem; + + if(!ios->ioproc){ + return PIO_NOERR; + } + + Hdf5_enddef_info *info = new Hdf5_enddef_info{file}; + + /* Create async task */ + pio_async_op_t *pnew = static_cast(calloc(1, sizeof(pio_async_op_t))); + if(pnew == NULL){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Queuing asynchronous op/task for ending define mode of file (%s) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for async task internal struct", pio_get_fname_from_file(file), static_cast(sizeof(pio_async_op_t))); + } + + pnew->op_type = PIO_ASYNC_HDF5_ENDDEF_OP; + pnew->pdata = static_cast(info); + pnew->wait = spio_iosys_async_op_hdf5_enddef; + pnew->poke = pio_async_poke_func_unavail; + pnew->free = spio_iosys_async_op_hdf5_enddef_free; + + /* One more pending op using this file */ + file->npend_ops++; + SPIO_Util::GVars::npend_hdf5_async_ops++; + + /* Get the mt queue and queue the async task */ + ret = pio_async_tpool_op_add(pnew); + if(ret != PIO_NOERR){ + LOG((1, "Adding file pending ops to tpool failed, ret = %d", ret)); + return pio_err(ios, NULL, ret, __FILE__, __LINE__, + "Internal error while adding asynchronous pending operation to the thread pool (iosystem = %d). Adding the asynchronous operation failed", ios->iosysid); + } + + return PIO_NOERR; +} #endif // _HDF5 int spio_wait_all_hdf5_async_ops(int iosysid) diff --git a/src/clib/spio_async_hdf5_utils.hpp b/src/clib/spio_async_hdf5_utils.hpp index b6cd8db5cd..f95a796570 100644 --- a/src/clib/spio_async_hdf5_utils.hpp +++ b/src/clib/spio_async_hdf5_utils.hpp @@ -12,6 +12,7 @@ namespace SPIO_Util{ int spio_iosys_async_hdf5_create_op_add(file_desc_t *file, const char *filename); int spio_iosys_async_hdf5_def_var_op_add(file_desc_t *file, const char *name, nc_type xtype, int ndims, const int *dimidsp, int varid); +int spio_iosys_async_hdf5_enddef_op_add(file_desc_t *file); int spio_wait_all_hdf5_async_ops(int iosysid); int pio_iosys_async_op_hdf5_write(void *pdata); diff --git a/src/clib/spio_async_tpool.cpp b/src/clib/spio_async_tpool.cpp index 89f136db9e..4083f4d155 100644 --- a/src/clib/spio_async_tpool.cpp +++ b/src/clib/spio_async_tpool.cpp @@ -63,7 +63,10 @@ int PIO_Util::PIO_async_tpool::dequeue_and_process( LOG((2, " Tpool processing async op, kind = %s", pio_async_op_type_to_string(op->op_type).c_str())); /* We currently support only file write ops here */ //assert(op->op_type == PIO_ASYNC_FILE_WRITE_OPS); - assert((op->op_type == PIO_ASYNC_HDF5_CREATE_OP) || (op->op_type == PIO_ASYNC_HDF5_DEF_VAR_OP) || (op->op_type == PIO_ASYNC_HDF5_WRITE_OP) || + assert((op->op_type == PIO_ASYNC_HDF5_CREATE_OP) || + (op->op_type == PIO_ASYNC_HDF5_DEF_VAR_OP) || + (op->op_type == PIO_ASYNC_HDF5_ENDDEF_OP) || + (op->op_type == PIO_ASYNC_HDF5_WRITE_OP) || (op->op_type == PIO_ASYNC_FILE_CLOSE_OP)); ret = op->wait(op->pdata); if(ret != PIO_NOERR){ diff --git a/src/clib/spio_async_utils.cpp b/src/clib/spio_async_utils.cpp index 51554f7ede..5dbd180e88 100644 --- a/src/clib/spio_async_utils.cpp +++ b/src/clib/spio_async_utils.cpp @@ -41,6 +41,7 @@ std::string pio_async_op_type_to_string(pio_async_op_type_t op) case PIO_ASYNC_PNETCDF_WRITE_OP: return "PIO_ASYNC_PNETCDF_WRITE_OP"; case PIO_ASYNC_HDF5_CREATE_OP: return "PIO_ASYNC_HDF5_CREATE_OP"; case PIO_ASYNC_HDF5_DEF_VAR_OP: return "PIO_ASYNC_HDF5_DEF_VAR_OP"; + case PIO_ASYNC_HDF5_ENDDEF_OP: return "PIO_ASYNC_HDF5_ENDDEF_OP"; case PIO_ASYNC_HDF5_WRITE_OP: return "PIO_ASYNC_HDF5_WRITE_OP"; case PIO_ASYNC_FILE_WRITE_OPS: return "PIO_ASYNC_FILE_WRITE_OPS"; case PIO_ASYNC_FILE_CLOSE_OP: return "PIO_ASYNC_FILE_CLOSE_OP"; @@ -493,6 +494,8 @@ static file_async_pend_ops_kwait_func_t pio_async_wait_func_unavail, /* PIO_ASYNC_HDF5_DEF_VAR_OP */ pio_async_wait_func_unavail, + /* PIO_ASYNC_HDF5_ENDDEF_OP */ + pio_async_wait_func_unavail, /* PIO_ASYNC_HDF5_WRITE_OP */ pio_async_hdf5_write_kwait, /* PIO_ASYNC_FILE_WRITE_OPS */ diff --git a/src/clib/spio_hdf5_utils.cpp b/src/clib/spio_hdf5_utils.cpp index 414027a551..ed5ec7f256 100644 --- a/src/clib/spio_hdf5_utils.cpp +++ b/src/clib/spio_hdf5_utils.cpp @@ -637,15 +637,6 @@ int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); assert(ios->ioproc); - /* FIXME: Relax this wait */ - ret = spio_wait_all_hdf5_async_ops(ios->iosysid); - if(ret != PIO_NOERR){ - return pio_err(ios, file, ret, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "Error waiting on all pending asynchronous HDF5 ops", - pio_get_fname_from_file(file), file->pio_ncid); - } - for(i = 0; i < file->hdf5_num_dims; i++){ /* For dimensions without an associated coordinate var, define them here. However since the * the user can call redef() multiple times define it only its not already defined/valid From 031cfff50a3f274ad50d27e8a0d6712dd7ba87c8 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 14 Jan 2026 12:25:34 -0600 Subject: [PATCH 112/194] Async offload HDF5 put att Offloading put for attributes in an HDF5 file to the asynchronous I/O framework --- src/clib/pio_getput_int.cpp | 16 ++++++ src/clib/pio_types.hpp | 1 + src/clib/spio_async_hdf5_utils.cpp | 90 ++++++++++++++++++++++++++++++ src/clib/spio_async_hdf5_utils.hpp | 2 + src/clib/spio_async_tpool.cpp | 1 + src/clib/spio_async_utils.cpp | 3 + src/clib/spio_hdf5_utils.cpp | 9 --- 7 files changed, 113 insertions(+), 9 deletions(-) diff --git a/src/clib/pio_getput_int.cpp b/src/clib/pio_getput_int.cpp index 3ebacd0e3f..eb3f22fcce 100644 --- a/src/clib/pio_getput_int.cpp +++ b/src/clib/pio_getput_int.cpp @@ -15,6 +15,7 @@ #include "spio_io_summary.h" #include "spio_hash.h" #include "spio_hdf5_utils.hpp" +#include "spio_async_hdf5_utils.hpp" /** * Write a netCDF attribute of any type, converting to any type. @@ -59,6 +60,17 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, spio_ltimer_start(ios->io_fstats->wr_timer_name); spio_ltimer_start(ios->io_fstats->tot_timer_name); +#ifdef PIO_USE_ASYNC_WR_THREAD + /* FIXME: Relax this wait */ + ierr = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ierr != PIO_NOERR){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "Error waiting on all pending asynchronous HDF5 ops", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } +#endif + #ifdef _ADIOS2 if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) { @@ -443,7 +455,11 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, file->io_fstats->wb += len * atttype_len; } +#ifdef PIO_USE_ASYNC_WR_THREAD + ierr = spio_iosys_async_hdf5_put_att_op_add(file, varid, name, atttype, len, op); +#else ierr = spio_hdf5_put_att(ios, file, varid, name, atttype, len, op); +#endif } #endif /* _HDF5 */ diff --git a/src/clib/pio_types.hpp b/src/clib/pio_types.hpp index 9a9610f480..72dc5322c5 100644 --- a/src/clib/pio_types.hpp +++ b/src/clib/pio_types.hpp @@ -353,6 +353,7 @@ typedef enum pio_async_op_type PIO_ASYNC_PNETCDF_WRITE_OP, PIO_ASYNC_HDF5_CREATE_OP, PIO_ASYNC_HDF5_DEF_VAR_OP, + PIO_ASYNC_HDF5_PUT_ATT_OP, PIO_ASYNC_HDF5_ENDDEF_OP, PIO_ASYNC_HDF5_WRITE_OP, PIO_ASYNC_FILE_WRITE_OPS, diff --git a/src/clib/spio_async_hdf5_utils.cpp b/src/clib/spio_async_hdf5_utils.cpp index a46a32ee52..d6978cb991 100644 --- a/src/clib/spio_async_hdf5_utils.cpp +++ b/src/clib/spio_async_hdf5_utils.cpp @@ -47,6 +47,15 @@ struct Hdf5_def_var_info{ int varid; }; +struct Hdf5_put_att_info{ + file_desc_t *file; + int varid; + std::string aname; + nc_type atype; + PIO_Offset alen; + void *abuf; +}; + struct Hdf5_enddef_info{ file_desc_t *file; }; @@ -233,6 +242,87 @@ int spio_iosys_async_hdf5_def_var_op_add(file_desc_t *file, const char *name, return PIO_NOERR; } +void spio_iosys_async_op_hdf5_put_att_free(void *pdata) +{ + if(pdata){ + Hdf5_put_att_info *info = static_cast(pdata); + free(info->abuf); + delete(info); + } +} + +int spio_iosys_async_op_hdf5_put_att(void *pdata) +{ + int ret = PIO_NOERR; + + Hdf5_put_att_info *info = static_cast(pdata); + + assert(info && info->file && info->file->iosystem); + assert((info->varid >= 0) || (info->varid == PIO_GLOBAL)); + assert(info->alen > 0); + + ret = spio_hdf5_put_att(info->file->iosystem, info->file, + info->varid, info->aname.c_str(), info->atype, + info->alen, info->abuf); + + info->file->npend_ops--; + SPIO_Util::GVars::npend_hdf5_async_ops--; + + return ret; +} + +int spio_iosys_async_hdf5_put_att_op_add(file_desc_t *file, int varid, + const char *aname, nc_type atype, PIO_Offset alen, const void *abuf) +{ + int ret = PIO_NOERR; + + assert(file && file->iosystem && aname && (alen > 0) && abuf); + assert((varid >= 0) || (varid = PIO_GLOBAL)); + + iosystem_desc_t *ios = file->iosystem; + + if(!ios->ioproc){ + return PIO_NOERR; + } + + void *buf = malloc(alen * spio_get_nc_type_size(atype)); + if(buf == NULL){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Queuing asynchronous op/task for writing attribute (%s, variable=%s, file=%s) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for caching attribute value", aname, pio_get_vname_from_file(file, varid), pio_get_fname_from_file(file), static_cast(alen)); + } + + memcpy(buf, abuf, alen * spio_get_nc_type_size(atype)); + + Hdf5_put_att_info *info = new Hdf5_put_att_info{file, varid, aname, atype, alen, buf}; + + /* Create async task */ + pio_async_op_t *pnew = static_cast(calloc(1, sizeof(pio_async_op_t))); + if(pnew == NULL){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Queuing asynchronous op/task for writing attribute (%s, variable=%s, file=%s) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for async task internal struct", aname, pio_get_vname_from_file(file, varid), pio_get_fname_from_file(file), static_cast(sizeof(pio_async_op_t))); + } + + pnew->op_type = PIO_ASYNC_HDF5_PUT_ATT_OP; + pnew->pdata = static_cast(info); + pnew->wait = spio_iosys_async_op_hdf5_put_att; + pnew->poke = pio_async_poke_func_unavail; + pnew->free = spio_iosys_async_op_hdf5_put_att_free; + + /* One more pending op using this iodesc & file */ + file->npend_ops++; + SPIO_Util::GVars::npend_hdf5_async_ops++; + + /* Get the mt queue and queue the async task */ + ret = pio_async_tpool_op_add(pnew); + if(ret != PIO_NOERR){ + LOG((1, "Adding file pending ops to tpool failed, ret = %d", ret)); + return pio_err(ios, NULL, ret, __FILE__, __LINE__, + "Internal error while adding asynchronous pending operation to the thread pool (iosystem = %d). Adding the asynchronous operation failed", ios->iosysid); + } + + return PIO_NOERR; +} + void spio_iosys_async_op_hdf5_enddef_free(void *pdata) { if(pdata){ diff --git a/src/clib/spio_async_hdf5_utils.hpp b/src/clib/spio_async_hdf5_utils.hpp index f95a796570..97c4f57c06 100644 --- a/src/clib/spio_async_hdf5_utils.hpp +++ b/src/clib/spio_async_hdf5_utils.hpp @@ -12,6 +12,8 @@ namespace SPIO_Util{ int spio_iosys_async_hdf5_create_op_add(file_desc_t *file, const char *filename); int spio_iosys_async_hdf5_def_var_op_add(file_desc_t *file, const char *name, nc_type xtype, int ndims, const int *dimidsp, int varid); +int spio_iosys_async_hdf5_put_att_op_add(file_desc_t *file, int varid, + const char *aname, nc_type atype, PIO_Offset alen, const void *abuf); int spio_iosys_async_hdf5_enddef_op_add(file_desc_t *file); int spio_wait_all_hdf5_async_ops(int iosysid); diff --git a/src/clib/spio_async_tpool.cpp b/src/clib/spio_async_tpool.cpp index 4083f4d155..a3e3866aad 100644 --- a/src/clib/spio_async_tpool.cpp +++ b/src/clib/spio_async_tpool.cpp @@ -65,6 +65,7 @@ int PIO_Util::PIO_async_tpool::dequeue_and_process( //assert(op->op_type == PIO_ASYNC_FILE_WRITE_OPS); assert((op->op_type == PIO_ASYNC_HDF5_CREATE_OP) || (op->op_type == PIO_ASYNC_HDF5_DEF_VAR_OP) || + (op->op_type == PIO_ASYNC_HDF5_PUT_ATT_OP) || (op->op_type == PIO_ASYNC_HDF5_ENDDEF_OP) || (op->op_type == PIO_ASYNC_HDF5_WRITE_OP) || (op->op_type == PIO_ASYNC_FILE_CLOSE_OP)); diff --git a/src/clib/spio_async_utils.cpp b/src/clib/spio_async_utils.cpp index 5dbd180e88..3d2812c48e 100644 --- a/src/clib/spio_async_utils.cpp +++ b/src/clib/spio_async_utils.cpp @@ -41,6 +41,7 @@ std::string pio_async_op_type_to_string(pio_async_op_type_t op) case PIO_ASYNC_PNETCDF_WRITE_OP: return "PIO_ASYNC_PNETCDF_WRITE_OP"; case PIO_ASYNC_HDF5_CREATE_OP: return "PIO_ASYNC_HDF5_CREATE_OP"; case PIO_ASYNC_HDF5_DEF_VAR_OP: return "PIO_ASYNC_HDF5_DEF_VAR_OP"; + case PIO_ASYNC_HDF5_PUT_ATT_OP: return "PIO_ASYNC_HDF5_PUT_ATT_OP"; case PIO_ASYNC_HDF5_ENDDEF_OP: return "PIO_ASYNC_HDF5_ENDDEF_OP"; case PIO_ASYNC_HDF5_WRITE_OP: return "PIO_ASYNC_HDF5_WRITE_OP"; case PIO_ASYNC_FILE_WRITE_OPS: return "PIO_ASYNC_FILE_WRITE_OPS"; @@ -494,6 +495,8 @@ static file_async_pend_ops_kwait_func_t pio_async_wait_func_unavail, /* PIO_ASYNC_HDF5_DEF_VAR_OP */ pio_async_wait_func_unavail, + /* PIO_ASYNC_HDF5_PUT_ATT_OP */ + pio_async_wait_func_unavail, /* PIO_ASYNC_HDF5_ENDDEF_OP */ pio_async_wait_func_unavail, /* PIO_ASYNC_HDF5_WRITE_OP */ diff --git a/src/clib/spio_hdf5_utils.cpp b/src/clib/spio_hdf5_utils.cpp index ed5ec7f256..6ae89b52d8 100644 --- a/src/clib/spio_hdf5_utils.cpp +++ b/src/clib/spio_hdf5_utils.cpp @@ -901,15 +901,6 @@ int spio_hdf5_put_att(iosystem_desc_t *ios, file_desc_t *file, int varid, const assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); assert(ios->ioproc); - /* FIXME: Relax this wait */ - ret = spio_wait_all_hdf5_async_ops(ios->iosysid); - if(ret != PIO_NOERR){ - return pio_err(ios, file, ret, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "Error waiting on all pending asynchronous HDF5 ops", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); - } - if(varid == PIO_GLOBAL){ loc_id = file->hdf5_file_id; } From 8dcebd30d2f9be5ddc3b587b598bc1bb83cf588c Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 14 Jan 2026 13:45:05 -0600 Subject: [PATCH 113/194] Offload HDF5 put var Offloading put on HDF5 variables to the asynchronous framework --- src/clib/pio_getput_int.cpp | 13 ++++ src/clib/pio_types.hpp | 1 + src/clib/spio_async_hdf5_utils.cpp | 114 +++++++++++++++++++++++++++++ src/clib/spio_async_hdf5_utils.hpp | 3 + src/clib/spio_async_tpool.cpp | 1 + src/clib/spio_async_utils.cpp | 3 + src/clib/spio_hdf5_utils.cpp | 9 --- 7 files changed, 135 insertions(+), 9 deletions(-) diff --git a/src/clib/pio_getput_int.cpp b/src/clib/pio_getput_int.cpp index eb3f22fcce..f28bb5d180 100644 --- a/src/clib/pio_getput_int.cpp +++ b/src/clib/pio_getput_int.cpp @@ -2606,6 +2606,15 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off LOG((2, "spio_put_vars_tc complete bcast from comproot ndims = %d", ndims)); } + /* FIXME: Relax this wait */ + ierr = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ierr != PIO_NOERR){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. " + "Error waiting on all pending asynchronous HDF5 ops", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + /* ADIOS: assume all procs are also IO tasks */ #ifdef _ADIOS2 if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) @@ -3289,7 +3298,11 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off file->io_fstats->wb += num_elem * typelen; } +#ifdef PIO_USE_ASYNC_WR_THREAD + ierr = spio_iosys_async_hdf5_put_var_op_add(file, varid, start, count, stride, xtype, buf); +#else ierr = spio_hdf5_put_var(ios, file, varid, start, count, stride, xtype, buf); +#endif } #endif /* _HDF5 */ diff --git a/src/clib/pio_types.hpp b/src/clib/pio_types.hpp index 72dc5322c5..42e0181a7c 100644 --- a/src/clib/pio_types.hpp +++ b/src/clib/pio_types.hpp @@ -355,6 +355,7 @@ typedef enum pio_async_op_type PIO_ASYNC_HDF5_DEF_VAR_OP, PIO_ASYNC_HDF5_PUT_ATT_OP, PIO_ASYNC_HDF5_ENDDEF_OP, + PIO_ASYNC_HDF5_PUT_VAR_OP, PIO_ASYNC_HDF5_WRITE_OP, PIO_ASYNC_FILE_WRITE_OPS, PIO_ASYNC_FILE_CLOSE_OP, diff --git a/src/clib/spio_async_hdf5_utils.cpp b/src/clib/spio_async_hdf5_utils.cpp index d6978cb991..717ca00d02 100644 --- a/src/clib/spio_async_hdf5_utils.cpp +++ b/src/clib/spio_async_hdf5_utils.cpp @@ -60,6 +60,17 @@ struct Hdf5_enddef_info{ file_desc_t *file; }; +struct Hdf5_put_var_info{ + file_desc_t *file; + int varid; + std::vector start; + std::vector count; + std::vector stride; + nc_type xtype; + PIO_Offset vbuf_sz; + void *vbuf; +}; + struct Hdf5_wcache{ file_desc_t *file; int nvars; @@ -387,6 +398,109 @@ int spio_iosys_async_hdf5_enddef_op_add(file_desc_t *file) return PIO_NOERR; } + +void spio_iosys_async_op_hdf5_put_var_free(void *pdata) +{ + if(pdata){ + Hdf5_put_var_info *info = static_cast(pdata); + free(info->vbuf); + delete(info); + } +} + +int spio_iosys_async_op_hdf5_put_var(void *pdata) +{ + int ret = PIO_NOERR; + + Hdf5_put_var_info *info = static_cast(pdata); + + assert(info && info->file && info->file->iosystem); + assert((info->varid >= 0) || (info->varid == PIO_GLOBAL)); + + ret = spio_hdf5_put_var(info->file->iosystem, info->file, + info->varid, + (!info->start.empty()) ? (info->start.data()) : NULL, + (!info->count.empty()) ? (info->count.data()) : NULL, + (!info->stride.empty()) ? (info->stride.data()) : NULL, + info->xtype, info->vbuf); + + info->file->npend_ops--; + SPIO_Util::GVars::npend_hdf5_async_ops--; + + return ret; +} + +int spio_iosys_async_hdf5_put_var_op_add(file_desc_t *file, int varid, + const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, + nc_type xtype, const void *vbuf) +{ + int ret = PIO_NOERR; + + assert(file && file->iosystem && (varid >= 0) && vbuf); + + iosystem_desc_t *ios = file->iosystem; + + if(!ios->ioproc){ + return PIO_NOERR; + } + + int ndims = file->hdf5_vars[varid].ndims; + PIO_Offset vbuf_sz = 0; + if(count){ + vbuf_sz = std::accumulate(count, count + ndims, 1, std::multiplies()); + } + else{ + int *dimids = file->hdf5_vars[varid].hdf5_dimids; + vbuf_sz = std::accumulate(dimids, dimids + ndims, 1, + [file](PIO_Offset acc_sz, const int &dimid){ + return acc_sz * file->hdf5_dims[dimid].len; + }); + } + + vbuf_sz *= spio_get_nc_type_size(xtype); + + void *buf = malloc(vbuf_sz); + if(buf == NULL){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Queuing asynchronous op/task for writing variable(%s, varid=%d, file=%s) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for caching variable value", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), static_cast(vbuf_sz)); + } + + memcpy(buf, vbuf, vbuf_sz); + + Hdf5_put_var_info *info = new Hdf5_put_var_info{file, varid, + (start) ? std::vector{start, start + ndims} : std::vector{}, + (count) ? std::vector{count, count + ndims} : std::vector{}, + (stride) ? std::vector{stride, stride + ndims} : std::vector{}, + xtype, vbuf_sz, buf}; + + /* Create async task */ + pio_async_op_t *pnew = static_cast(calloc(1, sizeof(pio_async_op_t))); + if(pnew == NULL){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Queuing asynchronous op/task for writing variable(%s, varid=%d, file=%s) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for async internal struct", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), static_cast(sizeof(pio_async_op_t))); + } + + pnew->op_type = PIO_ASYNC_HDF5_PUT_VAR_OP; + pnew->pdata = static_cast(info); + pnew->wait = spio_iosys_async_op_hdf5_put_var; + pnew->poke = pio_async_poke_func_unavail; + pnew->free = spio_iosys_async_op_hdf5_put_var_free; + + /* One more pending op using this file */ + file->npend_ops++; + SPIO_Util::GVars::npend_hdf5_async_ops++; + + /* Get the mt queue and queue the async task */ + ret = pio_async_tpool_op_add(pnew); + if(ret != PIO_NOERR){ + LOG((1, "Adding file pending ops to tpool failed, ret = %d", ret)); + return pio_err(ios, NULL, ret, __FILE__, __LINE__, + "Internal error while adding asynchronous pending operation to the thread pool (iosystem = %d). Adding the asynchronous operation failed", ios->iosysid); + } + + return PIO_NOERR; +} + #endif // _HDF5 int spio_wait_all_hdf5_async_ops(int iosysid) diff --git a/src/clib/spio_async_hdf5_utils.hpp b/src/clib/spio_async_hdf5_utils.hpp index 97c4f57c06..0b594f56f2 100644 --- a/src/clib/spio_async_hdf5_utils.hpp +++ b/src/clib/spio_async_hdf5_utils.hpp @@ -15,6 +15,9 @@ int spio_iosys_async_hdf5_def_var_op_add(file_desc_t *file, const char *name, int spio_iosys_async_hdf5_put_att_op_add(file_desc_t *file, int varid, const char *aname, nc_type atype, PIO_Offset alen, const void *abuf); int spio_iosys_async_hdf5_enddef_op_add(file_desc_t *file); +int spio_iosys_async_hdf5_put_var_op_add(file_desc_t *file, int varid, + const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, + nc_type xtype, const void *vbuf); int spio_wait_all_hdf5_async_ops(int iosysid); int pio_iosys_async_op_hdf5_write(void *pdata); diff --git a/src/clib/spio_async_tpool.cpp b/src/clib/spio_async_tpool.cpp index a3e3866aad..31d8056b2c 100644 --- a/src/clib/spio_async_tpool.cpp +++ b/src/clib/spio_async_tpool.cpp @@ -67,6 +67,7 @@ int PIO_Util::PIO_async_tpool::dequeue_and_process( (op->op_type == PIO_ASYNC_HDF5_DEF_VAR_OP) || (op->op_type == PIO_ASYNC_HDF5_PUT_ATT_OP) || (op->op_type == PIO_ASYNC_HDF5_ENDDEF_OP) || + (op->op_type == PIO_ASYNC_HDF5_PUT_VAR_OP) || (op->op_type == PIO_ASYNC_HDF5_WRITE_OP) || (op->op_type == PIO_ASYNC_FILE_CLOSE_OP)); ret = op->wait(op->pdata); diff --git a/src/clib/spio_async_utils.cpp b/src/clib/spio_async_utils.cpp index 3d2812c48e..d69f126980 100644 --- a/src/clib/spio_async_utils.cpp +++ b/src/clib/spio_async_utils.cpp @@ -43,6 +43,7 @@ std::string pio_async_op_type_to_string(pio_async_op_type_t op) case PIO_ASYNC_HDF5_DEF_VAR_OP: return "PIO_ASYNC_HDF5_DEF_VAR_OP"; case PIO_ASYNC_HDF5_PUT_ATT_OP: return "PIO_ASYNC_HDF5_PUT_ATT_OP"; case PIO_ASYNC_HDF5_ENDDEF_OP: return "PIO_ASYNC_HDF5_ENDDEF_OP"; + case PIO_ASYNC_HDF5_PUT_VAR_OP: return "PIO_ASYNC_HDF5_PUT_VAR_OP"; case PIO_ASYNC_HDF5_WRITE_OP: return "PIO_ASYNC_HDF5_WRITE_OP"; case PIO_ASYNC_FILE_WRITE_OPS: return "PIO_ASYNC_FILE_WRITE_OPS"; case PIO_ASYNC_FILE_CLOSE_OP: return "PIO_ASYNC_FILE_CLOSE_OP"; @@ -499,6 +500,8 @@ static file_async_pend_ops_kwait_func_t pio_async_wait_func_unavail, /* PIO_ASYNC_HDF5_ENDDEF_OP */ pio_async_wait_func_unavail, + /* PIO_ASYNC_HDF5_PUT_VAR_OP */ + pio_async_wait_func_unavail, /* PIO_ASYNC_HDF5_WRITE_OP */ pio_async_hdf5_write_kwait, /* PIO_ASYNC_FILE_WRITE_OPS */ diff --git a/src/clib/spio_hdf5_utils.cpp b/src/clib/spio_hdf5_utils.cpp index 6ae89b52d8..036a7bc737 100644 --- a/src/clib/spio_hdf5_utils.cpp +++ b/src/clib/spio_hdf5_utils.cpp @@ -1046,15 +1046,6 @@ int spio_hdf5_put_var(iosystem_desc_t *ios, file_desc_t *file, int varid, assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); assert(ios->ioproc); - /* FIXME: Relax this wait */ - ret = spio_wait_all_hdf5_async_ops(ios->iosysid); - if(ret != PIO_NOERR){ - return pio_err(ios, file, ret, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "Error waiting on all pending asynchronous HDF5 ops", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - hid_t file_space_id = H5Dget_space(file->hdf5_vars[varid].hdf5_dataset_id); if(file_space_id == H5I_INVALID_HID){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, From eae7d4bbe9c912e0ddfed62e0efb3caa1a38d268 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 14 Jan 2026 16:17:12 -0600 Subject: [PATCH 114/194] Disable file sync for HDF5 on anl compute nodes Disable MPI file syncing for HDF5 output on ANL compute nodes. This setting is required when using HDF5+ROMIO+NFS to relax the sync requirements imposed by default. This is essentially equivalent to setting environment variable HDF5_DO_MPI_FILE_SYNC=FALSE --- CMakeLists.txt | 8 ++++++++ src/clib/pio_config.h.in | 3 +++ src/clib/spio_hdf5_utils.cpp | 9 +++++++++ 3 files changed, 20 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d2f080e55..cfcc850f1c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -218,6 +218,14 @@ else() endif() endif() +# Default - Do not disable MPI file syncing for HDF5 output files +set(SPIO_DISABLE_HDF5_MPI_FILE_SYNC 0) +if(FQDN_SITENAME MATCHES "^compute-386") + # On ANL compute nodes with NFS+ROMIO, disable MPI file syncing for HDF5 output + message(STATUS "Disabling HDF5 file syncing") + set(SPIO_DISABLE_HDF5_MPI_FILE_SYNC 1) +endif() + set(USE_INDEP_MODE 0) if(PIO_USE_INDEP_MODE) if(FQDN_SITENAME MATCHES "^chrlogin" OR FQDN_SITENAME MATCHES "^compute-240" OR FQDN_SITENAME MATCHES "^compute-386") diff --git a/src/clib/pio_config.h.in b/src/clib/pio_config.h.in index 28d0c6362a..b4bd7382cd 100644 --- a/src/clib/pio_config.h.in +++ b/src/clib/pio_config.h.in @@ -55,6 +55,9 @@ /** Striping unit hint in bytes for a Lustre or GPFS file system. */ #define PIO_STRIPING_UNIT @PIO_STRIPING_UNIT@ +/** If MPI File sync needs to be explicitly disabled (default : false) */ +#define SPIO_DISABLE_HDF5_MPI_FILE_SYNC @SPIO_DISABLE_HDF5_MPI_FILE_SYNC@ + /** Extra bytes reserved in the header when creating NetCDF files. */ #define PIO_RESERVED_FILE_HEADER_SIZE @PIO_RESERVED_FILE_HEADER_SIZE@ diff --git a/src/clib/spio_hdf5_utils.cpp b/src/clib/spio_hdf5_utils.cpp index 036a7bc737..3d6d784836 100644 --- a/src/clib/spio_hdf5_utils.cpp +++ b/src/clib/spio_hdf5_utils.cpp @@ -129,6 +129,15 @@ int spio_hdf5_create(iosystem_desc_t *ios, file_desc_t *file, const char *filena filename); } +#if SPIO_DISABLE_HDF5_MPI_FILE_SYNC + /* This is essentially the same as setting env variable, HDF5_DO_MPI_FILE_SYNC=FALSE */ + if(H5Fset_mpi_atomicity(file->hdf5_file_id, false) < 0){ + std::string warn_msg = std::string("Unable to turn off MPI file syncing for HDF5 output") + + "( file = " + pio_get_fname_from_file(file) + ")"; + PIOc_warn(ios->iosysid, file->pio_ncid, __FILE__, __LINE__, warn_msg.c_str()); + } +#endif + if(H5Pclose(fcpl_id) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, "Creating file (%s) using HDF5 iotype failed. " From 41ed316d837a49571286505e83cccb5962d16e86 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 15 Jan 2026 16:57:06 -0600 Subject: [PATCH 115/194] Add util for data type conversion without caching Adding function to use the datatype converter without internal caching of the temporary (converted) buffers --- src/clib/spio_dt_converter.cpp | 11 +++++++++++ src/clib/spio_dt_converter.hpp | 35 +++++++++++++++++++++------------- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/clib/spio_dt_converter.cpp b/src/clib/spio_dt_converter.cpp index 2ee65713cd..3b74e9eb56 100644 --- a/src/clib/spio_dt_converter.cpp +++ b/src/clib/spio_dt_converter.cpp @@ -24,6 +24,17 @@ void *SPIO_Util::File_Util::DTConverter::convert(int ncid, void *buf, std::size_ return cbuf.buf; } +void *SPIO_Util::File_Util::DTConverter::convert(const void *buf, std::size_t sz, int from_pio_type, int to_pio_type) +{ + std::size_t nelems = sz / size_of(from_pio_type); + + void *rbuf = bget(nelems * size_of(to_pio_type)); + + copy_to(buf, from_pio_type, rbuf, to_pio_type, nelems); + + return rbuf; +} + void SPIO_Util::File_Util::DTConverter::free(int ncid) { std::map >::iterator cbufs_iter = cbufs_.find(ncid); diff --git a/src/clib/spio_dt_converter.hpp b/src/clib/spio_dt_converter.hpp index 8fa23b8646..70ca9fed00 100644 --- a/src/clib/spio_dt_converter.hpp +++ b/src/clib/spio_dt_converter.hpp @@ -18,8 +18,17 @@ namespace SPIO_Util{ */ class DTConverter{ public: - /* Convert buffer to requested type, buffer size, sz, is in bytes */ + /* Convert buffer to requested type, buffer size, sz, is in bytes + * - the returned buffer (converted buffer) is owned by the datatype converter & + * can be freed via the free(ncid) member function + */ void *convert(int ncid, void *buf, std::size_t sz, int from_pio_type, int to_pio_type); + /* Convert buffer to requested type, buffer size, sz, is in bytes + * - the returned buffer (converted buffer) is owned by the caller & + * needs to be freed using the brel(PTR_RETURNED_BY_FUNCTION) function + * by the caller + */ + void *convert(const void *buf, std::size_t sz, int from_pio_type, int to_pio_type); /* Check if the converter has any cached buffers - useful for debugging */ bool empty(void ) const { return cbufs_.empty(); } /* Free the scratch/temp buffers associated with ncid/file */ @@ -76,19 +85,19 @@ namespace SPIO_Util{ } } - static inline void copy_to(void *from_buf, int from_pio_type, void *to_buf, int to_pio_type, std::size_t nelems){ + static inline void copy_to(const void *from_buf, int from_pio_type, void *to_buf, int to_pio_type, std::size_t nelems){ switch(from_pio_type){ - case PIO_DOUBLE : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; - case PIO_FLOAT : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; - case PIO_INT : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; - case PIO_UINT : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; - case PIO_SHORT : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; - case PIO_USHORT : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; - case PIO_INT64 : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; - case PIO_UINT64 : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; - case PIO_CHAR : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; - case PIO_BYTE : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; - case PIO_UBYTE : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; + case PIO_DOUBLE : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; + case PIO_FLOAT : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; + case PIO_INT : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; + case PIO_UINT : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; + case PIO_SHORT : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; + case PIO_USHORT : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; + case PIO_INT64 : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; + case PIO_UINT64 : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; + case PIO_CHAR : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; + case PIO_BYTE : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; + case PIO_UBYTE : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; default : assert(0); } } From 5dfbf7983301869113dc84cc0d569e048343c492 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 21 Jan 2026 09:52:44 -0600 Subject: [PATCH 116/194] Config setting for async timeout Move the max timeout for asynchronous I/O events to a CMake configure setting --- CMakeLists.txt | 6 ++++++ src/clib/pio_config.h.in | 3 +++ src/clib/pio_file.cpp | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cfcc850f1c..5dc100105e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -340,6 +340,12 @@ else() endif() endif() +# Maximum wait for asynchronous I/O operations (in milliseconds) +if(NOT DEFINED SPIO_ASYNC_OP_WAIT_TIMEOUT) + # 2 minutes = 2 * 60 * 1000 milliseconds + set(SPIO_ASYNC_OP_WAIT_TIMEOUT 120000) +endif() + if(DEFINED SPIO_OVERRIDE_HDF5_COMPRESSION_VNAME_REGEX) if(WITH_HDF5 AND HDF5_USE_COMPRESSION) message(STATUS "Overriding HDF5 compression for variables matching regex: ${SPIO_OVERRIDE_HDF5_COMPRESSION_VNAME_REGEX}") diff --git a/src/clib/pio_config.h.in b/src/clib/pio_config.h.in index b4bd7382cd..d5374bd6b3 100644 --- a/src/clib/pio_config.h.in +++ b/src/clib/pio_config.h.in @@ -176,4 +176,7 @@ * 0 otherwise */ #define PIO_USE_ASYNC_WR_THREAD @USE_ASYNC_WR_THREAD@ +/** Maximum wait for asynchronous I/O operations (in milliseconds) */ +#define SPIO_ASYNC_OP_WAIT_TIMEOUT @SPIO_ASYNC_OP_WAIT_TIMEOUT@ + #endif /* _PIO_CONFIG_ */ diff --git a/src/clib/pio_file.cpp b/src/clib/pio_file.cpp index ab8bb4075f..1c2ddeb603 100644 --- a/src/clib/pio_file.cpp +++ b/src/clib/pio_file.cpp @@ -445,7 +445,7 @@ static int sync_file(int ncid) int spio_wait_on_hard_close(iosystem_desc_t *ios, file_desc_t *file) { /* FIXME: Make the max time configurable */ - const int MAX_SLEEP_TIME_IN_MILLISECONDS = 5000; + const int MAX_SLEEP_TIME_IN_MILLISECONDS = SPIO_ASYNC_OP_WAIT_TIMEOUT; const int SLEEP_TIME_IN_MILLISECONDS = 500; /* For files that will never be closed, due to user error for ex, we cannot wait From 38ba67b627bcfc8773868eee07ce6314c8d4ebb5 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 21 Jan 2026 09:54:39 -0600 Subject: [PATCH 117/194] Warn on pending async I/O events every 2s Add logic to warn users on pending asynchronous I/O events in a different cadence (2s) than the wait itself (0.5s). --- src/clib/spio_async_hdf5_utils.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/clib/spio_async_hdf5_utils.cpp b/src/clib/spio_async_hdf5_utils.cpp index 717ca00d02..d6a924b4fc 100644 --- a/src/clib/spio_async_hdf5_utils.cpp +++ b/src/clib/spio_async_hdf5_utils.cpp @@ -505,11 +505,18 @@ int spio_iosys_async_hdf5_put_var_op_add(file_desc_t *file, int varid, int spio_wait_all_hdf5_async_ops(int iosysid) { + unsigned long long int sleep_time = 0; + /* Sleep for 0.5 seconds */ const int SLEEP_TIME_IN_MILLISECONDS = 500; + /* Warn every 2 seconds */ + const int WARN_TIME_IN_MILLISECONDS = 2000; while(SPIO_Util::GVars::npend_hdf5_async_ops > 0){ std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME_IN_MILLISECONDS)); - if(SPIO_Util::GVars::npend_hdf5_async_ops > 0){ - PIOc_warn(iosysid, PIO_DEFAULT, __FILE__, __LINE__, "Continuing to wait on all HDF5 async ops..."); + sleep_time += SLEEP_TIME_IN_MILLISECONDS; + if((SPIO_Util::GVars::npend_hdf5_async_ops > 0) && (sleep_time % WARN_TIME_IN_MILLISECONDS == 0)){ + std::string warn_msg = std::string("Continuing to wait on all HDF5 async ops... ") + + "(Elapsed time = " + std::to_string(sleep_time) + " ms)"; + PIOc_warn(iosysid, PIO_DEFAULT, __FILE__, __LINE__, warn_msg.c_str()); } } From c15ecd8b56699a3023f866b14ed79526489e4d54 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 21 Jan 2026 09:56:39 -0600 Subject: [PATCH 118/194] Avoid type conv from nc_type to int in dtype conv Avoid implicit type convertion from nc_type to int in the datatype converter --- src/clib/spio_dt_converter.cpp | 4 ++-- src/clib/spio_dt_converter.hpp | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/clib/spio_dt_converter.cpp b/src/clib/spio_dt_converter.cpp index 3b74e9eb56..c3572c22ba 100644 --- a/src/clib/spio_dt_converter.cpp +++ b/src/clib/spio_dt_converter.cpp @@ -1,6 +1,6 @@ #include "spio_dt_converter.hpp" -void *SPIO_Util::File_Util::DTConverter::convert(int ncid, void *buf, std::size_t sz, int from_pio_type, int to_pio_type) +void *SPIO_Util::File_Util::DTConverter::convert(int ncid, void *buf, std::size_t sz, nc_type from_pio_type, nc_type to_pio_type) { if(from_pio_type == to_pio_type){ /* No conversion required, return the buffer as is */ @@ -24,7 +24,7 @@ void *SPIO_Util::File_Util::DTConverter::convert(int ncid, void *buf, std::size_ return cbuf.buf; } -void *SPIO_Util::File_Util::DTConverter::convert(const void *buf, std::size_t sz, int from_pio_type, int to_pio_type) +void *SPIO_Util::File_Util::DTConverter::convert(const void *buf, std::size_t sz, nc_type from_pio_type, nc_type to_pio_type) { std::size_t nelems = sz / size_of(from_pio_type); diff --git a/src/clib/spio_dt_converter.hpp b/src/clib/spio_dt_converter.hpp index 70ca9fed00..c7ef20e7fc 100644 --- a/src/clib/spio_dt_converter.hpp +++ b/src/clib/spio_dt_converter.hpp @@ -22,13 +22,13 @@ namespace SPIO_Util{ * - the returned buffer (converted buffer) is owned by the datatype converter & * can be freed via the free(ncid) member function */ - void *convert(int ncid, void *buf, std::size_t sz, int from_pio_type, int to_pio_type); + void *convert(int ncid, void *buf, std::size_t sz, nc_type from_pio_type, nc_type to_pio_type); /* Convert buffer to requested type, buffer size, sz, is in bytes * - the returned buffer (converted buffer) is owned by the caller & * needs to be freed using the brel(PTR_RETURNED_BY_FUNCTION) function * by the caller */ - void *convert(const void *buf, std::size_t sz, int from_pio_type, int to_pio_type); + void *convert(const void *buf, std::size_t sz, nc_type from_pio_type, nc_type to_pio_type); /* Check if the converter has any cached buffers - useful for debugging */ bool empty(void ) const { return cbufs_.empty(); } /* Free the scratch/temp buffers associated with ncid/file */ @@ -36,7 +36,7 @@ namespace SPIO_Util{ /* Clear all scratch/temp buffers */ void clear(void ); - static inline std::size_t size_of(int pio_type){ + static inline std::size_t size_of(nc_type pio_type){ switch(pio_type){ case PIO_DOUBLE : return sizeof(double); case PIO_FLOAT : return sizeof(float); @@ -68,7 +68,7 @@ namespace SPIO_Util{ } template - static inline void copy_to(F *from_buf, void *to_buf, int to_pio_type, std::size_t nelems){ + static inline void copy_to(F *from_buf, void *to_buf, nc_type to_pio_type, std::size_t nelems){ switch(to_pio_type){ case PIO_DOUBLE : copy_to(from_buf, static_cast(to_buf), nelems); break; case PIO_FLOAT : copy_to(from_buf, static_cast(to_buf), nelems); break; @@ -85,7 +85,7 @@ namespace SPIO_Util{ } } - static inline void copy_to(const void *from_buf, int from_pio_type, void *to_buf, int to_pio_type, std::size_t nelems){ + static inline void copy_to(const void *from_buf, nc_type from_pio_type, void *to_buf, nc_type to_pio_type, std::size_t nelems){ switch(from_pio_type){ case PIO_DOUBLE : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; case PIO_FLOAT : copy_to(static_cast(from_buf), to_buf, to_pio_type, nelems); break; From 79f59fc5c486b5bac6de83d975ab2a9c85e6666a Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 21 Jan 2026 09:57:55 -0600 Subject: [PATCH 119/194] Avoid type conv from nc_type to int in hdf5 utils Avoid implicit conversion from nc_type to int in HDF5 utils --- src/clib/spio_hdf5_utils.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clib/spio_hdf5_utils.hpp b/src/clib/spio_hdf5_utils.hpp index 2ede67942b..e7e26bec6f 100644 --- a/src/clib/spio_hdf5_utils.hpp +++ b/src/clib/spio_hdf5_utils.hpp @@ -48,7 +48,7 @@ inline hid_t spio_nc_type_to_hdf5_type(nc_type xtype) return H5I_INVALID_HID; } -inline int spio_hdf5_type_to_pio_type(hid_t ntype) +inline nc_type spio_hdf5_type_to_pio_type(hid_t ntype) { /* switch() does not work with HDF5 "types" since these types are macros * (which include library initialization call, H5Open(), if needed) From cc8dd4b5437ac850717a7bd9e7c3a653e7f5a436 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 21 Jan 2026 09:58:45 -0600 Subject: [PATCH 120/194] Explicit dtype conversion for HDF5 puts Adding explicit datatype conversion, if needed, for HDF5 puts. This support is already available for distributed HDF5 writes. --- src/clib/spio_hdf5_utils.cpp | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/clib/spio_hdf5_utils.cpp b/src/clib/spio_hdf5_utils.cpp index 3d6d784836..d4035b10d1 100644 --- a/src/clib/spio_hdf5_utils.cpp +++ b/src/clib/spio_hdf5_utils.cpp @@ -1193,9 +1193,29 @@ int spio_hdf5_put_var(iosystem_desc_t *ios, file_desc_t *file, int varid, } } + hid_t file_var_type_id = H5Dget_type(file->hdf5_vars[varid].hdf5_dataset_id); + assert(file_var_type_id != H5I_INVALID_HID); + + hid_t file_var_ntype_id = H5Tget_native_type(file_var_type_id, H5T_DIR_DEFAULT); + assert(file_var_ntype_id != H5I_INVALID_HID); + + void *wbuf = NULL; + bool dt_conv_reqd = (nelems > 0) && !H5Tequal(mem_type_id, file_var_ntype_id); + if(dt_conv_reqd){ + assert(file->dt_converter); + wbuf = static_cast(file->dt_converter)->convert(buf, spio_get_nc_type_size(xtype) * nelems, xtype, spio_hdf5_type_to_pio_type(file_var_ntype_id)); + assert(wbuf != NULL); + if(wbuf == NULL){ + return pio_err(ios, file, PIO_EINTERNAL, __FILE__, __LINE__, + "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "Unable to convert buffer from %d (buffer type in memory) to %d (variable type in file)", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, static_cast(xtype), spio_hdf5_type_to_pio_type(file_var_ntype_id)); + } + } + /* Independent write */ - if(H5Dwrite(file->hdf5_vars[varid].hdf5_dataset_id, mem_type_id, mem_space_id, - file_space_id, file->dxplid_indep, buf) < 0){ + if(H5Dwrite(file->hdf5_vars[varid].hdf5_dataset_id, file_var_ntype_id, mem_space_id, + file_space_id, file->dxplid_indep, (dt_conv_reqd) ? wbuf : buf) < 0){ H5Eprint2(H5E_DEFAULT, stderr); return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " @@ -1203,6 +1223,10 @@ int spio_hdf5_put_var(iosystem_desc_t *ios, file_desc_t *file, int varid, pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); } + if(dt_conv_reqd){ + brel(wbuf); + } + if(H5Sclose(mem_space_id) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, "Writing variable (%s, varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " From 73cecb4bd48b7d1a188cf9dd9ff1a50c53d2358f Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 21 Jan 2026 11:10:17 -0600 Subject: [PATCH 121/194] Move num async threads to configure Moving the choice of number of asynchronous I/O threads to CMake configure. Also adding some user messages on the asynchronous I/O operation timeout --- CMakeLists.txt | 20 ++++++++++++++++++++ src/clib/pio_config.h.in | 3 +++ src/clib/spio_async_tpool.cpp | 2 +- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5dc100105e..d7032e4db9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -340,10 +340,30 @@ else() endif() endif() +# Asynchronous I/O options # Maximum wait for asynchronous I/O operations (in milliseconds) if(NOT DEFINED SPIO_ASYNC_OP_WAIT_TIMEOUT) # 2 minutes = 2 * 60 * 1000 milliseconds set(SPIO_ASYNC_OP_WAIT_TIMEOUT 120000) + if(PIO_USE_ASYNC_WR_THREAD) + message(STATUS "Setting timeout for asynchronous I/O operations to ${SPIO_ASYNC_OP_WAIT_TIMEOUT} ms (default)") + endif() +else() + if(PIO_USE_ASYNC_WR_THREAD) + message(STATUS "Setting timeout for asynchronous I/O operations to ${SPIO_ASYNC_OP_WAIT_TIMEOUT} ms") + endif() +endif() + +# Maximum number of threads performing asynchronous I/O operations +if(NOT DEFINED SPIO_ASYNC_NTHREADS) + set(SPIO_ASYNC_NTHREADS 1) + if(PIO_USE_ASYNC_WR_THREAD) + message(STATUS "Setting number of asynchronous I/O threads to ${SPIO_ASYNC_NTHREADS} (default)") + endif() +else() + if(PIO_USE_ASYNC_WR_THREAD) + message(STATUS "Setting number of asynchronous I/O threads to ${SPIO_ASYNC_NTHREADS}") + endif() endif() if(DEFINED SPIO_OVERRIDE_HDF5_COMPRESSION_VNAME_REGEX) diff --git a/src/clib/pio_config.h.in b/src/clib/pio_config.h.in index d5374bd6b3..113cac53a9 100644 --- a/src/clib/pio_config.h.in +++ b/src/clib/pio_config.h.in @@ -179,4 +179,7 @@ /** Maximum wait for asynchronous I/O operations (in milliseconds) */ #define SPIO_ASYNC_OP_WAIT_TIMEOUT @SPIO_ASYNC_OP_WAIT_TIMEOUT@ +/** Number of threads performing asynchronous I/O operations */ +#define SPIO_ASYNC_NTHREADS @SPIO_ASYNC_NTHREADS@ + #endif /* _PIO_CONFIG_ */ diff --git a/src/clib/spio_async_tpool.cpp b/src/clib/spio_async_tpool.cpp index 31d8056b2c..23a971e2ed 100644 --- a/src/clib/spio_async_tpool.cpp +++ b/src/clib/spio_async_tpool.cpp @@ -87,7 +87,7 @@ PIO_Util::PIO_async_tpool * PIO_Util::PIO_async_tpool_manager::get_tpool_instance(void ) { /* We need to make NUM_THREADS configurable by the user (compile-time) */ - const int NUM_THREADS = 1; + const int NUM_THREADS = SPIO_ASYNC_NTHREADS; if(tpool_ == NULL){ LOG((2, "PIO_async_tpool_manager:get_tpool_instance: Creating new tpool instance")); tpool_ = new PIO_Util::PIO_async_tpool(NUM_THREADS); From 1793ed5253f6b2e358b05d2248c0380f7ab97c4f Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 26 Jan 2026 16:09:47 -0600 Subject: [PATCH 122/194] Adding thread local comms Adding thread local comms. The comms are copied or duped from the comms for the main thread. --- src/clib/CMakeLists.txt | 3 +- src/clib/pio_types.hpp | 7 ++ src/clib/pioc.cpp | 12 +++ src/clib/spio_async_tcomm.cpp | 152 ++++++++++++++++++++++++++++++++++ src/clib/spio_async_tcomm.hpp | 67 +++++++++++++++ src/clib/spio_async_tpool.cpp | 13 +++ src/clib/spio_async_tpool.hpp | 1 + 7 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 src/clib/spio_async_tcomm.cpp create mode 100644 src/clib/spio_async_tcomm.hpp diff --git a/src/clib/CMakeLists.txt b/src/clib/CMakeLists.txt index 32ddc18942..1fb982d263 100644 --- a/src/clib/CMakeLists.txt +++ b/src/clib/CMakeLists.txt @@ -46,7 +46,8 @@ set (pio_lib_src spio_ltimer.cpp spio_serializer.cpp spio_file_mvcache.cpp spio_tracer.cpp spio_tracer_mdata.cpp spio_tracer_decomp.cpp spio_rearrange_any.cpp spio_dt_converter.cpp - spio_async_tpool.cpp spio_async_utils.cpp spio_hdf5_utils.cpp spio_async_hdf5_utils.cpp) + spio_async_tpool.cpp spio_async_utils.cpp spio_async_tcomm.cpp + spio_hdf5_utils.cpp spio_async_hdf5_utils.cpp) # Add sources for libpioc.a add_library (pioc ${pio_api_src} ${pio_lib_src}) diff --git a/src/clib/pio_types.hpp b/src/clib/pio_types.hpp index 42e0181a7c..cf01438721 100644 --- a/src/clib/pio_types.hpp +++ b/src/clib/pio_types.hpp @@ -61,6 +61,11 @@ struct spio_hmap; /* Fwd declaration to use back pointer to var_desc_t in viobuf_cache */ struct var_desc_t; +/* Fwd declaration of thread-specific comm class used in iosystem_desc_t */ +namespace SPIO_Util{ + class TComm_info; +} + /** The viobuf_cache is used to cache the rearranged data for the * variable. The iobuf inside the cache is freed when the data * is written out. @@ -474,6 +479,8 @@ typedef struct iosystem_desc_t * of IO tasks in async situations. */ int comproot; + SPIO_Util::TComm_info *tcomm_info; + /** An array of the ranks of all IO tasks within the union * communicator. */ int *ioranks; diff --git a/src/clib/pioc.cpp b/src/clib/pioc.cpp index 15021a4b4a..cf129ec935 100644 --- a/src/clib/pioc.cpp +++ b/src/clib/pioc.cpp @@ -24,6 +24,7 @@ #include "spio_dbg_utils.hpp" #include "spio_decomp_map_info_pool.hpp" #include "spio_decomp_logger.hpp" +#include "spio_async_tcomm.hpp" /* Include headers for HDF5 compression filters */ #if PIO_USE_HDF5 @@ -1677,6 +1678,9 @@ int PIOc_Init_Intracomm_impl(MPI_Comm comp_comm, int num_iotasks, int stride, in /* Rank in the union comm is the same as rank in the comp comm. */ ios->union_rank = ios->comp_rank; + /* FIXME: Catch exceptions and return error */ + ios->tcomm_info = new SPIO_Util::TComm_info(ios->union_comm, ios->union_rank, ios->ioroot, ios->comproot, ios->io_comm, ios->io_rank, (ios->iomaster) ? true : false, ios->comp_comm, ios->comp_rank, (ios->compmaster) ? true : false, ios->intercomm, ios->my_comm, ios->node_comm); + /* Async I/O service message info - not used here */ ios->async_ios_msg_info.seq_num = PIO_MSG_START_SEQ_NUM; ios->async_ios_msg_info.prev_msg = PIO_MSG_INVALID; @@ -2016,6 +2020,7 @@ int PIOc_finalize_impl(int iosysid) MPI_Comm_free(&ios->io_comm); if (ios->node_comm != MPI_COMM_NULL) MPI_Comm_free(&ios->node_comm); + if(ios->tcomm_info) { delete(ios->tcomm_info); } /* Delete the iosystem_desc_t data associated with this id. */ LOG((2, "About to delete iosysid %d.", iosysid)); @@ -2611,6 +2616,9 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li LOG((3, "intercomm created for cmp = %d", cmp)); } + /* FIXME: Catch exceptions and return error */ + my_iosys->tcomm_info = new SPIO_Util::TComm_info(my_iosys->union_comm, my_iosys->union_rank, my_iosys->ioroot, my_iosys->comproot, my_iosys->io_comm, my_iosys->io_rank, (my_iosys->iomaster) ? true : false, my_iosys->comp_comm, my_iosys->comp_rank, (my_iosys->compmaster) ? true : false, my_iosys->intercomm, my_iosys->my_comm, my_iosys->node_comm); + /* Async I/O service message info */ my_iosys->async_ios_msg_info.seq_num = PIO_MSG_START_SEQ_NUM; my_iosys->async_ios_msg_info.prev_msg = PIO_MSG_INVALID; @@ -3209,6 +3217,10 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, } iosys[i]->my_comm = iosys[i]->union_comm; + + /* FIXME: Catch exceptions and return error */ + iosys[i]->tcomm_info = new SPIO_Util::TComm_info(iosys[i]->union_comm, iosys[i]->union_rank, iosys[i]->ioroot, iosys[i]->comproot, iosys[i]->io_comm, iosys[i]->io_rank, (iosys[i]->iomaster) ? true : false, iosys[i]->comp_comm, iosys[i]->comp_rank, (iosys[i]->compmaster) ? true : false, iosys[i]->intercomm, iosys[i]->my_comm, iosys[i]->node_comm); + /* Async I/O service message info */ iosys[i]->async_ios_msg_info.seq_num = PIO_MSG_START_SEQ_NUM; iosys[i]->async_ios_msg_info.prev_msg = PIO_MSG_INVALID; diff --git a/src/clib/spio_async_tcomm.cpp b/src/clib/spio_async_tcomm.cpp new file mode 100644 index 0000000000..769daba9f6 --- /dev/null +++ b/src/clib/spio_async_tcomm.cpp @@ -0,0 +1,152 @@ +#include +#include +#include +#include "spio_async_tcomm.hpp" +#include "spio_async_tpool.hpp" + +/* Static variables */ +thread_local std::size_t SPIO_Util::TComm_info::tidx_ = -1; +thread_local bool SPIO_Util::TComm_info::is_thread_init_ = false; + +SPIO_Util::TComm_info::TComm_info(MPI_Comm union_comm, int union_comm_rank, int union_comm_io_root, int union_comm_comp_root, MPI_Comm io_comm, int io_comm_rank, bool is_io_master, MPI_Comm comp_comm, int comp_comm_rank, bool is_comp_master, MPI_Comm intercomm, MPI_Comm my_comm, MPI_Comm node_comm): union_comm_rank_(union_comm_rank), union_comm_io_root_(union_comm_io_root), union_comm_comp_root_(union_comm_comp_root), io_comm_rank_(io_comm_rank), is_io_master_(is_io_master), comp_comm_rank_(comp_comm_rank), is_comp_master_(is_comp_master) +{ + tids_ = PIO_Util::PIO_async_tpool_manager::get_tpool_instance()->get_thread_ids(); + + /* Total number of comms = Main/Default thread + Number of threads in thread pool + * Main thread info is the first in the list + */ + tidx_ = 0; is_thread_init_ = true; + + union_comms_.push_back(union_comm); + io_comms_.push_back(io_comm); + comp_comms_.push_back(comp_comm); + intercomms_.push_back(intercomm); + my_comms_.push_back(my_comm); + node_comms_.push_back(node_comm); + + int ret = MPI_SUCCESS; + for(std::size_t i = 0; i < tids_.size(); i++){ + MPI_Comm tmp_union_comm = MPI_COMM_NULL; + if(union_comm != MPI_COMM_NULL){ + ret = MPI_Comm_dup(union_comm, &tmp_union_comm); assert(ret == MPI_SUCCESS); + } + union_comms_.push_back(tmp_union_comm); + + MPI_Comm tmp_io_comm = MPI_COMM_NULL; + if(io_comm != MPI_COMM_NULL){ + ret = MPI_Comm_dup(io_comm, &tmp_io_comm); assert(ret == MPI_SUCCESS); + } + io_comms_.push_back(tmp_io_comm); + + MPI_Comm tmp_comp_comm = MPI_COMM_NULL; + if(comp_comm != MPI_COMM_NULL){ + ret = MPI_Comm_dup(comp_comm, &tmp_comp_comm); assert(ret == MPI_SUCCESS); + } + comp_comms_.push_back(tmp_comp_comm); + + MPI_Comm tmp_comm = MPI_COMM_NULL; + if(intercomm != MPI_COMM_NULL){ + ret = MPI_Comm_dup(intercomm, &tmp_comm); assert(ret == MPI_SUCCESS); + } + intercomms_.push_back(tmp_comm); + + /* my_comm, see iosystem_desc_t for details, is just a copy (not dup) + * of union_comm or comp_comm + */ + if(my_comm == union_comm){ + my_comms_.push_back(tmp_union_comm); + } + else if(my_comm == comp_comm){ + my_comms_.push_back(tmp_comp_comm); + } + else if(my_comm == io_comm){ + my_comms_.push_back(tmp_io_comm); + } + else{ + assert(0); + } + + tmp_comm = MPI_COMM_NULL; + if(node_comm != MPI_COMM_NULL){ + ret = MPI_Comm_dup(node_comm, &tmp_comm); assert(ret == MPI_SUCCESS); + } + node_comms_.push_back(tmp_comm); + } +} + +MPI_Comm SPIO_Util::TComm_info::get_union_comm(void ) +{ + return union_comms_[get_tidx()]; +} + +MPI_Comm SPIO_Util::TComm_info::get_io_comm(void ) +{ + return io_comms_[get_tidx()]; +} + +MPI_Comm SPIO_Util::TComm_info::get_comp_comm(void ) +{ + return comp_comms_[get_tidx()]; +} + +MPI_Comm SPIO_Util::TComm_info::get_intercomm(void ) +{ + return intercomms_[get_tidx()]; +} + +MPI_Comm SPIO_Util::TComm_info::get_my_comm(void ) +{ + return my_comms_[get_tidx()]; +} + +MPI_Comm SPIO_Util::TComm_info::get_node_comm(void ) +{ + return node_comms_[get_tidx()]; +} + +SPIO_Util::TComm_info::~TComm_info() +{ + /* The main thread comms, in tidx == 0, was just copied over (not duped) + * Similarly my_comms are also just copied over + * Free other comms + */ + + /* Number of threads including the main thread */ + std::size_t nthreads = tids_.size() + 1; + assert(union_comms_.size() == nthreads); + for(std::size_t tidx = 1; tidx < nthreads; tidx++){ + if(union_comms_[tidx] != MPI_COMM_NULL) { MPI_Comm_free(&union_comms_[tidx]); } + if(io_comms_[tidx] != MPI_COMM_NULL) { MPI_Comm_free(&io_comms_[tidx]); } + if(comp_comms_[tidx] != MPI_COMM_NULL) { MPI_Comm_free(&comp_comms_[tidx]); } + if(intercomms_[tidx] != MPI_COMM_NULL) { MPI_Comm_free(&intercomms_[tidx]); } + if(node_comms_[tidx] != MPI_COMM_NULL) { MPI_Comm_free(&node_comms_[tidx]); } + } +} + +void SPIO_Util::TComm_info::init_thread_info(void ) +{ + tidx_ = INVALID_IDX; + /* Since we do this once per thread, and have a small number of threads a linear + * search should be ok + */ + std::hash tid_hasher; + std::size_t tid = tid_hasher(std::this_thread::get_id()); + + for(std::size_t i = 0; i < tids_.size(); i++){ + if(tid == tids_[i]){ + /* First tidx_ (tidx_ == 0) corresponds to main thread info */ + tidx_ = i + 1; + assert(tidx_ < union_comms_.size()); + break; + } + } + + assert(tidx_ != INVALID_IDX); + is_thread_init_ = true; +} + +std::size_t SPIO_Util::TComm_info::get_tidx(void ) +{ + if(!is_thread_init_) { init_thread_info(); } + return tidx_; +} diff --git a/src/clib/spio_async_tcomm.hpp b/src/clib/spio_async_tcomm.hpp new file mode 100644 index 0000000000..3102174e05 --- /dev/null +++ b/src/clib/spio_async_tcomm.hpp @@ -0,0 +1,67 @@ +#ifndef __SPIO_ASYNC_TCOMM_HPP__ +#define __SPIO_ASYNC_TCOMM_HPP__ + +#include +#include +#include +#include "mpi.h" +#include "pio_config.h" +#include "spio_async_tpool.hpp" + +namespace SPIO_Util{ + +/* Keep track of thread-specific MPI communicators */ +class TComm_info{ + public: + /* See iosystem_desc_t{} for info on the communicators cached here */ + TComm_info(MPI_Comm union_comm, int union_comm_rank, int union_comm_io_root, int union_comm_comp_root, MPI_Comm io_comm, int io_comm_rank, bool is_io_master, MPI_Comm comp_comm, int comp_comm_rank, bool is_comp_master, MPI_Comm intercomm, MPI_Comm my_comm, MPI_Comm node_comm); + MPI_Comm get_union_comm(void ); + int get_union_comm_rank(void ) const { return union_comm_rank_; } + int get_union_comm_io_root(void ) const { return union_comm_io_root_; } + int get_union_comm_comp_root(void ) const { return union_comm_comp_root_; } + + MPI_Comm get_io_comm(void ); + int get_io_comm_rank(void ) const { return io_comm_rank_; } + bool is_io_master(void ) const { return is_io_master_; } + + MPI_Comm get_comp_comm(void ); + int get_comp_comm_rank(void ) const { return comp_comm_rank_; } + bool is_comp_master(void ) const { return is_comp_master_; } + + MPI_Comm get_intercomm(void ); + MPI_Comm get_my_comm(void ); + MPI_Comm get_node_comm(void ); + + ~TComm_info(); + private: + const std::size_t INVALID_IDX = -1; + /* Index to thread-specific comm in the comm vectors. Index 0 + * is reserved for the main thread + * e.g. union_comms_[tidx_] is the union comm for current thread + */ + static thread_local std::size_t tidx_; + static thread_local bool is_thread_init_; + + int union_comm_rank_; + int union_comm_io_root_; + int union_comm_comp_root_; + int io_comm_rank_; + bool is_io_master_; + int comp_comm_rank_; + bool is_comp_master_; + + std::vector tids_; + std::vector union_comms_; + std::vector io_comms_; + std::vector comp_comms_; + std::vector intercomms_; + std::vector my_comms_; + std::vector node_comms_; + + void init_thread_info(void ); + std::size_t get_tidx(void ); +}; + +} // namespace SPIO_Util + +#endif // __SPIO_ASYNC_TCOMM_HPP__ diff --git a/src/clib/spio_async_tpool.cpp b/src/clib/spio_async_tpool.cpp index 23a971e2ed..077f612caf 100644 --- a/src/clib/spio_async_tpool.cpp +++ b/src/clib/spio_async_tpool.cpp @@ -1,6 +1,8 @@ #include #include #include +#include +#include extern "C"{ #include "pio_config.h" } // extern "C" @@ -27,6 +29,17 @@ void PIO_Util::PIO_async_tpool::finalize(void ) mtq_.signal(PIO_Util::PIO_mtq::PIO_MTQ_SIG_COMPLETE); } +std::vector PIO_Util::PIO_async_tpool::get_thread_ids(void ) const +{ + std::vector htids; + + std::hash tid_hasher; + std::for_each(pool_threads_.cbegin(), pool_threads_.cend(), + [&tid_hasher, &htids](const std::thread &t) { htids.push_back(tid_hasher(t.get_id())); }); + + return htids; +} + PIO_Util::PIO_async_tpool::PIO_async_tpool(int nthreads) { LOG((2, "PIO_async_tpool:PIO_async_tpool: Creating %d threads", nthreads)); diff --git a/src/clib/spio_async_tpool.hpp b/src/clib/spio_async_tpool.hpp index 3633b58124..4b04f561cf 100644 --- a/src/clib/spio_async_tpool.hpp +++ b/src/clib/spio_async_tpool.hpp @@ -17,6 +17,7 @@ class PIO_async_tpool{ public: void enqueue(pio_async_op_t *op); void finalize(void ); + std::vector get_thread_ids(void ) const; private: friend class PIO_async_tpool_manager; PIO_async_tpool(int nthreads); From efb1ea05eaee754b69a389516ebd09259272155b Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 27 Jan 2026 10:52:43 -0600 Subject: [PATCH 123/194] Update pio err & warn to use tlocal comms Updating PIOc_error() and PIOc_warn() calls to use thread local comms --- src/clib/pioc_support.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/clib/pioc_support.cpp b/src/clib/pioc_support.cpp index a37985a59e..414582022f 100644 --- a/src/clib/pioc_support.cpp +++ b/src/clib/pioc_support.cpp @@ -31,6 +31,7 @@ #include "spio_async_utils.hpp" #include "spio_hdf5_utils.hpp" #include "spio_async_hdf5_utils.hpp" +#include "spio_async_tcomm.hpp" #include #include #include @@ -1418,7 +1419,7 @@ int pio_err(iosystem_desc_t *ios, file_desc_t *file, /* If the user does not explicitly ask to return error, print * the error message in stderr on the root IO proc */ - bool print_err_msg = (ios) ? (ios->union_rank == ios->ioroot) : true; + bool print_err_msg = (ios) ? (ios->tcomm_info->get_union_comm_rank() == ios->tcomm_info->get_union_comm_io_root()) : true; if (print_err_msg) { @@ -1509,7 +1510,7 @@ void PIOc_warn(int iosysid, int ncid, ios = pio_get_iosystem_from_id(iosysid); } - bool print_warn_msg = (ios) ? (ios->union_rank == ios->ioroot) : true; + bool print_warn_msg = (ios) ? (ios->tcomm_info->get_union_comm_rank() == ios->tcomm_info->get_union_comm_io_root()) : true; if(print_warn_msg){ fprintf(stderr, "PIO: WARNING: %s, (%s:%d)\n", uwarn_msg, (fname) ? fname : "\0", line); fflush(stderr); From 35e6f6b808829f25ae00eb6ffed57d5a32376b73 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 27 Jan 2026 10:55:42 -0600 Subject: [PATCH 124/194] Util to create tlocal MPI infos Updating thread local comm info to support creating to thread local MPI infos --- src/clib/spio_async_tcomm.cpp | 17 +++++++++++++++++ src/clib/spio_async_tcomm.hpp | 9 +++++++++ 2 files changed, 26 insertions(+) diff --git a/src/clib/spio_async_tcomm.cpp b/src/clib/spio_async_tcomm.cpp index 769daba9f6..a4f953fabe 100644 --- a/src/clib/spio_async_tcomm.cpp +++ b/src/clib/spio_async_tcomm.cpp @@ -1,6 +1,8 @@ #include #include +#include #include +#include #include "spio_async_tcomm.hpp" #include "spio_async_tpool.hpp" @@ -104,6 +106,19 @@ MPI_Comm SPIO_Util::TComm_info::get_node_comm(void ) return node_comms_[get_tidx()]; } +MPI_Info *SPIO_Util::TComm_info::create_mpi_info(void ) +{ + int ret = MPI_SUCCESS; + MPI_Info info; + std::mutex mtx; + std::lock_guard lg(mtx); + + ret = MPI_Info_create(&info); assert(ret == MPI_SUCCESS); + + comm_infos_.push_back(info); + return &(comm_infos_.back()); +} + SPIO_Util::TComm_info::~TComm_info() { /* The main thread comms, in tidx == 0, was just copied over (not duped) @@ -121,6 +136,8 @@ SPIO_Util::TComm_info::~TComm_info() if(intercomms_[tidx] != MPI_COMM_NULL) { MPI_Comm_free(&intercomms_[tidx]); } if(node_comms_[tidx] != MPI_COMM_NULL) { MPI_Comm_free(&node_comms_[tidx]); } } + + std::for_each(comm_infos_.begin(), comm_infos_.end(), [](MPI_Info &info) { MPI_Info_free(&info); }); } void SPIO_Util::TComm_info::init_thread_info(void ) diff --git a/src/clib/spio_async_tcomm.hpp b/src/clib/spio_async_tcomm.hpp index 3102174e05..36dd8711d4 100644 --- a/src/clib/spio_async_tcomm.hpp +++ b/src/clib/spio_async_tcomm.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "mpi.h" #include "pio_config.h" #include "spio_async_tpool.hpp" @@ -32,6 +33,11 @@ class TComm_info{ MPI_Comm get_my_comm(void ); MPI_Comm get_node_comm(void ); + /* The MPI_Info object is owned by this class. The user can use it + * but its a "weak pointer" + */ + MPI_Info *create_mpi_info(void ); + ~TComm_info(); private: const std::size_t INVALID_IDX = -1; @@ -58,6 +64,9 @@ class TComm_info{ std::vector my_comms_; std::vector node_comms_; + /* Note: We return pointers to elements of this list back to user */ + std::list comm_infos_; + void init_thread_info(void ); std::size_t get_tidx(void ); }; From 87960e7bac5ae195602fdd8d3767a905d94d07a1 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 27 Jan 2026 10:56:55 -0600 Subject: [PATCH 125/194] Updating HDF5 utils to use tlocal comms Updating all HDF5 util functions to use thread local comms --- src/clib/spio_hdf5_utils.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/clib/spio_hdf5_utils.cpp b/src/clib/spio_hdf5_utils.cpp index d4035b10d1..c278fe3de6 100644 --- a/src/clib/spio_hdf5_utils.cpp +++ b/src/clib/spio_hdf5_utils.cpp @@ -22,6 +22,7 @@ //#include "pio_rearr_contig.hpp" //#include "spio_decomp_logger.hpp" #include "spio_async_utils.hpp" +#include "spio_async_tcomm.hpp" #include #include #include @@ -62,21 +63,22 @@ int spio_hdf5_create(iosystem_desc_t *ios, file_desc_t *file, const char *filena } else{ /* Clobber mode : Delete HDF5 file (from root I/O proc) if it exists */ - if(ios->io_rank == 0){ + if(ios->tcomm_info->get_io_comm_rank() == 0){ struct stat sd; if(0 == stat(filename, &sd)) { unlink(filename); } } /* Wait for root process (that might delete an existing file) */ - if((mpierr = MPI_Barrier(ios->io_comm))){ + if((mpierr = MPI_Barrier(ios->tcomm_info->get_io_comm()))){ return check_mpi(ios, file, mpierr, __FILE__, __LINE__); } } - if(ios->info == MPI_INFO_NULL){ - if((mpierr = MPI_Info_create(&ios->info))){ - return check_mpi(ios, file, mpierr, __FILE__, __LINE__); - } + MPI_Info *pinfo = ios->tcomm_info->create_mpi_info(); + if(!pinfo){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Creating file (%s) using HDF5 iotype failed. " + "Failed to create MPI Info object for the file", filename); } hid_t fcpl_id = H5Pcreate(H5P_FILE_CREATE); @@ -114,7 +116,7 @@ int spio_hdf5_create(iosystem_desc_t *ios, file_desc_t *file, const char *filena filename); } - if(H5Pset_fapl_mpio(fapl_id, ios->io_comm, ios->info) < 0){ + if(H5Pset_fapl_mpio(fapl_id, ios->tcomm_info->get_io_comm(), *pinfo) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, "Creating file (%s) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to store the user-supplied MPI IO parameters", @@ -886,7 +888,7 @@ int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) * step between the ranks. * Workaround: place a barrier to sync H5DSattach_scale calls. */ - MPI_Barrier(ios->io_comm); + MPI_Barrier(ios->tcomm_info->get_io_comm()); } } } From 2cba4b00938ee8d49fa9391163d4c4df9db4172b Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 21 Jan 2026 13:41:14 -0600 Subject: [PATCH 126/194] Adding missing stdint hdr Adding missing stdint header for uint64_t type --- src/clib/spio_dt_converter.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/clib/spio_dt_converter.hpp b/src/clib/spio_dt_converter.hpp index c7ef20e7fc..e03341b711 100644 --- a/src/clib/spio_dt_converter.hpp +++ b/src/clib/spio_dt_converter.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "pio_config.h" #include "pio.h" From 7849bc8b7117080ac8731fa134dac969a17fa914 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 27 Jan 2026 15:06:37 -0600 Subject: [PATCH 127/194] Adding test with empty string att Adding a test writing an empty string attribute (some E3SM components write out attributes with no values) --- tests/general/ncdf_get_put.F90.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/general/ncdf_get_put.F90.in b/tests/general/ncdf_get_put.F90.in index 13f04083b1..6506f306ce 100644 --- a/tests/general/ncdf_get_put.F90.in +++ b/tests/general/ncdf_get_put.F90.in @@ -39,6 +39,9 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_1datt ret = PIO_put_att(pio_file, pio_cvar, 'dummy_att_put_cval', cval); PIO_TF_CHECK_ERR(ret, "Failed to put char attribute:" // trim(filename)) + ret = PIO_put_att(pio_file, pio_cvar, 'empty_str_att', ""); + PIO_TF_CHECK_ERR(ret, "Failed to put char attribute:" // trim(filename)) + ret = PIO_enddef(pio_file) PIO_TF_CHECK_ERR(ret, "Failed to enddef:" // trim(filename)) From 88c0d43d2d6602c20979fe589b4c2e4fe74f93e9 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 27 Jan 2026 15:07:55 -0600 Subject: [PATCH 128/194] Allow empty string att for async HDF5 writes Relax asserts to allow writing/putting empty string attributes with HDF5 when using asynchronous I/O --- src/clib/spio_async_hdf5_utils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/clib/spio_async_hdf5_utils.cpp b/src/clib/spio_async_hdf5_utils.cpp index d6a924b4fc..e278be4593 100644 --- a/src/clib/spio_async_hdf5_utils.cpp +++ b/src/clib/spio_async_hdf5_utils.cpp @@ -270,7 +270,7 @@ int spio_iosys_async_op_hdf5_put_att(void *pdata) assert(info && info->file && info->file->iosystem); assert((info->varid >= 0) || (info->varid == PIO_GLOBAL)); - assert(info->alen > 0); + assert(info->alen >= 0); ret = spio_hdf5_put_att(info->file->iosystem, info->file, info->varid, info->aname.c_str(), info->atype, @@ -287,7 +287,7 @@ int spio_iosys_async_hdf5_put_att_op_add(file_desc_t *file, int varid, { int ret = PIO_NOERR; - assert(file && file->iosystem && aname && (alen > 0) && abuf); + assert(file && file->iosystem && aname && (alen >= 0) && ((alen == 0) || abuf)); assert((varid >= 0) || (varid = PIO_GLOBAL)); iosystem_desc_t *ios = file->iosystem; From 3ee3cd3b0df96ece8972d8d551e93edb05daff29 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 30 Jan 2026 16:51:15 -0600 Subject: [PATCH 129/194] Avoid file del on async close on compute procs Avoid deleting the file on a soft close on compute procs. These files will get deleted when waiting on a soft close or when finalizing the I/O system --- src/clib/pio_file.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/clib/pio_file.cpp b/src/clib/pio_file.cpp index 1c2ddeb603..732e0dc274 100644 --- a/src/clib/pio_file.cpp +++ b/src/clib/pio_file.cpp @@ -1022,10 +1022,13 @@ int PIOc_closefile_impl(int ncid) /* FIXME: How to account for async case ? */ spio_write_file_io_summary(file); - if(!soft_close){ - /* Delete file from our list of open files. */ +#if PIO_USE_ASYNC_WR_THREAD + if((file->iotype != PIO_IOTYPE_HDF5) && (file->iotype != PIO_IOTYPE_HDF5C)){ pio_delete_file_from_list(ncid); } +#else + pio_delete_file_from_list(ncid); +#endif return ierr; } From 7004706063267834c422631ce3d51aaac7d919f8 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 30 Jan 2026 16:53:39 -0600 Subject: [PATCH 130/194] Sync all procs after waiting on a soft close Sync across all procs after waiting on a soft close of a file --- src/clib/pio_file.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/clib/pio_file.cpp b/src/clib/pio_file.cpp index 732e0dc274..f828de2fcd 100644 --- a/src/clib/pio_file.cpp +++ b/src/clib/pio_file.cpp @@ -13,6 +13,7 @@ #include #include #include "spio_hdf5_utils.hpp" +#include "spio_async_tcomm.hpp" #ifdef _ADIOS2 #include "../../tools/adios2pio-nm/adios2pio-nm-lib-c.h" @@ -448,6 +449,7 @@ int spio_wait_on_hard_close(iosystem_desc_t *ios, file_desc_t *file) const int MAX_SLEEP_TIME_IN_MILLISECONDS = SPIO_ASYNC_OP_WAIT_TIMEOUT; const int SLEEP_TIME_IN_MILLISECONDS = 500; + assert(ios && file); /* For files that will never be closed, due to user error for ex, we cannot wait * indefenitely. On the other hand we do want to have enough time to finish async ops */ @@ -468,6 +470,9 @@ int spio_wait_on_hard_close(iosystem_desc_t *ios, file_desc_t *file) PIOc_warn(ios->iosysid, file->pio_ncid, __FILE__, __LINE__, msg.c_str()); } + /* Sync compute procs with I/O procs */ + MPI_Barrier(ios->tcomm_info->get_union_comm()); + return PIO_NOERR; } From 8328d5b2e2a7ed134e5a67ec2a12e67dab9a7506 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 30 Jan 2026 16:55:31 -0600 Subject: [PATCH 131/194] Skip partially init files in enddef Skipping partially init (during sync part of the def calls) variables in files during an enddef() call. This skipping is necessary for queued async enddef() calls since these calls could be queued before the def() calls. --- src/clib/spio_hdf5_utils.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/clib/spio_hdf5_utils.cpp b/src/clib/spio_hdf5_utils.cpp index c278fe3de6..82c7bd003a 100644 --- a/src/clib/spio_hdf5_utils.cpp +++ b/src/clib/spio_hdf5_utils.cpp @@ -795,6 +795,11 @@ int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) } for(i = 0; i < file->hdf5_num_vars; i++){ + /* Note: For async I/O operations enddef() calls queued before + * the HDF5 variable is defined will see partially initialized + * "files" (file->hdf5_vars[i] is partially inited) + */ + if(file->hdf5_vars[i].hdf5_dataset_id == H5I_INVALID_HID) { continue; } /* Upgrade the dataset of a coordinate variable to a dimension scale */ if(file->hdf5_vars[i].is_coord_var){ /* Write a special attribute (_Netcdf4Dimid) for the netCDF-4 dimension ID. */ From 088af64a104d8979352477ccf3b406c29abfdbaa Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 30 Jan 2026 16:59:22 -0600 Subject: [PATCH 132/194] Commenting out wait on async hdf5 calls No longer synchronizing async HDF5 calls by waiting on pending calls. The wait calls are currently commented out, but will be removed in a later cleanup commit --- src/clib/pio_file.cpp | 2 ++ src/clib/pio_getput_int.cpp | 18 ++++++++++++------ src/clib/pio_nc.cpp | 2 ++ src/clib/pioc_support.cpp | 15 +++++++++++---- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/clib/pio_file.cpp b/src/clib/pio_file.cpp index f828de2fcd..e45f35da8a 100644 --- a/src/clib/pio_file.cpp +++ b/src/clib/pio_file.cpp @@ -976,11 +976,13 @@ int PIOc_closefile_impl(int ncid) } else{ /* Wait on all hdf5 async ops before a "hard close" */ + /* ierr = spio_wait_all_hdf5_async_ops(ios->iosysid); if(ierr != PIO_NOERR){ return pio_err(ios, file, ierr, __FILE__, __LINE__, "Closing file (%s, ncid=%d) failed. Error sending async msg PIO_MSG_CLOSE_FILE", pio_get_fname_from_file(file), ncid); } + */ } } else{ diff --git a/src/clib/pio_getput_int.cpp b/src/clib/pio_getput_int.cpp index f28bb5d180..eacb3cd255 100644 --- a/src/clib/pio_getput_int.cpp +++ b/src/clib/pio_getput_int.cpp @@ -62,13 +62,17 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, #ifdef PIO_USE_ASYNC_WR_THREAD /* FIXME: Relax this wait */ - ierr = spio_wait_all_hdf5_async_ops(ios->iosysid); - if(ierr != PIO_NOERR){ - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " - "Error waiting on all pending asynchronous HDF5 ops", - name, varid, pio_get_fname_from_file(file), file->pio_ncid); + /* + if((file->iotype != PIO_IOTYPE_HDF5) && (file->iotype != PIO_IOTYPE_HDF5C)){ + ierr = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ierr != PIO_NOERR){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Writing attribute (%s) associated with variable (varid=%d) to file (%s, ncid=%d) using HDF5 iotype failed. " + "Error waiting on all pending asynchronous HDF5 ops", + name, varid, pio_get_fname_from_file(file), file->pio_ncid); + } } + */ #endif #ifdef _ADIOS2 @@ -2607,6 +2611,7 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off } /* FIXME: Relax this wait */ + /* ierr = spio_wait_all_hdf5_async_ops(ios->iosysid); if(ierr != PIO_NOERR){ return pio_err(ios, file, ierr, __FILE__, __LINE__, @@ -2614,6 +2619,7 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off "Error waiting on all pending asynchronous HDF5 ops", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); } + */ /* ADIOS: assume all procs are also IO tasks */ #ifdef _ADIOS2 diff --git a/src/clib/pio_nc.cpp b/src/clib/pio_nc.cpp index bec15b93c2..62e17cd191 100644 --- a/src/clib/pio_nc.cpp +++ b/src/clib/pio_nc.cpp @@ -3386,6 +3386,7 @@ int PIOc_def_var_impl(int ncid, const char *name, nc_type xtype, int ndims, } /* FIXME: Relax this wait */ + /* ierr = spio_wait_all_hdf5_async_ops(ios->iosysid); if(ierr != PIO_NOERR){ return pio_err(ios, file, ierr, __FILE__, __LINE__, @@ -3393,6 +3394,7 @@ int PIOc_def_var_impl(int ncid, const char *name, nc_type xtype, int ndims, "Error waiting on all pending asynchronous HDF5 ops", name, pio_get_fname_from_file(file), file->pio_ncid); } + */ /* ADIOS: assume all procs are also IO tasks */ #ifdef _ADIOS2 diff --git a/src/clib/pioc_support.cpp b/src/clib/pioc_support.cpp index 414582022f..ee2137b51b 100644 --- a/src/clib/pioc_support.cpp +++ b/src/clib/pioc_support.cpp @@ -3108,11 +3108,15 @@ int spio_createfile_int(int iosysid, int *ncidp, const int *iotype, const char * #if PIO_USE_ASYNC_WR_THREAD /* FIXME: Relax this wait */ - ierr = spio_wait_all_hdf5_async_ops(ios->iosysid); - if(ierr != PIO_NOERR){ - return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Creating file (%s) failed. Error waiting on all pending asynchronous HDF5 ops", filename); + /* + if((*iotype != PIO_IOTYPE_HDF5) && (*iotype != PIO_IOTYPE_HDF5C)){ + ierr = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ierr != PIO_NOERR){ + return pio_err(ios, NULL, ierr, __FILE__, __LINE__, + "Creating file (%s) failed. Error waiting on all pending asynchronous HDF5 ops", filename); + } } + */ ierr = spio_close_soft_closed_file(filename); if(ierr != PIO_NOERR){ @@ -4832,6 +4836,7 @@ int PIOc_openfile_retry_impl(int iosysid, int *ncidp, int *iotype, const char *f "Creating file (%s) failed. Error closing previous soft closed file", filename); } + //if(((*iotype == PIO_IOTYPE_HDF5) || (*iotype == PIO_IOTYPE_HDF5C)) && !(mode & PIO_WRITE)){ if((*iotype == PIO_IOTYPE_HDF5) || (*iotype == PIO_IOTYPE_HDF5C)){ ierr = spio_wait_all_hdf5_async_ops(ios->iosysid); if(ierr != PIO_NOERR){ @@ -5801,6 +5806,7 @@ int spio_change_def(int ncid, int is_enddef) #ifdef PIO_USE_ASYNC_WR_THREAD /* FIXME: Relax this wait */ + /* ierr = spio_wait_all_hdf5_async_ops(ios->iosysid); if(ierr != PIO_NOERR){ return pio_err(ios, file, ierr, __FILE__, __LINE__, @@ -5808,6 +5814,7 @@ int spio_change_def(int ncid, int is_enddef) "Error waiting on all pending asynchronous HDF5 ops", pio_get_fname_from_file(file), file->pio_ncid); } + */ #endif /* If this is an IO task, then call the netCDF function. */ From 27bb4abe159f9cce333ee6895f5ef534143b042a Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 30 Jan 2026 18:36:50 -0600 Subject: [PATCH 133/194] Async offload HDF5 set frame Move HDF5 set frame to a util function and offload it as needed for async I/O --- src/clib/pio_types.hpp | 1 + src/clib/pioc.cpp | 63 ++++++-------------------- src/clib/spio_async_hdf5_utils.cpp | 73 +++++++++++++++++++++++++++++- src/clib/spio_async_hdf5_utils.hpp | 1 + src/clib/spio_async_tpool.cpp | 1 + src/clib/spio_async_utils.cpp | 3 ++ src/clib/spio_hdf5_utils.cpp | 50 ++++++++++++++++++++ src/clib/spio_hdf5_utils.hpp | 1 + 8 files changed, 143 insertions(+), 50 deletions(-) diff --git a/src/clib/pio_types.hpp b/src/clib/pio_types.hpp index cf01438721..080c993033 100644 --- a/src/clib/pio_types.hpp +++ b/src/clib/pio_types.hpp @@ -360,6 +360,7 @@ typedef enum pio_async_op_type PIO_ASYNC_HDF5_DEF_VAR_OP, PIO_ASYNC_HDF5_PUT_ATT_OP, PIO_ASYNC_HDF5_ENDDEF_OP, + PIO_ASYNC_HDF5_SET_FRAME_OP, PIO_ASYNC_HDF5_PUT_VAR_OP, PIO_ASYNC_HDF5_WRITE_OP, PIO_ASYNC_FILE_WRITE_OPS, diff --git a/src/clib/pioc.cpp b/src/clib/pioc.cpp index cf129ec935..e58e758b5f 100644 --- a/src/clib/pioc.cpp +++ b/src/clib/pioc.cpp @@ -24,7 +24,9 @@ #include "spio_dbg_utils.hpp" #include "spio_decomp_map_info_pool.hpp" #include "spio_decomp_logger.hpp" +#include "spio_hdf5_utils.hpp" #include "spio_async_tcomm.hpp" +#include "spio_async_hdf5_utils.hpp" /* Include headers for HDF5 compression filters */ #if PIO_USE_HDF5 @@ -349,56 +351,19 @@ int PIOc_setframe_impl(int ncid, int varid, int frame) #endif #ifdef _HDF5 - if ((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)) - { - if (frame >= 0) - { - if (ios->ioproc) - { - hsize_t dims[H5S_MAX_RANK]; - hsize_t mdims[H5S_MAX_RANK]; - - /* Get current dimension size */ - hid_t file_space_id = H5Dget_space(file->hdf5_vars[varid].hdf5_dataset_id); - if (file_space_id == H5I_INVALID_HID) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Setting frame to variable (%s, varid=%d) in file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to make a copy of the dataspace of the dataset associated with this variable", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - int ndim = H5Sget_simple_extent_dims(file_space_id, dims, mdims); - if (ndim < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Setting frame to variable (%s, varid=%d) in file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to retrieve dimension size and maximum size of a dataspace copied from the dataset associated with this variable", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - if (H5Sclose(file_space_id) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Setting frame to variable (%s, varid=%d) in file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to release a dataspace copied from the dataset associated with this variable", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - - /* Extend record dimension if needed */ - if (ndim > 0 && mdims[0] == H5S_UNLIMITED && dims[0] < (hsize_t)(frame + 1)) - { - dims[0] = frame + 1; - if (H5Dextend(file->hdf5_vars[varid].hdf5_dataset_id, dims) < 0) - { - return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Setting frame to variable (%s, varid=%d) in file (%s, ncid=%d) using HDF5 iotype failed. " - "The low level (HDF5) I/O library call failed to extend the dataset associated with this variable", - pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); - } - } - } + if((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)){ + if((frame >= 0) && (ios->ioproc)){ +#if PIO_USE_ASYNC_WR_THREAD + ret = spio_iosys_async_hdf5_set_frame_op_add(file, varid, frame); +#else + ret = spio_hdf5_set_frame(file, varid, frame); +#endif + if(ret != PIO_NOERR){ + return pio_err(ios, file, ret, __FILE__, __LINE__, + "Setting frame to variable (%s, varid=%d) in file (%s, ncid=%d) using HDF5 iotype failed", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); } + } } #endif diff --git a/src/clib/spio_async_hdf5_utils.cpp b/src/clib/spio_async_hdf5_utils.cpp index e278be4593..6ca0d2c2ed 100644 --- a/src/clib/spio_async_hdf5_utils.cpp +++ b/src/clib/spio_async_hdf5_utils.cpp @@ -71,6 +71,12 @@ struct Hdf5_put_var_info{ void *vbuf; }; +struct Hdf5_set_frame_info{ + file_desc_t *file; + int varid; + int frame; +}; + struct Hdf5_wcache{ file_desc_t *file; int nvars; @@ -501,6 +507,71 @@ int spio_iosys_async_hdf5_put_var_op_add(file_desc_t *file, int varid, return PIO_NOERR; } +void spio_iosys_async_op_hdf5_set_frame_free(void *pdata) +{ + if(pdata){ + delete(static_cast(pdata)); + } +} + +int spio_iosys_async_op_hdf5_set_frame(void *pdata) +{ + int ret = PIO_NOERR; + + Hdf5_set_frame_info *info = static_cast(pdata); + + assert(info && info->file && info->file->iosystem); + + ret = spio_hdf5_set_frame(info->file, info->varid, info->frame); + + info->file->npend_ops--; + SPIO_Util::GVars::npend_hdf5_async_ops--; + + return ret; +} + +int spio_iosys_async_hdf5_set_frame_op_add(file_desc_t *file, int varid, int frame) +{ + int ret = PIO_NOERR; + + assert(file && file->iosystem && (varid >= 0) && (frame >= 0)); + + iosystem_desc_t *ios = file->iosystem; + + if(!ios->ioproc){ + return PIO_NOERR; + } + + Hdf5_set_frame_info *info = new Hdf5_set_frame_info{file, varid, frame}; + + /* Create async task */ + pio_async_op_t *pnew = static_cast(calloc(1, sizeof(pio_async_op_t))); + if(pnew == NULL){ + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Queuing asynchronous op/task for setting frame for variable (%s, file=%s) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for async task internal struct", pio_get_vname_from_file(file, varid), pio_get_fname_from_file(file), static_cast(sizeof(pio_async_op_t))); + } + + pnew->op_type = PIO_ASYNC_HDF5_SET_FRAME_OP; + pnew->pdata = static_cast(info); + pnew->wait = spio_iosys_async_op_hdf5_set_frame; + pnew->poke = pio_async_poke_func_unavail; + pnew->free = spio_iosys_async_op_hdf5_set_frame_free; + + /* One more pending op using this iodesc & file */ + file->npend_ops++; + SPIO_Util::GVars::npend_hdf5_async_ops++; + + /* Get the mt queue and queue the async task */ + ret = pio_async_tpool_op_add(pnew); + if(ret != PIO_NOERR){ + LOG((1, "Adding file pending ops to tpool failed, ret = %d", ret)); + return pio_err(ios, NULL, ret, __FILE__, __LINE__, + "Internal error while adding asynchronous pending operation to the thread pool (iosystem = %d). Adding the asynchronous operation failed", ios->iosysid); + } + + return PIO_NOERR; +} + #endif // _HDF5 int spio_wait_all_hdf5_async_ops(int iosysid) @@ -509,7 +580,7 @@ int spio_wait_all_hdf5_async_ops(int iosysid) /* Sleep for 0.5 seconds */ const int SLEEP_TIME_IN_MILLISECONDS = 500; /* Warn every 2 seconds */ - const int WARN_TIME_IN_MILLISECONDS = 2000; + const int WARN_TIME_IN_MILLISECONDS = 500; while(SPIO_Util::GVars::npend_hdf5_async_ops > 0){ std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME_IN_MILLISECONDS)); sleep_time += SLEEP_TIME_IN_MILLISECONDS; diff --git a/src/clib/spio_async_hdf5_utils.hpp b/src/clib/spio_async_hdf5_utils.hpp index 0b594f56f2..f52368204a 100644 --- a/src/clib/spio_async_hdf5_utils.hpp +++ b/src/clib/spio_async_hdf5_utils.hpp @@ -24,6 +24,7 @@ int pio_iosys_async_op_hdf5_write(void *pdata); void pio_iosys_async_op_hdf5_write_free(void *pdata); int pio_iosys_async_hdf5_write_op_add(file_desc_t *file, int nvars, int fndims, const int *varids, io_desc_t *iodesc, int fill, const int *frame); +int spio_iosys_async_hdf5_set_frame_op_add(file_desc_t *file, int varid, int frame); #define __SPIO_ASYNC_HDF5_UTILS_HPP__ #endif // __SPIO_ASYNC_HDF5_UTILS_HPP__ diff --git a/src/clib/spio_async_tpool.cpp b/src/clib/spio_async_tpool.cpp index 077f612caf..76255a5333 100644 --- a/src/clib/spio_async_tpool.cpp +++ b/src/clib/spio_async_tpool.cpp @@ -80,6 +80,7 @@ int PIO_Util::PIO_async_tpool::dequeue_and_process( (op->op_type == PIO_ASYNC_HDF5_DEF_VAR_OP) || (op->op_type == PIO_ASYNC_HDF5_PUT_ATT_OP) || (op->op_type == PIO_ASYNC_HDF5_ENDDEF_OP) || + (op->op_type == PIO_ASYNC_HDF5_SET_FRAME_OP) || (op->op_type == PIO_ASYNC_HDF5_PUT_VAR_OP) || (op->op_type == PIO_ASYNC_HDF5_WRITE_OP) || (op->op_type == PIO_ASYNC_FILE_CLOSE_OP)); diff --git a/src/clib/spio_async_utils.cpp b/src/clib/spio_async_utils.cpp index d69f126980..7c055c4cf2 100644 --- a/src/clib/spio_async_utils.cpp +++ b/src/clib/spio_async_utils.cpp @@ -43,6 +43,7 @@ std::string pio_async_op_type_to_string(pio_async_op_type_t op) case PIO_ASYNC_HDF5_DEF_VAR_OP: return "PIO_ASYNC_HDF5_DEF_VAR_OP"; case PIO_ASYNC_HDF5_PUT_ATT_OP: return "PIO_ASYNC_HDF5_PUT_ATT_OP"; case PIO_ASYNC_HDF5_ENDDEF_OP: return "PIO_ASYNC_HDF5_ENDDEF_OP"; + case PIO_ASYNC_HDF5_SET_FRAME_OP: return "PIO_ASYNC_HDF5_SET_FRAME_OP"; case PIO_ASYNC_HDF5_PUT_VAR_OP: return "PIO_ASYNC_HDF5_PUT_VAR_OP"; case PIO_ASYNC_HDF5_WRITE_OP: return "PIO_ASYNC_HDF5_WRITE_OP"; case PIO_ASYNC_FILE_WRITE_OPS: return "PIO_ASYNC_FILE_WRITE_OPS"; @@ -500,6 +501,8 @@ static file_async_pend_ops_kwait_func_t pio_async_wait_func_unavail, /* PIO_ASYNC_HDF5_ENDDEF_OP */ pio_async_wait_func_unavail, + /* PIO_ASYNC_HDF5_SET_FRAME_OP */ + pio_async_wait_func_unavail, /* PIO_ASYNC_HDF5_PUT_VAR_OP */ pio_async_wait_func_unavail, /* PIO_ASYNC_HDF5_WRITE_OP */ diff --git a/src/clib/spio_hdf5_utils.cpp b/src/clib/spio_hdf5_utils.cpp index 82c7bd003a..ed6646fffb 100644 --- a/src/clib/spio_hdf5_utils.cpp +++ b/src/clib/spio_hdf5_utils.cpp @@ -1324,4 +1324,54 @@ int spio_hdf5_close(iosystem_desc_t *ios, file_desc_t *file) return PIO_NOERR; } + +int spio_hdf5_set_frame(file_desc_t *file, int varid, int frame) +{ + assert(file && file->iosystem && (frame >= 0)); + iosystem_desc_t *ios = file->iosystem; + assert(ios->ioproc); + + hsize_t dims[H5S_MAX_RANK]; + hsize_t mdims[H5S_MAX_RANK]; + + /* Get current dimension size */ + hid_t file_space_id = H5Dget_space(file->hdf5_vars[varid].hdf5_dataset_id); + if(file_space_id == H5I_INVALID_HID){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Setting frame to variable (%s, varid=%d) in file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to make a copy of the dataspace of the dataset associated with this variable", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + int ndim = H5Sget_simple_extent_dims(file_space_id, dims, mdims); + if(ndim < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Setting frame to variable (%s, varid=%d) in file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to retrieve dimension size and maximum size of a dataspace copied from the dataset associated with this variable", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + if(H5Sclose(file_space_id) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Setting frame to variable (%s, varid=%d) in file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to release a dataspace copied from the dataset associated with this variable", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + + /* Extend record dimension if needed */ + if(ndim > 0 && mdims[0] == H5S_UNLIMITED && dims[0] < (hsize_t)(frame + 1)){ + dims[0] = frame + 1; + if(H5Dextend(file->hdf5_vars[varid].hdf5_dataset_id, dims) < 0){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Setting frame to variable (%s, varid=%d) in file (%s, ncid=%d) using HDF5 iotype failed. " + "The low level (HDF5) I/O library call failed to extend the dataset associated with this variable", + pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid); + } + } + + /* Cache the frame in the varlist (used by the next write call) */ + file->varlist[varid].record = frame; + + return PIO_NOERR; +} #endif diff --git a/src/clib/spio_hdf5_utils.hpp b/src/clib/spio_hdf5_utils.hpp index e7e26bec6f..3bf53bc73b 100644 --- a/src/clib/spio_hdf5_utils.hpp +++ b/src/clib/spio_hdf5_utils.hpp @@ -26,6 +26,7 @@ int spio_hdf5_put_var(iosystem_desc_t *ios, file_desc_t *file, int varid, const PIO_Offset *stride, nc_type xtype, const void *buf); int spio_hdf5_close(iosystem_desc_t *ios, file_desc_t *file); +int spio_hdf5_set_frame(file_desc_t *file, int varid, int frame); /* Inline functions */ inline hid_t spio_nc_type_to_hdf5_type(nc_type xtype) From 2a472f000b00923fba00c5f504ff6b872e3c45e7 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Sat, 31 Jan 2026 18:18:54 -0600 Subject: [PATCH 134/194] Fix async compile-time checks Fixing bugs in compile-time check for async I/O. Replacing incorrect preprocessor checks, ifdefs, with ifs This fix is required for non-async builds --- src/clib/pio_getput_int.cpp | 6 +++--- src/clib/pio_nc.cpp | 2 +- src/clib/pioc_support.cpp | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/clib/pio_getput_int.cpp b/src/clib/pio_getput_int.cpp index eacb3cd255..9f947ed6e9 100644 --- a/src/clib/pio_getput_int.cpp +++ b/src/clib/pio_getput_int.cpp @@ -60,7 +60,7 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, spio_ltimer_start(ios->io_fstats->wr_timer_name); spio_ltimer_start(ios->io_fstats->tot_timer_name); -#ifdef PIO_USE_ASYNC_WR_THREAD +#if PIO_USE_ASYNC_WR_THREAD /* FIXME: Relax this wait */ /* if((file->iotype != PIO_IOTYPE_HDF5) && (file->iotype != PIO_IOTYPE_HDF5C)){ @@ -459,7 +459,7 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, file->io_fstats->wb += len * atttype_len; } -#ifdef PIO_USE_ASYNC_WR_THREAD +#if PIO_USE_ASYNC_WR_THREAD ierr = spio_iosys_async_hdf5_put_att_op_add(file, varid, name, atttype, len, op); #else ierr = spio_hdf5_put_att(ios, file, varid, name, atttype, len, op); @@ -3304,7 +3304,7 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off file->io_fstats->wb += num_elem * typelen; } -#ifdef PIO_USE_ASYNC_WR_THREAD +#if PIO_USE_ASYNC_WR_THREAD ierr = spio_iosys_async_hdf5_put_var_op_add(file, varid, start, count, stride, xtype, buf); #else ierr = spio_hdf5_put_var(ios, file, varid, start, count, stride, xtype, buf); diff --git a/src/clib/pio_nc.cpp b/src/clib/pio_nc.cpp index 62e17cd191..4214ba9042 100644 --- a/src/clib/pio_nc.cpp +++ b/src/clib/pio_nc.cpp @@ -3688,7 +3688,7 @@ int PIOc_def_var_impl(int ncid, const char *name, nc_type xtype, int ndims, #ifdef _HDF5 if ((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)) { -#ifdef PIO_USE_ASYNC_WR_THREAD +#if PIO_USE_ASYNC_WR_THREAD ierr = spio_iosys_async_hdf5_def_var_op_add(file, name, xtype, ndims, dimidsp, *varidp); #else ierr = spio_hdf5_def_var(ios, file, name, xtype, ndims, dimidsp, *varidp); diff --git a/src/clib/pioc_support.cpp b/src/clib/pioc_support.cpp index ee2137b51b..839f1e381d 100644 --- a/src/clib/pioc_support.cpp +++ b/src/clib/pioc_support.cpp @@ -3825,7 +3825,7 @@ int spio_createfile_int(int iosysid, int *ncidp, const int *iotype, const char * #ifdef _HDF5 case PIO_IOTYPE_HDF5: case PIO_IOTYPE_HDF5C: -#ifdef PIO_USE_ASYNC_WR_THREAD +#if PIO_USE_ASYNC_WR_THREAD ierr = spio_iosys_async_hdf5_create_op_add(file, filename); #else ierr = spio_hdf5_create(ios, file, filename); @@ -5804,7 +5804,7 @@ int spio_change_def(int ncid, int is_enddef) } } -#ifdef PIO_USE_ASYNC_WR_THREAD +#if PIO_USE_ASYNC_WR_THREAD /* FIXME: Relax this wait */ /* ierr = spio_wait_all_hdf5_async_ops(ios->iosysid); @@ -5942,7 +5942,7 @@ int spio_change_def(int ncid, int is_enddef) #ifdef _HDF5 if((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)){ if(is_enddef){ -#ifdef PIO_USE_ASYNC_WR_THREAD +#if PIO_USE_ASYNC_WR_THREAD ierr = spio_iosys_async_hdf5_enddef_op_add(file); #else ierr = spio_hdf5_enddef(ios, file); From 189dfa13c43d9f8f5dba9122b6ac4b28fa7aeec1 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 2 Feb 2026 14:03:11 -0600 Subject: [PATCH 135/194] Avoid calling user apis in PIOc_inq_vardimid Avoid calling the user API to get the number of dimensions in PIOc_inq_vardimid(). Call the implementation instead. This is required for avoiding recursive calls when tracing/timing APIs --- src/clib/api/spio_misc_var_api.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clib/api/spio_misc_var_api.cpp b/src/clib/api/spio_misc_var_api.cpp index 04b1bee290..eb79f72d3e 100644 --- a/src/clib/api/spio_misc_var_api.cpp +++ b/src/clib/api/spio_misc_var_api.cpp @@ -120,7 +120,7 @@ int PIOc_inq_vardimid(int ncid, int varid, int *dimidsp) #if SPIO_ENABLE_API_TRACING int ndims = 0; - int rval = PIOc_inq_varndims(ncid, varid, &ndims); + int rval = PIOc_inq_varndims_impl(ncid, varid, &ndims); if((rval == PIO_NOERR) && dimidsp){ tr.add_rval("*dimidsp", dimidsp, ndims); } From 63df1d938558b5b2dc4da8c889910afad3f11ee2 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 4 Feb 2026 10:23:15 -0600 Subject: [PATCH 136/194] Skip wait on close for read only files Some applications, due to bugs in the app, don't close read-only files. Skipping wait on close for read-only files avoids waiting and timing out on close for these files. --- src/clib/pio_file.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/clib/pio_file.cpp b/src/clib/pio_file.cpp index e45f35da8a..f9e7e822aa 100644 --- a/src/clib/pio_file.cpp +++ b/src/clib/pio_file.cpp @@ -450,6 +450,12 @@ int spio_wait_on_hard_close(iosystem_desc_t *ios, file_desc_t *file) const int SLEEP_TIME_IN_MILLISECONDS = 500; assert(ios && file); + /* For read-only files, we don't have any async ops. This check is useful for + * applications that do not close - due to a bug in the application - read-only + * files + */ + if(!(file->mode & PIO_WRITE)) { return PIO_NOERR; } + /* For files that will never be closed, due to user error for ex, we cannot wait * indefenitely. On the other hand we do want to have enough time to finish async ops */ From 667607023a7810072e4e6c4817c5cc05dca28509 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 11 Feb 2026 11:27:50 -0600 Subject: [PATCH 137/194] Code reformatting Reformatting PIOc_openfile_retry() function. No change in code (only updating source code format) --- src/clib/pioc_support.cpp | 1382 ++++++++++++++++++------------------- 1 file changed, 660 insertions(+), 722 deletions(-) diff --git a/src/clib/pioc_support.cpp b/src/clib/pioc_support.cpp index 839f1e381d..b23ed4df08 100644 --- a/src/clib/pioc_support.cpp +++ b/src/clib/pioc_support.cpp @@ -4792,881 +4792,819 @@ static size_t adios_read_vars_vars(file_desc_t *file, size_t var_size, char *con int PIOc_openfile_retry_impl(int iosysid, int *ncidp, int *iotype, const char *filename, int mode, int retry) { - char tname[SPIO_TIMER_MAX_NAME]; - iosystem_desc_t *ios; /* Pointer to io system information. */ - file_desc_t *file; /* Pointer to file information. */ - int imode; /* Internal mode val for netcdf4 file open. */ - int mpierr = MPI_SUCCESS; /** Return code from MPI function codes. */ - int ierr = PIO_NOERR; /* Return code from function calls. */ - int ierr2 = PIO_NOERR; /* Return code from function calls. */ - - /* Get the IO system info from the iosysid. */ - if (!(ios = pio_get_iosystem_from_id(iosysid))) - { - return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, - "Opening file (%s) failed. Invalid iosystem id (%d) provided", (filename) ? filename : "UNKNOWN", iosysid); - } + char tname[SPIO_TIMER_MAX_NAME]; + iosystem_desc_t *ios; /* Pointer to io system information. */ + file_desc_t *file; /* Pointer to file information. */ + int imode; /* Internal mode val for netcdf4 file open. */ + int mpierr = MPI_SUCCESS; /** Return code from MPI function codes. */ + int ierr = PIO_NOERR; /* Return code from function calls. */ + int ierr2 = PIO_NOERR; /* Return code from function calls. */ + + /* Get the IO system info from the iosysid. */ + if(!(ios = pio_get_iosystem_from_id(iosysid))){ + return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, + "Opening file (%s) failed. Invalid iosystem id (%d) provided", (filename) ? filename : "UNKNOWN", iosysid); + } - /* User must provide valid input for these parameters. */ - if (!ncidp || !iotype || !filename || strlen(filename) > PIO_MAX_NAME) - { - return pio_err(ios, NULL, PIO_EINVAL, __FILE__, __LINE__, - "Opening file (%s) failed. Invalid arguments provided. ncidp is %s (expected not NULL), iotype is %s (expected not NULL), filename is %s (expected not NULL), filename length = %lld (expected <= %d)", (filename) ? filename : "UNKNOWN", PIO_IS_NULL(ncidp), PIO_IS_NULL(iotype), PIO_IS_NULL(filename), (filename) ? ((unsigned long long )strlen(filename)) : 0, (int )PIO_MAX_NAME); - } + /* User must provide valid input for these parameters. */ + if(!ncidp || !iotype || !filename || strlen(filename) > PIO_MAX_NAME){ + return pio_err(ios, NULL, PIO_EINVAL, __FILE__, __LINE__, + "Opening file (%s) failed. Invalid arguments provided. ncidp is %s (expected not NULL), iotype is %s (expected not NULL), filename is %s (expected not NULL), filename length = %lld (expected <= %d)", (filename) ? filename : "UNKNOWN", PIO_IS_NULL(ncidp), PIO_IS_NULL(iotype), PIO_IS_NULL(filename), (filename) ? ((unsigned long long )strlen(filename)) : 0, (int )PIO_MAX_NAME); + } - /* A valid iotype must be specified. */ - if (!iotype_is_valid(*iotype)) - { - char avail_iotypes[PIO_MAX_NAME + 1]; - PIO_get_avail_iotypes(avail_iotypes, PIO_MAX_NAME); - return pio_err(ios, NULL, PIO_EBADIOTYPE, __FILE__, __LINE__, - "Opening file (%s) failed. Invalid iotype (%s:%d) specified. Available iotypes are : %s", filename, pio_iotype_to_string(*iotype), *iotype, avail_iotypes); - } + /* A valid iotype must be specified. */ + if(!iotype_is_valid(*iotype)){ + char avail_iotypes[PIO_MAX_NAME + 1]; + PIO_get_avail_iotypes(avail_iotypes, PIO_MAX_NAME); + return pio_err(ios, NULL, PIO_EBADIOTYPE, __FILE__, __LINE__, + "Opening file (%s) failed. Invalid iotype (%s:%d) specified. Available iotypes are : %s", filename, pio_iotype_to_string(*iotype), *iotype, avail_iotypes); + } - spio_ltimer_start(ios->io_fstats->rd_timer_name); - spio_ltimer_start(ios->io_fstats->tot_timer_name); + spio_ltimer_start(ios->io_fstats->rd_timer_name); + spio_ltimer_start(ios->io_fstats->tot_timer_name); - LOG((2, "PIOc_openfile_retry iosysid = %d iotype = %d filename = %s mode = %d retry = %d", - iosysid, *iotype, filename, mode, retry)); + LOG((2, "PIOc_openfile_retry iosysid = %d iotype = %d filename = %s mode = %d retry = %d", + iosysid, *iotype, filename, mode, retry)); #if PIO_USE_ASYNC_WR_THREAD - ierr = spio_close_soft_closed_file(filename); + ierr = spio_close_soft_closed_file(filename); + if(ierr != PIO_NOERR){ + return pio_err(ios, NULL, ierr, __FILE__, __LINE__, + "Creating file (%s) failed. Error closing previous soft closed file", filename); + } + + //if(((*iotype == PIO_IOTYPE_HDF5) || (*iotype == PIO_IOTYPE_HDF5C)) && !(mode & PIO_WRITE)){ + if((*iotype == PIO_IOTYPE_HDF5) || (*iotype == PIO_IOTYPE_HDF5C)){ + ierr = spio_wait_all_hdf5_async_ops(ios->iosysid); if(ierr != PIO_NOERR){ return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Creating file (%s) failed. Error closing previous soft closed file", filename); - } - - //if(((*iotype == PIO_IOTYPE_HDF5) || (*iotype == PIO_IOTYPE_HDF5C)) && !(mode & PIO_WRITE)){ - if((*iotype == PIO_IOTYPE_HDF5) || (*iotype == PIO_IOTYPE_HDF5C)){ - ierr = spio_wait_all_hdf5_async_ops(ios->iosysid); - if(ierr != PIO_NOERR){ - return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Creating file (%s) failed. Error waiting on all pending asynchronous HDF5 ops", filename); - } + "Creating file (%s) failed. Error waiting on all pending asynchronous HDF5 ops", filename); } + } #endif - /* Allocate space for the file info. */ - if (!(file = (file_desc_t *) calloc(sizeof(file_desc_t), 1))) - { - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, - "Opening file (%s) failed. Out of memory allocating %lld bytes for the file structure", filename, (unsigned long long) (sizeof(*file))); - } + /* Allocate space for the file info. */ + if(!(file = (file_desc_t *) calloc(sizeof(file_desc_t), 1))){ + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, + "Opening file (%s) failed. Out of memory allocating %lld bytes for the file structure", filename, (unsigned long long) (sizeof(*file))); + } - file->pmtx = new std::mutex(); - assert(file->pmtx); + file->pmtx = new std::mutex(); + assert(file->pmtx); - file->io_fstats = (spio_io_fstats_summary_t *) calloc(sizeof(spio_io_fstats_summary_t), 1); - if(!(file->io_fstats)) - { - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, - "Opening file (%s) failed. Out of memory allocating %lld bytes for caching file I/O statistics", filename, (unsigned long long) (sizeof(spio_io_fstats_summary_t))); - } + file->io_fstats = (spio_io_fstats_summary_t *) calloc(sizeof(spio_io_fstats_summary_t), 1); + if(!(file->io_fstats)){ + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, + "Opening file (%s) failed. Out of memory allocating %lld bytes for caching file I/O statistics", filename, (unsigned long long) (sizeof(spio_io_fstats_summary_t))); + } - /* Fill in some file values. */ - file->fh = -1; - file->reserve_extra_header_space = false; /* Set to true for creating output NetCDF files only. */ - file->is_reopened = true; - strncpy(file->fname, filename, PIO_MAX_NAME); - ierr = pio_create_uniq_str(ios, NULL, tname, SPIO_TIMER_MAX_NAME, "tmp_", "_file"); - if(ierr != PIO_NOERR) - { - /* Not a fatal error */ - LOG((0, "Creating a unique name for the write timer for file (%s, ncid=%d) failed, ret = %d", file->fname, file->pio_ncid, ierr)); - tname[0] = '\0'; - } + /* Fill in some file values. */ + file->fh = -1; + file->reserve_extra_header_space = false; /* Set to true for creating output NetCDF files only. */ + file->is_reopened = true; + strncpy(file->fname, filename, PIO_MAX_NAME); + ierr = pio_create_uniq_str(ios, NULL, tname, SPIO_TIMER_MAX_NAME, "tmp_", "_file"); + if(ierr != PIO_NOERR){ + /* Not a fatal error */ + LOG((0, "Creating a unique name for the write timer for file (%s, ncid=%d) failed, ret = %d", file->fname, file->pio_ncid, ierr)); + tname[0] = '\0'; + } - snprintf(file->io_fstats->wr_timer_name, SPIO_TIMER_MAX_NAME, "PIO:wr_%s", tname); - snprintf(file->io_fstats->rd_timer_name, SPIO_TIMER_MAX_NAME, "PIO:rd_%s", tname); - snprintf(file->io_fstats->tot_timer_name, SPIO_TIMER_MAX_NAME, "PIO:tot_%s", tname); + snprintf(file->io_fstats->wr_timer_name, SPIO_TIMER_MAX_NAME, "PIO:wr_%s", tname); + snprintf(file->io_fstats->rd_timer_name, SPIO_TIMER_MAX_NAME, "PIO:rd_%s", tname); + snprintf(file->io_fstats->tot_timer_name, SPIO_TIMER_MAX_NAME, "PIO:tot_%s", tname); - /* FIXME: Files can be opened for rds and writes */ - spio_ltimer_start(file->io_fstats->rd_timer_name); - spio_ltimer_start(file->io_fstats->tot_timer_name); + /* FIXME: Files can be opened for rds and writes */ + spio_ltimer_start(file->io_fstats->rd_timer_name); + spio_ltimer_start(file->io_fstats->tot_timer_name); - file->iotype = *iotype; + file->iotype = *iotype; #ifdef _ADIOS2 - if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) - { - /* Trying to open a file with adios unless ADIOS_BP2NC_TEST option is enabled for unit tests */ - bool adios2_file_exist = false; + if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ + /* Trying to open a file with adios unless ADIOS_BP2NC_TEST option is enabled for unit tests */ + bool adios2_file_exist = false; #ifndef _ADIOS_BP2NC_TEST - adios2_error adiosErr = adios2_error_none; - char declare_name[PIO_MAX_NAME] = {'\0'}; - char bpname[PIO_MAX_NAME] = {'\0'}; - struct stat sd; + adios2_error adiosErr = adios2_error_none; + char declare_name[PIO_MAX_NAME] = {'\0'}; + char bpname[PIO_MAX_NAME] = {'\0'}; + struct stat sd; - strcat(bpname, filename); - strcat(bpname, ".bp"); + strcat(bpname, filename); + strcat(bpname, ".bp"); - if (0 == stat(bpname, &sd)) - { - strncpy(file->fname, bpname, PIO_MAX_NAME); - snprintf(declare_name, PIO_MAX_NAME, "%s%lu", file->fname, get_adios2_io_cnt()); - strncpy(file->io_name_reader, declare_name, PIO_MAX_NAME); + if(0 == stat(bpname, &sd)){ + strncpy(file->fname, bpname, PIO_MAX_NAME); + snprintf(declare_name, PIO_MAX_NAME, "%s%lu", file->fname, get_adios2_io_cnt()); + strncpy(file->io_name_reader, declare_name, PIO_MAX_NAME); - file->ioH = adios2_declare_io(ios->adios_readerH, file->io_name_reader); - if (file->ioH == NULL) - { - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - return pio_err(ios, NULL, PIO_EADIOS2ERR, __FILE__, __LINE__, - "Opening file (%s) using ADIOS iotype failed. " - "The low level (ADIOS) I/O library call failed to declare a new io handler", - filename); - } + file->ioH = adios2_declare_io(ios->adios_readerH, file->io_name_reader); + if(file->ioH == NULL){ + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->rd_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + return pio_err(ios, NULL, PIO_EADIOS2ERR, __FILE__, __LINE__, + "Opening file (%s) using ADIOS iotype failed. " + "The low level (ADIOS) I/O library call failed to declare a new io handler", + filename); + } - adiosErr = adios2_set_parameter(file->ioH, "BufferVType", "chunk"); - if (adiosErr != adios2_error_none) - { - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - return pio_err(ios, NULL, PIO_EADIOS2ERR, __FILE__, __LINE__, - "Opening file (%s) using ADIOS iotype failed. " - "The low level (ADIOS) I/O library call failed to set a single parameter (adios2_error=%s)", - filename, convert_adios2_error_to_string(adiosErr)); - } + adiosErr = adios2_set_parameter(file->ioH, "BufferVType", "chunk"); + if(adiosErr != adios2_error_none){ + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->rd_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + return pio_err(ios, NULL, PIO_EADIOS2ERR, __FILE__, __LINE__, + "Opening file (%s) using ADIOS iotype failed. " + "The low level (ADIOS) I/O library call failed to set a single parameter (adios2_error=%s)", + filename, convert_adios2_error_to_string(adiosErr)); + } - adiosErr = adios2_set_parameter(file->ioH, "BufferChunkSize", "1Gb"); - if (adiosErr != adios2_error_none) - { - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - return pio_err(ios, NULL, PIO_EADIOS2ERR, __FILE__, __LINE__, - "Opening file (%s) using ADIOS iotype failed. " - "The low level (ADIOS) I/O library call failed to set a single parameter (adios2_error=%s)", - filename, convert_adios2_error_to_string(adiosErr)); - } + adiosErr = adios2_set_parameter(file->ioH, "BufferChunkSize", "1Gb"); + if(adiosErr != adios2_error_none){ + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->rd_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + return pio_err(ios, NULL, PIO_EADIOS2ERR, __FILE__, __LINE__, + "Opening file (%s) using ADIOS iotype failed. " + "The low level (ADIOS) I/O library call failed to set a single parameter (adios2_error=%s)", + filename, convert_adios2_error_to_string(adiosErr)); + } - adiosErr = adios2_set_parameter(file->ioH, "InitialBufferSize", "1Gb"); - if (adiosErr != adios2_error_none) - { - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - return pio_err(ios, NULL, PIO_EADIOS2ERR, __FILE__, __LINE__, - "Opening file (%s) using ADIOS iotype failed. " - "The low level (ADIOS) I/O library call failed to set a single parameter (adios2_error=%s)", - filename, convert_adios2_error_to_string(adiosErr)); - } + adiosErr = adios2_set_parameter(file->ioH, "InitialBufferSize", "1Gb"); + if(adiosErr != adios2_error_none){ + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->rd_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + return pio_err(ios, NULL, PIO_EADIOS2ERR, __FILE__, __LINE__, + "Opening file (%s) using ADIOS iotype failed. " + "The low level (ADIOS) I/O library call failed to set a single parameter (adios2_error=%s)", + filename, convert_adios2_error_to_string(adiosErr)); + } - adiosErr = adios2_set_parameter(file->ioH, "OpenTimeoutSecs", "1"); - if (adiosErr != adios2_error_none) - { - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - return pio_err(ios, NULL, PIO_EADIOS2ERR, __FILE__, __LINE__, - "Opening file (%s) using ADIOS iotype failed. " - "The low level (ADIOS) I/O library call failed to set a single parameter (adios2_error=%s)", - filename, convert_adios2_error_to_string(adiosErr)); - } + adiosErr = adios2_set_parameter(file->ioH, "OpenTimeoutSecs", "1"); + if(adiosErr != adios2_error_none){ + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->rd_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + return pio_err(ios, NULL, PIO_EADIOS2ERR, __FILE__, __LINE__, + "Opening file (%s) using ADIOS iotype failed. " + "The low level (ADIOS) I/O library call failed to set a single parameter (adios2_error=%s)", + filename, convert_adios2_error_to_string(adiosErr)); + } - adiosErr = adios2_set_engine(file->ioH, "BP5"); - if (adiosErr != adios2_error_none) - { - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - return pio_err(ios, NULL, PIO_EADIOS2ERR, __FILE__, __LINE__, - "Opening file (%s) using ADIOS iotype failed. " - "The low level (ADIOS) I/O library call failed to set the engine type for current io handler (adios2_error=%s)", - filename, convert_adios2_error_to_string(adiosErr)); - } + adiosErr = adios2_set_engine(file->ioH, "BP5"); + if(adiosErr != adios2_error_none){ + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->rd_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + return pio_err(ios, NULL, PIO_EADIOS2ERR, __FILE__, __LINE__, + "Opening file (%s) using ADIOS iotype failed. " + "The low level (ADIOS) I/O library call failed to set the engine type for current io handler (adios2_error=%s)", + filename, convert_adios2_error_to_string(adiosErr)); + } - adios2_file_exist = true; + adios2_file_exist = true; - file->engineH = adios2_open(file->ioH, file->fname, adios2_mode_read); - if (file->engineH == NULL) - adios2_file_exist = false; /* Failed to open with adios2 trying pnetcdf */ - else - strncpy(file->fname, bpname, PIO_MAX_NAME); - } + file->engineH = adios2_open(file->ioH, file->fname, adios2_mode_read); + if(file->engineH == NULL){ + adios2_file_exist = false; /* Failed to open with adios2 trying pnetcdf */ + } + else{ + strncpy(file->fname, bpname, PIO_MAX_NAME); + } + } #endif - if (!adios2_file_exist) - { - /* Fall back to open as pnetcdf */ + if(!adios2_file_exist){ + /* Fall back to open as pnetcdf */ #ifdef _PNETCDF - file->iotype = PIO_IOTYPE_PNETCDF; + file->iotype = PIO_IOTYPE_PNETCDF; #else #ifdef _NETCDF4 #ifdef _MPISERIAL - file->iotype = PIO_IOTYPE_NETCDF4C; + file->iotype = PIO_IOTYPE_NETCDF4C; #else - file->iotype = PIO_IOTYPE_NETCDF4P; + file->iotype = PIO_IOTYPE_NETCDF4P; #endif #endif #endif - } } + } #endif #ifdef _HDF5 - if ((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)) - { - if (H5Fis_hdf5(filename) > 0) - { + if((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)){ + if(H5Fis_hdf5(filename) > 0){ #ifdef _NETCDF4 - /* Use NETCDF4 IO type to read files generated with HDF5 IO type so far */ + /* Use NETCDF4 IO type to read files generated with HDF5 IO type so far */ #ifdef _MPISERIAL - file->iotype = PIO_IOTYPE_NETCDF4C; + file->iotype = PIO_IOTYPE_NETCDF4C; #else - file->iotype = PIO_IOTYPE_NETCDF4P; + file->iotype = PIO_IOTYPE_NETCDF4P; #endif #else - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - return pio_err(ios, NULL, PIO_EBADIOTYPE, __FILE__, __LINE__, - "Opening file (%s) with PIO_IOTYPE_HDF5 failed. HDF5 IO type currently requires NETCDF4 (not configured for SCORPIO) to support read operations", filename); + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->rd_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + return pio_err(ios, NULL, PIO_EBADIOTYPE, __FILE__, __LINE__, + "Opening file (%s) with PIO_IOTYPE_HDF5 failed. HDF5 IO type currently requires NETCDF4 (not configured for SCORPIO) to support read operations", filename); #endif - } - else - { + } + else{ #ifdef _PNETCDF - file->iotype = PIO_IOTYPE_PNETCDF; + file->iotype = PIO_IOTYPE_PNETCDF; #else #ifdef _NETCDF - file->iotype = PIO_IOTYPE_NETCDF; + file->iotype = PIO_IOTYPE_NETCDF; #endif #endif - } } + } #endif - file->iosystem = ios; - file->mode = mode; - /* - file->num_unlim_dimids = 0; - file->unlim_dimids = NULL; - */ + file->iosystem = ios; + file->mode = mode; + /* + file->num_unlim_dimids = 0; + file->unlim_dimids = NULL; + */ #ifdef _ADIOS2 - file->num_dim_vars = 0; + file->num_dim_vars = 0; #endif - for (int i = 0; i < PIO_MAX_VARS; i++) - { - file->varlist[i].varid = -1; - file->varlist[i].vname[0] = '\0'; - file->varlist[i].vdesc[0] = '\0'; - file->varlist[i].rec_var = 0; - file->varlist[i].record = -1; - file->varlist[i].request = NULL; - file->varlist[i].request_sz = NULL; - file->varlist[i].nreqs = 0; - file->varlist[i].fillvalue = NULL; - file->varlist[i].pio_type = PIO_NAT; - file->varlist[i].type_size = 0; - file->varlist[i].vrsize = 0; - file->varlist[i].rb_pend = 0; - file->varlist[i].vrsize = 0; - file->varlist[i].wb_pend = 0; - file->varlist[i].use_fill = 0; - file->varlist[i].fillbuf = NULL; - } + for(int i = 0; i < PIO_MAX_VARS; i++){ + file->varlist[i].varid = -1; + file->varlist[i].vname[0] = '\0'; + file->varlist[i].vdesc[0] = '\0'; + file->varlist[i].rec_var = 0; + file->varlist[i].record = -1; + file->varlist[i].request = NULL; + file->varlist[i].request_sz = NULL; + file->varlist[i].nreqs = 0; + file->varlist[i].fillvalue = NULL; + file->varlist[i].pio_type = PIO_NAT; + file->varlist[i].type_size = 0; + file->varlist[i].vrsize = 0; + file->varlist[i].rb_pend = 0; + file->varlist[i].vrsize = 0; + file->varlist[i].wb_pend = 0; + file->varlist[i].use_fill = 0; + file->varlist[i].fillbuf = NULL; + } #ifdef _ADIOS2 - /* Set communicator for all adios processes, process rank, and I/O master node */ - file->all_comm = ios->union_comm; - file->all_rank = ios->union_rank; - file->num_alltasks = ios->num_uniontasks; + /* Set communicator for all adios processes, process rank, and I/O master node */ + file->all_comm = ios->union_comm; + file->all_rank = ios->union_rank; + file->num_alltasks = ios->num_uniontasks; #endif - /* Set to true if this task should participate in IO (only true - * for one task with netcdf serial files. */ - if (file->iotype == PIO_IOTYPE_NETCDF4P || file->iotype == PIO_IOTYPE_NETCDF4P_NCZARR || - file->iotype == PIO_IOTYPE_PNETCDF || - ios->io_rank == 0) - file->do_io = 1; + /* Set to true if this task should participate in IO (only true + * for one task with netcdf serial files. */ + if(file->iotype == PIO_IOTYPE_NETCDF4P || file->iotype == PIO_IOTYPE_NETCDF4P_NCZARR || + file->iotype == PIO_IOTYPE_PNETCDF || + ios->io_rank == 0) { file->do_io = 1; } - /* If async is in use, bcast the parameters from compute to I/O procs. */ - if(ios->async) - { - int len = strlen(filename) + 1; - PIO_SEND_ASYNC_MSG(ios, PIO_MSG_OPEN_FILE, &ierr, len, filename, file->iotype, file->mode, retry); - if(ierr != PIO_NOERR) - { - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Opening file (%s) failed. Sending asynchronous message, PIO_MSG_OPEN_FILE, failed on iosystem (iosysid=%d)", filename, ios->iosysid); - } + /* If async is in use, bcast the parameters from compute to I/O procs. */ + if(ios->async){ + int len = strlen(filename) + 1; + PIO_SEND_ASYNC_MSG(ios, PIO_MSG_OPEN_FILE, &ierr, len, filename, file->iotype, file->mode, retry); + if(ierr != PIO_NOERR){ + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->rd_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Opening file (%s) failed. Sending asynchronous message, PIO_MSG_OPEN_FILE, failed on iosystem (iosysid=%d)", filename, ios->iosysid); } + } #ifdef _ADIOS2 - if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) - { - /* Get available variables and set structures. Restrict to the first step only */ - adios2_step_status status; - size_t nsteps = 0, step = 0; - adios2_error err_steps = adios2_steps(&nsteps, file->engineH); - adios2_error adiosErr = adios2_error_none; - - /* Initialize adios structure */ - assert(file->num_vars < PIO_MAX_VARS); - for (size_t var = 0; var < PIO_MAX_VARS; var++) - { - file->adios_vars[var].nc_type = PIO_NAT; - file->adios_vars[var].adios_type = adios2_type_unknown; - file->adios_vars[var].adios_type_size = 0; - file->adios_vars[var].nattrs = 0; - file->adios_vars[var].ndims = 0; - file->adios_vars[var].adios_varid = 0; - file->adios_vars[var].decomp_varid = 0; - file->adios_vars[var].frame_varid = 0; - file->adios_vars[var].fillval_varid = 0; - file->adios_vars[var].gdimids = NULL; - file->adios_vars[var].interval_map = NULL; - } + if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ + /* Get available variables and set structures. Restrict to the first step only */ + adios2_step_status status; + size_t nsteps = 0, step = 0; + adios2_error err_steps = adios2_steps(&nsteps, file->engineH); + adios2_error adiosErr = adios2_error_none; - file->cache_data_blocks = spio_hash(10000); - file->cache_block_sizes = spio_hash(10000); - file->cache_darray_info = spio_hash(10000); + /* Initialize adios structure */ + assert(file->num_vars < PIO_MAX_VARS); + for(size_t var = 0; var < PIO_MAX_VARS; var++){ + file->adios_vars[var].nc_type = PIO_NAT; + file->adios_vars[var].adios_type = adios2_type_unknown; + file->adios_vars[var].adios_type_size = 0; + file->adios_vars[var].nattrs = 0; + file->adios_vars[var].ndims = 0; + file->adios_vars[var].adios_varid = 0; + file->adios_vars[var].decomp_varid = 0; + file->adios_vars[var].frame_varid = 0; + file->adios_vars[var].fillval_varid = 0; + file->adios_vars[var].gdimids = NULL; + file->adios_vars[var].interval_map = NULL; + } + + file->cache_data_blocks = spio_hash(10000); + file->cache_block_sizes = spio_hash(10000); + file->cache_darray_info = spio_hash(10000); + + file->adios_reader_num_decomp_blocks = 0; + + file->store_adios_decomp = true; + + while(step < nsteps && adios2_begin_step(file->engineH, adios2_step_mode_read, -1.0, &status) == adios2_error_none){ + file->begin_step_called = 1; + if(status == adios2_step_status_end_of_stream) { break; } + + size_t var_size = 0; + char **var_names = adios2_available_variables(file->ioH, &var_size); + if(var_names == NULL){ + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->rd_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, + "Opening file (%s) using ADIOS iotype failed. " + "The low level (ADIOS) I/O library call failed to return an array or c strings for names of available variables", + filename); + } - file->adios_reader_num_decomp_blocks = 0; + adios_read_global_dimensions(ios, file, var_names, var_size); - file->store_adios_decomp = true; + /* Read names of variables from variables */ + size_t nvars = adios_read_vars_vars(file, var_size, var_names); - while (step < nsteps && adios2_begin_step(file->engineH, adios2_step_mode_read, -1.0, &status) == adios2_error_none) - { - file->begin_step_called = 1; - if (status == adios2_step_status_end_of_stream) - break; + /* Free memory */ + for(size_t i = 0; i < var_size; i++) { free(var_names[i]); } - size_t var_size = 0; - char **var_names = adios2_available_variables(file->ioH, &var_size); - if (var_names == NULL) - { - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, - "Opening file (%s) using ADIOS iotype failed. " - "The low level (ADIOS) I/O library call failed to return an array or c strings for names of available variables", - filename); - } + free(var_names); - adios_read_global_dimensions(ios, file, var_names, var_size); + /* Additionally read variables from attributes like + * /__pio__/var/dummy_scalar_var_int/def/ndims */ + size_t attr_size = 0; + char **attr_names = adios2_available_attributes(file->ioH, &attr_size); + if(attr_names == NULL){ + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->rd_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, + "Opening file (%s) using ADIOS iotype failed. " + "The low level (ADIOS) I/O library call failed to return an array or c strings for names of available attributes", + filename); + } - /* Read names of variables from variables */ - size_t nvars = adios_read_vars_vars(file, var_size, var_names); + nvars = adios_read_vars_attrs(file, attr_size, attr_names); - /* Free memory */ - for (size_t i = 0; i < var_size; i++) - free(var_names[i]); + for(size_t i = 0; i < attr_size; i++){ free(attr_names[i]); } - free(var_names); + free(attr_names); - /* Additionally read variables from attributes like - * /__pio__/var/dummy_scalar_var_int/def/ndims */ - size_t attr_size = 0; - char **attr_names = adios2_available_attributes(file->ioH, &attr_size); - if (attr_names == NULL) - { - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, - "Opening file (%s) using ADIOS iotype failed. " - "The low level (ADIOS) I/O library call failed to return an array or c strings for names of available attributes", - filename); - } - - nvars = adios_read_vars_attrs(file, attr_size, attr_names); - - for (size_t i = 0; i < attr_size; i++) - free(attr_names[i]); + /* Initialize variables */ + for(int var_id = 0; var_id < file->num_vars; var_id++){ + adios_get_nc_type(file, var_id); + adios_get_adios_type(file, var_id); + adios_get_ndims(file, var_id); + adios_get_nc_op_tag(file, var_id); + adios_get_dim_ids(file, var_id); + adios_get_step_info(file, var_id, step, nsteps); + } - free(attr_names); + if(step == 0){ + adios_get_num_decomp_blocks(file); + adios_get_decomp_storage_info(file); + } - /* Initialize variables */ - for (int var_id = 0; var_id < file->num_vars; var_id++) - { - adios_get_nc_type(file, var_id); - adios_get_adios_type(file, var_id); - adios_get_ndims(file, var_id); - adios_get_nc_op_tag(file, var_id); - adios_get_dim_ids(file, var_id); - adios_get_step_info(file, var_id, step, nsteps); - } + adiosErr = adios2_end_step(file->engineH); + if(adiosErr != adios2_error_none){ + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->rd_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, + "Opening file (%s) using ADIOS iotype failed. " + "The low level (ADIOS) I/O library call failed to terminate interaction with current step (adios2_error=%s)", + filename, convert_adios2_error_to_string(adiosErr)); + } - if (step == 0) - { - adios_get_num_decomp_blocks(file); - adios_get_decomp_storage_info(file); - } + file->begin_step_called = 0; + step++; + } - adiosErr = adios2_end_step(file->engineH); - if (adiosErr != adios2_error_none) - { - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, - "Opening file (%s) using ADIOS iotype failed. " - "The low level (ADIOS) I/O library call failed to terminate interaction with current step (adios2_error=%s)", - filename, convert_adios2_error_to_string(adiosErr)); - } + int attr_id = 0; + size_t attr_size = 0; + char **attr_names = adios2_available_attributes(file->ioH, &attr_size); + if(attr_names == NULL){ + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->rd_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, + "Opening file (%s) using ADIOS iotype failed. " + "The low level (ADIOS) I/O library call failed to return an array or c strings for names of available attributes", + filename); + } + + /** Parse global attributes */ + for(size_t i = 0; i < attr_size; i++){ + /* Get global attributes */ + /* Strings that start with /__pio__/var/ are variables */ + if(strncmp(attr_names[i], adios_pio_global_prefix, strlen(adios_pio_global_prefix)) == 0){ + /* Get substring from string for name */ + int sub_length = strlen(attr_names[i]) - strlen(adios_pio_global_prefix); + int full_length = strlen(attr_names[i]); + int prefix_length = strlen(adios_pio_global_prefix); + + file->adios_attrs[attr_id].att_name = (char *) calloc(sub_length + 1, 1); + if(file->adios_attrs[attr_id].att_name == NULL){ + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->rd_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Opening file (%s) using ADIOS iotype failed. " + "Out of memory allocating %lld bytes for global attribute %s", + filename, (long long int)(sub_length + 1), attr_names[i]); + } + + strncpy(file->adios_attrs[attr_id].att_name, &attr_names[i][prefix_length], sub_length); + file->adios_attrs[attr_id].att_varid = -1; + + adios_get_attr(file, attr_id, attr_names, i); + + attr_id++; + assert(attr_id < PIO_MAX_ATTRS); + } - file->begin_step_called = 0; - step++; - } + /* Cache decomp attributes */ + if(strncmp(attr_names[i], adios_pio_var_prefix, strlen(adios_pio_var_prefix)) == 0 && + strstr(attr_names[i], adios_def_decomp_suffix) != NULL){ + adios2_attribute const *attributeH = adios2_inquire_attribute(file->ioH, attr_names[i]); + if(attributeH != NULL){ + size_t size_attr = 0; + char *attr_data = (char *) calloc(PIO_MAX_NAME, 1); + if(attr_data == NULL){ + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->rd_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Opening file (%s) using ADIOS iotype failed. " + "Out of memory allocating %lld bytes for decomposition attribute (%s)", + filename, (long long int)PIO_MAX_NAME, attr_names[i]); + } - int attr_id = 0; - size_t attr_size = 0; - char **attr_names = adios2_available_attributes(file->ioH, &attr_size); - if (attr_names == NULL) - { + adiosErr = adios2_attribute_data(attr_data, &size_attr, attributeH); + if(adiosErr != adios2_error_none){ spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, "Opening file (%s) using ADIOS iotype failed. " - "The low level (ADIOS) I/O library call failed to return an array or c strings for names of available attributes", - filename); - } - - /** Parse global attributes */ - for (size_t i = 0; i < attr_size; i++) - { - /* Get global attributes */ - /* Strings that start with /__pio__/var/ are variables */ - if (strncmp(attr_names[i], adios_pio_global_prefix, strlen(adios_pio_global_prefix)) == 0) - { - /* Get substring from string for name */ - int sub_length = strlen(attr_names[i]) - strlen(adios_pio_global_prefix); - int full_length = strlen(attr_names[i]); - int prefix_length = strlen(adios_pio_global_prefix); - - file->adios_attrs[attr_id].att_name = (char *) calloc(sub_length + 1, 1); - if (file->adios_attrs[attr_id].att_name == NULL) - { - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, - "Opening file (%s) using ADIOS iotype failed. " - "Out of memory allocating %lld bytes for global attribute %s", - filename, (long long int)(sub_length + 1), attr_names[i]); - } - - strncpy(file->adios_attrs[attr_id].att_name, &attr_names[i][prefix_length], sub_length); - file->adios_attrs[attr_id].att_varid = -1; - - adios_get_attr(file, attr_id, attr_names, i); - - attr_id++; - assert(attr_id < PIO_MAX_ATTRS); - } - - /* Cache decomp attributes */ - if (strncmp(attr_names[i], adios_pio_var_prefix, strlen(adios_pio_var_prefix)) == 0 && - strstr(attr_names[i], adios_def_decomp_suffix) != NULL) - { - adios2_attribute const *attributeH = adios2_inquire_attribute(file->ioH, attr_names[i]); - if (attributeH != NULL) - { - size_t size_attr = 0; - char *attr_data = (char *) calloc(PIO_MAX_NAME, 1); - if (attr_data == NULL) - { - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, - "Opening file (%s) using ADIOS iotype failed. " - "Out of memory allocating %lld bytes for decomposition attribute (%s)", - filename, (long long int)PIO_MAX_NAME, attr_names[i]); - } - - adiosErr = adios2_attribute_data(attr_data, &size_attr, attributeH); - if (adiosErr != adios2_error_none) - { - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - return pio_err(ios, file, PIO_EADIOS2ERR, __FILE__, __LINE__, - "Opening file (%s) using ADIOS iotype failed. " - "The low level (ADIOS) I/O library call failed to retrieve attribute data pointer (adios2_error=%s)", - filename, convert_adios2_error_to_string(adiosErr)); - } + "The low level (ADIOS) I/O library call failed to retrieve attribute data pointer (adios2_error=%s)", + filename, convert_adios2_error_to_string(adiosErr)); + } - /* attr_data will be deleted in the cache delete operation */ - file->cache_darray_info->put(file->cache_darray_info, attr_names[i], attr_data); - } - } + /* attr_data will be deleted in the cache delete operation */ + file->cache_darray_info->put(file->cache_darray_info, attr_names[i], attr_data); } - file->num_gattrs += attr_id; + } + } - /* Parse variable attributes */ - for (size_t i = 0; i < attr_size; i++) - { - /* Get variable attribute */ - char suffix_att_name[] = "/"; + file->num_gattrs += attr_id; - for (size_t var_cnt = 0; var_cnt < file->num_vars; var_cnt++) - { - char *attr_full_prefix = adios_name(adios_pio_var_prefix, file->adios_vars[var_cnt].name, - suffix_att_name); - if (strncmp(attr_names[i], attr_full_prefix, strlen(attr_full_prefix)) == 0) - { - int sub_length = strlen(attr_names[i]) - strlen(attr_full_prefix); - int full_length = strlen(attr_names[i]); - int prefix_length = strlen(attr_full_prefix); - if (strrchr(attr_names[i], '/') > &attr_names[i][prefix_length]) - continue; - - file->adios_attrs[attr_id].att_name = (char *) calloc(sub_length + 1, 1); - if (file->adios_attrs[attr_id].att_name == NULL) - { - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, - "Opening file (%s) using ADIOS iotype failed. " - "Out of memory allocating %lld bytes for attribute (id = %d) name", - filename, (long long int)(sub_length + 1), attr_id); - } + /* Parse variable attributes */ + for(size_t i = 0; i < attr_size; i++){ + /* Get variable attribute */ + char suffix_att_name[] = "/"; - strncpy(file->adios_attrs[attr_id].att_name, &attr_names[i][prefix_length], sub_length); - file->adios_attrs[attr_id].att_varid = var_cnt; - adios_get_attr(file, attr_id, attr_names, i); + for(size_t var_cnt = 0; var_cnt < file->num_vars; var_cnt++){ + char *attr_full_prefix = adios_name(adios_pio_var_prefix, file->adios_vars[var_cnt].name, + suffix_att_name); + if(strncmp(attr_names[i], attr_full_prefix, strlen(attr_full_prefix)) == 0){ + int sub_length = strlen(attr_names[i]) - strlen(attr_full_prefix); + int full_length = strlen(attr_names[i]); + int prefix_length = strlen(attr_full_prefix); + if(strrchr(attr_names[i], '/') > &attr_names[i][prefix_length]) { continue; } - assert(attr_id < PIO_MAX_ATTRS); - attr_id++; - } - } + file->adios_attrs[attr_id].att_name = (char *) calloc(sub_length + 1, 1); + if(file->adios_attrs[attr_id].att_name == NULL){ + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->rd_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Opening file (%s) using ADIOS iotype failed. " + "Out of memory allocating %lld bytes for attribute (id = %d) name", + filename, (long long int)(sub_length + 1), attr_id); + } + + strncpy(file->adios_attrs[attr_id].att_name, &attr_names[i][prefix_length], sub_length); + file->adios_attrs[attr_id].att_varid = var_cnt; + adios_get_attr(file, attr_id, attr_names, i); - free(attr_names[i]); + assert(attr_id < PIO_MAX_ATTRS); + attr_id++; } + } - free(attr_names); - file->num_attrs += attr_id; + free(attr_names[i]); } + + free(attr_names); + file->num_attrs += attr_id; + } #endif - /* If this is an IO task, then call the netCDF function. */ - if (ios->ioproc) - { - switch (file->iotype) - { + /* If this is an IO task, then call the netCDF function. */ + if(ios->ioproc){ + switch(file->iotype){ #ifdef _NETCDF4 - case PIO_IOTYPE_NETCDF4P: + case PIO_IOTYPE_NETCDF4P: #ifdef _MPISERIAL - ierr = nc_open(filename, file->mode, &file->fh); + ierr = nc_open(filename, file->mode, &file->fh); #else - imode = file->mode | NC_MPIIO; - if ((ierr = nc_open_par(filename, imode, ios->io_comm, ios->info, &file->fh))) - break; - file->mode = imode; - - /* Check the vars for valid use of unlim dims. */ - if ((ierr = check_unlim_use(file->fh))) - break; - LOG((2, "PIOc_openfile_retry:nc_open_par filename = %s mode = %d imode = %d ierr = %d", - filename, file->mode, imode, ierr)); + imode = file->mode | NC_MPIIO; + if ((ierr = nc_open_par(filename, imode, ios->io_comm, ios->info, &file->fh))) { break; } + file->mode = imode; + + /* Check the vars for valid use of unlim dims. */ + if ((ierr = check_unlim_use(file->fh))) { break; } + LOG((2, "PIOc_openfile_retry:nc_open_par filename = %s mode = %d imode = %d ierr = %d", + filename, file->mode, imode, ierr)); #endif - break; + break; - case PIO_IOTYPE_NETCDF4P_NCZARR: - file->mode = file->mode | NC_NETCDF4; - LOG((2, "Calling nc_open_par (nczarr) io_comm = %d mode = %d fh = %d", - ios->io_comm, file->mode, file->fh)); - ierr = PIO_ENOTBUILT; + case PIO_IOTYPE_NETCDF4P_NCZARR: + file->mode = file->mode | NC_NETCDF4; + LOG((2, "Calling nc_open_par (nczarr) io_comm = %d mode = %d fh = %d", + ios->io_comm, file->mode, file->fh)); + ierr = PIO_ENOTBUILT; #ifndef _MPISERIAL #if PIO_USE_NETCDF4_NCZARR - { - std::string filename_nczarr = spio_get_nczarr_fname(filename); - if(!filename_nczarr.empty()){ - ierr = nc_open_par(filename_nczarr.c_str(), file->mode, - ios->io_comm, ios->info, &file->fh); - if(ierr != NC_NOERR){ - /* The file being opened may not be NCZarr, for now retry with NetCDF4 */ - file->iotype = PIO_IOTYPE_NETCDF4P; - ierr = nc_open_par(filename, file->mode, ios->io_comm, ios->info, &file->fh); - } - } - } - LOG((2, "nc_open_par returned %d file->fh = %d", ierr, file->fh)); + { + std::string filename_nczarr = spio_get_nczarr_fname(filename); + if(!filename_nczarr.empty()){ + ierr = nc_open_par(filename_nczarr.c_str(), file->mode, + ios->io_comm, ios->info, &file->fh); + if(ierr != NC_NOERR){ + /* The file being opened may not be NCZarr, for now retry with NetCDF4 */ + file->iotype = PIO_IOTYPE_NETCDF4P; + ierr = nc_open_par(filename, file->mode, ios->io_comm, ios->info, &file->fh); + } + } + } + LOG((2, "nc_open_par returned %d file->fh = %d", ierr, file->fh)); #else - LOG((2, "nc_open_par returned %d, NCZarr support not built/enabled", ierr)); + LOG((2, "nc_open_par returned %d, NCZarr support not built/enabled", ierr)); #endif #endif - break; - case PIO_IOTYPE_NETCDF4C: - if (ios->io_rank == 0) - { - imode = file->mode | NC_NETCDF4; - if ((ierr = nc_open(filename, imode, &file->fh))) - break; - file->mode = imode; - /* Check the vars for valid use of unlim dims. */ - if ((ierr = check_unlim_use(file->fh))) - break; - } - break; + break; + case PIO_IOTYPE_NETCDF4C: + if(ios->io_rank == 0){ + imode = file->mode | NC_NETCDF4; + if((ierr = nc_open(filename, imode, &file->fh))) { break; } + file->mode = imode; + /* Check the vars for valid use of unlim dims. */ + if((ierr = check_unlim_use(file->fh))) { break; } + } + break; #endif /* _NETCDF4 */ #ifdef _NETCDF - case PIO_IOTYPE_NETCDF: - if (ios->io_rank == 0) - ierr = nc_open(filename, file->mode, &file->fh); - break; + case PIO_IOTYPE_NETCDF: + if(ios->io_rank == 0){ + ierr = nc_open(filename, file->mode, &file->fh); + } + break; #endif /* _NETCDF */ #ifdef _PNETCDF - case PIO_IOTYPE_PNETCDF: - ierr = ncmpi_open(ios->io_comm, filename, file->mode, ios->info, &file->fh); + case PIO_IOTYPE_PNETCDF: + ierr = ncmpi_open(ios->io_comm, filename, file->mode, ios->info, &file->fh); - // This should only be done with a file opened to append - if (ierr == PIO_NOERR && (file->mode & PIO_WRITE)) - { - if (ios->iomaster == MPI_ROOT) - LOG((2, "%d Setting IO buffer %ld", __LINE__, pio_buffer_size_limit)); + // This should only be done with a file opened to append + if(ierr == PIO_NOERR && (file->mode & PIO_WRITE)){ + if(ios->iomaster == MPI_ROOT) { LOG((2, "%d Setting IO buffer %ld", __LINE__, pio_buffer_size_limit)); } - /* Please refer to a previous related comment for why we ensure a minimum buffer size (16 MiB) for - buffered put APIs in PnetCDF. - */ - const PIO_Offset min_bufsize = 16777216; /* Minimum buffer size (16 MiB) for buffered put APIs in PnetCDF */ - ierr = ncmpi_buffer_attach(file->fh, (pio_buffer_size_limit > min_bufsize)? pio_buffer_size_limit : min_bufsize); - } - LOG((2, "ncmpi_open(%s) : fd = %d", filename, file->fh)); - break; + /* Please refer to a previous related comment for why we ensure a minimum buffer size (16 MiB) for + buffered put APIs in PnetCDF. + */ + const PIO_Offset min_bufsize = 16777216; /* Minimum buffer size (16 MiB) for buffered put APIs in PnetCDF */ + ierr = ncmpi_buffer_attach(file->fh, (pio_buffer_size_limit > min_bufsize)? pio_buffer_size_limit : min_bufsize); + } + LOG((2, "ncmpi_open(%s) : fd = %d", filename, file->fh)); + break; #endif #ifdef _ADIOS2 - case PIO_IOTYPE_ADIOS: - case PIO_IOTYPE_ADIOSC: - break; /* This case has been handled above */ + case PIO_IOTYPE_ADIOS: + case PIO_IOTYPE_ADIOSC: + break; /* This case has been handled above */ #endif - default: - { - char avail_iotypes[PIO_MAX_NAME + 1]; - int tmp_iotype = file->iotype; - - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - - free(file->io_fstats); - free(file); - PIO_get_avail_iotypes(avail_iotypes, PIO_MAX_NAME); - return pio_err(ios, NULL, PIO_EBADIOTYPE, __FILE__, __LINE__, - "Opening file (%s) failed. Invalid iotype (%s:%d) specified. Available iotypes are : %s", filename, pio_iotype_to_string(tmp_iotype), tmp_iotype, avail_iotypes); - } - } - - /* If the caller requested a retry, and we failed to open a - file due to an incompatible type of NetCDF, try it once - with just plain old basic NetCDF. */ - if (retry) - { -#ifdef _NETCDF - LOG((2, "retry error code ierr = %d io_rank %d", ierr, ios->io_rank)); - /* Bcast error code from io rank 0 to all io procs */ - mpierr = MPI_Bcast(&ierr, 1, MPI_INT, 0, ios->io_comm); - if(mpierr != MPI_SUCCESS){ - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - return check_mpi(NULL, file, ierr, __FILE__, __LINE__); - } - if ((ierr != NC_NOERR) && (file->iotype != PIO_IOTYPE_NETCDF)) - { - /* reset file markers for NETCDF on all IO tasks */ - file->iotype = PIO_IOTYPE_NETCDF; - - /* FIXME: The changes below to modify the user-specified - * iotype needs to be propogated to all tasks. */ - /* modify the user-specified iotype on all tasks */ - /* Modifying the user-specified iotype unfortunately - * causes some E3SM model components to reset the iotype - * to NetCDF for all subsequent reads and writes - * (eventhough only some files read are in the NetCDF4 - * format) - * Commenting this out for now, until we introduce - * PIO_IOTYPE_ANY that would allow users to explicitly - * specify that the lib can internally modify iotypes - */ - /* *iotype = PIO_IOTYPE_NETCDF; */ - - /* open netcdf file serially on main task */ - if (ios->io_rank == 0) - { - char errmsg[PIO_MAX_NAME]; - - ierr2 = PIOc_strerror_impl(ierr, errmsg, PIO_MAX_NAME); - printf("PIO: WARNING: Opening file (%s) with iotype=%d (%s) failed (ierr=%d, %s). Retrying with iotype=PIO_IOTYPE_NETCDF\n", filename, *iotype, pio_iotype_to_string(*iotype), ierr, ((ierr2 == PIO_NOERR) ? errmsg : "")); - ierr = nc_open(filename, file->mode, &file->fh); - if(ierr == NC_NOERR) - { - printf("PIO: WARNING: Opening file (%s) with iotype=%d (%s) failed. But retrying with iotype PIO_IOTYPE_NETCDF was successful. Switching iotype to PIO_IOTYPE_NETCDF for this file\n", filename, *iotype, pio_iotype_to_string(*iotype)); - } - } - else - { - /* reset ierr */ - ierr = PIO_NOERR; - - file->do_io = 0; - } - } - LOG((2, "retry nc_open(%s) : fd = %d, iotype = %d, do_io = %d, ierr = %d", - filename, file->fh, file->iotype, file->do_io, ierr)); -#endif /* _NETCDF */ - } - } + default: + { + char avail_iotypes[PIO_MAX_NAME + 1]; + int tmp_iotype = file->iotype; - /* Broadcast open mode to all tasks. */ - if ((mpierr = MPI_Bcast(&file->mode, 1, MPI_INT, ios->ioroot, ios->my_comm))) - { spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); + free(file->io_fstats); free(file); - return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); - } + PIO_get_avail_iotypes(avail_iotypes, PIO_MAX_NAME); + return pio_err(ios, NULL, PIO_EBADIOTYPE, __FILE__, __LINE__, + "Opening file (%s) failed. Invalid iotype (%s:%d) specified. Available iotypes are : %s", filename, pio_iotype_to_string(tmp_iotype), tmp_iotype, avail_iotypes); + } + } // switch(file->iotype) - if (retry) - { - /* Broadcast IO type (might be switched on IO tasks) to all tasks. */ - if ((mpierr = MPI_Bcast(&file->iotype, 1, MPI_INT, ios->ioroot, ios->my_comm))) - { - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - free(file->io_fstats); - free(file); - return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + /* If the caller requested a retry, and we failed to open a + file due to an incompatible type of NetCDF, try it once + with just plain old basic NetCDF. */ + if(retry){ +#ifdef _NETCDF + LOG((2, "retry error code ierr = %d io_rank %d", ierr, ios->io_rank)); + /* Bcast error code from io rank 0 to all io procs */ + mpierr = MPI_Bcast(&ierr, 1, MPI_INT, 0, ios->io_comm); + if(mpierr != MPI_SUCCESS){ + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->rd_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + return check_mpi(NULL, file, ierr, __FILE__, __LINE__); + } + + if((ierr != NC_NOERR) && (file->iotype != PIO_IOTYPE_NETCDF)){ + /* reset file markers for NETCDF on all IO tasks */ + file->iotype = PIO_IOTYPE_NETCDF; + + /* FIXME: The changes below to modify the user-specified + * iotype needs to be propogated to all tasks. */ + /* modify the user-specified iotype on all tasks */ + /* Modifying the user-specified iotype unfortunately + * causes some E3SM model components to reset the iotype + * to NetCDF for all subsequent reads and writes + * (eventhough only some files read are in the NetCDF4 + * format) + * Commenting this out for now, until we introduce + * PIO_IOTYPE_ANY that would allow users to explicitly + * specify that the lib can internally modify iotypes + */ + /* *iotype = PIO_IOTYPE_NETCDF; */ + + /* open netcdf file serially on main task */ + if(ios->io_rank == 0){ + char errmsg[PIO_MAX_NAME]; + + ierr2 = PIOc_strerror_impl(ierr, errmsg, PIO_MAX_NAME); + printf("PIO: WARNING: Opening file (%s) with iotype=%d (%s) failed (ierr=%d, %s). Retrying with iotype=PIO_IOTYPE_NETCDF\n", filename, *iotype, pio_iotype_to_string(*iotype), ierr, ((ierr2 == PIO_NOERR) ? errmsg : "")); + ierr = nc_open(filename, file->mode, &file->fh); + if(ierr == NC_NOERR) + { + printf("PIO: WARNING: Opening file (%s) with iotype=%d (%s) failed. But retrying with iotype PIO_IOTYPE_NETCDF was successful. Switching iotype to PIO_IOTYPE_NETCDF for this file\n", filename, *iotype, pio_iotype_to_string(*iotype)); + } } - } + else{ + /* reset ierr */ + ierr = PIO_NOERR; - ierr = check_netcdf(ios, file, ierr, __FILE__, __LINE__); - /* If there was an error, free allocated memory and deal with the error. */ - if(ierr != PIO_NOERR){ - int tmp_iotype = file->iotype; - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - free(file->io_fstats); - free(file); - LOG((1, "PIOc_openfile_retry failed, ierr = %d", ierr)); - return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Opening file (%s) with iotype %d (%s) failed. The low level I/O library call failed", filename, tmp_iotype, pio_iotype_to_string(tmp_iotype));; - } + file->do_io = 0; + } + } + LOG((2, "retry nc_open(%s) : fd = %d, iotype = %d, do_io = %d, ierr = %d", + filename, file->fh, file->iotype, file->do_io, ierr)); +#endif /* _NETCDF */ + } // if(retry) + } // if(ios->ioproc) - /* Add this file to the list of currently open files. */ - MPI_Comm comm = MPI_COMM_NULL; - if(ios->async) - { - /* For asynchronous I/O service, since file ids are passed across - * disjoint comms we need it to be unique across the union comm - */ - comm = ios->union_comm; + /* Broadcast open mode to all tasks. */ + if((mpierr = MPI_Bcast(&file->mode, 1, MPI_INT, ios->ioroot, ios->my_comm))){ + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->rd_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + free(file->io_fstats); + free(file); + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); + } + + if(retry){ + /* Broadcast IO type (might be switched on IO tasks) to all tasks. */ + if((mpierr = MPI_Bcast(&file->iotype, 1, MPI_INT, ios->ioroot, ios->my_comm))){ + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->rd_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + free(file->io_fstats); + free(file); + return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); } + } + + ierr = check_netcdf(ios, file, ierr, __FILE__, __LINE__); + /* If there was an error, free allocated memory and deal with the error. */ + if(ierr != PIO_NOERR){ + int tmp_iotype = file->iotype; + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->rd_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + free(file->io_fstats); + free(file); + LOG((1, "PIOc_openfile_retry failed, ierr = %d", ierr)); + return pio_err(ios, NULL, ierr, __FILE__, __LINE__, + "Opening file (%s) with iotype %d (%s) failed. The low level I/O library call failed", filename, tmp_iotype, pio_iotype_to_string(tmp_iotype));; + } - /* Initialize the multi-variable cache used to cache data for - * multiple variables before writing it to the output file - * Note: The MVCache is not used by ADIOS or a file opened - * as "read only" + /* Add this file to the list of currently open files. */ + MPI_Comm comm = MPI_COMM_NULL; + if(ios->async){ + /* For asynchronous I/O service, since file ids are passed across + * disjoint comms we need it to be unique across the union comm */ - spio_file_mvcache_init(file); + comm = ios->union_comm; + } + + /* Initialize the multi-variable cache used to cache data for + * multiple variables before writing it to the output file + * Note: The MVCache is not used by ADIOS or a file opened + * as "read only" + */ + spio_file_mvcache_init(file); #ifdef _HDF5 - /* A datatype converter for converting user buffer to a "file type" buffer */ - file->dt_converter = static_cast(new SPIO_Util::File_Util::DTConverter()); + /* A datatype converter for converting user buffer to a "file type" buffer */ + file->dt_converter = static_cast(new SPIO_Util::File_Util::DTConverter()); #endif - *ncidp = pio_add_to_file_list(file, comm); + *ncidp = pio_add_to_file_list(file, comm); - LOG((2, "Opened file %s file->pio_ncid = %d file->fh = %d ierr = %d", - filename, file->pio_ncid, file->fh, ierr)); + LOG((2, "Opened file %s file->pio_ncid = %d file->fh = %d ierr = %d", + filename, file->pio_ncid, file->fh, ierr)); - /* Set ncid to ADIOS attributes */ - if ((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)) - { + /* Set ncid to ADIOS attributes */ + if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ #ifdef _ADIOS2 - for (int i = 0; i < file->num_attrs; i++) - file->adios_attrs[i].att_ncid = *ncidp; + for(int i = 0; i < file->num_attrs; i++) { file->adios_attrs[i].att_ncid = *ncidp; } #endif - } - - /* Check if the file has unlimited dimensions */ - if(!ios->async || !ios->ioproc) - { - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - ierr = PIOc_inq_unlimdims_impl(*ncidp, &(file->num_unlim_dimids), NULL); - if(ierr != PIO_NOERR) - { - spio_file_mvcache_finalize(file); - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Opening file (%s) failed. Although the file was opened successfully, querying the number of unlimited dimensions in the file failed", filename); - } - if(file->num_unlim_dimids > 0) - { - file->unlim_dimids = (int *)malloc(file->num_unlim_dimids * sizeof(int)); - if(!file->unlim_dimids) - { - spio_file_mvcache_finalize(file); - return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, - "Opening file (%s) failed. Out of memory allocating %lld bytes for caching the unlimited dimension ids", filename, (unsigned long long) (file->num_unlim_dimids * sizeof(int))); - } - ierr = PIOc_inq_unlimdims_impl(*ncidp, NULL, file->unlim_dimids); - if(ierr != PIO_NOERR) - { - spio_file_mvcache_finalize(file); - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Opening file (%s) failed. Although the file was opened successfully, querying the unlimited dimensions in the file failed", filename); - } - } - spio_ltimer_start(ios->io_fstats->rd_timer_name); - spio_ltimer_start(ios->io_fstats->tot_timer_name); - spio_ltimer_start(file->io_fstats->rd_timer_name); - spio_ltimer_start(file->io_fstats->tot_timer_name); - LOG((3, "File has %d unlimited dimensions", file->num_unlim_dimids)); - } + } + /* Check if the file has unlimited dimensions */ + if(!ios->async || !ios->ioproc){ spio_ltimer_stop(ios->io_fstats->rd_timer_name); spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); - return ierr; + + ierr = PIOc_inq_unlimdims_impl(*ncidp, &(file->num_unlim_dimids), NULL); + if(ierr != PIO_NOERR){ + spio_file_mvcache_finalize(file); + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Opening file (%s) failed. Although the file was opened successfully, querying the number of unlimited dimensions in the file failed", filename); + } + + if(file->num_unlim_dimids > 0){ + file->unlim_dimids = (int *)malloc(file->num_unlim_dimids * sizeof(int)); + if(!file->unlim_dimids){ + spio_file_mvcache_finalize(file); + return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + "Opening file (%s) failed. Out of memory allocating %lld bytes for caching the unlimited dimension ids", filename, (unsigned long long) (file->num_unlim_dimids * sizeof(int))); + } + ierr = PIOc_inq_unlimdims_impl(*ncidp, NULL, file->unlim_dimids); + if(ierr != PIO_NOERR){ + spio_file_mvcache_finalize(file); + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Opening file (%s) failed. Although the file was opened successfully, querying the unlimited dimensions in the file failed", filename); + } + } + + spio_ltimer_start(ios->io_fstats->rd_timer_name); + spio_ltimer_start(ios->io_fstats->tot_timer_name); + spio_ltimer_start(file->io_fstats->rd_timer_name); + spio_ltimer_start(file->io_fstats->tot_timer_name); + LOG((3, "File has %d unlimited dimensions", file->num_unlim_dimids)); + } + + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->rd_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + return ierr; } /** From d59958b17afd81e42668e33b27c3176a68cd8301 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 11 Feb 2026 11:32:31 -0600 Subject: [PATCH 138/194] Warn when we switch hdf5 iotype during open Adding a user warning when we switch the HDF5 iotype during open. The HDF5 iotype currently does not support opening files (for reads etc). Ensure that the user is aware of the switch of the iotype within the library. --- src/clib/pioc_support.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/clib/pioc_support.cpp b/src/clib/pioc_support.cpp index b23ed4df08..c42bd71744 100644 --- a/src/clib/pioc_support.cpp +++ b/src/clib/pioc_support.cpp @@ -5031,6 +5031,10 @@ int PIOc_openfile_retry_impl(int iosysid, int *ncidp, int *iotype, const char *f #endif #endif } + std::string warn_msg = std::string("Opening files with the HDF5 library is currently not supported.") + + std::string(" Switching from PIO_IOTYPE_HDF5 to ") + pio_iotype_to_string(file->iotype) + + std::string(" for file, ") + filename; + PIOc_warn(ios->iosysid, file->fh, __FILE__, __LINE__, warn_msg.c_str()); } #endif From 0fb265634c21828e4cc0f1ad8240b570e2cfe7af Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 26 Feb 2026 12:28:23 -0600 Subject: [PATCH 139/194] Adding Queue exceptions to multi-threaded queue Adding exceptions for signal handling, empty cases. A new dequeue method is added that uses these exceptions to always return a valid element (in the noexcept case) --- src/clib/spio_async_mtq.hpp | 77 +++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/src/clib/spio_async_mtq.hpp b/src/clib/spio_async_mtq.hpp index aab7228380..33a4033208 100644 --- a/src/clib/spio_async_mtq.hpp +++ b/src/clib/spio_async_mtq.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "pio_internal.h" namespace PIO_Util{ @@ -14,6 +15,27 @@ namespace PIO_Util{ template class PIO_mtq{ public: + /* Multi-threaded queue exceptions */ + class Mtq_exception{ + public: + Mtq_exception(const std::string &msg) : msg_(msg){} + std::string what(void ) const { return msg_; } + private: + std::string msg_; + }; + /* Exception : Signal received on MT queue */ + class Qsignal_exception : public Mtq_exception{ + public: + Qsignal_exception(const std::string &msg) : Mtq_exception(msg){} + }; + /* Exception : Queue is empty + * e.g. After a signal was received, queue is empty + */ + class Qempty_exception : public Mtq_exception{ + public: + Qempty_exception(const std::string &msg) : Mtq_exception(msg){} + }; + typedef enum SigTypes{ PIO_MTQ_SIG_INVALID=1, /* Stop processing elements in the queue */ @@ -24,6 +46,7 @@ class PIO_mtq{ PIO_mtq(); void enqueue(const T& val); int dequeue(T &val); + T dequeue(void ); void signal(SigTypes_t sig); int size(void ); @@ -101,6 +124,60 @@ int PIO_mtq::dequeue(T &val) return 0; } +template +T PIO_mtq::dequeue(void ) +{ + std::unique_lock lk(mtx_); + do{ + LOG((2, "PIO_mtq:dequeue: Waiting for dequeueing val from mtq...")); + while(queue_.empty() && (sig_ == PIO_MTQ_SIG_INVALID)){ + cv_.wait(lk, [this]{ return (queue_.empty() && (sig_ == PIO_MTQ_SIG_INVALID));}); + /* + cv_.wait_for(lk, DEFAULT_TIMEOUT, + [this]{ return (queue_.empty() && (sig_ == PIO_MTQ_SIG_INVALID));}); + */ + /* At least on Linux (Ubuntu 4.5.0-040500-generic) just waiting on the condition + * variable (with/without timeouts) does not allow other threads to acquire + * the lock. So we explicitly unlock, sleep for 0 seconds and reacquire the + * lock to allow other threads to be able to get scheduled and acquire the lock + */ + thread_yield(lk); + } + if(sig_ == PIO_MTQ_SIG_STOP){ + LOG((2, "PIO_mtq:dequeue: Received STOP signal on mtq (exiting...)")); + throw Qsignal_exception("Received STOP signal on multi-threaded queue"); + } + else if(sig_ == PIO_MTQ_SIG_COMPLETE){ + if(queue_.empty()){ + /* Reset signal */ + sig_ = PIO_MTQ_SIG_INVALID; + lk.unlock(); + /* Notify threads that all async ops are complete */ + cv_sig_.notify_all(); + lk.lock(); + } + else{ + break; + } + } + else{ + break; + } + }while(true); + + if(!queue_.empty()){ + T val = queue_.front(); + queue_.pop(); + LOG((2, "PIO_mtq:dequeue: Successfully dequeued val from mtq")); + lk.unlock(); + return val; + } + else{ + lk.unlock(); + throw Qempty_exception("Multi-threaded queue is empty"); + } +} + template void PIO_mtq::signal(PIO_mtq::SigTypes_t sig) { From d499f9507dd7979bb8305c272c8fa9a4de566365 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 26 Feb 2026 12:38:55 -0600 Subject: [PATCH 140/194] Using an Async_op class for async ops Moving from C-style pio_async_op_t to Async_op class to represent async ops. The list of async ops in file/iosystem is now moved to C++ deques Also, removing the C-interface header for MT queue (we no longer need it since we don't have a mix of C/C++ code within pioc lib) Updated tests as needed --- src/clib/pio_internal.h | 2 +- src/clib/pio_spmd.cpp | 64 ++-- src/clib/pio_types.hpp | 65 +--- src/clib/spio_async_hdf5_utils.cpp | 145 +++------ src/clib/spio_async_op.hpp | 86 ++++++ src/clib/spio_async_tpool.cpp | 49 ++- src/clib/spio_async_tpool.hpp | 14 +- src/clib/spio_async_tpool_cint.h | 14 - src/clib/spio_async_utils.cpp | 477 ++++++++++------------------- src/clib/spio_async_utils.hpp | 11 +- tests/cunit/test_async_tpool.cpp | 12 +- 11 files changed, 369 insertions(+), 570 deletions(-) create mode 100644 src/clib/spio_async_op.hpp delete mode 100644 src/clib/spio_async_tpool_cint.h diff --git a/src/clib/pio_internal.h b/src/clib/pio_internal.h index 967f6fe8cb..be5baf346c 100644 --- a/src/clib/pio_internal.h +++ b/src/clib/pio_internal.h @@ -200,7 +200,7 @@ extern "C" { MPI_Comm comm, const rearr_comm_fc_opt_t *fc); /* Non blocking wait for pio swapm user request */ - int pio_swapm_iwait(void *p, int *flag); + int pio_swapm_iwait(void *p, bool &flag); /* Blocking wait for pio swapm user request */ int pio_swapm_wait(void *p); diff --git a/src/clib/pio_spmd.cpp b/src/clib/pio_spmd.cpp index 6499c04314..8aaa4e5637 100644 --- a/src/clib/pio_spmd.cpp +++ b/src/clib/pio_spmd.cpp @@ -468,47 +468,41 @@ int pio_swapm(const void *sendbuf, const int *sendcounts, const int *sdispls, co /** * Non-blocking wait on swapm request * @param p User swapm request (the request passed to pio_swapm() call) - * @param flag Pointer to a flag that holds the status of the user request. - * The flag is 0 if the request is pending and 1 if the request is completed + * @param flag bool that holds the status of the user request. + * The flag is false if some requests are pending and true if all the requests are completed * @returns PIO_NOERR on success, a pio error code otherwise * - Similar to MPI_Testall(), makes progress on all requests */ -int pio_swapm_iwait(void *p, int *flag) +int pio_swapm_iwait(void *p, bool &flag) { - pio_swapm_req *ureq = (pio_swapm_req *)p; - int mpierr; - - assert((ureq != NULL) && (flag != NULL)); - *flag = 1; - if(ureq->nrcvids != 0) - { - mpierr = MPI_Testall(ureq->nrcvids, ureq->rcvids, flag, MPI_STATUSES_IGNORE); - if(mpierr != MPI_SUCCESS) - { - return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); - } - - if(*flag == 1) - { - free(ureq->rcvids); - ureq->nrcvids = 0; - } + pio_swapm_req *ureq = (pio_swapm_req *)p; + int status = 0; + int mpierr; + + assert(ureq != NULL); + if(ureq->nrcvids != 0){ + mpierr = MPI_Testall(ureq->nrcvids, ureq->rcvids, &status, MPI_STATUSES_IGNORE); + if(mpierr != MPI_SUCCESS){ return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); } + + /* status == 1 (true), implies that all the request have completed */ + if(status == 1){ + free(ureq->rcvids); + ureq->nrcvids = 0; } - if(ureq->nsndids != 0) - { - mpierr = MPI_Testall(ureq->nsndids, ureq->sndids, flag, MPI_STATUSES_IGNORE); - if(mpierr != MPI_SUCCESS) - { - return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); - } - - if(*flag == 1) - { - free(ureq->sndids); - ureq->nsndids = 0; - } + } + if(ureq->nsndids != 0){ + mpierr = MPI_Testall(ureq->nsndids, ureq->sndids, &status, MPI_STATUSES_IGNORE); + if(mpierr != MPI_SUCCESS){ return check_mpi(NULL, NULL, mpierr, __FILE__, __LINE__); } + + /* status == 1 (true), implies that all the request have completed */ + if(status == 1){ + free(ureq->sndids); + ureq->nsndids = 0; } - return PIO_NOERR; + } + + flag = (status == 1); + return PIO_NOERR; } /** diff --git a/src/clib/pio_types.hpp b/src/clib/pio_types.hpp index 080c993033..12996122bd 100644 --- a/src/clib/pio_types.hpp +++ b/src/clib/pio_types.hpp @@ -49,6 +49,8 @@ extern "C" { #include #include +#include +#include "spio_async_op.hpp" #ifdef PIO_MICRO_TIMING /** Some fwd declarations to avoid including internal headers */ @@ -348,50 +350,6 @@ typedef struct io_desc_t struct io_desc_t *next; } io_desc_t; -/** - * PIO asynchronous operation types - */ -typedef enum pio_async_op_type -{ - PIO_ASYNC_INVALID_OP = 0, - PIO_ASYNC_REARR_OP, - PIO_ASYNC_PNETCDF_WRITE_OP, - PIO_ASYNC_HDF5_CREATE_OP, - PIO_ASYNC_HDF5_DEF_VAR_OP, - PIO_ASYNC_HDF5_PUT_ATT_OP, - PIO_ASYNC_HDF5_ENDDEF_OP, - PIO_ASYNC_HDF5_SET_FRAME_OP, - PIO_ASYNC_HDF5_PUT_VAR_OP, - PIO_ASYNC_HDF5_WRITE_OP, - PIO_ASYNC_FILE_WRITE_OPS, - PIO_ASYNC_FILE_CLOSE_OP, - PIO_ASYNC_NUM_OP_TYPES -} pio_async_op_type_t; - -/** - * PIO asynchronous op - */ -typedef struct pio_async_op -{ - pio_async_op_type_t op_type; - void *pdata; - /* Blocking wait function for this async op - * param 1 : A user defined data pointer - * return : PIO_NOERR on success, pio error code on failure - */ - int (*wait)(void *); - /* Non-blocking function for making progress on this async op - * param 1 : A user defined data pointer - * param 2 : Pointer to a flag that is set to true if async op - * is complete, false otherwise - * return : PIO_NOERR on success, pio error code on failure - */ - int (*poke)(void *, int *); - /* Free function for user defined pdata */ - void (*free)(void *); - struct pio_async_op *next; -} pio_async_op_t; - /* Forward decl for I/O file summary stats info */ struct spio_io_fstats_summary; @@ -547,11 +505,8 @@ typedef struct iosystem_desc_t /** I/O statistics associated with this I/O system */ struct spio_io_fstats_summary *io_fstats; - /* Number of pending async operations on this iosystem */ - int nasync_pend_ops; - /* List of pending async operations on this iosystem */ - pio_async_op_t *async_pend_ops; + std::deque async_pend_ops; /** Pointer to the next iosystem_desc_t in the list. */ struct iosystem_desc_t *next; @@ -951,17 +906,15 @@ typedef struct file_desc_t /** I/O statistics associated with this file */ struct spio_io_fstats_summary *io_fstats; - /* Number of pending async operations on this file */ - int nasync_pend_ops; - /* List of pending async operations on this file */ - pio_async_op_t *async_pend_ops; + std::deque async_pend_ops; /** Total number of pending ops on this file, including - * nasync_pend_ops. In the case where nasync_pend_ops == 0 - * npend_ops shows any other pending ops (e.g. non-blocking - * write done of rearranged data, still need to wait - * on it) */ + * the ones queued in async_pend_ops. In the case where + * async_pend_ops.size() == 0, npend_ops shows any other + * pending ops (e.g. non-blocking write done of rearranged + * data, still need to wait on it) + */ std::atomic npend_ops; std::atomic is_hard_closed; std::mutex *pmtx; diff --git a/src/clib/spio_async_hdf5_utils.cpp b/src/clib/spio_async_hdf5_utils.cpp index 6ca0d2c2ed..7d259d9a9d 100644 --- a/src/clib/spio_async_hdf5_utils.cpp +++ b/src/clib/spio_async_hdf5_utils.cpp @@ -20,18 +20,15 @@ extern "C"{ #endif /* PIO_ENABLE_LOGGING */ #include } // extern "C" -#if PIO_USE_ASYNC_WR_THREAD -#include "spio_async_tpool_cint.h" -#endif #include "pio_timer.h" #include +#include "spio_async_op.hpp" #include "spio_async_utils.hpp" #include "spio_async_tpool.hpp" #include "spio_file_mvcache.h" #include "spio_dbg_utils.hpp" #include "spio_dt_converter.hpp" #include "spio_hdf5_utils.hpp" -#include "spio_async_tpool_cint.h" struct Hdf5_create_info{ file_desc_t *file; @@ -163,28 +160,22 @@ int spio_iosys_async_hdf5_create_op_add(file_desc_t *file, const char *filename) Hdf5_create_info *cinfo = new Hdf5_create_info{file, filename}; /* Create async task */ - pio_async_op_t *pnew = static_cast(calloc(1, sizeof(pio_async_op_t))); - if(pnew == NULL){ - return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, - "Queuing asynchronous op/task for creating file (%s) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for async task internal struct", filename, static_cast(sizeof(pio_async_op_t))); - } - - pnew->op_type = PIO_ASYNC_HDF5_CREATE_OP; - pnew->pdata = static_cast(cinfo); - pnew->wait = spio_iosys_async_op_hdf5_create; - pnew->poke = pio_async_poke_func_unavail; - pnew->free = spio_iosys_async_op_hdf5_create_free; + SPIO_Util::Async_op op = {SPIO_Util::Async_op::Op_type::SPIO_ASYNC_HDF5_CREATE_OP, + static_cast(cinfo), + spio_iosys_async_op_hdf5_create, + pio_async_poke_func_unavail, + spio_iosys_async_op_hdf5_create_free}; /* One more pending op using this iodesc & file */ file->npend_ops++; SPIO_Util::GVars::npend_hdf5_async_ops++; /* Get the mt queue and queue the async task */ - ret = pio_async_tpool_op_add(pnew); + ret = pio_async_tpool_op_add(op); if(ret != PIO_NOERR){ LOG((1, "Adding file pending ops to tpool failed, ret = %d", ret)); return pio_err(ios, NULL, ret, __FILE__, __LINE__, - "Internal error while adding asynchronous pending operation to the thread pool (iosystem = %d). Adding the asynchronous operation failed", ios->iosysid); + "Internal error while adding asynchronous pending operation (to create file = %s) to the thread pool (iosystem = %d). Adding the asynchronous operation failed", filename, ios->iosysid); } return PIO_NOERR; @@ -232,28 +223,22 @@ int spio_iosys_async_hdf5_def_var_op_add(file_desc_t *file, const char *name, {dimidsp, dimidsp + ndims}, varid}; /* Create async task */ - pio_async_op_t *pnew = static_cast(calloc(1, sizeof(pio_async_op_t))); - if(pnew == NULL){ - return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, - "Queuing asynchronous op/task for defining variable (%s, file=%s) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for async task internal struct", name, pio_get_fname_from_file(file), static_cast(sizeof(pio_async_op_t))); - } - - pnew->op_type = PIO_ASYNC_HDF5_DEF_VAR_OP; - pnew->pdata = static_cast(def_var_info); - pnew->wait = spio_iosys_async_op_hdf5_def_var; - pnew->poke = pio_async_poke_func_unavail; - pnew->free = spio_iosys_async_op_hdf5_def_var_free; + SPIO_Util::Async_op op = {SPIO_Util::Async_op::Op_type::SPIO_ASYNC_HDF5_DEF_VAR_OP, + static_cast(def_var_info), + spio_iosys_async_op_hdf5_def_var, + pio_async_poke_func_unavail, + spio_iosys_async_op_hdf5_def_var_free}; /* One more pending op using this iodesc & file */ file->npend_ops++; SPIO_Util::GVars::npend_hdf5_async_ops++; /* Get the mt queue and queue the async task */ - ret = pio_async_tpool_op_add(pnew); + ret = pio_async_tpool_op_add(op); if(ret != PIO_NOERR){ LOG((1, "Adding file pending ops to tpool failed, ret = %d", ret)); return pio_err(ios, NULL, ret, __FILE__, __LINE__, - "Internal error while adding asynchronous pending operation to the thread pool (iosystem = %d). Adding the asynchronous operation failed", ios->iosysid); + "Internal error while adding asynchronous pending operation (to define var = %s, in file = %s) to the thread pool (iosystem = %d). Adding the asynchronous operation failed", name, pio_get_fname_from_file(file), ios->iosysid); } return PIO_NOERR; @@ -313,28 +298,22 @@ int spio_iosys_async_hdf5_put_att_op_add(file_desc_t *file, int varid, Hdf5_put_att_info *info = new Hdf5_put_att_info{file, varid, aname, atype, alen, buf}; /* Create async task */ - pio_async_op_t *pnew = static_cast(calloc(1, sizeof(pio_async_op_t))); - if(pnew == NULL){ - return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, - "Queuing asynchronous op/task for writing attribute (%s, variable=%s, file=%s) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for async task internal struct", aname, pio_get_vname_from_file(file, varid), pio_get_fname_from_file(file), static_cast(sizeof(pio_async_op_t))); - } - - pnew->op_type = PIO_ASYNC_HDF5_PUT_ATT_OP; - pnew->pdata = static_cast(info); - pnew->wait = spio_iosys_async_op_hdf5_put_att; - pnew->poke = pio_async_poke_func_unavail; - pnew->free = spio_iosys_async_op_hdf5_put_att_free; + SPIO_Util::Async_op op = {SPIO_Util::Async_op::Op_type::SPIO_ASYNC_HDF5_PUT_ATT_OP, + static_cast(info), + spio_iosys_async_op_hdf5_put_att, + pio_async_poke_func_unavail, + spio_iosys_async_op_hdf5_put_att_free}; /* One more pending op using this iodesc & file */ file->npend_ops++; SPIO_Util::GVars::npend_hdf5_async_ops++; /* Get the mt queue and queue the async task */ - ret = pio_async_tpool_op_add(pnew); + ret = pio_async_tpool_op_add(op); if(ret != PIO_NOERR){ LOG((1, "Adding file pending ops to tpool failed, ret = %d", ret)); return pio_err(ios, NULL, ret, __FILE__, __LINE__, - "Internal error while adding asynchronous pending operation to the thread pool (iosystem = %d). Adding the asynchronous operation failed", ios->iosysid); + "Internal error while adding asynchronous pending operation (to define attribute = %s, for var = %s in file = %s) to the thread pool (iosystem = %d). Adding the asynchronous operation failed", aname, pio_get_vname_from_file(file, varid), pio_get_fname_from_file(file), ios->iosysid); } return PIO_NOERR; @@ -378,28 +357,22 @@ int spio_iosys_async_hdf5_enddef_op_add(file_desc_t *file) Hdf5_enddef_info *info = new Hdf5_enddef_info{file}; /* Create async task */ - pio_async_op_t *pnew = static_cast(calloc(1, sizeof(pio_async_op_t))); - if(pnew == NULL){ - return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, - "Queuing asynchronous op/task for ending define mode of file (%s) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for async task internal struct", pio_get_fname_from_file(file), static_cast(sizeof(pio_async_op_t))); - } - - pnew->op_type = PIO_ASYNC_HDF5_ENDDEF_OP; - pnew->pdata = static_cast(info); - pnew->wait = spio_iosys_async_op_hdf5_enddef; - pnew->poke = pio_async_poke_func_unavail; - pnew->free = spio_iosys_async_op_hdf5_enddef_free; + SPIO_Util::Async_op op = {SPIO_Util::Async_op::Op_type::SPIO_ASYNC_HDF5_ENDDEF_OP, + static_cast(info), + spio_iosys_async_op_hdf5_enddef, + pio_async_poke_func_unavail, + spio_iosys_async_op_hdf5_enddef_free}; /* One more pending op using this file */ file->npend_ops++; SPIO_Util::GVars::npend_hdf5_async_ops++; /* Get the mt queue and queue the async task */ - ret = pio_async_tpool_op_add(pnew); + ret = pio_async_tpool_op_add(op); if(ret != PIO_NOERR){ LOG((1, "Adding file pending ops to tpool failed, ret = %d", ret)); return pio_err(ios, NULL, ret, __FILE__, __LINE__, - "Internal error while adding asynchronous pending operation to the thread pool (iosystem = %d). Adding the asynchronous operation failed", ios->iosysid); + "Internal error while adding asynchronous pending operation (to end define mode in file = %s) to the thread pool (iosystem = %d). Adding the asynchronous operation failed", pio_get_fname_from_file(file), ios->iosysid); } return PIO_NOERR; @@ -480,28 +453,22 @@ int spio_iosys_async_hdf5_put_var_op_add(file_desc_t *file, int varid, xtype, vbuf_sz, buf}; /* Create async task */ - pio_async_op_t *pnew = static_cast(calloc(1, sizeof(pio_async_op_t))); - if(pnew == NULL){ - return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, - "Queuing asynchronous op/task for writing variable(%s, varid=%d, file=%s) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for async internal struct", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), static_cast(sizeof(pio_async_op_t))); - } - - pnew->op_type = PIO_ASYNC_HDF5_PUT_VAR_OP; - pnew->pdata = static_cast(info); - pnew->wait = spio_iosys_async_op_hdf5_put_var; - pnew->poke = pio_async_poke_func_unavail; - pnew->free = spio_iosys_async_op_hdf5_put_var_free; + SPIO_Util::Async_op op = {SPIO_Util::Async_op::Op_type::SPIO_ASYNC_HDF5_PUT_VAR_OP, + static_cast(info), + spio_iosys_async_op_hdf5_put_var, + pio_async_poke_func_unavail, + spio_iosys_async_op_hdf5_put_var_free}; /* One more pending op using this file */ file->npend_ops++; SPIO_Util::GVars::npend_hdf5_async_ops++; /* Get the mt queue and queue the async task */ - ret = pio_async_tpool_op_add(pnew); + ret = pio_async_tpool_op_add(op); if(ret != PIO_NOERR){ LOG((1, "Adding file pending ops to tpool failed, ret = %d", ret)); return pio_err(ios, NULL, ret, __FILE__, __LINE__, - "Internal error while adding asynchronous pending operation to the thread pool (iosystem = %d). Adding the asynchronous operation failed", ios->iosysid); + "Internal error while adding asynchronous pending operation (to write/put var = %s in file = %s) to the thread pool (iosystem = %d). Adding the asynchronous operation failed", pio_get_vname_from_file(file, varid), pio_get_fname_from_file(file), ios->iosysid); } return PIO_NOERR; @@ -545,28 +512,22 @@ int spio_iosys_async_hdf5_set_frame_op_add(file_desc_t *file, int varid, int fra Hdf5_set_frame_info *info = new Hdf5_set_frame_info{file, varid, frame}; /* Create async task */ - pio_async_op_t *pnew = static_cast(calloc(1, sizeof(pio_async_op_t))); - if(pnew == NULL){ - return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, - "Queuing asynchronous op/task for setting frame for variable (%s, file=%s) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for async task internal struct", pio_get_vname_from_file(file, varid), pio_get_fname_from_file(file), static_cast(sizeof(pio_async_op_t))); - } - - pnew->op_type = PIO_ASYNC_HDF5_SET_FRAME_OP; - pnew->pdata = static_cast(info); - pnew->wait = spio_iosys_async_op_hdf5_set_frame; - pnew->poke = pio_async_poke_func_unavail; - pnew->free = spio_iosys_async_op_hdf5_set_frame_free; + SPIO_Util::Async_op op = {SPIO_Util::Async_op::Op_type::SPIO_ASYNC_HDF5_SET_FRAME_OP, + static_cast(info), + spio_iosys_async_op_hdf5_set_frame, + pio_async_poke_func_unavail, + spio_iosys_async_op_hdf5_set_frame_free}; /* One more pending op using this iodesc & file */ file->npend_ops++; SPIO_Util::GVars::npend_hdf5_async_ops++; /* Get the mt queue and queue the async task */ - ret = pio_async_tpool_op_add(pnew); + ret = pio_async_tpool_op_add(op); if(ret != PIO_NOERR){ LOG((1, "Adding file pending ops to tpool failed, ret = %d", ret)); return pio_err(ios, NULL, ret, __FILE__, __LINE__, - "Internal error while adding asynchronous pending operation to the thread pool (iosystem = %d). Adding the asynchronous operation failed", ios->iosysid); + "Internal error while adding asynchronous pending operation (to set frame to %d for variable = %s in file = %s) to the thread pool (iosystem = %d). Adding the asynchronous operation failed", frame, pio_get_vname_from_file(file, varid), pio_get_fname_from_file(file), ios->iosysid); } return PIO_NOERR; @@ -905,17 +866,11 @@ int pio_iosys_async_hdf5_write_op_add(file_desc_t *file, int nvars, int fndims, } /* Create async task */ - pio_async_op_t *pnew = static_cast(calloc(1, sizeof(pio_async_op_t))); - if(pnew == NULL){ - return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, - "Queuing asynchronous op/task for writing fillvalue for variables (number of variables = %d) to file (%s, ncid=%d) using PIO_IOTYPE_HDF5x failed. Unable to allocate memory (%lld bytes) for async task internal struct", nvars, pio_get_fname_from_file(file), file->pio_ncid, static_cast(sizeof(pio_async_op_t))); - } - - pnew->op_type = PIO_ASYNC_HDF5_WRITE_OP; - pnew->pdata = static_cast(wcache); - pnew->wait = pio_iosys_async_op_hdf5_write; - pnew->poke = pio_async_poke_func_unavail; - pnew->free = pio_iosys_async_op_hdf5_write_free; + SPIO_Util::Async_op op = {SPIO_Util::Async_op::Op_type::SPIO_ASYNC_HDF5_WRITE_OP, + static_cast(wcache), + pio_iosys_async_op_hdf5_write, + pio_async_poke_func_unavail, + pio_iosys_async_op_hdf5_write_free}; /* One more pending op using this iodesc & file */ iodesc->nasync_pend_ops++; @@ -923,11 +878,11 @@ int pio_iosys_async_hdf5_write_op_add(file_desc_t *file, int nvars, int fndims, SPIO_Util::GVars::npend_hdf5_async_ops++; /* Get the mt queue and queue the async task */ - ret = pio_async_tpool_op_add(pnew); + ret = pio_async_tpool_op_add(op); if(ret != PIO_NOERR){ LOG((1, "Adding file pending ops to tpool failed, ret = %d", ret)); return pio_err(ios, NULL, ret, __FILE__, __LINE__, - "Internal error while adding asynchronous pending operation to the thread pool (iosystem = %d). Adding the asynchronous operation failed", ios->iosysid); + "Internal error while adding asynchronous pending operation (to write %d variables in file = %s) to the thread pool (iosystem = %d). Adding the asynchronous operation failed", nvars, pio_get_fname_from_file(file), ios->iosysid); } return PIO_NOERR; diff --git a/src/clib/spio_async_op.hpp b/src/clib/spio_async_op.hpp new file mode 100644 index 0000000000..1cf1f5f4e3 --- /dev/null +++ b/src/clib/spio_async_op.hpp @@ -0,0 +1,86 @@ +#ifndef __SPIO_ASYNC_OP_HPP__ +#define __SPIO_ASYNC_OP_HPP__ + +#include +#include + +namespace SPIO_Util{ + +/** + * PIO asynchronous op + */ +class Async_op{ + public: + /** + * PIO asynchronous operation types + */ + enum class Op_type{ + SPIO_ASYNC_INVALID_OP, + SPIO_ASYNC_REARR_OP, + SPIO_ASYNC_PNETCDF_WRITE_OP, + SPIO_ASYNC_HDF5_CREATE_OP, + SPIO_ASYNC_HDF5_DEF_VAR_OP, + SPIO_ASYNC_HDF5_PUT_ATT_OP, + SPIO_ASYNC_HDF5_ENDDEF_OP, + SPIO_ASYNC_HDF5_SET_FRAME_OP, + SPIO_ASYNC_HDF5_PUT_VAR_OP, + SPIO_ASYNC_HDF5_WRITE_OP, + SPIO_ASYNC_FILE_WRITE_OPS, + SPIO_ASYNC_FILE_CLOSE_OP + }; + + static std::string op_type_to_string(Op_type type){ + const std::string UNKNOWN_OP("SPIO_ASYNC_INVALID_OP"); + switch(type){ + case Op_type::SPIO_ASYNC_INVALID_OP : return "SPIO_ASYNC_INVALID_OP"; + case Op_type::SPIO_ASYNC_REARR_OP : return "SPIO_ASYNC_REARR_OP"; + case Op_type::SPIO_ASYNC_PNETCDF_WRITE_OP : return "SPIO_ASYNC_PNETCDF_WRITE_OP"; + case Op_type::SPIO_ASYNC_HDF5_CREATE_OP : return "SPIO_ASYNC_HDF5_CREATE_OP"; + case Op_type::SPIO_ASYNC_HDF5_DEF_VAR_OP : return "SPIO_ASYNC_HDF5_DEF_VAR_OP"; + case Op_type::SPIO_ASYNC_HDF5_PUT_ATT_OP : return "SPIO_ASYNC_HDF5_PUT_ATT_OP"; + case Op_type::SPIO_ASYNC_HDF5_ENDDEF_OP : return "SPIO_ASYNC_HDF5_ENDDEF_OP"; + case Op_type::SPIO_ASYNC_HDF5_SET_FRAME_OP : return "SPIO_ASYNC_HDF5_SET_FRAME_OP"; + case Op_type::SPIO_ASYNC_HDF5_PUT_VAR_OP : return "SPIO_ASYNC_HDF5_PUT_VAR_OP"; + case Op_type::SPIO_ASYNC_HDF5_WRITE_OP : return "SPIO_ASYNC_HDF5_WRITE_OP"; + case Op_type::SPIO_ASYNC_FILE_WRITE_OPS : return "SPIO_ASYNC_FILE_WRITE_OPS"; + case Op_type::SPIO_ASYNC_FILE_CLOSE_OP : return "SPIO_ASYNC_FILE_CLOSE_OP"; + default : return UNKNOWN_OP; + } + } + + Async_op(Op_type type, void *pdata, + std::function wait_fn, + std::function poke_fn, + std::function free_fn): + type_(type), pdata_(pdata), + wait_fn_(wait_fn), poke_fn_(poke_fn), free_fn_(free_fn){} + + Op_type type(void ) const { return type_; } + void *data(void ) const { return pdata_; } + int wait(void ) { return wait_fn_(pdata_); } + int poke(bool &is_complete) { return poke_fn_(pdata_, is_complete); } + int poke(void ) { bool is_complete = false; return poke_fn_(pdata_, is_complete); } + void free(void ) { return free_fn_(pdata_); } + + private: + Op_type type_; + void *pdata_; + /* Blocking wait function for this async op + * param 1 : A user defined data pointer + * return : PIO_NOERR on success, pio error code on failure + */ + std::function wait_fn_; + /* Non-blocking function for making progress on this async op + * param 1 : A user defined data pointer + * param 2 : Pointer to a flag that is set to true if async op + * is complete, false otherwise + * return : PIO_NOERR on success, pio error code on failure + */ + std::function poke_fn_; + /* Free function for user defined pdata */ + std::function free_fn_; +}; + +} // namespace SPIO_Util + +#endif // __SPIO_ASYNC_OP_HPP__ diff --git a/src/clib/spio_async_tpool.cpp b/src/clib/spio_async_tpool.cpp index 76255a5333..f96d271717 100644 --- a/src/clib/spio_async_tpool.cpp +++ b/src/clib/spio_async_tpool.cpp @@ -9,24 +9,20 @@ extern "C"{ #include "spio_async_mtq.hpp" #include "spio_async_tpool.hpp" #include "pio_internal.h" -extern "C"{ -#include "spio_async_tpool_cint.h" -} // extern "C" int pio_async_init_cnt = 0; PIO_Util::PIO_async_tpool *PIO_Util::PIO_async_tpool_manager::tpool_ = NULL; static PIO_Util::PIO_async_tpool_manager tpool_mgr; -void PIO_Util::PIO_async_tpool::enqueue(pio_async_op_t *op) +void PIO_Util::PIO_async_tpool::enqueue(const SPIO_Util::Async_op &op) { - assert(op); - LOG((2, "PIO_async_tpool:enqueue: Enqueing async op, kind = %s", pio_async_op_type_to_string(op->op_type).c_str())); + LOG((2, "PIO_async_tpool:enqueue: Enqueing async op, kind = %s", SPIO_Util::Async_op::op_type_to_string(op.type()).c_str())); mtq_.enqueue(op); } void PIO_Util::PIO_async_tpool::finalize(void ) { - mtq_.signal(PIO_Util::PIO_mtq::PIO_MTQ_SIG_COMPLETE); + mtq_.signal(PIO_Util::PIO_mtq::PIO_MTQ_SIG_COMPLETE); } std::vector PIO_Util::PIO_async_tpool::get_thread_ids(void ) const @@ -51,7 +47,7 @@ PIO_Util::PIO_async_tpool::PIO_async_tpool(int nthreads) PIO_Util::PIO_async_tpool::~PIO_async_tpool() { LOG((2, "PIO_async_tpool:~PIO_async_tpool: Sending STOP signal")); - mtq_.signal(PIO_Util::PIO_mtq::PIO_MTQ_SIG_STOP); + mtq_.signal(PIO_Util::PIO_mtq::PIO_MTQ_SIG_STOP); for(std::vector::iterator iter = pool_threads_.begin(); iter != pool_threads_.end(); ++iter){ if(iter->joinable()){ @@ -63,36 +59,29 @@ PIO_Util::PIO_async_tpool::~PIO_async_tpool() int PIO_Util::PIO_async_tpool::dequeue_and_process( PIO_Util::PIO_async_tpool *tpool) { - int ret = 0; + int ret = PIO_NOERR; assert(tpool); /* Wait in an infinite loop (until the threads receive a signal) for * pending asynchronous operations queued in the thread pool */ - do{ + while(true){ LOG((2, "PIO_async_tpool:dequeue_and_process: Waiting for async ops...")); - pio_async_op_t *op = NULL; - ret = tpool->mtq_.dequeue(op); - if(ret == 0){ - LOG((2, " Tpool processing async op, kind = %s", pio_async_op_type_to_string(op->op_type).c_str())); - /* We currently support only file write ops here */ - //assert(op->op_type == PIO_ASYNC_FILE_WRITE_OPS); - assert((op->op_type == PIO_ASYNC_HDF5_CREATE_OP) || - (op->op_type == PIO_ASYNC_HDF5_DEF_VAR_OP) || - (op->op_type == PIO_ASYNC_HDF5_PUT_ATT_OP) || - (op->op_type == PIO_ASYNC_HDF5_ENDDEF_OP) || - (op->op_type == PIO_ASYNC_HDF5_SET_FRAME_OP) || - (op->op_type == PIO_ASYNC_HDF5_PUT_VAR_OP) || - (op->op_type == PIO_ASYNC_HDF5_WRITE_OP) || - (op->op_type == PIO_ASYNC_FILE_CLOSE_OP)); - ret = op->wait(op->pdata); + + try{ + SPIO_Util::Async_op op = tpool->mtq_.dequeue(); + ret = op.wait(); if(ret != PIO_NOERR){ return pio_err(NULL, NULL, PIO_EINTERNAL, __FILE__, __LINE__, - "Internal error dequeuing and processing asynchronous operations in the thread pool. Internal error waiting on asynchronous file write operation"); + "Internal error dequeuing and processing asynchronous operation (%s) in the thread pool. Internal error waiting on asynchronous file write operation", + SPIO_Util::Async_op::op_type_to_string(op.type()).c_str()); } - op->free(op->pdata); - free(op); + op.free(); + }catch(const PIO_Util::PIO_mtq::Mtq_exception &e){ + /* MTQ exceptions are for MTQ signal handling, stop waiting on the queue */ + LOG((1, "MTQ exception : %s", e.what().c_str())); + break; } - } while(ret == 0); + } return PIO_NOERR; } @@ -138,7 +127,7 @@ int pio_async_tpool_create(void ) return PIO_NOERR; } -int pio_async_tpool_op_add(pio_async_op_t *op) +int pio_async_tpool_op_add(const SPIO_Util::Async_op &op) { PIO_Util::PIO_async_tpool *tpool = tpool_mgr.get_tpool_instance(); assert(tpool); diff --git a/src/clib/spio_async_tpool.hpp b/src/clib/spio_async_tpool.hpp index 4b04f561cf..8a6a9d0cf7 100644 --- a/src/clib/spio_async_tpool.hpp +++ b/src/clib/spio_async_tpool.hpp @@ -4,18 +4,16 @@ #include #include #include +#include "spio_async_op.hpp" #include "spio_async_mtq.hpp" #include "spio_async_utils.hpp" #include "pio_internal.h" -extern "C"{ -#include "spio_async_tpool_cint.h" -} // extern "C" namespace PIO_Util{ class PIO_async_tpool{ public: - void enqueue(pio_async_op_t *op); + void enqueue(const SPIO_Util::Async_op &op); void finalize(void ); std::vector get_thread_ids(void ) const; private: @@ -23,7 +21,7 @@ class PIO_async_tpool{ PIO_async_tpool(int nthreads); ~PIO_async_tpool(); static int dequeue_and_process(PIO_async_tpool *tpool); - PIO_Util::PIO_mtq mtq_; + PIO_Util::PIO_mtq mtq_; std::vector pool_threads_; }; @@ -37,4 +35,10 @@ class PIO_async_tpool_manager{ } // namespace PIO_Util +/* FIXME: Move it inside the SPIO_Util namespace */ +int pio_async_tpool_create(void ); +int pio_async_tpool_op_add(const SPIO_Util::Async_op &op); +int pio_async_tpool_ops_wait(void ); +int pio_async_tpool_finalize(void ); + #endif // _SPIO_ASYNC_TPOOL_HPP_ diff --git a/src/clib/spio_async_tpool_cint.h b/src/clib/spio_async_tpool_cint.h deleted file mode 100644 index 5699bb4d70..0000000000 --- a/src/clib/spio_async_tpool_cint.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _PIO_ASYNC_THREAD_H_ -#define _PIO_ASYNC_THREAD_H_ - -#include "pio.h" -#include "pio_internal.h" - -extern "C"{ -int pio_async_tpool_create(void ); -int pio_async_tpool_op_add(pio_async_op_t *op); -int pio_async_tpool_ops_wait(void ); -int pio_async_tpool_finalize(void ); -} // extern "C" - -#endif // _PIO_ASYNC_THREAD_H_ diff --git a/src/clib/spio_async_utils.cpp b/src/clib/spio_async_utils.cpp index 7c055c4cf2..b2bed720ea 100644 --- a/src/clib/spio_async_utils.cpp +++ b/src/clib/spio_async_utils.cpp @@ -8,6 +8,7 @@ #include #include #include +#include extern "C"{ @@ -20,37 +21,15 @@ extern "C"{ #endif /* PIO_ENABLE_LOGGING */ #include } // extern "C" -#if PIO_USE_ASYNC_WR_THREAD -#include "spio_async_tpool_cint.h" -#endif #include "pio_timer.h" #include +#include "spio_async_op.hpp" #include "spio_async_utils.hpp" #include "spio_async_tpool.hpp" #include "spio_file_mvcache.h" #include "spio_dbg_utils.hpp" #include "spio_dt_converter.hpp" #include "spio_hdf5_utils.hpp" -#include "spio_async_tpool_cint.h" - -std::string pio_async_op_type_to_string(pio_async_op_type_t op) -{ - switch(op){ - case PIO_ASYNC_INVALID_OP: return "PIO_ASYNC_INVALID_OP"; - case PIO_ASYNC_REARR_OP: return "PIO_ASYNC_REARR_OP"; - case PIO_ASYNC_PNETCDF_WRITE_OP: return "PIO_ASYNC_PNETCDF_WRITE_OP"; - case PIO_ASYNC_HDF5_CREATE_OP: return "PIO_ASYNC_HDF5_CREATE_OP"; - case PIO_ASYNC_HDF5_DEF_VAR_OP: return "PIO_ASYNC_HDF5_DEF_VAR_OP"; - case PIO_ASYNC_HDF5_PUT_ATT_OP: return "PIO_ASYNC_HDF5_PUT_ATT_OP"; - case PIO_ASYNC_HDF5_ENDDEF_OP: return "PIO_ASYNC_HDF5_ENDDEF_OP"; - case PIO_ASYNC_HDF5_SET_FRAME_OP: return "PIO_ASYNC_HDF5_SET_FRAME_OP"; - case PIO_ASYNC_HDF5_PUT_VAR_OP: return "PIO_ASYNC_HDF5_PUT_VAR_OP"; - case PIO_ASYNC_HDF5_WRITE_OP: return "PIO_ASYNC_HDF5_WRITE_OP"; - case PIO_ASYNC_FILE_WRITE_OPS: return "PIO_ASYNC_FILE_WRITE_OPS"; - case PIO_ASYNC_FILE_CLOSE_OP: return "PIO_ASYNC_FILE_CLOSE_OP"; - default : return "UNKNOWN"; - } -} /* Use this function for op kinds with no wait functions * We use it to indicate, @@ -69,7 +48,7 @@ int pio_async_wait_func_unavail(void *pdata) *pio_iosys_async_op_hdf5_write so any generic code that uses the poke function must * check the existence of this function before using it */ -int pio_async_poke_func_unavail(void *pdata, int *flag) +int pio_async_poke_func_unavail(void *pdata, bool &flag) { assert(0); } @@ -85,28 +64,22 @@ int pio_file_async_pend_ops_wait(file_desc_t *file) int ret; assert(file != NULL); - if(file->nasync_pend_ops == 0){ - return PIO_NOERR; - } + while(!file->async_pend_ops.empty()){ + SPIO_Util::Async_op op = file->async_pend_ops.front(); + LOG((2, "Waiting on async op, kind = %s", SPIO_Util::Async_op::op_type_to_string(op.type()).c_str())); - pio_async_op_t *p = file->async_pend_ops, *q=NULL; - while(p){ - LOG((2, "Waiting on async op, kind = %s", - (p->op_type == PIO_ASYNC_REARR_OP) ? "PIO_ASYNC_REARR_OP" : - ((p->op_type == PIO_ASYNC_PNETCDF_WRITE_OP) ? "PIO_ASYNC_PNETCDF_WRITE_OP" : - "UNKNOWN"))); - ret = p->wait(p->pdata); + ret = op.wait(); if(ret != PIO_NOERR){ return pio_err(NULL, NULL, PIO_EINTERNAL, __FILE__, __LINE__, - "Error waiting for pending asynchronous operation on file, %s (ncid = %d)", pio_get_fname_from_file(file), file->pio_ncid); + "Error waiting for pending asynchronous operation (%s) on file, %s (ncid = %d)", + SPIO_Util::Async_op::op_type_to_string(op.type()).c_str(), + pio_get_fname_from_file(file), file->pio_ncid); } - q = p; - p = p->next; - q->free(q->pdata); - free(q); + + op.free(); + + file->async_pend_ops.pop_front(); } - file->async_pend_ops = NULL; - file->nasync_pend_ops = 0; return PIO_NOERR; } @@ -308,122 +281,85 @@ int pio_async_pnetcdf_write_kwait(void *f) assert(file); assert(file->iotype == PIO_IOTYPE_PNETCDF); + if(file->async_pend_ops.empty()) { return PIO_NOERR; } + /* Gather up all requests corresponding to all vdescs associated * with the pending async ops * Also delete these async ops from the list since we wait for * the requests associated with the ops here * */ - if(file->nasync_pend_ops > 0){ - int nreqs = 0; - int *reqs = (int *)malloc(file->nasync_pend_ops * sizeof(int)); - if(!reqs){ - return pio_err(file->iosystem, file, PIO_ENOMEM, __FILE__, __LINE__, - "Error while waiting for asynchronous writes to complete for the PIO_IOTYPE_PNETCDF I/O type on file (%s, ncid=%d). Unable to allocate %lld bytes to consolidate requests associated with pending asynchronous operations on the file", pio_get_fname_from_file(file), file->pio_ncid, (unsigned long long) (file->nasync_pend_ops * sizeof(int))); + std::vector reqs; + std::vector vdescs; + std::vector viobufs; + + for(std::deque::iterator iter = file->async_pend_ops.begin(); iter != file->async_pend_ops.end();){ + SPIO_Util::Async_op op = *iter; + /* Only process PnetCDF write ops */ + if(op.type() == SPIO_Util::Async_op::Op_type::SPIO_ASYNC_PNETCDF_WRITE_OP){ + viobuf_cache_t *pviobuf = static_cast(op.data()); + assert(pviobuf); + + reqs.push_back(pviobuf->req); + viobufs.push_back(pviobuf); + vdescs.push_back(pviobuf->vdesc); + + iter = file->async_pend_ops.erase(iter); } - int nvdescs = 0; - var_desc_t **vdescs = (var_desc_t **)malloc(file->nasync_pend_ops * sizeof(var_desc_t *)); - if(!vdescs){ - return pio_err(file->iosystem, file, PIO_ENOMEM, __FILE__, __LINE__, - "Error while waiting for asynchronous writes to complete for the PIO_IOTYPE_PNETCDF I/O type on file (%s, ncid=%d). Unable to allocate %lld bytes to keep track of variable descriptors associated with pending asynchronous operations on the file", pio_get_fname_from_file(file), file->pio_ncid, (unsigned long long) (file->nasync_pend_ops * sizeof(var_desc_t *))); + else{ + ++iter; } + } - viobuf_cache_t **viobufs = (viobuf_cache_t **) malloc(file->nasync_pend_ops * sizeof(viobuf_cache_t *)); - if(!viobufs){ - return pio_err(file->iosystem, file, PIO_ENOMEM, __FILE__, __LINE__, - "Error while waiting for asynchronous writes to complete for the PIO_IOTYPE_PNETCDF I/O type on file (%s, ncid=%d). Unable to allocate %lld bytes to keep track of buffered data associated with pending asynchronous operations on the file", pio_get_fname_from_file(file), file->pio_ncid, (unsigned long long) (file->nasync_pend_ops * sizeof(viobuf_cache_t *))); - } - - pio_async_op_t *p = file->async_pend_ops, *q=NULL; - pio_async_op_t *prev = file->async_pend_ops; - while(p){ - if(p->op_type == PIO_ASYNC_PNETCDF_WRITE_OP){ - viobuf_cache_t *pviobuf = (viobuf_cache_t *)(p->pdata); - assert(pviobuf); - - reqs[nreqs] = pviobuf->req; - viobufs[nreqs] = pviobuf; - nreqs++; - - vdescs[nvdescs] = pviobuf->vdesc; - nvdescs++; - - q = p->next; - /* Free node */ - free(p); - /* p == file->async_pend_ops => First node */ - if(p == file->async_pend_ops){ - /* Update head and prev */ - file->async_pend_ops = q; - prev = q; - } - else{ - /* Skip node p, already deleted */ - prev->next = q; - } - p = q; - } - else{ - /* Ignore op kinds/types that are not pnetcdf writes */ - prev = p; - p = p->next; - } - } + if(reqs.empty()) { return PIO_NOERR; } - /* We don't expect any other pending operations when writes are - * pending on this file - * This was a constraint that was introduced by resuing a - * single file buffer, file->iobuf, for rearrange and write. - * So a write needed to complete before a rearrange occurs. - * FIXME: Since this is no longer a constraint for async writes - * investigate on how to relax the constraint - */ - assert(nreqs <= file->nasync_pend_ops); - LOG((2, "pio_async_pnetcdf_write_kwait(): nreqs= %d, file->nasync_pend_ops= %d\n", - nreqs, file->nasync_pend_ops)); + /* We don't expect any other pending operations when writes are + * pending on this file + * This was a constraint that was introduced by resuing a + * single file buffer, file->iobuf, for rearrange and write. + * So a write needed to complete before a rearrange occurs. + * FIXME: Since this is no longer a constraint for async writes + * investigate on how to relax the constraint + */ + assert(reqs.size() <= file->async_pend_ops.size()); + LOG((2, "pio_async_pnetcdf_write_kwait(): nreqs= %d, file->nasync_pend_ops= %d\n", + reqs.size(), file->async_pend_ops.size())); #ifdef PIO_MICRO_TIMING - pio_async_pnetcdf_wr_timer_info_t wr_info; - ret = pio_async_pnetcdf_setup_wr_timers(file, vdescs, nvdescs, &wr_info); - if(ret != PIO_NOERR){ - LOG((1, "Initializing var write timers failed")); - return ret; - } + pio_async_pnetcdf_wr_timer_info_t wr_info; + ret = pio_async_pnetcdf_setup_wr_timers(file, vdescs.data(), vdescs.size(), &wr_info); + if(ret != PIO_NOERR){ + LOG((1, "Initializing var write timers failed")); + return ret; + } #endif - /* Wait on all requests in one call */ - /* We don't care about the status of each request, we - * only care whether wait succeeded or not - * Requires pnetcdf ver >= 1.7.0 to support a - * NULL value for the status array - */ - ret = ncmpi_wait_all(file->fh, nreqs, reqs, NULL); - if(ret != NC_NOERR){ - return pio_err(file->iosystem, file, ret, __FILE__, __LINE__, - "Error while waiting for asynchronous writes to complete for the PIO_IOTYPE_PNETCDF I/O type on file (%s, ncid=%d). Internal I/O library error while waiting for pending PnetCDF operations.", pio_get_fname_from_file(file), file->pio_ncid); - } + /* Wait on all requests in one call */ + /* We don't care about the status of each request, we + * only care whether wait succeeded or not + * Requires pnetcdf ver >= 1.7.0 to support a + * NULL value for the status array + */ + /* FIXME: Replace with op.wait() */ + ret = ncmpi_wait_all(file->fh, reqs.size(), reqs.data(), NULL); + if(ret != NC_NOERR){ + return pio_err(file->iosystem, file, ret, __FILE__, __LINE__, + "Error while waiting for asynchronous writes to complete for the PIO_IOTYPE_PNETCDF I/O type on file (%s, ncid=%d). Internal I/O library error while waiting for pending PnetCDF operations.", pio_get_fname_from_file(file), file->pio_ncid); + } - for(int i=0; iiosystem, file, PIO_EINTERNAL, __FILE__, __LINE__, - "Error while waiting for asynchronous writes to complete for the PIO_IOTYPE_PNETCDF I/O type on file (%s, ncid=%d). Resetting variable descriptors associated with the completed asynchronous operations failed", pio_get_fname_from_file(file), file->pio_ncid); - } - - free(viobufs); - free(vdescs); - free(reqs); - - file->nasync_pend_ops -= nreqs; + ret = pio_async_pnetcdf_reset_vdesc(vdescs.data(), vdescs.size()); + if(ret != PIO_NOERR){ + return pio_err(file->iosystem, file, PIO_EINTERNAL, __FILE__, __LINE__, + "Error while waiting for asynchronous writes to complete for the PIO_IOTYPE_PNETCDF I/O type on file (%s, ncid=%d). Resetting variable descriptors associated with the completed asynchronous operations failed", pio_get_fname_from_file(file), file->pio_ncid); } return PIO_NOERR; @@ -436,43 +372,22 @@ int pio_async_rearr_kwait(void *f) file_desc_t *file = (file_desc_t *)f; assert(file); - if(file->nasync_pend_ops > 0){ - int nreqs = 0; - pio_async_op_t *p = file->async_pend_ops, *q=NULL; - pio_async_op_t *prev = file->async_pend_ops; - while(p){ - if(p->op_type == PIO_ASYNC_REARR_OP){ - nreqs++; - ret = p->wait(p->pdata); - if(ret != PIO_NOERR){ - LOG((1, "Waiting for rearr async op failed")); - return pio_err(file->iosystem, file, PIO_EINTERNAL, - __FILE__, __LINE__, - "Internal error while waiting for asynchronous rearrangement operations (number of pending ops = %d) on file (%s, ncid=%d)", file->nasync_pend_ops, pio_get_fname_from_file(file), file->pio_ncid); - } - p->free(p->pdata); - q = p->next; - /* Free node */ - free(p); - /* p == file->async_pend_ops => First node */ - if(p == file->async_pend_ops){ - /* Update head and prev to delete/skip node p */ - file->async_pend_ops = q; - prev = q; - } - else{ - /* Delete node p, already freed */ - prev->next = q; - } - p = q; - } - else{ - /* Ignore op kinds/types that are not pnetcdf writes */ - prev = p; - p = p->next; + if(file->async_pend_ops.empty()) { return PIO_NOERR; } + + for(std::deque::iterator iter = file->async_pend_ops.begin(); iter != file->async_pend_ops.end();){ + SPIO_Util::Async_op op = *iter; + if(op.type() == SPIO_Util::Async_op::Op_type::SPIO_ASYNC_REARR_OP){ + ret = op.wait(); + if(ret != PIO_NOERR){ + LOG((1, "Waiting for rearr async op failed")); + return pio_err(file->iosystem, file, PIO_EINTERNAL, __FILE__, __LINE__, "Internal error while waiting for asynchronous rearrangement operations (number of pending ops = %zu) on file (%s, ncid=%d)", file->async_pend_ops.size(), pio_get_fname_from_file(file), file->pio_ncid); } + op.free(); + iter = file->async_pend_ops.erase(iter); + } + else{ + ++iter; } - file->nasync_pend_ops -= nreqs; } return PIO_NOERR; @@ -483,47 +398,21 @@ int pio_async_hdf5_write_kwait(void *file) assert(0); } -/* Optimized wait functions for different async op kinds/types on a file */ -typedef int (*file_async_pend_ops_kwait_func_t) (void *file); -static file_async_pend_ops_kwait_func_t - file_async_pend_ops_kwait_funcs[PIO_ASYNC_NUM_OP_TYPES] = { - /* PIO_ASYNC_INVALID_OP */ - pio_async_wait_func_unavail, - /* PIO_ASYNC_REARR_OP */ - pio_async_rearr_kwait, - /* PIO_ASYNC_PNETCDF_WRITE_OP */ - pio_async_pnetcdf_write_kwait, - /* PIO_ASYNC_HDF5_CREATE_OP */ - pio_async_wait_func_unavail, - /* PIO_ASYNC_HDF5_DEF_VAR_OP */ - pio_async_wait_func_unavail, - /* PIO_ASYNC_HDF5_PUT_ATT_OP */ - pio_async_wait_func_unavail, - /* PIO_ASYNC_HDF5_ENDDEF_OP */ - pio_async_wait_func_unavail, - /* PIO_ASYNC_HDF5_SET_FRAME_OP */ - pio_async_wait_func_unavail, - /* PIO_ASYNC_HDF5_PUT_VAR_OP */ - pio_async_wait_func_unavail, - /* PIO_ASYNC_HDF5_WRITE_OP */ - pio_async_hdf5_write_kwait, - /* PIO_ASYNC_FILE_WRITE_OPS */ - pio_async_wait_func_unavail, - /* PIO_ASYNC_FILE_CLOSE_OP */ - pio_async_wait_func_unavail - }; - /* Wait for pending asynchronous operations of kind, op_kind, on this file * @param file Pointer to the file_desc for the file * Returns PIO_NOERR on success, a pio error code otherwise */ -int pio_file_async_pend_ops_kwait(file_desc_t *file, pio_async_op_type_t op_kind) +int pio_file_async_pend_ops_kwait(file_desc_t *file, SPIO_Util::Async_op::Op_type op_kind) { assert(file); - assert((op_kind > PIO_ASYNC_INVALID_OP) - && (op_kind < PIO_ASYNC_NUM_OP_TYPES)); - int ret = file_async_pend_ops_kwait_funcs[op_kind](file); + int ret = PIO_NOERR; + switch(op_kind){ + case SPIO_Util::Async_op::Op_type::SPIO_ASYNC_REARR_OP : ret = pio_async_rearr_kwait(file); break; + case SPIO_Util::Async_op::Op_type::SPIO_ASYNC_PNETCDF_WRITE_OP : ret = pio_async_pnetcdf_write_kwait(file); break; + default : ret = pio_async_wait_func_unavail(file); break; + } + if(ret != PIO_NOERR){ return pio_err(NULL, NULL, PIO_EINTERNAL, __FILE__, __LINE__, "Internal error while waiting for pending asynchronous operations on file (%s, ncid=%d)", pio_get_fname_from_file(file), file->pio_ncid); @@ -539,37 +428,26 @@ int pio_file_async_pend_ops_kwait(file_desc_t *file, pio_async_op_type_t op_kind * Returns PIO_NOERR on success, a pio error code otherwise */ int pio_file_async_pend_op_add(file_desc_t *file, - pio_async_op_type_t op_type, void *pdata) + SPIO_Util::Async_op::Op_type op_type, void *pdata) { assert(file != NULL); - assert((op_type > PIO_ASYNC_INVALID_OP) - && (op_type < PIO_ASYNC_NUM_OP_TYPES)); + assert( (op_type != SPIO_Util::Async_op::Op_type::SPIO_ASYNC_INVALID_OP) && + ( (op_type == SPIO_Util::Async_op::Op_type::SPIO_ASYNC_REARR_OP) || + (op_type == SPIO_Util::Async_op::Op_type::SPIO_ASYNC_PNETCDF_WRITE_OP) ) ); + assert(pdata != NULL); - pio_async_op_t *pnew = (pio_async_op_t *) calloc(1, sizeof(pio_async_op_t)); - if(pnew == NULL){ - return pio_err(NULL, NULL, PIO_ENOMEM, __FILE__, __LINE__, - "Adding an asynchronous operation to file (%s, ncid=%d) failed. Unable to allocate %lld bytes to cache the asynchronous operation", pio_get_fname_from_file(file), file->pio_ncid, (unsigned long long) (sizeof(pio_async_op_t))); + if(op_type == SPIO_Util::Async_op::Op_type::SPIO_ASYNC_REARR_OP){ + file->async_pend_ops.push_back({op_type, pdata, + pio_swapm_wait, pio_swapm_iwait, pio_swapm_req_free}); } - - pnew->op_type = op_type; - pnew->pdata = pdata; - if(op_type == PIO_ASYNC_REARR_OP){ - pnew->wait = pio_swapm_wait; - pnew->poke = pio_swapm_iwait; - pnew->free = pio_swapm_req_free; + else if(op_type == SPIO_Util::Async_op::Op_type::SPIO_ASYNC_PNETCDF_WRITE_OP){ + file->async_pend_ops.push_back({op_type, pdata, + pio_async_wait_func_unavail, pio_async_poke_func_unavail, pio_viobuf_free}); } - else if(op_type == PIO_ASYNC_PNETCDF_WRITE_OP){ - /* Don't wait on individual ops, do coll wait on all ops */ - pnew->wait = pio_async_wait_func_unavail; - /* PnetCDF does not have a non-blocking test/poke function */ - pnew->poke = pio_async_poke_func_unavail; - pnew->free = pio_viobuf_free; + else{ + assert(0); } - pnew->next = file->async_pend_ops; - - file->async_pend_ops = pnew; - file->nasync_pend_ops++; return PIO_NOERR; } @@ -824,30 +702,23 @@ int pio_iosys_async_pend_ops_wait(iosystem_desc_t *iosys) int ret; assert(iosys != NULL); - if(iosys->nasync_pend_ops == 0){ - return PIO_NOERR; - } + if(iosys->async_pend_ops.empty()) { return PIO_NOERR; } + + for(std::deque::iterator iter = iosys->async_pend_ops.begin(); + iter != iosys->async_pend_ops.end();){ + SPIO_Util::Async_op op = *iter; - pio_async_op_t *p = iosys->async_pend_ops, *q=NULL; - while(p){ - LOG((2, "Waiting on async op, kind = %s", - (p->op_type == PIO_ASYNC_REARR_OP) ? "PIO_ASYNC_REARR_OP" : - ((p->op_type == PIO_ASYNC_PNETCDF_WRITE_OP) ? "PIO_ASYNC_PNETCDF_WRITE_OP" : - ((p->op_type == PIO_ASYNC_FILE_WRITE_OPS) ? "PIO_ASYNC_FILE_WRITE_OPS" : - "UNKNOWN")))); - assert(p->op_type == PIO_ASYNC_FILE_WRITE_OPS); - ret = p->wait(p->pdata); + assert(op.type() == SPIO_Util::Async_op::Op_type::SPIO_ASYNC_FILE_WRITE_OPS); + ret = op.wait(); if(ret != PIO_NOERR){ - return pio_err(NULL, NULL, PIO_EINTERNAL, __FILE__, __LINE__, - "Internal error waiting for pending asynchronous operations on iosystem (iosysid=%d). Waiting for an asynchronous operation failed.", iosys->iosysid); + return pio_err(iosys, NULL, PIO_EINTERNAL, __FILE__, __LINE__, + "Internal error waiting for pending asynchronous operations on iosystem (iosysid=%d). Waiting for an asynchronous operation (%s) failed.", + iosys->iosysid, SPIO_Util::Async_op::op_type_to_string(op.type()).c_str()); } - q = p; - p = p->next; - q->free(q->pdata); - free(q); + + op.free(); + iter = iosys->async_pend_ops.erase(iter); } - iosys->async_pend_ops = NULL; - iosys->nasync_pend_ops = 0; return PIO_NOERR; } @@ -862,20 +733,20 @@ int pio_iosys_async_pend_ops_wait(iosystem_desc_t *iosys) int pio_file_async_pend_op_wait(void *pdata) { int ret; - assert(pdata != NULL); - file_desc_t *file = (file_desc_t *)pdata; - if(file->nasync_pend_ops == 0){ - return PIO_NOERR; - } + file_desc_t *file = static_cast(pdata); + assert(file); + + if(file->async_pend_ops.empty()) { return PIO_NOERR; } /* We only wait for pending pnetcdf writes. So the caller * needs to make sure that no data rearrangement ops are * pending */ - ret = pio_file_async_pend_ops_kwait(file, PIO_ASYNC_PNETCDF_WRITE_OP); + ret = pio_file_async_pend_ops_kwait(file, SPIO_Util::Async_op::Op_type::SPIO_ASYNC_PNETCDF_WRITE_OP); if(ret != PIO_NOERR){ return pio_err(file->iosystem, file, ret, __FILE__, __LINE__, - "Internal error while waiting for pending asynchronous write operations on file (%s, ncid=%d) for the PIO_IOTYPE_PNETCDF iotype", pio_get_fname_from_file(file), file->pio_ncid); + "Internal error while waiting for pending asynchronous write operations on file (%s, ncid=%d) for the PIO_IOTYPE_PNETCDF iotype", + pio_get_fname_from_file(file), file->pio_ncid); } file->wb_pend = 0; @@ -891,9 +762,9 @@ int pio_file_async_pend_op_wait(void *pdata) void pio_file_close_and_free(void *pdata) { int ret; - assert(pdata != NULL); - file_desc_t *file = (file_desc_t *)pdata; + assert(file); + bool sync_with_ioprocs = false; ret = spio_hard_closefile(file->iosystem, file, sync_with_ioprocs); if(ret != PIO_NOERR){ @@ -909,32 +780,14 @@ void pio_file_close_and_free(void *pdata) * Returns PIO_NOERR on success, a pio error code otherwise */ int pio_iosys_async_pend_op_add(iosystem_desc_t *iosys, - pio_async_op_type_t op_type, void *pdata) + SPIO_Util::Async_op::Op_type op_type, void *pdata) { - assert(iosys != NULL); - assert((op_type > PIO_ASYNC_INVALID_OP) - && (op_type < PIO_ASYNC_NUM_OP_TYPES)); - assert(pdata != NULL); - assert(op_type == PIO_ASYNC_FILE_WRITE_OPS); - - pio_async_op_t *pnew = (pio_async_op_t *) calloc(1, sizeof(pio_async_op_t)); - if(pnew == NULL){ - return pio_err(NULL, NULL, PIO_ENOMEM, __FILE__, __LINE__, - "Internal error while adding a pending asynchronous operations on the iosystem (iosysid=%d). Unable to allocate %lld bytes to keep track of the asynchronous operation", iosys->iosysid, (unsigned long long) (sizeof(pio_async_op_t))); - } + assert((iosys != NULL) && (pdata != NULL)); + assert(op_type != SPIO_Util::Async_op::Op_type::SPIO_ASYNC_INVALID_OP); - pnew->op_type = op_type; - pnew->pdata = pdata; - if(op_type == PIO_ASYNC_FILE_WRITE_OPS){ - pnew->wait = pio_file_async_pend_op_wait; - /* File writes do not have a non-blocking test/poke function */ - pnew->poke = pio_async_poke_func_unavail; - pnew->free = pio_file_close_and_free; - } - pnew->next = iosys->async_pend_ops; - - iosys->async_pend_ops = pnew; - iosys->nasync_pend_ops++; + assert(op_type == SPIO_Util::Async_op::Op_type::SPIO_ASYNC_FILE_WRITE_OPS); + iosys->async_pend_ops.push_back({op_type, pdata, + pio_file_async_pend_op_wait, pio_async_poke_func_unavail, pio_file_close_and_free}); return PIO_NOERR; } @@ -946,31 +799,16 @@ int pio_iosys_async_pend_op_add(iosystem_desc_t *iosys, * Returns PIO_NOERR on success, a pio error code otherwise */ int pio_tpool_async_pend_op_add(iosystem_desc_t *iosys, - pio_async_op_type_t op_type, void *pdata) + SPIO_Util::Async_op::Op_type op_type, void *pdata) { int ret; - assert(iosys != NULL); - assert((op_type > PIO_ASYNC_INVALID_OP) - && (op_type < PIO_ASYNC_NUM_OP_TYPES)); - assert(pdata != NULL); - assert(op_type == PIO_ASYNC_FILE_WRITE_OPS); - - pio_async_op_t *pnew = (pio_async_op_t *) calloc(1, sizeof(pio_async_op_t)); - if(pnew == NULL){ - return pio_err(NULL, NULL, PIO_ENOMEM, __FILE__, __LINE__, - "Internal error while adding asynchronous pending operation to the thread pool (iosystem = %d). Unable to allocate %lld bytes to keep track of the asynchronous operation", iosys->iosysid, (unsigned long long) sizeof(pio_async_op_t)); - } + assert(iosys && pdata); + assert(op_type == SPIO_Util::Async_op::Op_type::SPIO_ASYNC_FILE_WRITE_OPS); - pnew->op_type = op_type; - pnew->pdata = pdata; - if(op_type == PIO_ASYNC_FILE_WRITE_OPS){ - pnew->wait = pio_file_async_pend_op_wait; - /* File writes do not have a non-blocking test/poke function */ - pnew->poke = pio_async_poke_func_unavail; - pnew->free = pio_file_close_and_free; - } + SPIO_Util::Async_op op = {op_type, pdata, pio_file_async_pend_op_wait, + pio_async_poke_func_unavail, pio_file_close_and_free}; - ret = pio_async_tpool_op_add(pnew); + ret = pio_async_tpool_op_add(op); if(ret != PIO_NOERR){ LOG((1, "Adding file pending ops to tpool failed, ret = %d", ret)); return pio_err(iosys, NULL, ret, __FILE__, __LINE__, @@ -1022,28 +860,25 @@ int pio_iosys_async_file_close_op_add(file_desc_t *file) { int ret = PIO_NOERR; - /* Create async task */ - pio_async_op_t *pnew = static_cast(calloc(1, sizeof(pio_async_op_t))); - if(pnew == NULL){ - return pio_err(file->iosystem, file, PIO_ENOMEM, __FILE__, __LINE__, - "Queuing asynchronous op/task for closing file (%s, ncid=%d) using PIO_IOTYPE_HDF5x failed. Allocating memory for async op task (%zu bytes)", pio_get_fname_from_file(file), file->pio_ncid, sizeof(pio_async_op_t)); - } + assert(file); - pnew->op_type = PIO_ASYNC_FILE_CLOSE_OP; - pnew->pdata = static_cast(file); - pnew->wait = pio_iosys_async_file_close_op_wait; - pnew->poke = pio_async_poke_func_unavail; - pnew->free = pio_iosys_async_file_close_op_free_no_op; + /* Create async task */ + SPIO_Util::Async_op op = {SPIO_Util::Async_op::Op_type::SPIO_ASYNC_FILE_CLOSE_OP, + static_cast(file), + pio_iosys_async_file_close_op_wait, + pio_async_poke_func_unavail, + pio_iosys_async_file_close_op_free_no_op}; //file->npend_ops++; SPIO_Util::GVars::npend_hdf5_async_ops++; /* Get the mt queue and queue the async task */ - ret = pio_async_tpool_op_add(pnew); + ret = pio_async_tpool_op_add(op); if(ret != PIO_NOERR){ LOG((1, "Adding file pending ops to tpool failed, ret = %d", ret)); - return pio_err(file->iosystem, file, PIO_ENOMEM, __FILE__, __LINE__, - "Queuing asynchronous op/task for closing file (%s, ncid=%d) using PIO_IOTYPE_HDF5x failed. Adding async op to thread pool failed", pio_get_fname_from_file(file), file->pio_ncid); + return pio_err(file->iosystem, file, PIO_EINTERNAL, __FILE__, __LINE__, + "Queuing asynchronous op/task for closing file (%s, ncid=%d) using PIO_IOTYPE_HDF5x failed. Adding async op to thread pool failed", + pio_get_fname_from_file(file), file->pio_ncid); } return PIO_NOERR; diff --git a/src/clib/spio_async_utils.hpp b/src/clib/spio_async_utils.hpp index 258e973c7d..981959462a 100644 --- a/src/clib/spio_async_utils.hpp +++ b/src/clib/spio_async_utils.hpp @@ -6,11 +6,12 @@ #include #include #include "spio_async_hdf5_utils.hpp" +#include "spio_async_op.hpp" -int pio_async_poke_func_unavail(void *pdata, int *flag); +int pio_async_poke_func_unavail(void *pdata, bool &flag); int pio_file_async_pend_ops_wait(file_desc_t *file); int pio_file_async_pend_op_add(file_desc_t *file, - pio_async_op_type_t op_type, void *pdata); + SPIO_Util::Async_op::Op_type op_type, void *pdata); int pio_var_rearr_and_cache(file_desc_t *file, var_desc_t *vdesc, io_desc_t *iodesc, void *buf, size_t buflen, void *fillvalue, int rec_num); @@ -20,14 +21,12 @@ int pio_file_compact_and_copy_rearr_data(void *dest, size_t dest_sz, const int *frames, int nvars); int pio_iosys_async_pend_op_add(iosystem_desc_t *iosys, - pio_async_op_type_t op_type, void *pdata); + SPIO_Util::Async_op::Op_type op_type, void *pdata); #if PIO_USE_ASYNC_WR_THREAD int pio_tpool_async_pend_op_add(iosystem_desc_t *iosys, - pio_async_op_type_t op_type, void *pdata); + SPIO_Util::Async_op::Op_type op_type, void *pdata); #endif // PIO_USE_ASYNC_WR_THREAD int pio_iosys_async_file_close_op_add(file_desc_t *file); -std::string pio_async_op_type_to_string(pio_async_op_type_t op); - #endif // _SPIO_ASYNC_UTILS_HPP_ diff --git a/tests/cunit/test_async_tpool.cpp b/tests/cunit/test_async_tpool.cpp index e8969e3e3f..9a891ed890 100644 --- a/tests/cunit/test_async_tpool.cpp +++ b/tests/cunit/test_async_tpool.cpp @@ -3,6 +3,7 @@ #include #include #include +#include "spio_async_op.hpp" #include "spio_async_mtq.hpp" #include "spio_async_tpool.hpp" extern "C"{ @@ -47,7 +48,7 @@ int pio_utype_wait(void *pdata) return PIO_NOERR; } -int pio_poke_func_unavail(void *pdata, int *) +int pio_poke_func_unavail(void *pdata, bool &flag) { assert(0); return PIO_NOERR; @@ -66,13 +67,10 @@ int tpool_enq_putype(int wrank, const int max_elems_in_q, std::vector &ud PIO_Util::PIO_async_tpool *tpool = tpool_mgr.get_tpool_instance(); for(int i=0; iop_type = PIO_ASYNC_FILE_WRITE_OPS; - op->pdata = &(udata[i]); - op->wait = pio_utype_wait; - op->poke = pio_poke_func_unavail; - op->free = pio_noop_free; + SPIO_Util::Async_op op = {SPIO_Util::Async_op::Op_type::SPIO_ASYNC_FILE_WRITE_OPS, + static_cast(&(udata[i])), + pio_utype_wait, pio_poke_func_unavail, pio_noop_free}; tpool->enqueue(op); } From 23b86cf19e6449944c02e0ce21173a447bc018f5 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Sat, 28 Feb 2026 19:48:04 -0600 Subject: [PATCH 141/194] Moving api build logic to subdir Moving build logic for the API layer (for /api/*.cpp) to the CMake config file inside the subdirectory. Using CMake interface libraries to package build flags. This change would allow us to modularize the CMake build logic within the config files --- src/clib/CMakeLists.txt | 285 ++++++++++++++++++------------------ src/clib/api/CMakeLists.txt | 37 +++++ 2 files changed, 178 insertions(+), 144 deletions(-) create mode 100644 src/clib/api/CMakeLists.txt diff --git a/src/clib/CMakeLists.txt b/src/clib/CMakeLists.txt index 1fb982d263..f8d1ba2925 100644 --- a/src/clib/CMakeLists.txt +++ b/src/clib/CMakeLists.txt @@ -4,53 +4,17 @@ include(CheckTypeSize) include(SPIOTypeUtils) project (PIOC C CXX) -message(STATUS "===== Configuring SCORPIO C library... =====") #============================================================================== -# DEFINE THE TARGET LIBRARY +# INTERFACE LIB : To cache compiler settings #============================================================================== -# PIO API source -set (pio_api_src - api/spio_lib_api.cpp - api/spio_ddata_api.cpp - api/spio_dim_api.cpp - api/spio_err_api.cpp - api/spio_file_api.cpp - api/spio_file_md_api.cpp - api/spio_get_att_api.cpp - api/spio_get_utils.cpp - api/spio_get_var1_api.cpp - api/spio_get_vara_api.cpp - api/spio_get_var_api.cpp - api/spio_get_varm_api.cpp - api/spio_get_vars_api.cpp - api/spio_io_decomp_api.cpp - api/spio_io_sys_api.cpp - api/spio_misc_att_api.cpp - api/spio_misc_var_api.cpp - api/spio_put_att_api.cpp - api/spio_put_var1_api.cpp - api/spio_put_vara_api.cpp - api/spio_put_var_api.cpp - api/spio_put_varm_api.cpp - api/spio_put_vars_api.cpp) - -# PIO lib source -set (pio_lib_src - topology.cpp pio_mpi_timer.cpp pio_timer.cpp pio_file.cpp - pioc_support.cpp pio_lists.cpp pio_print.cpp spio_dbg_ds.cpp - pioc.cpp pioc_sc.cpp pio_spmd.cpp pio_rearrange.cpp pio_rearr_utils.cpp pio_rearr_contig.cpp - pio_nc4.cpp bget.cpp - pio_nc.cpp pio_put_nc.cpp pio_get_nc.cpp pio_getput_int.cpp pio_msg.cpp pio_varm.cpp - pio_darray.cpp pio_darray_int.cpp spio_hash.cpp pio_sdecomps_regex.cpp spio_io_summary.cpp - spio_decomp_map_info_pool.cpp spio_decomp_nc_logger.cpp spio_decomp_txt_logger.cpp - spio_ltimer.cpp spio_serializer.cpp spio_file_mvcache.cpp - spio_tracer.cpp spio_tracer_mdata.cpp spio_tracer_decomp.cpp - spio_rearrange_any.cpp spio_dt_converter.cpp - spio_async_tpool.cpp spio_async_utils.cpp spio_async_tcomm.cpp - spio_hdf5_utils.cpp spio_async_hdf5_utils.cpp) +add_library (spio_default_public_options INTERFACE) +# Include the install include dir for all dep projects +target_include_directories(spio_default_public_options INTERFACE + $) -# Add sources for libpioc.a -add_library (pioc ${pio_api_src} ${pio_lib_src}) +add_library (spio_default_private_options INTERFACE) +set (spio_default_public_libs "") +set (spio_default_private_libs "") #============================================================================== # FIND EXTERNAL LIBRARIES/DEPENDENCIES @@ -73,29 +37,29 @@ if (PIO_ENABLE_TIMING) find_package (GPTL COMPONENTS C) if (GPTL_C_FOUND) message (STATUS "GPTL C library dependencies: ${GPTL_C_LIBRARIES}") - target_include_directories (pioc - PUBLIC ${GPTL_C_INCLUDE_DIRS}) - target_link_libraries (pioc - PUBLIC ${GPTL_C_LIBRARIES}) + target_include_directories (spio_default_public_options + INTERFACE ${GPTL_C_INCLUDE_DIRS}) + list (APPEND spio_default_public_libs ${GPTL_C_LIBRARIES}) # GPTL expects HAVE_MPI, if MPI is available, when using GPTL header files if (NOT PIO_USE_MPISERIAL) - target_compile_definitions (pioc PUBLIC HAVE_MPI) + target_compile_definitions (spio_default_public_options INTERFACE HAVE_MPI) endif () else () message (STATUS "Using internal GPTL C library for timing") - target_include_directories (pioc - PRIVATE ${PROJECT_SOURCE_DIR}/../gptl) - target_link_libraries (pioc - PUBLIC gptl) + target_include_directories (spio_default_private_options + INTERFACE $) + list (APPEND spio_default_public_libs gptl) endif () - target_compile_definitions (pioc - PUBLIC SPIO_ENABLE_GPTL_TIMING - PRIVATE TIMING) + target_compile_definitions (spio_default_public_options + INTERFACE SPIO_ENABLE_GPTL_TIMING) + target_compile_definitions(spio_default_private_options + INTERFACE TIMING) if (PIO_ENABLE_INTERNAL_TIMING) - target_compile_definitions (pioc - PUBLIC SPIO_ENABLE_GPTL_TIMING_INTERNAL - PRIVATE TIMING_INTERNAL) + target_compile_definitions (spio_default_public_options + INTERFACE SPIO_ENABLE_GPTL_TIMING_INTERNAL) + target_compile_definitions (spio_default_private_options + INTERFACE TIMING_INTERNAL) endif () endif () @@ -113,10 +77,9 @@ if (WITH_NETCDF) if (NetCDF_FOUND) message(STATUS "NetCDF C library dependencies: ${NetCDF_C_LIBRARIES}") set(PIO_USE_NETCDF 1) - target_include_directories (pioc - PUBLIC ${NetCDF_C_INCLUDE_DIRS}) - target_link_libraries (pioc - PUBLIC ${NetCDF_C_LIBRARIES}) + target_include_directories (spio_default_public_options + INTERFACE ${NetCDF_C_INCLUDE_DIRS}) + list (APPEND spio_default_public_libs ${NetCDF_C_LIBRARIES}) if (${NetCDF_C_HAS_PARALLEL}) set(PIO_USE_NETCDF4 1) set(PIO_USE_NETCDF4_NCZARR 0) @@ -124,8 +87,8 @@ if (WITH_NETCDF) if (PIO_ENABLE_NCZARR) message(STATUS "Enabling support for NCZarr") set(PIO_USE_NETCDF4_NCZARR 1) - target_compile_definitions (pioc - PUBLIC _SPIO_HAS_NETCDF4_NCZARR) + target_compile_definitions (spio_default_public_options + INTERFACE _SPIO_HAS_NETCDF4_NCZARR) else () message(STATUS "Disabling support for NCZarr (default)") endif () @@ -136,15 +99,15 @@ if (WITH_NETCDF) set(PIO_USE_NETCDF4 0) endif () if (${NetCDF_C_LOGGING_ENABLED}) - target_compile_definitions (pioc - PRIVATE NETCDF_C_LOGGING_ENABLED) + target_compile_definitions (spio_default_private_options + INTERFACE NETCDF_C_LOGGING_ENABLED) # netcdf.h needs this to be defined to use netCDF logging. - target_compile_definitions (pioc - PRIVATE LOGGING) + target_compile_definitions (spio_default_private_options + INTERFACE LOGGING) endif() if (${NetCDF_C_NC__ENDDEF_EXISTS}) - target_compile_definitions (pioc - PRIVATE NETCDF_C_NC__ENDDEF_EXISTS) + target_compile_definitions (spio_default_private_options + INTERFACE NETCDF_C_NC__ENDDEF_EXISTS) endif() else () message(STATUS "Could not find NetCDF C library, disabling support for NetCDF") @@ -170,18 +133,18 @@ if (WITH_PNETCDF) if (PnetCDF_FOUND) message(STATUS "PnetCDF C library dependencies: ${PnetCDF_C_LIBRARY}") set(PIO_USE_PNETCDF 1) - target_include_directories (pioc - PUBLIC ${PnetCDF_C_INCLUDE_DIRS}) - target_link_libraries (pioc - PUBLIC ${PnetCDF_C_LIBRARIES}) + target_include_directories (spio_default_public_options + INTERFACE ${PnetCDF_C_INCLUDE_DIRS}) + list (APPEND spio_default_public_libs ${PnetCDF_C_LIBRARIES}) # Check library for varn functions set (CMAKE_REQUIRED_LIBRARIES ${PnetCDF_C_LIBRARY}) check_function_exists (ncmpi_get_varn PnetCDF_C_HAS_VARN) if (PnetCDF_C_HAS_VARN) - target_compile_definitions(pioc - PRIVATE USE_PNETCDF_VARN - PRIVATE USE_PNETCDF_VARN_ON_READ) + target_compile_definitions(spio_default_private_options + INTERFACE USE_PNETCDF_VARN) + target_compile_definitions(spio_default_private_options + INTERFACE USE_PNETCDF_VARN_ON_READ) endif() else () message(STATUS "Could not find PnetCDF library, disabling support for PnetCDF") @@ -209,14 +172,14 @@ if (WITH_ADIOS2) if (ADIOS2_FOUND) message(STATUS "Found ADIOS library") set(PIO_USE_ADIOS 1) - target_compile_definitions (pioc - PUBLIC _ADIOS2) + target_compile_definitions (spio_default_public_options + INTERFACE _ADIOS2) # 2001 edition of the POSIX standard (IEEE Standard 1003.1-2001) # Required for symlink() support/decl in unistd.h - target_compile_definitions (pioc - PRIVATE _POSIX_C_SOURCE=200112L) - target_link_libraries (pioc - PUBLIC adios2::adios2 adios2pio-nm-lib) + target_compile_definitions (spio_default_private_options + INTERFACE _POSIX_C_SOURCE=200112L) + list (APPEND spio_default_public_libs "adios2::adios2") + list (APPEND spio_default_public_libs "adios2pio-nm-lib") else () message(STATUS "Could not find ADIOS library, disabling support for ADIOS") set(PIO_USE_ADIOS 0) @@ -232,12 +195,13 @@ if (WITH_HDF5) if (HDF5_C_FOUND) message(STATUS "HDF5 C library dependencies: ${HDF5_C_LIBRARIES} ${HDF5_HL_LIBRARIES}") set(PIO_USE_HDF5 1) - target_compile_definitions (pioc - PUBLIC _HDF5) - target_include_directories (pioc - PUBLIC ${HDF5_C_INCLUDE_DIRS} ${HDF5_HL_INCLUDE_DIRS}) - target_link_libraries (pioc - PUBLIC ${HDF5_C_LIBRARIES} ${HDF5_HL_LIBRARIES} ${CMAKE_DL_LIBS}) + target_compile_definitions (spio_default_public_options + INTERFACE _HDF5) + target_include_directories (spio_default_public_options + INTERFACE ${HDF5_C_INCLUDE_DIRS} ${HDF5_HL_INCLUDE_DIRS}) + list (APPEND spio_default_public_libs ${HDF5_C_LIBRARIES}) + list (APPEND spio_default_public_libs ${HDF5_HL_LIBRARIES}) + list (APPEND spio_default_public_libs ${CMAKE_DL_LIBS}) # Look for HDF5 ZFP (compression library) filter library set(H5Z_ZFP_USE_STATIC_LIBS ON) @@ -253,8 +217,8 @@ if (WITH_HDF5) find_package(H5Z_ZFP) if (H5Z_ZFP_FOUND) message (STATUS "Found ZFP filter for HDF5") - target_compile_definitions (pioc PUBLIC _SPIO_HAS_H5Z_ZFP) - target_link_libraries (pioc PUBLIC h5z_zfp::h5z_zfp) + target_compile_definitions (spio_default_public_options INTERFACE _SPIO_HAS_H5Z_ZFP) + list (APPEND spio_default_public_libs "h5z_zfp::h5z_zfp") else () message (STATUS "Could not find ZFP filter for HDF5, disabling ZFP with HDF5") endif () @@ -268,8 +232,8 @@ if (WITH_HDF5) find_package(H5Z_BLOSC2) if (H5Z_BLOSC2_FOUND) message (STATUS "Found BLOSC2 filter for HDF5") - target_compile_definitions (pioc PUBLIC _SPIO_HAS_H5Z_BLOSC2) - target_link_libraries (pioc PUBLIC h5z_blosc2::h5z_blosc2) + target_compile_definitions (spio_default_public_options INTERFACE _SPIO_HAS_H5Z_BLOSC2) + list (APPEND spio_default_public_libs "h5z_blosc2::h5z_blosc2") else () message (STATUS "Could not find Blosc2 filter, disabling HDF5 filter for Blosc2") endif () @@ -331,50 +295,46 @@ include_directories( "${PROJECT_BINARY_DIR}") # to find foo/config.h # Include the clib source and binary directory -target_include_directories (pioc - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) -target_include_directories (pioc - PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) - -# Include the install include dir for all dep projects -target_include_directories (pioc - PUBLIC $) +target_include_directories (spio_default_private_options + INTERFACE $) +target_include_directories (spio_default_private_options + INTERFACE $) # System and compiler CPP directives -target_compile_definitions (pioc - PRIVATE ${CMAKE_SYSTEM_DIRECTIVE}) -target_compile_definitions (pioc - PUBLIC ${CMAKE_C_COMPILER_DIRECTIVE}) +target_compile_definitions (spio_default_public_options + INTERFACE ${CMAKE_SYSTEM_DIRECTIVE}) +target_compile_definitions (spio_default_public_options + INTERFACE ${CMAKE_C_COMPILER_DIRECTIVE}) # Skip MPI C++ headers/bindings for MPICH lib -target_compile_definitions (pioc - PUBLIC MPICH_SKIP_MPICXX) +target_compile_definitions (spio_default_public_options + INTERFACE MPICH_SKIP_MPICXX) # Skip MPI C++ headers/bindings for OpenMPI lib -target_compile_definitions (pioc - PUBLIC OMPI_SKIP_MPICXX) +target_compile_definitions (spio_default_public_options + INTERFACE OMPI_SKIP_MPICXX) # Skip MPI C++ headers/bindings for SGI MPT lib -target_compile_definitions (pioc - PUBLIC MPI_NO_CPPBIND) +target_compile_definitions (spio_default_public_options + INTERFACE MPI_NO_CPPBIND) # Add user-specified include/libs/compiler/link options -target_include_directories (pioc - PUBLIC ${PIO_C_EXTRA_INCLUDE_DIRS}) -target_link_libraries (pioc - PUBLIC ${PIO_C_EXTRA_LIBRARIES}) -target_compile_options (pioc - PRIVATE ${PIO_C_EXTRA_COMPILE_OPTIONS}) -target_compile_definitions (pioc - PUBLIC ${PIO_C_EXTRA_COMPILE_DEFINITIONS}) +target_include_directories (spio_default_public_options + INTERFACE ${PIO_C_EXTRA_INCLUDE_DIRS}) +target_link_libraries (spio_default_public_options + INTERFACE ${PIO_C_EXTRA_LIBRARIES}) +target_compile_options (spio_default_public_options + INTERFACE ${PIO_C_EXTRA_COMPILE_OPTIONS}) +target_compile_definitions (spio_default_public_options + INTERFACE ${PIO_C_EXTRA_COMPILE_DEFINITIONS}) if (PIO_C_EXTRA_LINK_FLAGS) - set_target_properties(pioc PROPERTIES - LINK_FLAGS ${PIO_C_EXTRA_LINK_FLAGS}) + target_link_options(spio_default_public_options + INTERFACE ${PIO_C_EXTRA_LINK_FLAGS}) endif () # At least on Titan + Cray MPI, MPI_Irsends are buggy # causing hangs during I/O # Force Scorpio to use MPI_Isends instead of the default # MPI_Irsends -target_compile_definitions (pioc - PRIVATE USE_MPI_ISEND_FOR_FC) +target_compile_definitions (spio_default_private_options + INTERFACE USE_MPI_ISEND_FOR_FC) # Compiler-specific compiler options string (TOUPPER "${CMAKE_C_COMPILER_ID}" CMAKE_C_COMPILER_NAME) @@ -397,14 +357,14 @@ endif () if (ADIOS_BP2NC_TEST) message(STATUS "Building ADIOS to NetCDF conversion tool") - target_compile_definitions (pioc - PUBLIC _ADIOS_BP2NC_TEST) + target_compile_definitions (spio_default_public_options + INTERFACE _ADIOS_BP2NC_TEST) endif () if (ADIOS_NO_DECOMPS) message(STATUS "No decomposition data will be saved to ADIOS BP files to reduce disk usage") - target_compile_definitions (pioc - PUBLIC _SPIO_ADIOS_NO_DECOMPS) + target_compile_definitions (spio_default_public_options + INTERFACE _SPIO_ADIOS_NO_DECOMPS) endif () if (ADIOS_USE_COMPRESSION) @@ -414,8 +374,8 @@ if (ADIOS_USE_COMPRESSION) message(STATUS "Blosc2 compression level (range: 0 – 9) = 1 (default)") message(STATUS "Blosc2 shuffle mode (option: BLOSC_SHUFFLE, BLOSC_NOSHUFFLE, BLOSC_BITSHUFFLE) = BLOSC_BITSHUFFLE (default)") message(STATUS "These are the default settings for lossless compression. Use -DSPIO_COMPRESSION_OPTIONS to change the defaults") - target_compile_definitions (pioc - PUBLIC _SPIO_ADIOS_USE_COMPRESSION) + target_compile_definitions (spio_default_public_options + INTERFACE _SPIO_ADIOS_USE_COMPRESSION) endif () if (ADIOS_USE_LOSSY_COMPRESSION) @@ -424,8 +384,8 @@ if (ADIOS_USE_LOSSY_COMPRESSION) message(STATUS "Lossy compression error bound = 0.001 (default)") message(STATUS "These are the default settings for lossy compression. Use -DSPIO_COMPRESSION_OPTIONS to change the defaults") message(WARNING "The SZ or MGARD methods only support float or double types. For other types, lossless compression will be used instead") - target_compile_definitions (pioc - PRIVATE _SPIO_ADIOS_USE_LOSSY_COMPRESSION) + target_compile_definitions (spio_default_public_options + INTERFACE _SPIO_ADIOS_USE_LOSSY_COMPRESSION) endif () if (HDF5_USE_COMPRESSION) @@ -435,8 +395,8 @@ if (HDF5_USE_COMPRESSION) message(STATUS "Blosc2 compression level (range: 0 – 9) = 1 (default)") message(STATUS "Blosc2 shuffle mode (option: BLOSC_SHUFFLE, BLOSC_NOSHUFFLE, BLOSC_BITSHUFFLE) = BLOSC_BITSHUFFLE (default)") message(STATUS "These are the default settings for lossless compression. Use -DSPIO_COMPRESSION_OPTIONS to change the defaults") - target_compile_definitions (pioc - PUBLIC _SPIO_HDF5_USE_COMPRESSION) + target_compile_definitions (spio_default_public_options + INTERFACE _SPIO_HDF5_USE_COMPRESSION) endif () if (HDF5_USE_LOSSY_COMPRESSION) @@ -444,8 +404,8 @@ if (HDF5_USE_LOSSY_COMPRESSION) message(STATUS "Currently supported lossy compression methods : ZFP (default)") message(STATUS "Lossy compression error bound = 0.001 (default)") message(STATUS "These are the default settings for lossy compression. Use -DSPIO_COMPRESSION_OPTIONS to change the defaults") - target_compile_definitions (pioc - PRIVATE _SPIO_HDF5_USE_LOSSY_COMPRESSION) + target_compile_definitions (spio_default_public_options + INTERFACE _SPIO_HDF5_USE_LOSSY_COMPRESSION) endif () if (PIO_ENABLE_API_TRACING) @@ -466,12 +426,11 @@ endif () # The MPI library detection was done in the top level if (MPISERIAL_C_FOUND) - target_compile_definitions (pioc - PUBLIC MPI_SERIAL) - target_include_directories (pioc - PUBLIC ${MPISERIAL_C_INCLUDE_DIRS}) - target_link_libraries (pioc - PUBLIC ${MPISERIAL_C_LIBRARIES}) + target_compile_definitions (spio_default_public_options + INTERFACE MPI_SERIAL) + target_include_directories (spio_default_public_options + INTERFACE ${MPISERIAL_C_INCLUDE_DIRS}) + list (APPEND spio_default_public_libs ${MPISERIAL_C_LIBRARIES}) set (WITH_PNETCDF FALSE) endif () @@ -495,12 +454,50 @@ else () set(USE_MICRO_TIMING 0) endif () +#============================================================================== +# DEFINE THE TARGET LIBRARY +#============================================================================== +message(STATUS "===== Configuring SCORPIO C library... =====") +# PIO lib source +set (pio_lib_src + topology.cpp pio_mpi_timer.cpp pio_timer.cpp pio_file.cpp + pioc_support.cpp pio_lists.cpp pio_print.cpp spio_dbg_ds.cpp + pioc.cpp pioc_sc.cpp pio_spmd.cpp pio_rearrange.cpp pio_rearr_utils.cpp pio_rearr_contig.cpp + pio_nc4.cpp bget.cpp + pio_nc.cpp pio_put_nc.cpp pio_get_nc.cpp pio_getput_int.cpp pio_msg.cpp pio_varm.cpp + pio_darray.cpp pio_darray_int.cpp spio_hash.cpp pio_sdecomps_regex.cpp spio_io_summary.cpp + spio_decomp_map_info_pool.cpp spio_decomp_nc_logger.cpp spio_decomp_txt_logger.cpp + spio_ltimer.cpp spio_serializer.cpp spio_file_mvcache.cpp + spio_tracer.cpp spio_tracer_mdata.cpp spio_tracer_decomp.cpp + spio_rearrange_any.cpp spio_dt_converter.cpp + spio_async_tpool.cpp spio_async_utils.cpp spio_async_tcomm.cpp + spio_hdf5_utils.cpp spio_async_hdf5_utils.cpp) + +# Add subdirectories +add_subdirectory (api) +# Add sources for libpioc.a +add_library (pioc ${pio_lib_src} + $) +target_link_libraries (pioc + PUBLIC spio_default_public_options + PUBLIC ${spio_default_public_libs} + PRIVATE spio_default_private_options) + +# FIXME: CMake 3.26+ can completely hide the local private interface lib +# (No need to export it) +# PRIVATE $) + #============================================================================== # INSTALL #============================================================================== -# Install libpioc.a -install (TARGETS pioc +# 1. Install Interface library, spio_default_public_options, that contains +# all the public compiler options +# 2. Installing private interface library, spio_default_private_options, that +# contains all private compiler options. CMake 3.26+ can get rid of exporting +# this interface library using BUILD_LOCAL_INTERFACE generator expression +# 3. Install pioc (libpioc.a) +install (TARGETS pioc spio_default_public_options spio_default_private_options EXPORT spio-targets-pioc DESTINATION lib) diff --git a/src/clib/api/CMakeLists.txt b/src/clib/api/CMakeLists.txt new file mode 100644 index 0000000000..24ddd9b073 --- /dev/null +++ b/src/clib/api/CMakeLists.txt @@ -0,0 +1,37 @@ +#============================================================================== +# DEFINE THE TARGET LIBRARY +#============================================================================== +message(STATUS "===== Configuring SCORPIO C API ... =====") +# PIO API source +set (pio_api_src + spio_lib_api.cpp + spio_ddata_api.cpp + spio_dim_api.cpp + spio_err_api.cpp + spio_file_api.cpp + spio_file_md_api.cpp + spio_get_att_api.cpp + spio_get_utils.cpp + spio_get_var1_api.cpp + spio_get_vara_api.cpp + spio_get_var_api.cpp + spio_get_varm_api.cpp + spio_get_vars_api.cpp + spio_io_decomp_api.cpp + spio_io_sys_api.cpp + spio_misc_att_api.cpp + spio_misc_var_api.cpp + spio_put_att_api.cpp + spio_put_var1_api.cpp + spio_put_vara_api.cpp + spio_put_var_api.cpp + spio_put_varm_api.cpp + spio_put_vars_api.cpp) + +add_library (pioc_api OBJECT ${pio_api_src}) +target_include_directories(pioc_api + PUBLIC . + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/..) +target_link_libraries(pioc_api + PUBLIC spio_default_public_options + PRIVATE spio_default_private_options) From 52e25f1114f9a584468c75e8a61f969c92c9c6f6 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 3 Mar 2026 12:13:27 -0600 Subject: [PATCH 142/194] Code restructring - to core, util Moving sources from clib to core and util directories for better code organization. Removing the list of dependency libs and using the interface lib for all dependencies. Updating the location of headers and removing unused headers. Also updating the source include locations for unit tests. --- src/clib/CMakeLists.txt | 57 ++++++++----------- src/clib/api/CMakeLists.txt | 2 +- src/clib/core/CMakeLists.txt | 46 +++++++++++++++ .../{ => core}/README_pio_micro_timers.txt | 0 .../{ => core}/README_pio_sdecomps_regex.txt | 0 .../{ => core}/README_trace_and_replay.txt | 0 .../{ => core}/io_perf_summary.json_expected | 0 .../{ => core}/io_perf_summary.schema.json | 0 .../{ => core}/io_perf_summary.text_expected | 0 .../{ => core}/io_perf_summary.xml_expected | 0 src/clib/{ => core}/pio_darray.cpp | 0 src/clib/{ => core}/pio_darray_int.cpp | 0 src/clib/{ => core}/pio_file.cpp | 0 src/clib/{ => core}/pio_get_nc.cpp | 0 src/clib/{ => core}/pio_getput_int.cpp | 0 src/clib/{ => core}/pio_lists.cpp | 0 src/clib/{ => core}/pio_msg.cpp | 0 src/clib/{ => core}/pio_nc.cpp | 0 src/clib/{ => core}/pio_nc4.cpp | 0 src/clib/{ => core}/pio_print.cpp | 0 src/clib/{ => core}/pio_put_nc.cpp | 0 src/clib/{ => core}/pio_rearr_contig.cpp | 0 src/clib/{ => core}/pio_rearr_contig.hpp | 0 src/clib/{ => core}/pio_rearr_utils.cpp | 0 src/clib/{ => core}/pio_rearr_utils.hpp | 0 src/clib/{ => core}/pio_rearrange.cpp | 0 src/clib/{ => core}/pio_sdecomps_regex.cpp | 0 src/clib/{ => core}/pio_sdecomps_regex.h | 0 src/clib/{ => core}/pio_sdecomps_regex.hpp | 0 src/clib/{ => core}/pio_spmd.cpp | 0 src/clib/{ => core}/pio_varm.cpp | 0 src/clib/{ => core}/pioc.cpp | 0 src/clib/{ => core}/pioc_sc.cpp | 0 src/clib/{ => core}/pioc_support.cpp | 0 src/clib/{ => core}/spio_async_hdf5_utils.cpp | 0 src/clib/{ => core}/spio_async_hdf5_utils.hpp | 0 src/clib/{ => core}/spio_async_mtq.hpp | 0 src/clib/{ => core}/spio_async_op.hpp | 0 src/clib/{ => core}/spio_async_tcomm.cpp | 0 src/clib/{ => core}/spio_async_tcomm.hpp | 0 src/clib/{ => core}/spio_async_tpool.cpp | 0 src/clib/{ => core}/spio_async_tpool.hpp | 0 src/clib/{ => core}/spio_async_utils.cpp | 0 src/clib/{ => core}/spio_async_utils.hpp | 0 src/clib/{ => core}/spio_decomp_logger.hpp | 0 .../{ => core}/spio_decomp_map_info_pool.cpp | 0 .../{ => core}/spio_decomp_map_info_pool.hpp | 0 src/clib/{ => core}/spio_decomp_nc_logger.cpp | 0 .../{ => core}/spio_decomp_txt_logger.cpp | 0 src/clib/{ => core}/spio_file_mvcache.cpp | 0 src/clib/{ => core}/spio_file_mvcache.h | 0 src/clib/{ => core}/spio_file_mvcache.hpp | 0 src/clib/{ => core}/spio_hdf5_utils.cpp | 0 src/clib/{ => core}/spio_hdf5_utils.hpp | 0 src/clib/{ => core}/spio_io_summary.cpp | 0 src/clib/{ => core}/spio_io_summary.h | 0 src/clib/{ => core}/spio_io_summary.hpp | 0 src/clib/{ => core}/spio_rearrange_any.cpp | 0 src/clib/{ => core}/spio_rearrange_any.h | 0 src/clib/{ => core}/spio_serializer.cpp | 0 src/clib/{ => core}/spio_serializer.hpp | 0 src/clib/{ => core}/spio_sort_utils.hpp | 0 src/clib/dtypes.h | 5 -- src/clib/pio_internal.h | 4 +- src/clib/pio_types.hpp | 2 +- src/clib/util/CMakeLists.txt | 25 ++++++++ src/clib/{ => util}/bget.cpp | 0 src/clib/{ => util}/bget.h | 0 src/clib/{ => util}/gptl_skel.h | 0 src/clib/{ => util}/pio_minmax.h | 0 src/clib/{ => util}/pio_mpi_timer.cpp | 0 src/clib/{ => util}/pio_timer.cpp | 0 src/clib/{ => util}/pio_timer.h | 0 src/clib/{ => util}/spio_dbg_ds.cpp | 0 src/clib/{ => util}/spio_dbg_utils.hpp | 0 src/clib/{ => util}/spio_dt_converter.cpp | 0 src/clib/{ => util}/spio_dt_converter.hpp | 1 - src/clib/{ => util}/spio_gptl_utils.hpp | 0 src/clib/{ => util}/spio_hash.cpp | 0 src/clib/{ => util}/spio_hash.h | 0 src/clib/{ => util}/spio_logger.hpp | 0 src/clib/{ => util}/spio_ltimer.cpp | 0 src/clib/{ => util}/spio_ltimer.h | 0 src/clib/{ => util}/spio_ltimer.hpp | 0 src/clib/{ => util}/spio_ltimer_utils.hpp | 0 src/clib/{ => util}/spio_map_sorter.hpp | 0 src/clib/{ => util}/spio_tracer.cpp | 0 src/clib/{ => util}/spio_tracer.hpp | 0 src/clib/{ => util}/spio_tracer_decomp.cpp | 0 src/clib/{ => util}/spio_tracer_decomp.hpp | 0 src/clib/{ => util}/spio_tracer_mdata.cpp | 0 src/clib/{ => util}/spio_tracer_mdata.hpp | 0 src/clib/{ => util}/spio_tree.hpp | 0 src/clib/{ => util}/topology.cpp | 0 tests/cunit/CMakeLists.txt | 2 +- 95 files changed, 101 insertions(+), 43 deletions(-) create mode 100644 src/clib/core/CMakeLists.txt rename src/clib/{ => core}/README_pio_micro_timers.txt (100%) rename src/clib/{ => core}/README_pio_sdecomps_regex.txt (100%) rename src/clib/{ => core}/README_trace_and_replay.txt (100%) rename src/clib/{ => core}/io_perf_summary.json_expected (100%) rename src/clib/{ => core}/io_perf_summary.schema.json (100%) rename src/clib/{ => core}/io_perf_summary.text_expected (100%) rename src/clib/{ => core}/io_perf_summary.xml_expected (100%) rename src/clib/{ => core}/pio_darray.cpp (100%) rename src/clib/{ => core}/pio_darray_int.cpp (100%) rename src/clib/{ => core}/pio_file.cpp (100%) rename src/clib/{ => core}/pio_get_nc.cpp (100%) rename src/clib/{ => core}/pio_getput_int.cpp (100%) rename src/clib/{ => core}/pio_lists.cpp (100%) rename src/clib/{ => core}/pio_msg.cpp (100%) rename src/clib/{ => core}/pio_nc.cpp (100%) rename src/clib/{ => core}/pio_nc4.cpp (100%) rename src/clib/{ => core}/pio_print.cpp (100%) rename src/clib/{ => core}/pio_put_nc.cpp (100%) rename src/clib/{ => core}/pio_rearr_contig.cpp (100%) rename src/clib/{ => core}/pio_rearr_contig.hpp (100%) rename src/clib/{ => core}/pio_rearr_utils.cpp (100%) rename src/clib/{ => core}/pio_rearr_utils.hpp (100%) rename src/clib/{ => core}/pio_rearrange.cpp (100%) rename src/clib/{ => core}/pio_sdecomps_regex.cpp (100%) rename src/clib/{ => core}/pio_sdecomps_regex.h (100%) rename src/clib/{ => core}/pio_sdecomps_regex.hpp (100%) rename src/clib/{ => core}/pio_spmd.cpp (100%) rename src/clib/{ => core}/pio_varm.cpp (100%) rename src/clib/{ => core}/pioc.cpp (100%) rename src/clib/{ => core}/pioc_sc.cpp (100%) rename src/clib/{ => core}/pioc_support.cpp (100%) rename src/clib/{ => core}/spio_async_hdf5_utils.cpp (100%) rename src/clib/{ => core}/spio_async_hdf5_utils.hpp (100%) rename src/clib/{ => core}/spio_async_mtq.hpp (100%) rename src/clib/{ => core}/spio_async_op.hpp (100%) rename src/clib/{ => core}/spio_async_tcomm.cpp (100%) rename src/clib/{ => core}/spio_async_tcomm.hpp (100%) rename src/clib/{ => core}/spio_async_tpool.cpp (100%) rename src/clib/{ => core}/spio_async_tpool.hpp (100%) rename src/clib/{ => core}/spio_async_utils.cpp (100%) rename src/clib/{ => core}/spio_async_utils.hpp (100%) rename src/clib/{ => core}/spio_decomp_logger.hpp (100%) rename src/clib/{ => core}/spio_decomp_map_info_pool.cpp (100%) rename src/clib/{ => core}/spio_decomp_map_info_pool.hpp (100%) rename src/clib/{ => core}/spio_decomp_nc_logger.cpp (100%) rename src/clib/{ => core}/spio_decomp_txt_logger.cpp (100%) rename src/clib/{ => core}/spio_file_mvcache.cpp (100%) rename src/clib/{ => core}/spio_file_mvcache.h (100%) rename src/clib/{ => core}/spio_file_mvcache.hpp (100%) rename src/clib/{ => core}/spio_hdf5_utils.cpp (100%) rename src/clib/{ => core}/spio_hdf5_utils.hpp (100%) rename src/clib/{ => core}/spio_io_summary.cpp (100%) rename src/clib/{ => core}/spio_io_summary.h (100%) rename src/clib/{ => core}/spio_io_summary.hpp (100%) rename src/clib/{ => core}/spio_rearrange_any.cpp (100%) rename src/clib/{ => core}/spio_rearrange_any.h (100%) rename src/clib/{ => core}/spio_serializer.cpp (100%) rename src/clib/{ => core}/spio_serializer.hpp (100%) rename src/clib/{ => core}/spio_sort_utils.hpp (100%) delete mode 100644 src/clib/dtypes.h create mode 100644 src/clib/util/CMakeLists.txt rename src/clib/{ => util}/bget.cpp (100%) rename src/clib/{ => util}/bget.h (100%) rename src/clib/{ => util}/gptl_skel.h (100%) rename src/clib/{ => util}/pio_minmax.h (100%) rename src/clib/{ => util}/pio_mpi_timer.cpp (100%) rename src/clib/{ => util}/pio_timer.cpp (100%) rename src/clib/{ => util}/pio_timer.h (100%) rename src/clib/{ => util}/spio_dbg_ds.cpp (100%) rename src/clib/{ => util}/spio_dbg_utils.hpp (100%) rename src/clib/{ => util}/spio_dt_converter.cpp (100%) rename src/clib/{ => util}/spio_dt_converter.hpp (99%) rename src/clib/{ => util}/spio_gptl_utils.hpp (100%) rename src/clib/{ => util}/spio_hash.cpp (100%) rename src/clib/{ => util}/spio_hash.h (100%) rename src/clib/{ => util}/spio_logger.hpp (100%) rename src/clib/{ => util}/spio_ltimer.cpp (100%) rename src/clib/{ => util}/spio_ltimer.h (100%) rename src/clib/{ => util}/spio_ltimer.hpp (100%) rename src/clib/{ => util}/spio_ltimer_utils.hpp (100%) rename src/clib/{ => util}/spio_map_sorter.hpp (100%) rename src/clib/{ => util}/spio_tracer.cpp (100%) rename src/clib/{ => util}/spio_tracer.hpp (100%) rename src/clib/{ => util}/spio_tracer_decomp.cpp (100%) rename src/clib/{ => util}/spio_tracer_decomp.hpp (100%) rename src/clib/{ => util}/spio_tracer_mdata.cpp (100%) rename src/clib/{ => util}/spio_tracer_mdata.hpp (100%) rename src/clib/{ => util}/spio_tree.hpp (100%) rename src/clib/{ => util}/topology.cpp (100%) diff --git a/src/clib/CMakeLists.txt b/src/clib/CMakeLists.txt index f8d1ba2925..05bebfcc58 100644 --- a/src/clib/CMakeLists.txt +++ b/src/clib/CMakeLists.txt @@ -13,8 +13,9 @@ target_include_directories(spio_default_public_options INTERFACE $) add_library (spio_default_private_options INTERFACE) -set (spio_default_public_libs "") -set (spio_default_private_libs "") +# Include the install include dir for all dep projects +target_include_directories(spio_default_private_options INTERFACE + $) #============================================================================== # FIND EXTERNAL LIBRARIES/DEPENDENCIES @@ -39,7 +40,7 @@ if (PIO_ENABLE_TIMING) message (STATUS "GPTL C library dependencies: ${GPTL_C_LIBRARIES}") target_include_directories (spio_default_public_options INTERFACE ${GPTL_C_INCLUDE_DIRS}) - list (APPEND spio_default_public_libs ${GPTL_C_LIBRARIES}) + target_link_libraries (spio_default_public_options INTERFACE ${GPTL_C_LIBRARIES}) # GPTL expects HAVE_MPI, if MPI is available, when using GPTL header files if (NOT PIO_USE_MPISERIAL) @@ -49,7 +50,7 @@ if (PIO_ENABLE_TIMING) message (STATUS "Using internal GPTL C library for timing") target_include_directories (spio_default_private_options INTERFACE $) - list (APPEND spio_default_public_libs gptl) + target_link_libraries (spio_default_public_options INTERFACE gptl) endif () target_compile_definitions (spio_default_public_options INTERFACE SPIO_ENABLE_GPTL_TIMING) @@ -79,7 +80,7 @@ if (WITH_NETCDF) set(PIO_USE_NETCDF 1) target_include_directories (spio_default_public_options INTERFACE ${NetCDF_C_INCLUDE_DIRS}) - list (APPEND spio_default_public_libs ${NetCDF_C_LIBRARIES}) + target_link_libraries (spio_default_public_options INTERFACE ${NetCDF_C_LIBRARIES}) if (${NetCDF_C_HAS_PARALLEL}) set(PIO_USE_NETCDF4 1) set(PIO_USE_NETCDF4_NCZARR 0) @@ -135,7 +136,7 @@ if (WITH_PNETCDF) set(PIO_USE_PNETCDF 1) target_include_directories (spio_default_public_options INTERFACE ${PnetCDF_C_INCLUDE_DIRS}) - list (APPEND spio_default_public_libs ${PnetCDF_C_LIBRARIES}) + target_link_libraries (spio_default_public_options INTERFACE ${PnetCDF_C_LIBRARIES}) # Check library for varn functions set (CMAKE_REQUIRED_LIBRARIES ${PnetCDF_C_LIBRARY}) @@ -178,8 +179,7 @@ if (WITH_ADIOS2) # Required for symlink() support/decl in unistd.h target_compile_definitions (spio_default_private_options INTERFACE _POSIX_C_SOURCE=200112L) - list (APPEND spio_default_public_libs "adios2::adios2") - list (APPEND spio_default_public_libs "adios2pio-nm-lib") + target_link_libraries (spio_default_public_options INTERFACE adios2::adios2 adios2pio-nm-lib) else () message(STATUS "Could not find ADIOS library, disabling support for ADIOS") set(PIO_USE_ADIOS 0) @@ -199,9 +199,7 @@ if (WITH_HDF5) INTERFACE _HDF5) target_include_directories (spio_default_public_options INTERFACE ${HDF5_C_INCLUDE_DIRS} ${HDF5_HL_INCLUDE_DIRS}) - list (APPEND spio_default_public_libs ${HDF5_C_LIBRARIES}) - list (APPEND spio_default_public_libs ${HDF5_HL_LIBRARIES}) - list (APPEND spio_default_public_libs ${CMAKE_DL_LIBS}) + target_link_libraries (spio_default_public_options INTERFACE ${HDF5_C_LIBRARIES} ${HDF5_HL_LIBRARIES} ${CMAKE_DL_LIBS}) # Look for HDF5 ZFP (compression library) filter library set(H5Z_ZFP_USE_STATIC_LIBS ON) @@ -218,7 +216,8 @@ if (WITH_HDF5) if (H5Z_ZFP_FOUND) message (STATUS "Found ZFP filter for HDF5") target_compile_definitions (spio_default_public_options INTERFACE _SPIO_HAS_H5Z_ZFP) - list (APPEND spio_default_public_libs "h5z_zfp::h5z_zfp") + target_include_directories (spio_default_public_options INTERFACE ${H5Z_ZFP_INCLUDE_DIR}) + target_link_libraries (spio_default_public_options INTERFACE h5z_zfp::h5z_zfp) else () message (STATUS "Could not find ZFP filter for HDF5, disabling ZFP with HDF5") endif () @@ -233,7 +232,8 @@ if (WITH_HDF5) if (H5Z_BLOSC2_FOUND) message (STATUS "Found BLOSC2 filter for HDF5") target_compile_definitions (spio_default_public_options INTERFACE _SPIO_HAS_H5Z_BLOSC2) - list (APPEND spio_default_public_libs "h5z_blosc2::h5z_blosc2") + target_include_directories (spio_default_public_options INTERFACE ${H5Z_BLOSC2_INCLUDE_DIR}) + target_link_libraries (spio_default_public_options INTERFACE h5z_blosc2::h5z_blosc2) else () message (STATUS "Could not find Blosc2 filter, disabling HDF5 filter for Blosc2") endif () @@ -430,7 +430,7 @@ if (MPISERIAL_C_FOUND) INTERFACE MPI_SERIAL) target_include_directories (spio_default_public_options INTERFACE ${MPISERIAL_C_INCLUDE_DIRS}) - list (APPEND spio_default_public_libs ${MPISERIAL_C_LIBRARIES}) + target_link_libraries (spio_default_public_options INTERFACE ${MPISERIAL_C_LIBRARIES}) set (WITH_PNETCDF FALSE) endif () @@ -458,29 +458,22 @@ endif () # DEFINE THE TARGET LIBRARY #============================================================================== message(STATUS "===== Configuring SCORPIO C library... =====") -# PIO lib source -set (pio_lib_src - topology.cpp pio_mpi_timer.cpp pio_timer.cpp pio_file.cpp - pioc_support.cpp pio_lists.cpp pio_print.cpp spio_dbg_ds.cpp - pioc.cpp pioc_sc.cpp pio_spmd.cpp pio_rearrange.cpp pio_rearr_utils.cpp pio_rearr_contig.cpp - pio_nc4.cpp bget.cpp - pio_nc.cpp pio_put_nc.cpp pio_get_nc.cpp pio_getput_int.cpp pio_msg.cpp pio_varm.cpp - pio_darray.cpp pio_darray_int.cpp spio_hash.cpp pio_sdecomps_regex.cpp spio_io_summary.cpp - spio_decomp_map_info_pool.cpp spio_decomp_nc_logger.cpp spio_decomp_txt_logger.cpp - spio_ltimer.cpp spio_serializer.cpp spio_file_mvcache.cpp - spio_tracer.cpp spio_tracer_mdata.cpp spio_tracer_decomp.cpp - spio_rearrange_any.cpp spio_dt_converter.cpp - spio_async_tpool.cpp spio_async_utils.cpp spio_async_tcomm.cpp - spio_hdf5_utils.cpp spio_async_hdf5_utils.cpp) - # Add subdirectories add_subdirectory (api) +add_subdirectory (util) +add_subdirectory (core) + # Add sources for libpioc.a -add_library (pioc ${pio_lib_src} - $) +add_library (pioc + $ + $ + $) + +# PUBLIC ${spio_default_public_libs} +# PRIVATE ${spio_default_private_libs} + target_link_libraries (pioc PUBLIC spio_default_public_options - PUBLIC ${spio_default_public_libs} PRIVATE spio_default_private_options) # FIXME: CMake 3.26+ can completely hide the local private interface lib diff --git a/src/clib/api/CMakeLists.txt b/src/clib/api/CMakeLists.txt index 24ddd9b073..f12965bb16 100644 --- a/src/clib/api/CMakeLists.txt +++ b/src/clib/api/CMakeLists.txt @@ -31,7 +31,7 @@ set (pio_api_src add_library (pioc_api OBJECT ${pio_api_src}) target_include_directories(pioc_api PUBLIC . - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/..) + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../util) target_link_libraries(pioc_api PUBLIC spio_default_public_options PRIVATE spio_default_private_options) diff --git a/src/clib/core/CMakeLists.txt b/src/clib/core/CMakeLists.txt new file mode 100644 index 0000000000..55400103ad --- /dev/null +++ b/src/clib/core/CMakeLists.txt @@ -0,0 +1,46 @@ +#============================================================================== +# DEFINE THE TARGET LIBRARY +#============================================================================== +message(STATUS "===== Configuring SCORPIO C Core... =====") +# SCORPIO C library - core +set (spio_core_src + spio_async_utils.cpp + spio_async_tpool.cpp + spio_async_hdf5_utils.cpp + pio_spmd.cpp + spio_hdf5_utils.cpp + spio_decomp_txt_logger.cpp + spio_decomp_nc_logger.cpp + spio_decomp_map_info_pool.cpp + spio_async_tcomm.cpp + pioc_support.cpp + pioc.cpp + pio_rearrange.cpp + pio_rearr_utils.cpp + pio_rearr_contig.cpp + pio_print.cpp + pio_nc.cpp + pio_lists.cpp + pio_getput_int.cpp + pio_file.cpp + pio_darray_int.cpp + pio_darray.cpp + spio_serializer.cpp + pio_varm.cpp + pio_nc4.cpp + spio_rearrange_any.cpp + spio_io_summary.cpp + spio_file_mvcache.cpp + pioc_sc.cpp + pio_sdecomps_regex.cpp + pio_put_nc.cpp + pio_msg.cpp + pio_get_nc.cpp) + +add_library (spio_core OBJECT ${spio_core_src}) +target_include_directories(spio_core + PUBLIC . + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../util) +target_link_libraries(spio_core + PUBLIC spio_default_public_options + PRIVATE spio_default_private_options) diff --git a/src/clib/README_pio_micro_timers.txt b/src/clib/core/README_pio_micro_timers.txt similarity index 100% rename from src/clib/README_pio_micro_timers.txt rename to src/clib/core/README_pio_micro_timers.txt diff --git a/src/clib/README_pio_sdecomps_regex.txt b/src/clib/core/README_pio_sdecomps_regex.txt similarity index 100% rename from src/clib/README_pio_sdecomps_regex.txt rename to src/clib/core/README_pio_sdecomps_regex.txt diff --git a/src/clib/README_trace_and_replay.txt b/src/clib/core/README_trace_and_replay.txt similarity index 100% rename from src/clib/README_trace_and_replay.txt rename to src/clib/core/README_trace_and_replay.txt diff --git a/src/clib/io_perf_summary.json_expected b/src/clib/core/io_perf_summary.json_expected similarity index 100% rename from src/clib/io_perf_summary.json_expected rename to src/clib/core/io_perf_summary.json_expected diff --git a/src/clib/io_perf_summary.schema.json b/src/clib/core/io_perf_summary.schema.json similarity index 100% rename from src/clib/io_perf_summary.schema.json rename to src/clib/core/io_perf_summary.schema.json diff --git a/src/clib/io_perf_summary.text_expected b/src/clib/core/io_perf_summary.text_expected similarity index 100% rename from src/clib/io_perf_summary.text_expected rename to src/clib/core/io_perf_summary.text_expected diff --git a/src/clib/io_perf_summary.xml_expected b/src/clib/core/io_perf_summary.xml_expected similarity index 100% rename from src/clib/io_perf_summary.xml_expected rename to src/clib/core/io_perf_summary.xml_expected diff --git a/src/clib/pio_darray.cpp b/src/clib/core/pio_darray.cpp similarity index 100% rename from src/clib/pio_darray.cpp rename to src/clib/core/pio_darray.cpp diff --git a/src/clib/pio_darray_int.cpp b/src/clib/core/pio_darray_int.cpp similarity index 100% rename from src/clib/pio_darray_int.cpp rename to src/clib/core/pio_darray_int.cpp diff --git a/src/clib/pio_file.cpp b/src/clib/core/pio_file.cpp similarity index 100% rename from src/clib/pio_file.cpp rename to src/clib/core/pio_file.cpp diff --git a/src/clib/pio_get_nc.cpp b/src/clib/core/pio_get_nc.cpp similarity index 100% rename from src/clib/pio_get_nc.cpp rename to src/clib/core/pio_get_nc.cpp diff --git a/src/clib/pio_getput_int.cpp b/src/clib/core/pio_getput_int.cpp similarity index 100% rename from src/clib/pio_getput_int.cpp rename to src/clib/core/pio_getput_int.cpp diff --git a/src/clib/pio_lists.cpp b/src/clib/core/pio_lists.cpp similarity index 100% rename from src/clib/pio_lists.cpp rename to src/clib/core/pio_lists.cpp diff --git a/src/clib/pio_msg.cpp b/src/clib/core/pio_msg.cpp similarity index 100% rename from src/clib/pio_msg.cpp rename to src/clib/core/pio_msg.cpp diff --git a/src/clib/pio_nc.cpp b/src/clib/core/pio_nc.cpp similarity index 100% rename from src/clib/pio_nc.cpp rename to src/clib/core/pio_nc.cpp diff --git a/src/clib/pio_nc4.cpp b/src/clib/core/pio_nc4.cpp similarity index 100% rename from src/clib/pio_nc4.cpp rename to src/clib/core/pio_nc4.cpp diff --git a/src/clib/pio_print.cpp b/src/clib/core/pio_print.cpp similarity index 100% rename from src/clib/pio_print.cpp rename to src/clib/core/pio_print.cpp diff --git a/src/clib/pio_put_nc.cpp b/src/clib/core/pio_put_nc.cpp similarity index 100% rename from src/clib/pio_put_nc.cpp rename to src/clib/core/pio_put_nc.cpp diff --git a/src/clib/pio_rearr_contig.cpp b/src/clib/core/pio_rearr_contig.cpp similarity index 100% rename from src/clib/pio_rearr_contig.cpp rename to src/clib/core/pio_rearr_contig.cpp diff --git a/src/clib/pio_rearr_contig.hpp b/src/clib/core/pio_rearr_contig.hpp similarity index 100% rename from src/clib/pio_rearr_contig.hpp rename to src/clib/core/pio_rearr_contig.hpp diff --git a/src/clib/pio_rearr_utils.cpp b/src/clib/core/pio_rearr_utils.cpp similarity index 100% rename from src/clib/pio_rearr_utils.cpp rename to src/clib/core/pio_rearr_utils.cpp diff --git a/src/clib/pio_rearr_utils.hpp b/src/clib/core/pio_rearr_utils.hpp similarity index 100% rename from src/clib/pio_rearr_utils.hpp rename to src/clib/core/pio_rearr_utils.hpp diff --git a/src/clib/pio_rearrange.cpp b/src/clib/core/pio_rearrange.cpp similarity index 100% rename from src/clib/pio_rearrange.cpp rename to src/clib/core/pio_rearrange.cpp diff --git a/src/clib/pio_sdecomps_regex.cpp b/src/clib/core/pio_sdecomps_regex.cpp similarity index 100% rename from src/clib/pio_sdecomps_regex.cpp rename to src/clib/core/pio_sdecomps_regex.cpp diff --git a/src/clib/pio_sdecomps_regex.h b/src/clib/core/pio_sdecomps_regex.h similarity index 100% rename from src/clib/pio_sdecomps_regex.h rename to src/clib/core/pio_sdecomps_regex.h diff --git a/src/clib/pio_sdecomps_regex.hpp b/src/clib/core/pio_sdecomps_regex.hpp similarity index 100% rename from src/clib/pio_sdecomps_regex.hpp rename to src/clib/core/pio_sdecomps_regex.hpp diff --git a/src/clib/pio_spmd.cpp b/src/clib/core/pio_spmd.cpp similarity index 100% rename from src/clib/pio_spmd.cpp rename to src/clib/core/pio_spmd.cpp diff --git a/src/clib/pio_varm.cpp b/src/clib/core/pio_varm.cpp similarity index 100% rename from src/clib/pio_varm.cpp rename to src/clib/core/pio_varm.cpp diff --git a/src/clib/pioc.cpp b/src/clib/core/pioc.cpp similarity index 100% rename from src/clib/pioc.cpp rename to src/clib/core/pioc.cpp diff --git a/src/clib/pioc_sc.cpp b/src/clib/core/pioc_sc.cpp similarity index 100% rename from src/clib/pioc_sc.cpp rename to src/clib/core/pioc_sc.cpp diff --git a/src/clib/pioc_support.cpp b/src/clib/core/pioc_support.cpp similarity index 100% rename from src/clib/pioc_support.cpp rename to src/clib/core/pioc_support.cpp diff --git a/src/clib/spio_async_hdf5_utils.cpp b/src/clib/core/spio_async_hdf5_utils.cpp similarity index 100% rename from src/clib/spio_async_hdf5_utils.cpp rename to src/clib/core/spio_async_hdf5_utils.cpp diff --git a/src/clib/spio_async_hdf5_utils.hpp b/src/clib/core/spio_async_hdf5_utils.hpp similarity index 100% rename from src/clib/spio_async_hdf5_utils.hpp rename to src/clib/core/spio_async_hdf5_utils.hpp diff --git a/src/clib/spio_async_mtq.hpp b/src/clib/core/spio_async_mtq.hpp similarity index 100% rename from src/clib/spio_async_mtq.hpp rename to src/clib/core/spio_async_mtq.hpp diff --git a/src/clib/spio_async_op.hpp b/src/clib/core/spio_async_op.hpp similarity index 100% rename from src/clib/spio_async_op.hpp rename to src/clib/core/spio_async_op.hpp diff --git a/src/clib/spio_async_tcomm.cpp b/src/clib/core/spio_async_tcomm.cpp similarity index 100% rename from src/clib/spio_async_tcomm.cpp rename to src/clib/core/spio_async_tcomm.cpp diff --git a/src/clib/spio_async_tcomm.hpp b/src/clib/core/spio_async_tcomm.hpp similarity index 100% rename from src/clib/spio_async_tcomm.hpp rename to src/clib/core/spio_async_tcomm.hpp diff --git a/src/clib/spio_async_tpool.cpp b/src/clib/core/spio_async_tpool.cpp similarity index 100% rename from src/clib/spio_async_tpool.cpp rename to src/clib/core/spio_async_tpool.cpp diff --git a/src/clib/spio_async_tpool.hpp b/src/clib/core/spio_async_tpool.hpp similarity index 100% rename from src/clib/spio_async_tpool.hpp rename to src/clib/core/spio_async_tpool.hpp diff --git a/src/clib/spio_async_utils.cpp b/src/clib/core/spio_async_utils.cpp similarity index 100% rename from src/clib/spio_async_utils.cpp rename to src/clib/core/spio_async_utils.cpp diff --git a/src/clib/spio_async_utils.hpp b/src/clib/core/spio_async_utils.hpp similarity index 100% rename from src/clib/spio_async_utils.hpp rename to src/clib/core/spio_async_utils.hpp diff --git a/src/clib/spio_decomp_logger.hpp b/src/clib/core/spio_decomp_logger.hpp similarity index 100% rename from src/clib/spio_decomp_logger.hpp rename to src/clib/core/spio_decomp_logger.hpp diff --git a/src/clib/spio_decomp_map_info_pool.cpp b/src/clib/core/spio_decomp_map_info_pool.cpp similarity index 100% rename from src/clib/spio_decomp_map_info_pool.cpp rename to src/clib/core/spio_decomp_map_info_pool.cpp diff --git a/src/clib/spio_decomp_map_info_pool.hpp b/src/clib/core/spio_decomp_map_info_pool.hpp similarity index 100% rename from src/clib/spio_decomp_map_info_pool.hpp rename to src/clib/core/spio_decomp_map_info_pool.hpp diff --git a/src/clib/spio_decomp_nc_logger.cpp b/src/clib/core/spio_decomp_nc_logger.cpp similarity index 100% rename from src/clib/spio_decomp_nc_logger.cpp rename to src/clib/core/spio_decomp_nc_logger.cpp diff --git a/src/clib/spio_decomp_txt_logger.cpp b/src/clib/core/spio_decomp_txt_logger.cpp similarity index 100% rename from src/clib/spio_decomp_txt_logger.cpp rename to src/clib/core/spio_decomp_txt_logger.cpp diff --git a/src/clib/spio_file_mvcache.cpp b/src/clib/core/spio_file_mvcache.cpp similarity index 100% rename from src/clib/spio_file_mvcache.cpp rename to src/clib/core/spio_file_mvcache.cpp diff --git a/src/clib/spio_file_mvcache.h b/src/clib/core/spio_file_mvcache.h similarity index 100% rename from src/clib/spio_file_mvcache.h rename to src/clib/core/spio_file_mvcache.h diff --git a/src/clib/spio_file_mvcache.hpp b/src/clib/core/spio_file_mvcache.hpp similarity index 100% rename from src/clib/spio_file_mvcache.hpp rename to src/clib/core/spio_file_mvcache.hpp diff --git a/src/clib/spio_hdf5_utils.cpp b/src/clib/core/spio_hdf5_utils.cpp similarity index 100% rename from src/clib/spio_hdf5_utils.cpp rename to src/clib/core/spio_hdf5_utils.cpp diff --git a/src/clib/spio_hdf5_utils.hpp b/src/clib/core/spio_hdf5_utils.hpp similarity index 100% rename from src/clib/spio_hdf5_utils.hpp rename to src/clib/core/spio_hdf5_utils.hpp diff --git a/src/clib/spio_io_summary.cpp b/src/clib/core/spio_io_summary.cpp similarity index 100% rename from src/clib/spio_io_summary.cpp rename to src/clib/core/spio_io_summary.cpp diff --git a/src/clib/spio_io_summary.h b/src/clib/core/spio_io_summary.h similarity index 100% rename from src/clib/spio_io_summary.h rename to src/clib/core/spio_io_summary.h diff --git a/src/clib/spio_io_summary.hpp b/src/clib/core/spio_io_summary.hpp similarity index 100% rename from src/clib/spio_io_summary.hpp rename to src/clib/core/spio_io_summary.hpp diff --git a/src/clib/spio_rearrange_any.cpp b/src/clib/core/spio_rearrange_any.cpp similarity index 100% rename from src/clib/spio_rearrange_any.cpp rename to src/clib/core/spio_rearrange_any.cpp diff --git a/src/clib/spio_rearrange_any.h b/src/clib/core/spio_rearrange_any.h similarity index 100% rename from src/clib/spio_rearrange_any.h rename to src/clib/core/spio_rearrange_any.h diff --git a/src/clib/spio_serializer.cpp b/src/clib/core/spio_serializer.cpp similarity index 100% rename from src/clib/spio_serializer.cpp rename to src/clib/core/spio_serializer.cpp diff --git a/src/clib/spio_serializer.hpp b/src/clib/core/spio_serializer.hpp similarity index 100% rename from src/clib/spio_serializer.hpp rename to src/clib/core/spio_serializer.hpp diff --git a/src/clib/spio_sort_utils.hpp b/src/clib/core/spio_sort_utils.hpp similarity index 100% rename from src/clib/spio_sort_utils.hpp rename to src/clib/core/spio_sort_utils.hpp diff --git a/src/clib/dtypes.h b/src/clib/dtypes.h deleted file mode 100644 index 9076cf0f75..0000000000 --- a/src/clib/dtypes.h +++ /dev/null @@ -1,5 +0,0 @@ -#define TYPEDOUBLE 102 -#define TYPEINT 103 -#define TYPETEXT 100 -#define TYPELONG 104 -#define TYPEREAL 101 diff --git a/src/clib/pio_internal.h b/src/clib/pio_internal.h index be5baf346c..25e3eeff8b 100644 --- a/src/clib/pio_internal.h +++ b/src/clib/pio_internal.h @@ -22,7 +22,6 @@ #define NETCDF_INT_FLOAT_SIZE 4 #define NETCDF_DOUBLE_INT64_SIZE 8 -#include #include #include #ifdef SPIO_ENABLE_GPTL_TIMING @@ -31,7 +30,8 @@ #include "gptl_skel.h" #endif #include -#include "spio_ltimer.h" +#include "util/bget.h" +#include "util/spio_ltimer.h" #include "pio_types.hpp" #if defined(__cplusplus) diff --git a/src/clib/pio_types.hpp b/src/clib/pio_types.hpp index 12996122bd..4bb71fd729 100644 --- a/src/clib/pio_types.hpp +++ b/src/clib/pio_types.hpp @@ -50,7 +50,7 @@ extern "C" { #include #include #include -#include "spio_async_op.hpp" +#include "core/spio_async_op.hpp" #ifdef PIO_MICRO_TIMING /** Some fwd declarations to avoid including internal headers */ diff --git a/src/clib/util/CMakeLists.txt b/src/clib/util/CMakeLists.txt new file mode 100644 index 0000000000..4351b4b622 --- /dev/null +++ b/src/clib/util/CMakeLists.txt @@ -0,0 +1,25 @@ +#============================================================================== +# DEFINE THE TARGET LIBRARY +#============================================================================== +message(STATUS "===== Configuring SCORPIO C lib utils... =====") +# Util source - Utils used across the library +set (spio_util_src + spio_ltimer.cpp + spio_dt_converter.cpp + spio_dbg_ds.cpp + pio_timer.cpp + bget.cpp + topology.cpp + spio_hash.cpp + spio_tracer.cpp + spio_tracer_mdata.cpp + spio_tracer_decomp.cpp + pio_mpi_timer.cpp) + +add_library (spio_util OBJECT ${spio_util_src}) +target_include_directories(spio_util + PUBLIC . + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/..) +target_link_libraries(spio_util + PUBLIC spio_default_public_options + PRIVATE spio_default_private_options) diff --git a/src/clib/bget.cpp b/src/clib/util/bget.cpp similarity index 100% rename from src/clib/bget.cpp rename to src/clib/util/bget.cpp diff --git a/src/clib/bget.h b/src/clib/util/bget.h similarity index 100% rename from src/clib/bget.h rename to src/clib/util/bget.h diff --git a/src/clib/gptl_skel.h b/src/clib/util/gptl_skel.h similarity index 100% rename from src/clib/gptl_skel.h rename to src/clib/util/gptl_skel.h diff --git a/src/clib/pio_minmax.h b/src/clib/util/pio_minmax.h similarity index 100% rename from src/clib/pio_minmax.h rename to src/clib/util/pio_minmax.h diff --git a/src/clib/pio_mpi_timer.cpp b/src/clib/util/pio_mpi_timer.cpp similarity index 100% rename from src/clib/pio_mpi_timer.cpp rename to src/clib/util/pio_mpi_timer.cpp diff --git a/src/clib/pio_timer.cpp b/src/clib/util/pio_timer.cpp similarity index 100% rename from src/clib/pio_timer.cpp rename to src/clib/util/pio_timer.cpp diff --git a/src/clib/pio_timer.h b/src/clib/util/pio_timer.h similarity index 100% rename from src/clib/pio_timer.h rename to src/clib/util/pio_timer.h diff --git a/src/clib/spio_dbg_ds.cpp b/src/clib/util/spio_dbg_ds.cpp similarity index 100% rename from src/clib/spio_dbg_ds.cpp rename to src/clib/util/spio_dbg_ds.cpp diff --git a/src/clib/spio_dbg_utils.hpp b/src/clib/util/spio_dbg_utils.hpp similarity index 100% rename from src/clib/spio_dbg_utils.hpp rename to src/clib/util/spio_dbg_utils.hpp diff --git a/src/clib/spio_dt_converter.cpp b/src/clib/util/spio_dt_converter.cpp similarity index 100% rename from src/clib/spio_dt_converter.cpp rename to src/clib/util/spio_dt_converter.cpp diff --git a/src/clib/spio_dt_converter.hpp b/src/clib/util/spio_dt_converter.hpp similarity index 99% rename from src/clib/spio_dt_converter.hpp rename to src/clib/util/spio_dt_converter.hpp index e03341b711..b37f1857ca 100644 --- a/src/clib/spio_dt_converter.hpp +++ b/src/clib/util/spio_dt_converter.hpp @@ -9,7 +9,6 @@ #include "pio_config.h" #include "pio.h" #include "pio_internal.h" -#include "spio_file_mvcache.h" namespace SPIO_Util{ namespace File_Util{ diff --git a/src/clib/spio_gptl_utils.hpp b/src/clib/util/spio_gptl_utils.hpp similarity index 100% rename from src/clib/spio_gptl_utils.hpp rename to src/clib/util/spio_gptl_utils.hpp diff --git a/src/clib/spio_hash.cpp b/src/clib/util/spio_hash.cpp similarity index 100% rename from src/clib/spio_hash.cpp rename to src/clib/util/spio_hash.cpp diff --git a/src/clib/spio_hash.h b/src/clib/util/spio_hash.h similarity index 100% rename from src/clib/spio_hash.h rename to src/clib/util/spio_hash.h diff --git a/src/clib/spio_logger.hpp b/src/clib/util/spio_logger.hpp similarity index 100% rename from src/clib/spio_logger.hpp rename to src/clib/util/spio_logger.hpp diff --git a/src/clib/spio_ltimer.cpp b/src/clib/util/spio_ltimer.cpp similarity index 100% rename from src/clib/spio_ltimer.cpp rename to src/clib/util/spio_ltimer.cpp diff --git a/src/clib/spio_ltimer.h b/src/clib/util/spio_ltimer.h similarity index 100% rename from src/clib/spio_ltimer.h rename to src/clib/util/spio_ltimer.h diff --git a/src/clib/spio_ltimer.hpp b/src/clib/util/spio_ltimer.hpp similarity index 100% rename from src/clib/spio_ltimer.hpp rename to src/clib/util/spio_ltimer.hpp diff --git a/src/clib/spio_ltimer_utils.hpp b/src/clib/util/spio_ltimer_utils.hpp similarity index 100% rename from src/clib/spio_ltimer_utils.hpp rename to src/clib/util/spio_ltimer_utils.hpp diff --git a/src/clib/spio_map_sorter.hpp b/src/clib/util/spio_map_sorter.hpp similarity index 100% rename from src/clib/spio_map_sorter.hpp rename to src/clib/util/spio_map_sorter.hpp diff --git a/src/clib/spio_tracer.cpp b/src/clib/util/spio_tracer.cpp similarity index 100% rename from src/clib/spio_tracer.cpp rename to src/clib/util/spio_tracer.cpp diff --git a/src/clib/spio_tracer.hpp b/src/clib/util/spio_tracer.hpp similarity index 100% rename from src/clib/spio_tracer.hpp rename to src/clib/util/spio_tracer.hpp diff --git a/src/clib/spio_tracer_decomp.cpp b/src/clib/util/spio_tracer_decomp.cpp similarity index 100% rename from src/clib/spio_tracer_decomp.cpp rename to src/clib/util/spio_tracer_decomp.cpp diff --git a/src/clib/spio_tracer_decomp.hpp b/src/clib/util/spio_tracer_decomp.hpp similarity index 100% rename from src/clib/spio_tracer_decomp.hpp rename to src/clib/util/spio_tracer_decomp.hpp diff --git a/src/clib/spio_tracer_mdata.cpp b/src/clib/util/spio_tracer_mdata.cpp similarity index 100% rename from src/clib/spio_tracer_mdata.cpp rename to src/clib/util/spio_tracer_mdata.cpp diff --git a/src/clib/spio_tracer_mdata.hpp b/src/clib/util/spio_tracer_mdata.hpp similarity index 100% rename from src/clib/spio_tracer_mdata.hpp rename to src/clib/util/spio_tracer_mdata.hpp diff --git a/src/clib/spio_tree.hpp b/src/clib/util/spio_tree.hpp similarity index 100% rename from src/clib/spio_tree.hpp rename to src/clib/util/spio_tree.hpp diff --git a/src/clib/topology.cpp b/src/clib/util/topology.cpp similarity index 100% rename from src/clib/topology.cpp rename to src/clib/util/topology.cpp diff --git a/tests/cunit/CMakeLists.txt b/tests/cunit/CMakeLists.txt index c470c8a616..0447f19fa2 100644 --- a/tests/cunit/CMakeLists.txt +++ b/tests/cunit/CMakeLists.txt @@ -9,7 +9,7 @@ include(SPIOUtils) #============================================================================== # SET THE COMPILER OPTIONS #============================================================================== -include_directories("${SCORPIO_SOURCE_DIR}/tests/cunit" "${SCORPIO_SOURCE_DIR}/src/clib" "${SCORPIO_BINARY_DIR}/src/clib") +include_directories("${SCORPIO_SOURCE_DIR}/tests/cunit" "${SCORPIO_SOURCE_DIR}/src/clib" "${SCORPIO_BINARY_DIR}/src/clib" "${SCORPIO_SOURCE_DIR}/src/clib/core" "${SCORPIO_SOURCE_DIR}/src/clib/util") # Compiler-specific compiler options string (TOUPPER "${CMAKE_C_COMPILER_ID}" CMAKE_C_COMPILER_NAME) From 4478c624d9268a8e3529976611294d2a8ed5ed5b Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 4 Mar 2026 12:08:33 -0600 Subject: [PATCH 143/194] More code reorganization - core/iolib Moving some of hdf5-specific code to core/iolib/hdf5 Also moving serializer code to generic util (No source code changes) --- src/clib/CMakeLists.txt | 5 ++++- src/clib/core/CMakeLists.txt | 12 +++++++----- src/clib/core/iolib/CMakeLists.txt | 17 +++++++++++++++++ src/clib/core/iolib/hdf5/CMakeLists.txt | 19 +++++++++++++++++++ .../hdf5}/spio_async_hdf5_utils.cpp | 0 .../hdf5}/spio_async_hdf5_utils.hpp | 0 .../core/{ => iolib/hdf5}/spio_hdf5_utils.cpp | 0 src/clib/util/CMakeLists.txt | 1 + src/clib/{core => util}/spio_serializer.cpp | 0 src/clib/{core => util}/spio_serializer.hpp | 0 src/clib/{core => util}/spio_sort_utils.hpp | 0 tests/cunit/CMakeLists.txt | 2 +- 12 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 src/clib/core/iolib/CMakeLists.txt create mode 100644 src/clib/core/iolib/hdf5/CMakeLists.txt rename src/clib/core/{ => iolib/hdf5}/spio_async_hdf5_utils.cpp (100%) rename src/clib/core/{ => iolib/hdf5}/spio_async_hdf5_utils.hpp (100%) rename src/clib/core/{ => iolib/hdf5}/spio_hdf5_utils.cpp (100%) rename src/clib/{core => util}/spio_serializer.cpp (100%) rename src/clib/{core => util}/spio_serializer.hpp (100%) rename src/clib/{core => util}/spio_sort_utils.hpp (100%) diff --git a/src/clib/CMakeLists.txt b/src/clib/CMakeLists.txt index 05bebfcc58..6e3a34ea3f 100644 --- a/src/clib/CMakeLists.txt +++ b/src/clib/CMakeLists.txt @@ -463,11 +463,14 @@ add_subdirectory (api) add_subdirectory (util) add_subdirectory (core) +# FIXME : Use interface libs for subdir sources ? # Add sources for libpioc.a add_library (pioc $ $ - $) + $ + $ + $) # PUBLIC ${spio_default_public_libs} # PRIVATE ${spio_default_private_libs} diff --git a/src/clib/core/CMakeLists.txt b/src/clib/core/CMakeLists.txt index 55400103ad..8e2ffea147 100644 --- a/src/clib/core/CMakeLists.txt +++ b/src/clib/core/CMakeLists.txt @@ -6,9 +6,7 @@ message(STATUS "===== Configuring SCORPIO C Core... =====") set (spio_core_src spio_async_utils.cpp spio_async_tpool.cpp - spio_async_hdf5_utils.cpp pio_spmd.cpp - spio_hdf5_utils.cpp spio_decomp_txt_logger.cpp spio_decomp_nc_logger.cpp spio_decomp_map_info_pool.cpp @@ -25,7 +23,6 @@ set (spio_core_src pio_file.cpp pio_darray_int.cpp pio_darray.cpp - spio_serializer.cpp pio_varm.cpp pio_nc4.cpp spio_rearrange_any.cpp @@ -37,10 +34,15 @@ set (spio_core_src pio_msg.cpp pio_get_nc.cpp) -add_library (spio_core OBJECT ${spio_core_src}) +add_subdirectory (iolib) + +add_library (spio_core OBJECT + $ + ${spio_core_src}) + target_include_directories(spio_core PUBLIC . - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../util) + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../util ${CMAKE_CURRENT_SOURCE_DIR}/iolib/hdf5) target_link_libraries(spio_core PUBLIC spio_default_public_options PRIVATE spio_default_private_options) diff --git a/src/clib/core/iolib/CMakeLists.txt b/src/clib/core/iolib/CMakeLists.txt new file mode 100644 index 0000000000..86ed9db22b --- /dev/null +++ b/src/clib/core/iolib/CMakeLists.txt @@ -0,0 +1,17 @@ +#============================================================================== +# DEFINE THE TARGET LIBRARY +#============================================================================== +message(STATUS "===== Configuring SCORPIO C Core (I/O libraries)... =====") + +add_subdirectory (hdf5) + +add_library (spio_core_iolib OBJECT + $) + +target_include_directories(spio_core_iolib + PUBLIC . + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../.. ${CMAKE_CURRENT_BINARY_DIR}/../.. ${CMAKE_CURRENT_SOURCE_DIR}/../../util) + +target_link_libraries(spio_core_iolib + PUBLIC spio_default_public_options + PRIVATE spio_default_private_options) diff --git a/src/clib/core/iolib/hdf5/CMakeLists.txt b/src/clib/core/iolib/hdf5/CMakeLists.txt new file mode 100644 index 0000000000..d3eacf3713 --- /dev/null +++ b/src/clib/core/iolib/hdf5/CMakeLists.txt @@ -0,0 +1,19 @@ +#============================================================================== +# DEFINE THE TARGET LIBRARY +#============================================================================== +message(STATUS "===== Configuring SCORPIO C Core (hdf5)... =====") +# HDF5 Support +set (spio_core_iolib_hdf5_src + spio_async_hdf5_utils.cpp + spio_hdf5_utils.cpp) + +set (spio_clib_src_dir "${CMAKE_CURRENT_SOURCE_DIR}/../../..") +set (spio_clib_bin_dir "${CMAKE_CURRENT_BINARY_DIR}/../../..") + +add_library (spio_core_iolib_hdf5 OBJECT ${spio_core_iolib_hdf5_src}) +target_include_directories(spio_core_iolib_hdf5 + PUBLIC . + PRIVATE ${spio_clib_src_dir} ${spio_clib_bin_dir} ${spio_clib_src_dir}/util ${spio_clib_src_dir}/core) +target_link_libraries(spio_core_iolib_hdf5 + PUBLIC spio_default_public_options + PRIVATE spio_default_private_options) diff --git a/src/clib/core/spio_async_hdf5_utils.cpp b/src/clib/core/iolib/hdf5/spio_async_hdf5_utils.cpp similarity index 100% rename from src/clib/core/spio_async_hdf5_utils.cpp rename to src/clib/core/iolib/hdf5/spio_async_hdf5_utils.cpp diff --git a/src/clib/core/spio_async_hdf5_utils.hpp b/src/clib/core/iolib/hdf5/spio_async_hdf5_utils.hpp similarity index 100% rename from src/clib/core/spio_async_hdf5_utils.hpp rename to src/clib/core/iolib/hdf5/spio_async_hdf5_utils.hpp diff --git a/src/clib/core/spio_hdf5_utils.cpp b/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp similarity index 100% rename from src/clib/core/spio_hdf5_utils.cpp rename to src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp diff --git a/src/clib/util/CMakeLists.txt b/src/clib/util/CMakeLists.txt index 4351b4b622..be2e1bccc3 100644 --- a/src/clib/util/CMakeLists.txt +++ b/src/clib/util/CMakeLists.txt @@ -14,6 +14,7 @@ set (spio_util_src spio_tracer.cpp spio_tracer_mdata.cpp spio_tracer_decomp.cpp + spio_serializer.cpp pio_mpi_timer.cpp) add_library (spio_util OBJECT ${spio_util_src}) diff --git a/src/clib/core/spio_serializer.cpp b/src/clib/util/spio_serializer.cpp similarity index 100% rename from src/clib/core/spio_serializer.cpp rename to src/clib/util/spio_serializer.cpp diff --git a/src/clib/core/spio_serializer.hpp b/src/clib/util/spio_serializer.hpp similarity index 100% rename from src/clib/core/spio_serializer.hpp rename to src/clib/util/spio_serializer.hpp diff --git a/src/clib/core/spio_sort_utils.hpp b/src/clib/util/spio_sort_utils.hpp similarity index 100% rename from src/clib/core/spio_sort_utils.hpp rename to src/clib/util/spio_sort_utils.hpp diff --git a/tests/cunit/CMakeLists.txt b/tests/cunit/CMakeLists.txt index 0447f19fa2..c123afd890 100644 --- a/tests/cunit/CMakeLists.txt +++ b/tests/cunit/CMakeLists.txt @@ -9,7 +9,7 @@ include(SPIOUtils) #============================================================================== # SET THE COMPILER OPTIONS #============================================================================== -include_directories("${SCORPIO_SOURCE_DIR}/tests/cunit" "${SCORPIO_SOURCE_DIR}/src/clib" "${SCORPIO_BINARY_DIR}/src/clib" "${SCORPIO_SOURCE_DIR}/src/clib/core" "${SCORPIO_SOURCE_DIR}/src/clib/util") +include_directories("${SCORPIO_SOURCE_DIR}/tests/cunit" "${SCORPIO_SOURCE_DIR}/src/clib" "${SCORPIO_BINARY_DIR}/src/clib" "${SCORPIO_SOURCE_DIR}/src/clib/core" "${SCORPIO_SOURCE_DIR}/src/clib/core/iolib/hdf5" "${SCORPIO_SOURCE_DIR}/src/clib/util") # Compiler-specific compiler options string (TOUPPER "${CMAKE_C_COMPILER_ID}" CMAKE_C_COMPILER_NAME) From e6fa13ef3f06c6cda4abe75585d6e8c38dd886a3 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 4 Mar 2026 13:17:14 -0600 Subject: [PATCH 144/194] Code reorg - core/rearr Moving rearranger specific code to clib/core/rearr --- src/clib/CMakeLists.txt | 1 + src/clib/core/CMakeLists.txt | 9 ++++---- src/clib/core/rearr/CMakeLists.txt | 21 +++++++++++++++++++ .../core/{ => rearr}/pio_rearr_contig.cpp | 0 .../core/{ => rearr}/pio_rearr_contig.hpp | 0 src/clib/core/{ => rearr}/pio_rearr_utils.cpp | 0 src/clib/core/{ => rearr}/pio_rearr_utils.hpp | 0 src/clib/core/{ => rearr}/pio_rearrange.cpp | 0 .../core/{ => rearr}/spio_rearrange_any.cpp | 0 .../core/{ => rearr}/spio_rearrange_any.h | 0 tests/cunit/CMakeLists.txt | 3 ++- 11 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 src/clib/core/rearr/CMakeLists.txt rename src/clib/core/{ => rearr}/pio_rearr_contig.cpp (100%) rename src/clib/core/{ => rearr}/pio_rearr_contig.hpp (100%) rename src/clib/core/{ => rearr}/pio_rearr_utils.cpp (100%) rename src/clib/core/{ => rearr}/pio_rearr_utils.hpp (100%) rename src/clib/core/{ => rearr}/pio_rearrange.cpp (100%) rename src/clib/core/{ => rearr}/spio_rearrange_any.cpp (100%) rename src/clib/core/{ => rearr}/spio_rearrange_any.h (100%) diff --git a/src/clib/CMakeLists.txt b/src/clib/CMakeLists.txt index 6e3a34ea3f..2269d38cce 100644 --- a/src/clib/CMakeLists.txt +++ b/src/clib/CMakeLists.txt @@ -469,6 +469,7 @@ add_library (pioc $ $ $ + $ $ $) diff --git a/src/clib/core/CMakeLists.txt b/src/clib/core/CMakeLists.txt index 8e2ffea147..e3c3897e90 100644 --- a/src/clib/core/CMakeLists.txt +++ b/src/clib/core/CMakeLists.txt @@ -13,9 +13,6 @@ set (spio_core_src spio_async_tcomm.cpp pioc_support.cpp pioc.cpp - pio_rearrange.cpp - pio_rearr_utils.cpp - pio_rearr_contig.cpp pio_print.cpp pio_nc.cpp pio_lists.cpp @@ -25,7 +22,6 @@ set (spio_core_src pio_darray.cpp pio_varm.cpp pio_nc4.cpp - spio_rearrange_any.cpp spio_io_summary.cpp spio_file_mvcache.cpp pioc_sc.cpp @@ -34,15 +30,18 @@ set (spio_core_src pio_msg.cpp pio_get_nc.cpp) +add_subdirectory (rearr) add_subdirectory (iolib) add_library (spio_core OBJECT + $ $ ${spio_core_src}) target_include_directories(spio_core PUBLIC . - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../util ${CMAKE_CURRENT_SOURCE_DIR}/iolib/hdf5) + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../util ${CMAKE_CURRENT_SOURCE_DIR}/rearr ${CMAKE_CURRENT_SOURCE_DIR}/iolib/hdf5) + target_link_libraries(spio_core PUBLIC spio_default_public_options PRIVATE spio_default_private_options) diff --git a/src/clib/core/rearr/CMakeLists.txt b/src/clib/core/rearr/CMakeLists.txt new file mode 100644 index 0000000000..742fe8da16 --- /dev/null +++ b/src/clib/core/rearr/CMakeLists.txt @@ -0,0 +1,21 @@ +#============================================================================== +# DEFINE THE TARGET LIBRARY +#============================================================================== +message(STATUS "===== Configuring SCORPIO C Core (Data Rearrangers)... =====") + +set (spio_core_rearr_src + pio_rearrange.cpp + pio_rearr_utils.cpp + pio_rearr_contig.cpp + spio_rearrange_any.cpp) + +add_library (spio_core_rearr OBJECT + ${spio_core_rearr_src}) + +target_include_directories(spio_core_rearr + PUBLIC . + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../.. ${CMAKE_CURRENT_BINARY_DIR}/../.. ${CMAKE_CURRENT_SOURCE_DIR}/../../util) + +target_link_libraries(spio_core_rearr + PUBLIC spio_default_public_options + PRIVATE spio_default_private_options) diff --git a/src/clib/core/pio_rearr_contig.cpp b/src/clib/core/rearr/pio_rearr_contig.cpp similarity index 100% rename from src/clib/core/pio_rearr_contig.cpp rename to src/clib/core/rearr/pio_rearr_contig.cpp diff --git a/src/clib/core/pio_rearr_contig.hpp b/src/clib/core/rearr/pio_rearr_contig.hpp similarity index 100% rename from src/clib/core/pio_rearr_contig.hpp rename to src/clib/core/rearr/pio_rearr_contig.hpp diff --git a/src/clib/core/pio_rearr_utils.cpp b/src/clib/core/rearr/pio_rearr_utils.cpp similarity index 100% rename from src/clib/core/pio_rearr_utils.cpp rename to src/clib/core/rearr/pio_rearr_utils.cpp diff --git a/src/clib/core/pio_rearr_utils.hpp b/src/clib/core/rearr/pio_rearr_utils.hpp similarity index 100% rename from src/clib/core/pio_rearr_utils.hpp rename to src/clib/core/rearr/pio_rearr_utils.hpp diff --git a/src/clib/core/pio_rearrange.cpp b/src/clib/core/rearr/pio_rearrange.cpp similarity index 100% rename from src/clib/core/pio_rearrange.cpp rename to src/clib/core/rearr/pio_rearrange.cpp diff --git a/src/clib/core/spio_rearrange_any.cpp b/src/clib/core/rearr/spio_rearrange_any.cpp similarity index 100% rename from src/clib/core/spio_rearrange_any.cpp rename to src/clib/core/rearr/spio_rearrange_any.cpp diff --git a/src/clib/core/spio_rearrange_any.h b/src/clib/core/rearr/spio_rearrange_any.h similarity index 100% rename from src/clib/core/spio_rearrange_any.h rename to src/clib/core/rearr/spio_rearrange_any.h diff --git a/tests/cunit/CMakeLists.txt b/tests/cunit/CMakeLists.txt index c123afd890..b16e2115c7 100644 --- a/tests/cunit/CMakeLists.txt +++ b/tests/cunit/CMakeLists.txt @@ -9,7 +9,8 @@ include(SPIOUtils) #============================================================================== # SET THE COMPILER OPTIONS #============================================================================== -include_directories("${SCORPIO_SOURCE_DIR}/tests/cunit" "${SCORPIO_SOURCE_DIR}/src/clib" "${SCORPIO_BINARY_DIR}/src/clib" "${SCORPIO_SOURCE_DIR}/src/clib/core" "${SCORPIO_SOURCE_DIR}/src/clib/core/iolib/hdf5" "${SCORPIO_SOURCE_DIR}/src/clib/util") +# FIXME: Use an interface lib to track these include deps +include_directories("${SCORPIO_SOURCE_DIR}/tests/cunit" "${SCORPIO_SOURCE_DIR}/src/clib" "${SCORPIO_BINARY_DIR}/src/clib" "${SCORPIO_SOURCE_DIR}/src/clib/core" "${SCORPIO_SOURCE_DIR}/src/clib/core/rearr" "${SCORPIO_SOURCE_DIR}/src/clib/core/iolib/hdf5" "${SCORPIO_SOURCE_DIR}/src/clib/util") # Compiler-specific compiler options string (TOUPPER "${CMAKE_C_COMPILER_ID}" CMAKE_C_COMPILER_NAME) From bea1bdf24c27c61abf93b3b11c7f8466fb7da01f Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 5 Mar 2026 11:51:44 -0600 Subject: [PATCH 145/194] Core reorg - core/util core/progress_engine Reorganize source codes from core to core/util and core/progress_engine . Updating header files and paths in CMake config files as needed (No source code changes - except comments, hdr file location etc) --- src/clib/CMakeLists.txt | 2 ++ src/clib/core/CMakeLists.txt | 21 +++++++-------- src/clib/core/iolib/hdf5/CMakeLists.txt | 2 +- .../core/{ => iolib/hdf5}/spio_hdf5_utils.hpp | 0 src/clib/core/progress_engine/CMakeLists.txt | 23 ++++++++++++++++ .../{ => progress_engine}/spio_async_mtq.hpp | 0 .../{ => progress_engine}/spio_async_op.hpp | 0 .../spio_async_tcomm.cpp | 0 .../spio_async_tcomm.hpp | 0 .../spio_async_tpool.cpp | 0 .../spio_async_tpool.hpp | 0 .../spio_async_utils.cpp | 0 .../spio_async_utils.hpp | 1 + src/clib/core/util/CMakeLists.txt | 27 +++++++++++++++++++ .../{ => util}/README_pio_sdecomps_regex.txt | 0 .../{ => util}/io_perf_summary.json_expected | 0 .../{ => util}/io_perf_summary.schema.json | 0 .../{ => util}/io_perf_summary.text_expected | 0 .../{ => util}/io_perf_summary.xml_expected | 0 src/clib/core/{ => util}/pio_lists.cpp | 0 .../core/{ => util}/pio_sdecomps_regex.cpp | 0 src/clib/core/{ => util}/pio_sdecomps_regex.h | 0 .../core/{ => util}/pio_sdecomps_regex.hpp | 0 .../core/{ => util}/spio_decomp_logger.hpp | 0 .../{ => util}/spio_decomp_map_info_pool.cpp | 0 .../{ => util}/spio_decomp_map_info_pool.hpp | 0 .../core/{ => util}/spio_decomp_nc_logger.cpp | 0 .../{ => util}/spio_decomp_txt_logger.cpp | 0 .../core/{ => util}/spio_file_mvcache.cpp | 0 src/clib/core/{ => util}/spio_file_mvcache.h | 0 .../core/{ => util}/spio_file_mvcache.hpp | 0 src/clib/core/{ => util}/spio_io_summary.cpp | 0 src/clib/core/{ => util}/spio_io_summary.h | 0 src/clib/core/{ => util}/spio_io_summary.hpp | 0 src/clib/pio_types.hpp | 2 +- src/clib/util/CMakeLists.txt | 1 + .../README_pio_micro_timers.txt | 0 src/clib/{core => util}/pio_print.cpp | 0 tests/cunit/CMakeLists.txt | 2 +- 39 files changed, 66 insertions(+), 15 deletions(-) rename src/clib/core/{ => iolib/hdf5}/spio_hdf5_utils.hpp (100%) create mode 100644 src/clib/core/progress_engine/CMakeLists.txt rename src/clib/core/{ => progress_engine}/spio_async_mtq.hpp (100%) rename src/clib/core/{ => progress_engine}/spio_async_op.hpp (100%) rename src/clib/core/{ => progress_engine}/spio_async_tcomm.cpp (100%) rename src/clib/core/{ => progress_engine}/spio_async_tcomm.hpp (100%) rename src/clib/core/{ => progress_engine}/spio_async_tpool.cpp (100%) rename src/clib/core/{ => progress_engine}/spio_async_tpool.hpp (100%) rename src/clib/core/{ => progress_engine}/spio_async_utils.cpp (100%) rename src/clib/core/{ => progress_engine}/spio_async_utils.hpp (96%) create mode 100644 src/clib/core/util/CMakeLists.txt rename src/clib/core/{ => util}/README_pio_sdecomps_regex.txt (100%) rename src/clib/core/{ => util}/io_perf_summary.json_expected (100%) rename src/clib/core/{ => util}/io_perf_summary.schema.json (100%) rename src/clib/core/{ => util}/io_perf_summary.text_expected (100%) rename src/clib/core/{ => util}/io_perf_summary.xml_expected (100%) rename src/clib/core/{ => util}/pio_lists.cpp (100%) rename src/clib/core/{ => util}/pio_sdecomps_regex.cpp (100%) rename src/clib/core/{ => util}/pio_sdecomps_regex.h (100%) rename src/clib/core/{ => util}/pio_sdecomps_regex.hpp (100%) rename src/clib/core/{ => util}/spio_decomp_logger.hpp (100%) rename src/clib/core/{ => util}/spio_decomp_map_info_pool.cpp (100%) rename src/clib/core/{ => util}/spio_decomp_map_info_pool.hpp (100%) rename src/clib/core/{ => util}/spio_decomp_nc_logger.cpp (100%) rename src/clib/core/{ => util}/spio_decomp_txt_logger.cpp (100%) rename src/clib/core/{ => util}/spio_file_mvcache.cpp (100%) rename src/clib/core/{ => util}/spio_file_mvcache.h (100%) rename src/clib/core/{ => util}/spio_file_mvcache.hpp (100%) rename src/clib/core/{ => util}/spio_io_summary.cpp (100%) rename src/clib/core/{ => util}/spio_io_summary.h (100%) rename src/clib/core/{ => util}/spio_io_summary.hpp (100%) rename src/clib/{core => util}/README_pio_micro_timers.txt (100%) rename src/clib/{core => util}/pio_print.cpp (100%) diff --git a/src/clib/CMakeLists.txt b/src/clib/CMakeLists.txt index 2269d38cce..f1b6422b09 100644 --- a/src/clib/CMakeLists.txt +++ b/src/clib/CMakeLists.txt @@ -469,6 +469,8 @@ add_library (pioc $ $ $ + $ + $ $ $ $) diff --git a/src/clib/core/CMakeLists.txt b/src/clib/core/CMakeLists.txt index e3c3897e90..09fb86ec06 100644 --- a/src/clib/core/CMakeLists.txt +++ b/src/clib/core/CMakeLists.txt @@ -4,43 +4,40 @@ message(STATUS "===== Configuring SCORPIO C Core... =====") # SCORPIO C library - core set (spio_core_src - spio_async_utils.cpp - spio_async_tpool.cpp pio_spmd.cpp - spio_decomp_txt_logger.cpp - spio_decomp_nc_logger.cpp - spio_decomp_map_info_pool.cpp - spio_async_tcomm.cpp pioc_support.cpp pioc.cpp - pio_print.cpp pio_nc.cpp - pio_lists.cpp pio_getput_int.cpp pio_file.cpp pio_darray_int.cpp pio_darray.cpp pio_varm.cpp pio_nc4.cpp - spio_io_summary.cpp - spio_file_mvcache.cpp pioc_sc.cpp - pio_sdecomps_regex.cpp pio_put_nc.cpp pio_msg.cpp pio_get_nc.cpp) +add_subdirectory (util) +add_subdirectory (progress_engine) add_subdirectory (rearr) add_subdirectory (iolib) add_library (spio_core OBJECT + $ + $ $ $ + $ ${spio_core_src}) +set (spio_clib_src_dir "${CMAKE_CURRENT_SOURCE_DIR}/..") +set (spio_clib_bin_dir "${CMAKE_CURRENT_BINARY_DIR}/..") + target_include_directories(spio_core PUBLIC . - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../util ${CMAKE_CURRENT_SOURCE_DIR}/rearr ${CMAKE_CURRENT_SOURCE_DIR}/iolib/hdf5) + PRIVATE ${spio_clib_src_dir} ${spio_clib_bin_dir} ${spio_clib_src_dir}/util ${CMAKE_CURRENT_SOURCE_DIR}/util ${CMAKE_CURRENT_SOURCE_DIR}/progress_engine ${CMAKE_CURRENT_SOURCE_DIR}/rearr ${CMAKE_CURRENT_SOURCE_DIR}/iolib/hdf5) target_link_libraries(spio_core PUBLIC spio_default_public_options diff --git a/src/clib/core/iolib/hdf5/CMakeLists.txt b/src/clib/core/iolib/hdf5/CMakeLists.txt index d3eacf3713..d37607e15d 100644 --- a/src/clib/core/iolib/hdf5/CMakeLists.txt +++ b/src/clib/core/iolib/hdf5/CMakeLists.txt @@ -13,7 +13,7 @@ set (spio_clib_bin_dir "${CMAKE_CURRENT_BINARY_DIR}/../../..") add_library (spio_core_iolib_hdf5 OBJECT ${spio_core_iolib_hdf5_src}) target_include_directories(spio_core_iolib_hdf5 PUBLIC . - PRIVATE ${spio_clib_src_dir} ${spio_clib_bin_dir} ${spio_clib_src_dir}/util ${spio_clib_src_dir}/core) + PRIVATE ${spio_clib_src_dir} ${spio_clib_bin_dir} ${spio_clib_src_dir}/util ${spio_clib_src_dir}/core ${spio_clib_src_dir}/core/util ${spio_clib_src_dir}/core/progress_engine) target_link_libraries(spio_core_iolib_hdf5 PUBLIC spio_default_public_options PRIVATE spio_default_private_options) diff --git a/src/clib/core/spio_hdf5_utils.hpp b/src/clib/core/iolib/hdf5/spio_hdf5_utils.hpp similarity index 100% rename from src/clib/core/spio_hdf5_utils.hpp rename to src/clib/core/iolib/hdf5/spio_hdf5_utils.hpp diff --git a/src/clib/core/progress_engine/CMakeLists.txt b/src/clib/core/progress_engine/CMakeLists.txt new file mode 100644 index 0000000000..35e77775ce --- /dev/null +++ b/src/clib/core/progress_engine/CMakeLists.txt @@ -0,0 +1,23 @@ +#============================================================================== +# DEFINE THE TARGET LIBRARY +#============================================================================== +message(STATUS "===== Configuring SCORPIO C Core (progress engine)... =====") +# SCORPIO C library - core +set (spio_core_progress_engine_src + spio_async_utils.cpp + spio_async_tpool.cpp + spio_async_tcomm.cpp) + +add_library (spio_core_progress_engine OBJECT + ${spio_core_progress_engine_src}) + +set (spio_clib_src_dir "${CMAKE_CURRENT_SOURCE_DIR}/../..") +set (spio_clib_bin_dir "${CMAKE_CURRENT_BINARY_DIR}/../..") + +target_include_directories(spio_core_progress_engine + PUBLIC . + PRIVATE ${spio_clib_src_dir} ${spio_clib_bin_dir} ${spio_clib_src_dir}/util ${spio_clib_src_dir}/core ${spio_clib_src_dir}/core/util ${spio_clib_src_dir}/core/iolib/hdf5) + +target_link_libraries(spio_core_progress_engine + PUBLIC spio_default_public_options + PRIVATE spio_default_private_options) diff --git a/src/clib/core/spio_async_mtq.hpp b/src/clib/core/progress_engine/spio_async_mtq.hpp similarity index 100% rename from src/clib/core/spio_async_mtq.hpp rename to src/clib/core/progress_engine/spio_async_mtq.hpp diff --git a/src/clib/core/spio_async_op.hpp b/src/clib/core/progress_engine/spio_async_op.hpp similarity index 100% rename from src/clib/core/spio_async_op.hpp rename to src/clib/core/progress_engine/spio_async_op.hpp diff --git a/src/clib/core/spio_async_tcomm.cpp b/src/clib/core/progress_engine/spio_async_tcomm.cpp similarity index 100% rename from src/clib/core/spio_async_tcomm.cpp rename to src/clib/core/progress_engine/spio_async_tcomm.cpp diff --git a/src/clib/core/spio_async_tcomm.hpp b/src/clib/core/progress_engine/spio_async_tcomm.hpp similarity index 100% rename from src/clib/core/spio_async_tcomm.hpp rename to src/clib/core/progress_engine/spio_async_tcomm.hpp diff --git a/src/clib/core/spio_async_tpool.cpp b/src/clib/core/progress_engine/spio_async_tpool.cpp similarity index 100% rename from src/clib/core/spio_async_tpool.cpp rename to src/clib/core/progress_engine/spio_async_tpool.cpp diff --git a/src/clib/core/spio_async_tpool.hpp b/src/clib/core/progress_engine/spio_async_tpool.hpp similarity index 100% rename from src/clib/core/spio_async_tpool.hpp rename to src/clib/core/progress_engine/spio_async_tpool.hpp diff --git a/src/clib/core/spio_async_utils.cpp b/src/clib/core/progress_engine/spio_async_utils.cpp similarity index 100% rename from src/clib/core/spio_async_utils.cpp rename to src/clib/core/progress_engine/spio_async_utils.cpp diff --git a/src/clib/core/spio_async_utils.hpp b/src/clib/core/progress_engine/spio_async_utils.hpp similarity index 96% rename from src/clib/core/spio_async_utils.hpp rename to src/clib/core/progress_engine/spio_async_utils.hpp index 981959462a..b49543a7ba 100644 --- a/src/clib/core/spio_async_utils.hpp +++ b/src/clib/core/progress_engine/spio_async_utils.hpp @@ -5,6 +5,7 @@ #include #include #include +/* FIXME: Avoid including HDF5 async hdr here */ #include "spio_async_hdf5_utils.hpp" #include "spio_async_op.hpp" diff --git a/src/clib/core/util/CMakeLists.txt b/src/clib/core/util/CMakeLists.txt new file mode 100644 index 0000000000..1cd1437475 --- /dev/null +++ b/src/clib/core/util/CMakeLists.txt @@ -0,0 +1,27 @@ +#============================================================================== +# DEFINE THE TARGET LIBRARY +#============================================================================== +message(STATUS "===== Configuring SCORPIO C Core (util)... =====") +# SCORPIO C library - core +set (spio_core_util_src + spio_decomp_txt_logger.cpp + spio_decomp_nc_logger.cpp + spio_decomp_map_info_pool.cpp + pio_lists.cpp + spio_io_summary.cpp + spio_file_mvcache.cpp + pio_sdecomps_regex.cpp) + +add_library (spio_core_util OBJECT + ${spio_core_util_src}) + +set (spio_clib_src_dir "${CMAKE_CURRENT_SOURCE_DIR}/../..") +set (spio_clib_bin_dir "${CMAKE_CURRENT_BINARY_DIR}/../..") + +target_include_directories(spio_core_util + PUBLIC . + PRIVATE ${spio_clib_src_dir} ${spio_clib_bin_dir} ${spio_clib_src_dir}/util ${spio_clib_src_dir}/core) + +target_link_libraries(spio_core_util + PUBLIC spio_default_public_options + PRIVATE spio_default_private_options) diff --git a/src/clib/core/README_pio_sdecomps_regex.txt b/src/clib/core/util/README_pio_sdecomps_regex.txt similarity index 100% rename from src/clib/core/README_pio_sdecomps_regex.txt rename to src/clib/core/util/README_pio_sdecomps_regex.txt diff --git a/src/clib/core/io_perf_summary.json_expected b/src/clib/core/util/io_perf_summary.json_expected similarity index 100% rename from src/clib/core/io_perf_summary.json_expected rename to src/clib/core/util/io_perf_summary.json_expected diff --git a/src/clib/core/io_perf_summary.schema.json b/src/clib/core/util/io_perf_summary.schema.json similarity index 100% rename from src/clib/core/io_perf_summary.schema.json rename to src/clib/core/util/io_perf_summary.schema.json diff --git a/src/clib/core/io_perf_summary.text_expected b/src/clib/core/util/io_perf_summary.text_expected similarity index 100% rename from src/clib/core/io_perf_summary.text_expected rename to src/clib/core/util/io_perf_summary.text_expected diff --git a/src/clib/core/io_perf_summary.xml_expected b/src/clib/core/util/io_perf_summary.xml_expected similarity index 100% rename from src/clib/core/io_perf_summary.xml_expected rename to src/clib/core/util/io_perf_summary.xml_expected diff --git a/src/clib/core/pio_lists.cpp b/src/clib/core/util/pio_lists.cpp similarity index 100% rename from src/clib/core/pio_lists.cpp rename to src/clib/core/util/pio_lists.cpp diff --git a/src/clib/core/pio_sdecomps_regex.cpp b/src/clib/core/util/pio_sdecomps_regex.cpp similarity index 100% rename from src/clib/core/pio_sdecomps_regex.cpp rename to src/clib/core/util/pio_sdecomps_regex.cpp diff --git a/src/clib/core/pio_sdecomps_regex.h b/src/clib/core/util/pio_sdecomps_regex.h similarity index 100% rename from src/clib/core/pio_sdecomps_regex.h rename to src/clib/core/util/pio_sdecomps_regex.h diff --git a/src/clib/core/pio_sdecomps_regex.hpp b/src/clib/core/util/pio_sdecomps_regex.hpp similarity index 100% rename from src/clib/core/pio_sdecomps_regex.hpp rename to src/clib/core/util/pio_sdecomps_regex.hpp diff --git a/src/clib/core/spio_decomp_logger.hpp b/src/clib/core/util/spio_decomp_logger.hpp similarity index 100% rename from src/clib/core/spio_decomp_logger.hpp rename to src/clib/core/util/spio_decomp_logger.hpp diff --git a/src/clib/core/spio_decomp_map_info_pool.cpp b/src/clib/core/util/spio_decomp_map_info_pool.cpp similarity index 100% rename from src/clib/core/spio_decomp_map_info_pool.cpp rename to src/clib/core/util/spio_decomp_map_info_pool.cpp diff --git a/src/clib/core/spio_decomp_map_info_pool.hpp b/src/clib/core/util/spio_decomp_map_info_pool.hpp similarity index 100% rename from src/clib/core/spio_decomp_map_info_pool.hpp rename to src/clib/core/util/spio_decomp_map_info_pool.hpp diff --git a/src/clib/core/spio_decomp_nc_logger.cpp b/src/clib/core/util/spio_decomp_nc_logger.cpp similarity index 100% rename from src/clib/core/spio_decomp_nc_logger.cpp rename to src/clib/core/util/spio_decomp_nc_logger.cpp diff --git a/src/clib/core/spio_decomp_txt_logger.cpp b/src/clib/core/util/spio_decomp_txt_logger.cpp similarity index 100% rename from src/clib/core/spio_decomp_txt_logger.cpp rename to src/clib/core/util/spio_decomp_txt_logger.cpp diff --git a/src/clib/core/spio_file_mvcache.cpp b/src/clib/core/util/spio_file_mvcache.cpp similarity index 100% rename from src/clib/core/spio_file_mvcache.cpp rename to src/clib/core/util/spio_file_mvcache.cpp diff --git a/src/clib/core/spio_file_mvcache.h b/src/clib/core/util/spio_file_mvcache.h similarity index 100% rename from src/clib/core/spio_file_mvcache.h rename to src/clib/core/util/spio_file_mvcache.h diff --git a/src/clib/core/spio_file_mvcache.hpp b/src/clib/core/util/spio_file_mvcache.hpp similarity index 100% rename from src/clib/core/spio_file_mvcache.hpp rename to src/clib/core/util/spio_file_mvcache.hpp diff --git a/src/clib/core/spio_io_summary.cpp b/src/clib/core/util/spio_io_summary.cpp similarity index 100% rename from src/clib/core/spio_io_summary.cpp rename to src/clib/core/util/spio_io_summary.cpp diff --git a/src/clib/core/spio_io_summary.h b/src/clib/core/util/spio_io_summary.h similarity index 100% rename from src/clib/core/spio_io_summary.h rename to src/clib/core/util/spio_io_summary.h diff --git a/src/clib/core/spio_io_summary.hpp b/src/clib/core/util/spio_io_summary.hpp similarity index 100% rename from src/clib/core/spio_io_summary.hpp rename to src/clib/core/util/spio_io_summary.hpp diff --git a/src/clib/pio_types.hpp b/src/clib/pio_types.hpp index 4bb71fd729..56adf48c39 100644 --- a/src/clib/pio_types.hpp +++ b/src/clib/pio_types.hpp @@ -50,7 +50,7 @@ extern "C" { #include #include #include -#include "core/spio_async_op.hpp" +#include "core/progress_engine/spio_async_op.hpp" #ifdef PIO_MICRO_TIMING /** Some fwd declarations to avoid including internal headers */ diff --git a/src/clib/util/CMakeLists.txt b/src/clib/util/CMakeLists.txt index be2e1bccc3..9097b8e262 100644 --- a/src/clib/util/CMakeLists.txt +++ b/src/clib/util/CMakeLists.txt @@ -15,6 +15,7 @@ set (spio_util_src spio_tracer_mdata.cpp spio_tracer_decomp.cpp spio_serializer.cpp + pio_print.cpp pio_mpi_timer.cpp) add_library (spio_util OBJECT ${spio_util_src}) diff --git a/src/clib/core/README_pio_micro_timers.txt b/src/clib/util/README_pio_micro_timers.txt similarity index 100% rename from src/clib/core/README_pio_micro_timers.txt rename to src/clib/util/README_pio_micro_timers.txt diff --git a/src/clib/core/pio_print.cpp b/src/clib/util/pio_print.cpp similarity index 100% rename from src/clib/core/pio_print.cpp rename to src/clib/util/pio_print.cpp diff --git a/tests/cunit/CMakeLists.txt b/tests/cunit/CMakeLists.txt index b16e2115c7..a27e1c0e9c 100644 --- a/tests/cunit/CMakeLists.txt +++ b/tests/cunit/CMakeLists.txt @@ -10,7 +10,7 @@ include(SPIOUtils) # SET THE COMPILER OPTIONS #============================================================================== # FIXME: Use an interface lib to track these include deps -include_directories("${SCORPIO_SOURCE_DIR}/tests/cunit" "${SCORPIO_SOURCE_DIR}/src/clib" "${SCORPIO_BINARY_DIR}/src/clib" "${SCORPIO_SOURCE_DIR}/src/clib/core" "${SCORPIO_SOURCE_DIR}/src/clib/core/rearr" "${SCORPIO_SOURCE_DIR}/src/clib/core/iolib/hdf5" "${SCORPIO_SOURCE_DIR}/src/clib/util") +include_directories("${SCORPIO_SOURCE_DIR}/tests/cunit" "${SCORPIO_SOURCE_DIR}/src/clib" "${SCORPIO_BINARY_DIR}/src/clib" "${SCORPIO_SOURCE_DIR}/src/clib/core" "${SCORPIO_SOURCE_DIR}/src/clib/core/util" "${SCORPIO_SOURCE_DIR}/src/clib/core/rearr" "${SCORPIO_SOURCE_DIR}/src/clib/core/progress_engine" "${SCORPIO_SOURCE_DIR}/src/clib/core/iolib/hdf5" "${SCORPIO_SOURCE_DIR}/src/clib/util") # Compiler-specific compiler options string (TOUPPER "${CMAKE_C_COMPILER_ID}" CMAKE_C_COMPILER_NAME) From 3d87632d151345cd45a5281aacbc57dd1326ef59 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 9 Mar 2026 15:19:14 -0500 Subject: [PATCH 146/194] Adding gptl timers and cond timers Adding C++ timers that wrap GPTL timers under the hood. Also adding conditional timers --- src/clib/util/spio_gptl_utils.hpp | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/clib/util/spio_gptl_utils.hpp b/src/clib/util/spio_gptl_utils.hpp index 762a678ca4..193f371195 100644 --- a/src/clib/util/spio_gptl_utils.hpp +++ b/src/clib/util/spio_gptl_utils.hpp @@ -11,11 +11,33 @@ namespace SPIO_Util{ namespace GPTL_Util{ class GPTL_wrapper{ public: - GPTL_wrapper(const char *gptl_timer_name):gptl_timer_name_(gptl_timer_name){ GPTLstart(gptl_timer_name); } - ~GPTL_wrapper(){ GPTLstop(gptl_timer_name_.c_str()); } + GPTL_wrapper(const std::string &gptl_timer_name):gptl_timer_name_(gptl_timer_name), is_valid_(false){ + if(!gptl_timer_name_.empty()){ + GPTLstart(gptl_timer_name_.c_str()); + is_valid_ = true; + } + } + + ~GPTL_wrapper(){ + if(is_valid_) { GPTLstop(gptl_timer_name_.c_str()); } + } + private: const std::string gptl_timer_name_; + /* Is a valid GPTL timer - has a valid timer name */ + bool is_valid_; + }; + + class GPTL_timer : public GPTL_wrapper{ + public: + GPTL_timer(const std::string &name) : GPTL_wrapper(name) {} }; + + class GPTL_cond_timer : public GPTL_timer{ + public: + GPTL_cond_timer(const std::string &name, bool cond) : GPTL_timer((cond) ? name : "") {} + }; + } // namespace GPTL_Util } // namespace SPIO_Util #endif // __SPIO_GPTL_UTILS_HPP__ From f2e2537b3161ece93fe1bf764fca8749194a6524 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 9 Mar 2026 15:33:47 -0500 Subject: [PATCH 147/194] Using GPTL C++ wrapper timer Using the new GPTL C++ wrapper timer (instead of using the wrapper directly) --- src/clib/api/spio_ddata_api.cpp | 12 +++---- src/clib/api/spio_dim_api.cpp | 12 +++---- src/clib/api/spio_err_api.cpp | 4 +-- src/clib/api/spio_file_api.cpp | 22 ++++++------- src/clib/api/spio_file_md_api.cpp | 20 ++++++------ src/clib/api/spio_get_att_api.cpp | 26 +++++++-------- src/clib/api/spio_get_var1_api.cpp | 26 +++++++-------- src/clib/api/spio_get_var_api.cpp | 26 +++++++-------- src/clib/api/spio_get_vara_api.cpp | 26 +++++++-------- src/clib/api/spio_get_varm_api.cpp | 24 +++++++------- src/clib/api/spio_get_vars_api.cpp | 26 +++++++-------- src/clib/api/spio_io_decomp_api.cpp | 22 ++++++------- src/clib/api/spio_io_sys_api.cpp | 38 +++++++++++----------- src/clib/api/spio_misc_att_api.cpp | 16 +++++----- src/clib/api/spio_misc_var_api.cpp | 40 ++++++++++++------------ src/clib/api/spio_put_att_api.cpp | 26 +++++++-------- src/clib/api/spio_put_var1_api.cpp | 26 +++++++-------- src/clib/api/spio_put_var_api.cpp | 26 +++++++-------- src/clib/api/spio_put_vara_api.cpp | 26 +++++++-------- src/clib/api/spio_put_varm_api.cpp | 26 +++++++-------- src/clib/api/spio_put_vars_api.cpp | 26 +++++++-------- src/clib/core/pio_darray.cpp | 4 +-- src/clib/core/rearr/pio_rearr_contig.cpp | 20 ++++++------ src/clib/core/rearr/pio_rearr_utils.cpp | 8 ++--- 24 files changed, 264 insertions(+), 264 deletions(-) diff --git a/src/clib/api/spio_ddata_api.cpp b/src/clib/api/spio_ddata_api.cpp index 6a926f116a..dc905fae62 100644 --- a/src/clib/api/spio_ddata_api.cpp +++ b/src/clib/api/spio_ddata_api.cpp @@ -8,7 +8,7 @@ /* ================= Read/Write APIs for distributed data ================ */ int PIOc_advanceframe(int ncid, int varid) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_advanceframe"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_advanceframe"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_advanceframe"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid).flush(); @@ -18,7 +18,7 @@ int PIOc_advanceframe(int ncid, int varid) int PIOc_setframe(int ncid, int varid, int frame) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_setframe"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_setframe"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_setframe"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid). @@ -30,7 +30,7 @@ int PIOc_setframe(int ncid, int varid, int frame) int PIOc_write_darray(int ncid, int varid, int ioid, PIO_Offset arraylen, const void *array, const void *fillvalue) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_write_darray"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_write_darray"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_write_darray"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid). @@ -43,7 +43,7 @@ int PIOc_write_darray(int ncid, int varid, int ioid, PIO_Offset arraylen, const int PIOc_write_darray_multi(int ncid, const int *varids, int ioid, int nvars, PIO_Offset arraylen, const void *array, const int *frame, const void **fillvalue, bool flushtodisk) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_write_darray_multi"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_write_darray_multi"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_write_darray_multi"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("*varids", varids). @@ -59,7 +59,7 @@ int PIOc_write_darray_multi(int ncid, const int *varids, int ioid, int nvars, PI int PIOc_read_darray(int ncid, int varid, int ioid, PIO_Offset arraylen, void *array) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_read_darray"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_read_darray"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_read_darray"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid). @@ -71,7 +71,7 @@ int PIOc_read_darray(int ncid, int varid, int ioid, PIO_Offset arraylen, void *a int PIOc_get_local_array_size(int ioid) { - //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_local_array_size"); + //SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_local_array_size"); /* FIXME: How should we trace these non I/O system specific functions? */ return PIOc_get_local_array_size_impl(ioid); } diff --git a/src/clib/api/spio_dim_api.cpp b/src/clib/api/spio_dim_api.cpp index 97bb4c822c..b520a3f6d0 100644 --- a/src/clib/api/spio_dim_api.cpp +++ b/src/clib/api/spio_dim_api.cpp @@ -9,7 +9,7 @@ /* APIs for variable dimensions */ int PIOc_inq_dim(int ncid, int dimid, char *name, PIO_Offset *lenp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_dimx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inq_dimx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_dim"); @@ -26,7 +26,7 @@ int PIOc_inq_dim(int ncid, int dimid, char *name, PIO_Offset *lenp) int PIOc_inq_dimid(int ncid, const char *name, int *idp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_dimx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inq_dimx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_dimid"); @@ -44,7 +44,7 @@ int PIOc_inq_dimid(int ncid, const char *name, int *idp) int PIOc_inq_dimname(int ncid, int dimid, char *name) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_dimx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inq_dimx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_dimname"); @@ -61,7 +61,7 @@ int PIOc_inq_dimname(int ncid, int dimid, char *name) int PIOc_inq_dimlen(int ncid, int dimid, PIO_Offset *lenp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_dimx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inq_dimx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_dimlen"); @@ -78,7 +78,7 @@ int PIOc_inq_dimlen(int ncid, int dimid, PIO_Offset *lenp) int PIOc_rename_dim(int ncid, int dimid, const char *name) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_rename_dim"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_rename_dim"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_rename_dim"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("dimid", dimid). @@ -89,7 +89,7 @@ int PIOc_rename_dim(int ncid, int dimid, const char *name) int PIOc_def_dim(int ncid, const char *name, PIO_Offset len, int *idp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_def_dim"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_def_dim"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_def_dim"); diff --git a/src/clib/api/spio_err_api.cpp b/src/clib/api/spio_err_api.cpp index 11bed90165..a7afecc1a5 100644 --- a/src/clib/api/spio_err_api.cpp +++ b/src/clib/api/spio_err_api.cpp @@ -7,14 +7,14 @@ /* ========== Error handling APIs =========== */ int PIOc_strerror(int pioerr, char *errmsg, size_t errmsg_sz) { - //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_strerror"); + //SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_strerror"); /* FIXME: Handle non I/O system specific calls */ return PIOc_strerror_impl(pioerr, errmsg, errmsg_sz); } int PIOc_set_log_level(int level) { - //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_set_log_level"); + //SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_set_log_level"); /* FIXME: Handle non I/O system specific calls */ return PIOc_set_log_level_impl(level); } diff --git a/src/clib/api/spio_file_api.cpp b/src/clib/api/spio_file_api.cpp index 1a9a988581..8a13130f95 100644 --- a/src/clib/api/spio_file_api.cpp +++ b/src/clib/api/spio_file_api.cpp @@ -8,7 +8,7 @@ /* ================= File APIs ================= */ int PIOc_deletefile(int iosysid, const char *filename) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_deletefile"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_deletefile"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_deletefile"); tr.set_iosys_id(iosysid).add_arg("iosysid", iosysid). @@ -19,7 +19,7 @@ int PIOc_deletefile(int iosysid, const char *filename) int PIOc_createfile(int iosysid, int *ncidp, const int *iotype, const char *fname, int mode) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_createfile"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_createfile"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_createfile"); @@ -37,7 +37,7 @@ int PIOc_createfile(int iosysid, int *ncidp, const int *iotype, const char *fnam int PIOc_create(int iosysid, const char *path, int cmode, int *ncidp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_create"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_create"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_create"); @@ -55,7 +55,7 @@ int PIOc_create(int iosysid, const char *path, int cmode, int *ncidp) int PIOc_openfile(int iosysid, int *ncidp, int *iotype, const char *fname, int mode) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_openfile"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_openfile"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_openfile"); @@ -73,7 +73,7 @@ int PIOc_openfile(int iosysid, int *ncidp, int *iotype, const char *fname, int m int PIOc_openfile2(int iosysid, int *ncidp, int *iotype, const char *fname, int mode) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_openfile2"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_openfile2"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_openfile2"); @@ -92,7 +92,7 @@ int PIOc_openfile2(int iosysid, int *ncidp, int *iotype, const char *fname, int int PIOc_openfile_retry(int iosysid, int *ncidp, int *iotype, const char *filename, int mode, int retry) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_openfile_retry"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_openfile_retry"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_openfile_retry"); @@ -110,7 +110,7 @@ int PIOc_openfile_retry(int iosysid, int *ncidp, int *iotype, int PIOc_open(int iosysid, const char *path, int mode, int *ncidp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_open"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_open"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_open"); @@ -128,7 +128,7 @@ int PIOc_open(int iosysid, const char *path, int mode, int *ncidp) int PIOc_closefile(int ncid) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_closefile"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_closefile"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_closefile"); tr.set_file_id(ncid).add_arg("ncid", ncid).flush(); @@ -138,7 +138,7 @@ int PIOc_closefile(int ncid) int PIOc_File_is_Open(int ncid) { - //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_File_is_Open"); + //SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_File_is_Open"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_File_is_Open"); tr.set_file_id(ncid).add_arg("ncid", ncid).flush(); @@ -149,7 +149,7 @@ int PIOc_File_is_Open(int ncid) /* Set the error hanlding for a file. */ int PIOc_Set_File_Error_Handling(int ncid, int method) { - //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_Set_File_Error_Handling"); + //SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_Set_File_Error_Handling"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_Set_File_Error_Handling"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("method", method).flush(); @@ -159,7 +159,7 @@ int PIOc_Set_File_Error_Handling(int ncid, int method) int PIOc_sync(int ncid) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_sync"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_sync"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_sync"); tr.set_file_id(ncid).add_arg("ncid", ncid).flush(); diff --git a/src/clib/api/spio_file_md_api.cpp b/src/clib/api/spio_file_md_api.cpp index 9ff12077f4..85e2c05fbb 100644 --- a/src/clib/api/spio_file_md_api.cpp +++ b/src/clib/api/spio_file_md_api.cpp @@ -8,7 +8,7 @@ /* ================= File meta-data APIs ============== */ int PIOc_redef(int ncid) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_redef"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_redef"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_redef"); tr.set_file_id(ncid).add_arg("ncid", ncid).flush(); @@ -18,7 +18,7 @@ int PIOc_redef(int ncid) int PIOc_enddef(int ncid) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_enddef"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_enddef"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_enddef"); tr.set_file_id(ncid).add_arg("ncid", ncid).flush(); @@ -28,7 +28,7 @@ int PIOc_enddef(int ncid) int PIOc_inq_format(int ncid, int *formatp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inqx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inqx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING @@ -46,7 +46,7 @@ int PIOc_inq_format(int ncid, int *formatp) int PIOc_inq(int ncid, int *ndimsp, int *nvarsp, int *ngattsp, int *unlimdimidp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inqx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inqx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING @@ -66,7 +66,7 @@ int PIOc_inq(int ncid, int *ndimsp, int *nvarsp, int *ngattsp, int *unlimdimidp) int PIOc_inq_ndims(int ncid, int *ndimsp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inqx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inqx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING @@ -84,7 +84,7 @@ int PIOc_inq_ndims(int ncid, int *ndimsp) int PIOc_inq_nvars(int ncid, int *nvarsp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inqx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inqx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING @@ -102,7 +102,7 @@ int PIOc_inq_nvars(int ncid, int *nvarsp) int PIOc_inq_natts(int ncid, int *ngattsp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inqx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inqx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING @@ -120,7 +120,7 @@ int PIOc_inq_natts(int ncid, int *ngattsp) int PIOc_inq_unlimdim(int ncid, int *unlimdimidp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inqx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inqx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING @@ -138,7 +138,7 @@ int PIOc_inq_unlimdim(int ncid, int *unlimdimidp) int PIOc_inq_unlimdims(int ncid, int *nunlimdimsp, int *unlimdimidsp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inqx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inqx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING @@ -160,7 +160,7 @@ int PIOc_inq_unlimdims(int ncid, int *nunlimdimsp, int *unlimdimidsp) int PIOc_inq_type(int ncid, nc_type xtype, char *name, PIO_Offset *sizep) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inqx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inqx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING diff --git a/src/clib/api/spio_get_att_api.cpp b/src/clib/api/spio_get_att_api.cpp index 9e977a31e9..a0f2d9ac0b 100644 --- a/src/clib/api/spio_get_att_api.cpp +++ b/src/clib/api/spio_get_att_api.cpp @@ -8,7 +8,7 @@ /* APIs for reading file/variable attributes */ int PIOc_get_att(int ncid, int varid, const char *name, void *ip) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -20,7 +20,7 @@ int PIOc_get_att(int ncid, int varid, const char *name, void *ip) int PIOc_get_att_text(int ncid, int varid, const char *name, char *ip) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att_text"); @@ -38,7 +38,7 @@ int PIOc_get_att_text(int ncid, int varid, const char *name, char *ip) int PIOc_get_att_schar(int ncid, int varid, const char *name, signed char *ip) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att_schar"); @@ -56,7 +56,7 @@ int PIOc_get_att_schar(int ncid, int varid, const char *name, signed char *ip) int PIOc_get_att_short(int ncid, int varid, const char *name, short *ip) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att_short"); @@ -74,7 +74,7 @@ int PIOc_get_att_short(int ncid, int varid, const char *name, short *ip) int PIOc_get_att_int(int ncid, int varid, const char *name, int *ip) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att_int"); @@ -92,7 +92,7 @@ int PIOc_get_att_int(int ncid, int varid, const char *name, int *ip) int PIOc_get_att_long(int ncid, int varid, const char *name, long *ip) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att_long"); @@ -110,7 +110,7 @@ int PIOc_get_att_long(int ncid, int varid, const char *name, long *ip) int PIOc_get_att_float(int ncid, int varid, const char *name, float *ip) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att_float"); @@ -128,7 +128,7 @@ int PIOc_get_att_float(int ncid, int varid, const char *name, float *ip) int PIOc_get_att_double(int ncid, int varid, const char *name, double *ip) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att_double"); @@ -146,7 +146,7 @@ int PIOc_get_att_double(int ncid, int varid, const char *name, double *ip) int PIOc_get_att_uchar(int ncid, int varid, const char *name, unsigned char *ip) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att_uchar"); @@ -164,7 +164,7 @@ int PIOc_get_att_uchar(int ncid, int varid, const char *name, unsigned char *ip) int PIOc_get_att_ushort(int ncid, int varid, const char *name, unsigned short *ip) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att_ushort"); @@ -182,7 +182,7 @@ int PIOc_get_att_ushort(int ncid, int varid, const char *name, unsigned short *i int PIOc_get_att_uint(int ncid, int varid, const char *name, unsigned int *ip) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att_uint"); @@ -200,7 +200,7 @@ int PIOc_get_att_uint(int ncid, int varid, const char *name, unsigned int *ip) int PIOc_get_att_longlong(int ncid, int varid, const char *name, long long *ip) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att_longlong"); @@ -218,7 +218,7 @@ int PIOc_get_att_longlong(int ncid, int varid, const char *name, long long *ip) int PIOc_get_att_ulonglong(int ncid, int varid, const char *name, unsigned long long *ip) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_att_ulonglong"); diff --git a/src/clib/api/spio_get_var1_api.cpp b/src/clib/api/spio_get_var1_api.cpp index f8a48d9fa4..32b4bb1b8a 100644 --- a/src/clib/api/spio_get_var1_api.cpp +++ b/src/clib/api/spio_get_var1_api.cpp @@ -9,7 +9,7 @@ /* APIs for reading non-distributed data/variable at a specified index */ int PIOc_get_var1(int ncid, int varid, const PIO_Offset *index, void *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -21,7 +21,7 @@ int PIOc_get_var1(int ncid, int varid, const PIO_Offset *index, void *buf) int PIOc_get_var1_text(int ncid, int varid, const PIO_Offset *index, char *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1_text"); @@ -39,7 +39,7 @@ int PIOc_get_var1_text(int ncid, int varid, const PIO_Offset *index, char *buf) int PIOc_get_var1_schar(int ncid, int varid, const PIO_Offset *index, signed char *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1_schar"); @@ -57,7 +57,7 @@ int PIOc_get_var1_schar(int ncid, int varid, const PIO_Offset *index, signed cha int PIOc_get_var1_short(int ncid, int varid, const PIO_Offset *index, short *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1_short"); @@ -75,7 +75,7 @@ int PIOc_get_var1_short(int ncid, int varid, const PIO_Offset *index, short *buf int PIOc_get_var1_int(int ncid, int varid, const PIO_Offset *index, int *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1_int"); @@ -93,7 +93,7 @@ int PIOc_get_var1_int(int ncid, int varid, const PIO_Offset *index, int *buf) int PIOc_get_var1_long(int ncid, int varid, const PIO_Offset *index, long *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1_long"); @@ -111,7 +111,7 @@ int PIOc_get_var1_long(int ncid, int varid, const PIO_Offset *index, long *buf) int PIOc_get_var1_float(int ncid, int varid, const PIO_Offset *index, float *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1_float"); @@ -129,7 +129,7 @@ int PIOc_get_var1_float(int ncid, int varid, const PIO_Offset *index, float *buf int PIOc_get_var1_double(int ncid, int varid, const PIO_Offset *index, double *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1_double"); @@ -147,7 +147,7 @@ int PIOc_get_var1_double(int ncid, int varid, const PIO_Offset *index, double *b int PIOc_get_var1_uchar(int ncid, int varid, const PIO_Offset *index, unsigned char *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1_uchar"); @@ -165,7 +165,7 @@ int PIOc_get_var1_uchar(int ncid, int varid, const PIO_Offset *index, unsigned c int PIOc_get_var1_ushort(int ncid, int varid, const PIO_Offset *index, unsigned short *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1_ushort"); @@ -183,7 +183,7 @@ int PIOc_get_var1_ushort(int ncid, int varid, const PIO_Offset *index, unsigned int PIOc_get_var1_uint(int ncid, int varid, const PIO_Offset *index, unsigned int *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1_uint"); @@ -201,7 +201,7 @@ int PIOc_get_var1_uint(int ncid, int varid, const PIO_Offset *index, unsigned in int PIOc_get_var1_longlong(int ncid, int varid, const PIO_Offset *index, long long *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1_longlong"); @@ -219,7 +219,7 @@ int PIOc_get_var1_longlong(int ncid, int varid, const PIO_Offset *index, long lo int PIOc_get_var1_ulonglong(int ncid, int varid, const PIO_Offset *index, unsigned long long *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var1_ulonglong"); diff --git a/src/clib/api/spio_get_var_api.cpp b/src/clib/api/spio_get_var_api.cpp index 91af33400a..339d376b1d 100644 --- a/src/clib/api/spio_get_var_api.cpp +++ b/src/clib/api/spio_get_var_api.cpp @@ -9,7 +9,7 @@ /* APIs for reading entire non-distributed data/variable */ int PIOc_get_var(int ncid, int varid, void *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -20,7 +20,7 @@ int PIOc_get_var(int ncid, int varid, void *buf) int PIOc_get_var_text(int ncid, int varid, char *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_text"); @@ -38,7 +38,7 @@ int PIOc_get_var_text(int ncid, int varid, char *buf) int PIOc_get_var_schar(int ncid, int varid, signed char *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_schar"); @@ -55,7 +55,7 @@ int PIOc_get_var_schar(int ncid, int varid, signed char *buf) int PIOc_get_var_short(int ncid, int varid, short *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_short"); @@ -72,7 +72,7 @@ int PIOc_get_var_short(int ncid, int varid, short *buf) int PIOc_get_var_int(int ncid, int varid, int *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_int"); @@ -89,7 +89,7 @@ int PIOc_get_var_int(int ncid, int varid, int *buf) int PIOc_get_var_long(int ncid, int varid, long *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_long"); @@ -106,7 +106,7 @@ int PIOc_get_var_long(int ncid, int varid, long *buf) int PIOc_get_var_float(int ncid, int varid, float *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_float"); @@ -123,7 +123,7 @@ int PIOc_get_var_float(int ncid, int varid, float *buf) int PIOc_get_var_double(int ncid, int varid, double *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_double"); @@ -140,7 +140,7 @@ int PIOc_get_var_double(int ncid, int varid, double *buf) int PIOc_get_var_uchar(int ncid, int varid, unsigned char *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_uchar"); @@ -157,7 +157,7 @@ int PIOc_get_var_uchar(int ncid, int varid, unsigned char *buf) int PIOc_get_var_ushort(int ncid, int varid, unsigned short *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_ushort"); @@ -174,7 +174,7 @@ int PIOc_get_var_ushort(int ncid, int varid, unsigned short *buf) int PIOc_get_var_uint(int ncid, int varid, unsigned int *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_uint"); @@ -191,7 +191,7 @@ int PIOc_get_var_uint(int ncid, int varid, unsigned int *buf) int PIOc_get_var_longlong(int ncid, int varid, long long *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_longlong"); @@ -208,7 +208,7 @@ int PIOc_get_var_longlong(int ncid, int varid, long long *buf) int PIOc_get_var_ulonglong(int ncid, int varid, unsigned long long *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_ulonglong"); diff --git a/src/clib/api/spio_get_vara_api.cpp b/src/clib/api/spio_get_vara_api.cpp index 7d3fec58b6..59188d9ab4 100644 --- a/src/clib/api/spio_get_vara_api.cpp +++ b/src/clib/api/spio_get_vara_api.cpp @@ -10,7 +10,7 @@ /* APIs for reading a hyperslab of non-distributed data/variable */ int PIOc_get_vara(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, void *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -24,7 +24,7 @@ int PIOc_get_vara(int ncid, int varid, const PIO_Offset *start, const PIO_Offset int PIOc_get_vara_text(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, char *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara_text"); @@ -43,7 +43,7 @@ int PIOc_get_vara_text(int ncid, int varid, const PIO_Offset *start, const PIO_O int PIOc_get_vara_schar(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, signed char *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara_schar"); @@ -62,7 +62,7 @@ int PIOc_get_vara_schar(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_get_vara_short(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, short *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara_short"); @@ -81,7 +81,7 @@ int PIOc_get_vara_short(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_get_vara_int(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, int *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara_int"); @@ -100,7 +100,7 @@ int PIOc_get_vara_int(int ncid, int varid, const PIO_Offset *start, const PIO_Of int PIOc_get_vara_float(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, float *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara_float"); @@ -119,7 +119,7 @@ int PIOc_get_vara_float(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_get_vara_long(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, long *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara_long"); @@ -138,7 +138,7 @@ int PIOc_get_vara_long(int ncid, int varid, const PIO_Offset *start, const PIO_O int PIOc_get_vara_double(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, double *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara_double"); @@ -157,7 +157,7 @@ int PIOc_get_vara_double(int ncid, int varid, const PIO_Offset *start, int PIOc_get_vara_uchar(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, unsigned char *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara_uchar"); @@ -176,7 +176,7 @@ int PIOc_get_vara_uchar(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_get_vara_ushort(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, unsigned short *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara_ushort"); @@ -195,7 +195,7 @@ int PIOc_get_vara_ushort(int ncid, int varid, const PIO_Offset *start, const PIO int PIOc_get_vara_uint(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, unsigned int *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara_uint"); @@ -214,7 +214,7 @@ int PIOc_get_vara_uint(int ncid, int varid, const PIO_Offset *start, const PIO_O int PIOc_get_vara_longlong(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, long long *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara_longlong"); @@ -233,7 +233,7 @@ int PIOc_get_vara_longlong(int ncid, int varid, const PIO_Offset *start, const P int PIOc_get_vara_ulonglong(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, unsigned long long *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vara_ulonglong"); diff --git a/src/clib/api/spio_get_varm_api.cpp b/src/clib/api/spio_get_varm_api.cpp index c387213333..3ce3325b18 100644 --- a/src/clib/api/spio_get_varm_api.cpp +++ b/src/clib/api/spio_get_varm_api.cpp @@ -15,7 +15,7 @@ int PIOc_get_varm_schar(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, signed char *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_varm_schar"); @@ -34,7 +34,7 @@ int PIOc_get_varm_schar(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_get_varm_short(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, short *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_varm_short"); @@ -53,7 +53,7 @@ int PIOc_get_varm_short(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_get_varm_ulonglong(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, unsigned long long *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_varm_ulonglong"); @@ -72,7 +72,7 @@ int PIOc_get_varm_ulonglong(int ncid, int varid, const PIO_Offset *start, const int PIOc_get_varm_ushort(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, unsigned short *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_varm_ushort"); @@ -91,7 +91,7 @@ int PIOc_get_varm_ushort(int ncid, int varid, const PIO_Offset *start, const PIO int PIOc_get_varm_longlong(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, long long *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_varm_longlong"); @@ -110,7 +110,7 @@ int PIOc_get_varm_longlong(int ncid, int varid, const PIO_Offset *start, const P int PIOc_get_varm_double(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, double *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_varm_double"); @@ -129,7 +129,7 @@ int PIOc_get_varm_double(int ncid, int varid, const PIO_Offset *start, const PIO int PIOc_get_varm_text(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, char *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_varm_text"); @@ -148,7 +148,7 @@ int PIOc_get_varm_text(int ncid, int varid, const PIO_Offset *start, const PIO_O int PIOc_get_varm_int(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, int *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_varm_int"); @@ -167,7 +167,7 @@ int PIOc_get_varm_int(int ncid, int varid, const PIO_Offset *start, const PIO_Of int PIOc_get_varm_uint(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, unsigned int *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_varm_uint"); @@ -187,7 +187,7 @@ int PIOc_get_varm(int ncid, int varid, const PIO_Offset *start, const PIO_Offset const PIO_Offset *stride, const PIO_Offset *imap, void *buf, PIO_Offset bufcount, MPI_Datatype buftype) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_varm"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid). @@ -202,7 +202,7 @@ int PIOc_get_varm(int ncid, int varid, const PIO_Offset *start, const PIO_Offset int PIOc_get_varm_float(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, float *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_varm_float"); @@ -221,7 +221,7 @@ int PIOc_get_varm_float(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_get_varm_long(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, long *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_varm_long"); diff --git a/src/clib/api/spio_get_vars_api.cpp b/src/clib/api/spio_get_vars_api.cpp index 92d24de594..b289e040c6 100644 --- a/src/clib/api/spio_get_vars_api.cpp +++ b/src/clib/api/spio_get_vars_api.cpp @@ -10,7 +10,7 @@ int PIOc_get_vars(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, void *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid). @@ -23,7 +23,7 @@ int PIOc_get_vars(int ncid, int varid, const PIO_Offset *start, const PIO_Offset int PIOc_get_vars_text(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, char *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars_text"); @@ -42,7 +42,7 @@ int PIOc_get_vars_text(int ncid, int varid, const PIO_Offset *start, const PIO_O int PIOc_get_vars_schar(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, signed char *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars_schar"); @@ -61,7 +61,7 @@ int PIOc_get_vars_schar(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_get_vars_short(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, short *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars_short"); @@ -80,7 +80,7 @@ int PIOc_get_vars_short(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_get_vars_int(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, int *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars_int"); @@ -99,7 +99,7 @@ int PIOc_get_vars_int(int ncid, int varid, const PIO_Offset *start, const PIO_Of int PIOc_get_vars_long(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, long *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars_long"); @@ -118,7 +118,7 @@ int PIOc_get_vars_long(int ncid, int varid, const PIO_Offset *start, const PIO_O int PIOc_get_vars_float(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, float *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars_float"); @@ -137,7 +137,7 @@ int PIOc_get_vars_float(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_get_vars_double(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, double *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars_double"); @@ -156,7 +156,7 @@ int PIOc_get_vars_double(int ncid, int varid, const PIO_Offset *start, const PIO int PIOc_get_vars_uchar(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, unsigned char *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars_uchar"); @@ -175,7 +175,7 @@ int PIOc_get_vars_uchar(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_get_vars_ushort(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, unsigned short *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars_ushort"); @@ -194,7 +194,7 @@ int PIOc_get_vars_ushort(int ncid, int varid, const PIO_Offset *start, const PIO int PIOc_get_vars_uint(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, unsigned int *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars_uint"); @@ -213,7 +213,7 @@ int PIOc_get_vars_uint(int ncid, int varid, const PIO_Offset *start, const PIO_O int PIOc_get_vars_longlong(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, long long *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars_longlong"); @@ -233,7 +233,7 @@ int PIOc_get_vars_ulonglong(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, unsigned long long *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_vars_ulonglong"); diff --git a/src/clib/api/spio_io_decomp_api.cpp b/src/clib/api/spio_io_decomp_api.cpp index 34a7d65bfd..33c7abfca0 100644 --- a/src/clib/api/spio_io_decomp_api.cpp +++ b/src/clib/api/spio_io_decomp_api.cpp @@ -12,7 +12,7 @@ int PIOc_InitDecomp(int iosysid, int pio_type, int ndims, const int *gdimlen, in const PIO_Offset *compmap, int *ioidp, const int *rearr, const PIO_Offset *iostart, const PIO_Offset *iocount) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_InitDecomp"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_InitDecomp"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_InitDecomp"); @@ -35,7 +35,7 @@ int PIOc_InitDecomp(int iosysid, int pio_type, int ndims, const int *gdimlen, in int PIOc_InitDecomp_bc(int iosysid, int basetype, int ndims, const int *gdimlen, const long int *start, const long int *count, int *ioidp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_InitDecomp_bc"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_InitDecomp_bc"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_InitDecomp_bc"); @@ -59,7 +59,7 @@ int PIOc_init_decomp(int iosysid, int pio_type, int ndims, const int *gdimlen, i const PIO_Offset *compmap, int *ioidp, int rearranger, const PIO_Offset *iostart, const PIO_Offset *iocount) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_init_decomp"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_init_decomp"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_init_decomp"); @@ -84,7 +84,7 @@ int PIOc_init_decomp(int iosysid, int pio_type, int ndims, const int *gdimlen, i /* Free resources associated with a decomposition. */ int PIOc_freedecomp(int iosysid, int ioid) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_freedecomp"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_freedecomp"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_freedecomp"); tr.set_iosys_id(iosysid).add_arg("iosysid", iosysid).add_arg("ioid", ioid).flush(); @@ -97,7 +97,7 @@ int PIOc_freedecomp(int iosysid, int ioid) int PIOc_readmap(const char *file, int *ndims, int **gdims, PIO_Offset *fmaplen, PIO_Offset **map, MPI_Comm comm) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_readmap"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_readmap"); /* FIXME: Add support for tracing comm-specific calls */ return PIOc_readmap_impl(file, ndims, gdims, fmaplen, map, comm); } @@ -105,7 +105,7 @@ int PIOc_readmap(const char *file, int *ndims, int **gdims, PIO_Offset *fmaplen, int PIOc_readmap_from_f90(const char *file,int *ndims, int **gdims, PIO_Offset *maplen, PIO_Offset **map, int f90_comm) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_readmap_from_f90"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_readmap_from_f90"); /* FIXME: Add support for tracing comm-specific calls */ return PIOc_readmap_from_f90_impl(file, ndims, gdims, maplen, map, f90_comm); } @@ -113,7 +113,7 @@ int PIOc_readmap_from_f90(const char *file,int *ndims, int **gdims, PIO_Offset * int PIOc_writemap(const char *file, int ioid, int ndims, const int *gdims, PIO_Offset maplen, const PIO_Offset *map, MPI_Comm comm) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_writemap"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_writemap"); /* FIXME: Add support for tracing comm-specific calls */ return PIOc_writemap_impl(file, ioid, ndims, gdims, maplen, map, comm); } @@ -121,7 +121,7 @@ int PIOc_writemap(const char *file, int ioid, int ndims, const int *gdims, PIO_O int PIOc_writemap_from_f90(const char *file, int ioid, int ndims, const int *gdims, PIO_Offset maplen, const PIO_Offset *map, int f90_comm) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_writemap_from_f90"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_writemap_from_f90"); /* FIXME: Add support for tracing comm-specific calls */ return PIOc_writemap_from_f90_impl(file, ioid, ndims, gdims, maplen, map, f90_comm); } @@ -130,7 +130,7 @@ int PIOc_writemap_from_f90(const char *file, int ioid, int ndims, const int *gdi /* Write a decomposition file. */ int PIOc_write_decomp(const char *file, int iosysid, int ioid, MPI_Comm comm) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_write_decomp"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_write_decomp"); /* FIXME: Add support for tracing comm-specific calls */ return PIOc_write_decomp_impl(file, iosysid, ioid, comm); } @@ -140,7 +140,7 @@ int PIOc_write_decomp(const char *file, int iosysid, int ioid, MPI_Comm comm) int PIOc_write_nc_decomp(int iosysid, const char *filename, int cmode, int ioid, const char *title, const char *history, int fortran_order) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_write_nc_decomp"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_write_nc_decomp"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_write_nc_decomp"); tr.set_iosys_id(iosysid).add_arg("iosysid", iosysid). @@ -157,7 +157,7 @@ int PIOc_write_nc_decomp(int iosysid, const char *filename, int cmode, int ioid, int PIOc_read_nc_decomp(int iosysid, const char *filename, int *ioid, MPI_Comm comm, int pio_type, char *title, char *history, int *fortran_order) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_read_nc_decomp"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_read_nc_decomp"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_read_nc_decomp"); tr.set_iosys_id(iosysid).add_arg("iosysid", iosysid). diff --git a/src/clib/api/spio_io_sys_api.cpp b/src/clib/api/spio_io_sys_api.cpp index 7ef9c9bfa4..b394b8efa4 100644 --- a/src/clib/api/spio_io_sys_api.cpp +++ b/src/clib/api/spio_io_sys_api.cpp @@ -16,7 +16,7 @@ int PIOc_init_async(MPI_Comm world, int num_io_procs, const int *io_proc_list, i pio_init_gptl(); #endif #endif - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_init_async"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_init_async"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_init_async"); @@ -46,7 +46,7 @@ int PIOc_init_intercomm(int component_count, const MPI_Comm peer_comm, pio_init_gptl(); #endif #endif - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_Init_Intercommx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_Init_Intercommx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_init_intercomm"); @@ -88,7 +88,7 @@ int PIOc_Init_Intercomm_from_F90(int component_count, int f90_peer_comm, pio_init_gptl(); #endif #endif - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_Init_Intercommx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_Init_Intercommx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_Init_Intercomm_from_F90"); @@ -126,7 +126,7 @@ int PIOc_Init_Intercomm_from_F90(int component_count, int f90_peer_comm, int PIOc_get_numiotasks(int iosysid, int *numiotasks) { - //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_numiotasks"); + //SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_numiotasks"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_num_iotasks"); @@ -149,7 +149,7 @@ int PIOc_Init_Intracomm(MPI_Comm comp_comm, int num_iotasks, int stride, int bas pio_init_gptl(); #endif #endif - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_Init_Intracommx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_Init_Intracommx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_Init_Intracomm"); @@ -176,7 +176,7 @@ int PIOc_Init_Intracomm_from_F90(int f90_comp_comm, pio_init_gptl(); #endif #endif - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_Init_Intracommx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_Init_Intracommx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_Init_Intracomm_from_F90"); @@ -197,7 +197,7 @@ int PIOc_Init_Intracomm_from_F90(int f90_comp_comm, /* Finalize an I/O system */ int PIOc_finalize(int iosysid) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_finalize"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_finalize"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_finalize"); @@ -212,7 +212,7 @@ int PIOc_finalize(int iosysid) /* Set error handling for entire io system. */ int PIOc_Set_IOSystem_Error_Handling(int iosysid, int method) { - //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_Set_IOSystem_Error_Handling"); + //SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_Set_IOSystem_Error_Handling"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_Set_IOSystem_Error_Handling"); tr.set_iosys_id(iosysid).add_arg("iosysid", iosysid).add_arg("method", method).flush(); @@ -224,7 +224,7 @@ int PIOc_Set_IOSystem_Error_Handling(int iosysid, int method) /* Set error handling for entire io system. */ int PIOc_set_iosystem_error_handling(int iosysid, int method, int *old_method) { - //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_set_iosystem_error_handling"); + //SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_set_iosystem_error_handling"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_set_iosystem_error_handling"); tr.set_iosys_id(iosysid).add_arg("iosysid", iosysid).add_arg("method", method). @@ -236,7 +236,7 @@ int PIOc_set_iosystem_error_handling(int iosysid, int method, int *old_method) int PIOc_iam_iotask(int iosysid, bool *ioproc) { - //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_iam_iotask"); + //SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_iam_iotask"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_iam_iotask"); @@ -252,7 +252,7 @@ int PIOc_iam_iotask(int iosysid, bool *ioproc) int PIOc_iotask_rank(int iosysid, int *iorank) { - //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_iotask_rank"); + //SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_iotask_rank"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_iotask_rank"); @@ -268,7 +268,7 @@ int PIOc_iotask_rank(int iosysid, int *iorank) int PIOc_iosystem_is_active(int iosysid, bool *active) { - //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_iosystem_is_active"); + //SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_iosystem_is_active"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_iosystem_is_active"); @@ -284,7 +284,7 @@ int PIOc_iosystem_is_active(int iosysid, bool *active) int PIOc_iotype_available(int iotype) { - //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_iotype_available"); + //SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_iotype_available"); /* FIXME: Figure out how to trace these non I/O system specific calls */ return PIOc_iotype_available_impl(iotype); } @@ -295,7 +295,7 @@ int PIOc_set_rearr_opts(int iosysid, int comm_type, int fcd, bool enable_hs_i2c, bool enable_isend_i2c, int max_pend_req_i2c) { - //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_set_rearr_opts"); + //SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_set_rearr_opts"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_set_rearr_opts"); tr.set_iosys_id(iosysid).add_arg("iosysid", iosysid). @@ -316,7 +316,7 @@ int PIOc_set_rearr_opts(int iosysid, int comm_type, int fcd, int PIOc_set_hint(int iosysid, const char *hint, const char *hintval) { - //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_set_hint"); + //SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_set_hint"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_set_hint"); tr.set_iosys_id(iosysid).add_arg("iosysid", iosysid). @@ -328,7 +328,7 @@ int PIOc_set_hint(int iosysid, const char *hint, const char *hintval) int PIOc_set_chunk_cache(int iosysid, int iotype, PIO_Offset size, PIO_Offset nelems, float preemption) { - //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_set_chunk_cache"); + //SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_set_chunk_cache"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_set_chunk_cache"); tr.set_iosys_id(iosysid).add_arg("iosysid", iosysid).add_arg("iotype", iotype). @@ -342,7 +342,7 @@ int PIOc_set_chunk_cache(int iosysid, int iotype, PIO_Offset size, PIO_Offset ne int PIOc_get_chunk_cache(int iosysid, int iotype, PIO_Offset *sizep, PIO_Offset *nelemsp, float *preemptionp) { - //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_get_chunk_cache"); + //SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_get_chunk_cache"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_chunk_cache"); @@ -362,7 +362,7 @@ int PIOc_get_chunk_cache(int iosysid, int iotype, PIO_Offset *sizep, PIO_Offset int PIOc_set_blocksize(int newblocksize) { - //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_set_blocksize"); + //SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_set_blocksize"); /* FIXME: Figure out how to trace these non I/O system specific calls */ return PIOc_set_blocksize_impl(newblocksize); } @@ -370,7 +370,7 @@ int PIOc_set_blocksize(int newblocksize) /* Set the IO node data buffer size limit. */ PIO_Offset PIOc_set_buffer_size_limit(PIO_Offset limit) { - //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_set_buffer_size_limit"); + //SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_set_buffer_size_limit"); /* FIXME: Figure out how to trace these non I/O system specific calls */ return PIOc_set_buffer_size_limit_impl(limit); } diff --git a/src/clib/api/spio_misc_att_api.cpp b/src/clib/api/spio_misc_att_api.cpp index 343144fd3e..aba7b4846e 100644 --- a/src/clib/api/spio_misc_att_api.cpp +++ b/src/clib/api/spio_misc_att_api.cpp @@ -9,7 +9,7 @@ /* APIs for file/variable attributes */ int PIOc_rename_att(int ncid, int varid, const char *name, const char *newname) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_rename_att"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_rename_att"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_rename_att"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -21,7 +21,7 @@ int PIOc_rename_att(int ncid, int varid, const char *name, const char *newname) int PIOc_del_att(int ncid, int varid, const char *name) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_del_att"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_del_att"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_del_att"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -33,7 +33,7 @@ int PIOc_del_att(int ncid, int varid, const char *name) int PIOc_inq_att(int ncid, int varid, const char *name, nc_type *xtypep, PIO_Offset *lenp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inq_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_att"); @@ -52,7 +52,7 @@ int PIOc_inq_att(int ncid, int varid, const char *name, nc_type *xtypep, int PIOc_inq_attid(int ncid, int varid, const char *name, int *idp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inq_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_attid"); @@ -70,7 +70,7 @@ int PIOc_inq_attid(int ncid, int varid, const char *name, int *idp) int PIOc_inq_attlen(int ncid, int varid, const char *name, PIO_Offset *lenp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inq_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_attlen"); @@ -88,7 +88,7 @@ int PIOc_inq_attlen(int ncid, int varid, const char *name, PIO_Offset *lenp) int PIOc_inq_atttype(int ncid, int varid, const char *name, nc_type *xtypep) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inq_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_atttype"); @@ -106,7 +106,7 @@ int PIOc_inq_atttype(int ncid, int varid, const char *name, nc_type *xtypep) int PIOc_inq_attname(int ncid, int varid, int attnum, char *name) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inq_attx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_attname"); @@ -124,7 +124,7 @@ int PIOc_inq_attname(int ncid, int varid, int attnum, char *name) int PIOc_copy_att(int incid, int ivarid, const char *name, int oncid, int ovarid) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_copy_att"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_copy_att"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_copy_att"); tr.set_file_id(incid).add_arg("incid", incid). diff --git a/src/clib/api/spio_misc_var_api.cpp b/src/clib/api/spio_misc_var_api.cpp index eb79f72d3e..94d62b3f7a 100644 --- a/src/clib/api/spio_misc_var_api.cpp +++ b/src/clib/api/spio_misc_var_api.cpp @@ -8,7 +8,7 @@ /* APIs for file variables */ int PIOc_inq_varid(int ncid, const char *name, int *varidp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inq_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_varid"); @@ -27,7 +27,7 @@ int PIOc_inq_varid(int ncid, const char *name, int *varidp) int PIOc_inq_var(int ncid, int varid, char *name, int namelen, nc_type *xtypep, int *ndimsp, int *dimidsp, int *nattsp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inq_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_var"); @@ -58,7 +58,7 @@ int PIOc_inq_var(int ncid, int varid, char *name, int namelen, nc_type *xtypep, int PIOc_inq_varname(int ncid, int varid, char *name, int namelen) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inq_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_varname"); @@ -75,7 +75,7 @@ int PIOc_inq_varname(int ncid, int varid, char *name, int namelen) int PIOc_inq_vartype(int ncid, int varid, nc_type *xtypep) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inq_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_vartype"); @@ -92,7 +92,7 @@ int PIOc_inq_vartype(int ncid, int varid, nc_type *xtypep) int PIOc_inq_varndims(int ncid, int varid, int *ndimsp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inq_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_varndims"); @@ -109,7 +109,7 @@ int PIOc_inq_varndims(int ncid, int varid, int *ndimsp) int PIOc_inq_vardimid(int ncid, int varid, int *dimidsp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inq_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_vardimid"); @@ -130,7 +130,7 @@ int PIOc_inq_vardimid(int ncid, int varid, int *dimidsp) int PIOc_inq_varnatts(int ncid, int varid, int *nattsp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inq_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_varnatts"); @@ -148,7 +148,7 @@ int PIOc_inq_varnatts(int ncid, int varid, int *nattsp) int PIOc_def_var(int ncid, const char *name, nc_type xtype, int ndims, const int *dimidsp, int *varidp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_def_var"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_def_var"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING assert(ndims >= 0); @@ -169,7 +169,7 @@ int PIOc_def_var(int ncid, const char *name, nc_type xtype, int ndims, int PIOc_set_fill(int ncid, int fillmode, int *old_modep) { - //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_set_fill"); + //SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_set_fill"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_set_fill"); @@ -186,7 +186,7 @@ int PIOc_set_fill(int ncid, int fillmode, int *old_modep) int PIOc_def_var_fill(int ncid, int varid, int no_fill, const void *fill_value) { - //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_def_var_fill"); + //SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_def_var_fill"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_def_var_fill"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid). @@ -197,7 +197,7 @@ int PIOc_def_var_fill(int ncid, int varid, int no_fill, const void *fill_value) int PIOc_inq_var_fill(int ncid, int varid, int *no_fill, void *fill_valuep) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inq_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_var_fill"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid). @@ -208,7 +208,7 @@ int PIOc_inq_var_fill(int ncid, int varid, int *no_fill, void *fill_valuep) int PIOc_rename_var(int ncid, int varid, const char *name) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_rename_var"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_rename_var"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_rename_var"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid). @@ -221,7 +221,7 @@ int PIOc_rename_var(int ncid, int varid, const char *name) int PIOc_def_var_deflate(int ncid, int varid, int shuffle, int deflate, int deflate_level) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_def_var_deflate"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_def_var_deflate"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_def_var_deflate"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid). @@ -234,7 +234,7 @@ int PIOc_def_var_deflate(int ncid, int varid, int shuffle, int deflate, int PIOc_inq_var_deflate(int ncid, int varid, int *shufflep, int *deflatep, int *deflate_levelp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inq_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_var_deflate"); @@ -261,7 +261,7 @@ int PIOc_inq_var_szip(int ncid, int varid, int *options_maskp, int *pixels_per_b int PIOc_def_var_chunking(int ncid, int varid, int storage, const PIO_Offset *chunksizesp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_def_var_chunking"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_def_var_chunking"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_def_var_chunking"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid). @@ -272,7 +272,7 @@ int PIOc_def_var_chunking(int ncid, int varid, int storage, const PIO_Offset *ch int PIOc_inq_var_chunking(int ncid, int varid, int *storagep, PIO_Offset *chunksizesp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inq_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_var_chunking"); @@ -290,7 +290,7 @@ int PIOc_inq_var_chunking(int ncid, int varid, int *storagep, PIO_Offset *chunks int PIOc_def_var_endian(int ncid, int varid, int endian) { - //SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_def_var_endian"); + //SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_def_var_endian"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_def_var_endian"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid). @@ -301,7 +301,7 @@ int PIOc_def_var_endian(int ncid, int varid, int endian) int PIOc_inq_var_endian(int ncid, int varid, int *endianp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inq_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_inq_var_endian"); @@ -319,7 +319,7 @@ int PIOc_inq_var_endian(int ncid, int varid, int *endianp) int PIOc_set_var_chunk_cache(int ncid, int varid, PIO_Offset size, PIO_Offset nelems, float preemption) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_set_var_chunk_cache"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_set_var_chunk_cache"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_set_var_chunk_cache"); tr.set_file_id(ncid).add_arg("ncid", ncid).add_arg("varid", varid). @@ -333,7 +333,7 @@ int PIOc_set_var_chunk_cache(int ncid, int varid, PIO_Offset size, PIO_Offset ne int PIOc_get_var_chunk_cache(int ncid, int varid, PIO_Offset *sizep, PIO_Offset *nelemsp, float *preemptionp) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_inq_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_inq_varx"); int ret = PIO_NOERR; #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_get_var_chunk_cache"); diff --git a/src/clib/api/spio_put_att_api.cpp b/src/clib/api/spio_put_att_api.cpp index 1dde56bffa..d17a831cd3 100644 --- a/src/clib/api/spio_put_att_api.cpp +++ b/src/clib/api/spio_put_att_api.cpp @@ -8,7 +8,7 @@ /* Write APIs for file/variable attributes */ int PIOc_put_att(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const void *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -22,7 +22,7 @@ int PIOc_put_att(int ncid, int varid, const char *name, nc_type xtype, PIO_Offse int PIOc_put_att_text(int ncid, int varid, const char *name, PIO_Offset len, const char *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att_text"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -36,7 +36,7 @@ int PIOc_put_att_text(int ncid, int varid, const char *name, PIO_Offset len, con int PIOc_put_att_schar(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const signed char *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att_schar"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -51,7 +51,7 @@ int PIOc_put_att_schar(int ncid, int varid, const char *name, nc_type xtype, PIO int PIOc_put_att_short(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const short *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att_short"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -66,7 +66,7 @@ int PIOc_put_att_short(int ncid, int varid, const char *name, nc_type xtype, PIO int PIOc_put_att_int(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const int *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att_int"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -81,7 +81,7 @@ int PIOc_put_att_int(int ncid, int varid, const char *name, nc_type xtype, PIO_O int PIOc_put_att_long(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const long *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att_long"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -96,7 +96,7 @@ int PIOc_put_att_long(int ncid, int varid, const char *name, nc_type xtype, PIO_ int PIOc_put_att_float(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const float *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att_float"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -111,7 +111,7 @@ int PIOc_put_att_float(int ncid, int varid, const char *name, nc_type xtype, PIO int PIOc_put_att_double(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const double *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att_double"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -126,7 +126,7 @@ int PIOc_put_att_double(int ncid, int varid, const char *name, nc_type xtype, PI int PIOc_put_att_uchar(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const unsigned char *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att_uchar"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -141,7 +141,7 @@ int PIOc_put_att_uchar(int ncid, int varid, const char *name, nc_type xtype, PIO int PIOc_put_att_ushort(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const unsigned short *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att_ushort"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -156,7 +156,7 @@ int PIOc_put_att_ushort(int ncid, int varid, const char *name, nc_type xtype, PI int PIOc_put_att_uint(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const unsigned int *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att_uint"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -171,7 +171,7 @@ int PIOc_put_att_uint(int ncid, int varid, const char *name, nc_type xtype, PIO_ int PIOc_put_att_longlong(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const long long *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att_longlong"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -186,7 +186,7 @@ int PIOc_put_att_longlong(int ncid, int varid, const char *name, nc_type xtype, int PIOc_put_att_ulonglong(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const unsigned long long *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_attx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_attx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_att_ulonglong"); tr.set_file_id(ncid).add_arg("ncid", ncid). diff --git a/src/clib/api/spio_put_var1_api.cpp b/src/clib/api/spio_put_var1_api.cpp index cccad7a76c..3837279d0e 100644 --- a/src/clib/api/spio_put_var1_api.cpp +++ b/src/clib/api/spio_put_var1_api.cpp @@ -8,7 +8,7 @@ /* APIs for writing non-distributed data/variable at a specified index */ int PIOc_put_var1(int ncid, int varid, const PIO_Offset *index, const void *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -20,7 +20,7 @@ int PIOc_put_var1(int ncid, int varid, const PIO_Offset *index, const void *buf) int PIOc_put_var1_text(int ncid, int varid, const PIO_Offset *index, const char *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1_text"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -32,7 +32,7 @@ int PIOc_put_var1_text(int ncid, int varid, const PIO_Offset *index, const char int PIOc_put_var1_schar(int ncid, int varid, const PIO_Offset *index, const signed char *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1_schar"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -44,7 +44,7 @@ int PIOc_put_var1_schar(int ncid, int varid, const PIO_Offset *index, const sign int PIOc_put_var1_short(int ncid, int varid, const PIO_Offset *index, const short *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1_short"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -56,7 +56,7 @@ int PIOc_put_var1_short(int ncid, int varid, const PIO_Offset *index, const shor int PIOc_put_var1_int(int ncid, int varid, const PIO_Offset *index, const int *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1_int"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -68,7 +68,7 @@ int PIOc_put_var1_int(int ncid, int varid, const PIO_Offset *index, const int *o int PIOc_put_var1_long(int ncid, int varid, const PIO_Offset *index, const long *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1_long"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -80,7 +80,7 @@ int PIOc_put_var1_long(int ncid, int varid, const PIO_Offset *index, const long int PIOc_put_var1_float(int ncid, int varid, const PIO_Offset *index, const float *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1_float"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -92,7 +92,7 @@ int PIOc_put_var1_float(int ncid, int varid, const PIO_Offset *index, const floa int PIOc_put_var1_double(int ncid, int varid, const PIO_Offset *index, const double *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1_double"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -105,7 +105,7 @@ int PIOc_put_var1_double(int ncid, int varid, const PIO_Offset *index, const dou int PIOc_put_var1_uchar(int ncid, int varid, const PIO_Offset *index, const unsigned char *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1_uchar"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -118,7 +118,7 @@ int PIOc_put_var1_uchar(int ncid, int varid, const PIO_Offset *index, int PIOc_put_var1_ushort(int ncid, int varid, const PIO_Offset *index, const unsigned short *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1_ushort"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -131,7 +131,7 @@ int PIOc_put_var1_ushort(int ncid, int varid, const PIO_Offset *index, int PIOc_put_var1_uint(int ncid, int varid, const PIO_Offset *index, const unsigned int *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1_uint"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -143,7 +143,7 @@ int PIOc_put_var1_uint(int ncid, int varid, const PIO_Offset *index, int PIOc_put_var1_longlong(int ncid, int varid, const PIO_Offset *index, const long long *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1_longlong"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -156,7 +156,7 @@ int PIOc_put_var1_longlong(int ncid, int varid, const PIO_Offset *index, const l int PIOc_put_var1_ulonglong(int ncid, int varid, const PIO_Offset *index, const unsigned long long *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var1_ulonglong"); tr.set_file_id(ncid).add_arg("ncid", ncid). diff --git a/src/clib/api/spio_put_var_api.cpp b/src/clib/api/spio_put_var_api.cpp index 17f9d374ec..6dfab124d7 100644 --- a/src/clib/api/spio_put_var_api.cpp +++ b/src/clib/api/spio_put_var_api.cpp @@ -8,7 +8,7 @@ /* APIs for writing entire non-distributed data/variable */ int PIOc_put_var(int ncid, int varid, const void *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -19,7 +19,7 @@ int PIOc_put_var(int ncid, int varid, const void *buf) int PIOc_put_var_text(int ncid, int varid, const char *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var_text"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -30,7 +30,7 @@ int PIOc_put_var_text(int ncid, int varid, const char *op) int PIOc_put_var_schar(int ncid, int varid, const signed char *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var_schar"); /* Both bytes and chars are written using this interface, trying to trace/log @@ -44,7 +44,7 @@ int PIOc_put_var_schar(int ncid, int varid, const signed char *op) int PIOc_put_var_short(int ncid, int varid, const short *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var_short"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -55,7 +55,7 @@ int PIOc_put_var_short(int ncid, int varid, const short *op) int PIOc_put_var_int(int ncid, int varid, const int *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var_int"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -66,7 +66,7 @@ int PIOc_put_var_int(int ncid, int varid, const int *op) int PIOc_put_var_long(int ncid, int varid, const long *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var_long"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -77,7 +77,7 @@ int PIOc_put_var_long(int ncid, int varid, const long *op) int PIOc_put_var_float(int ncid, int varid, const float *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var_float"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -88,7 +88,7 @@ int PIOc_put_var_float(int ncid, int varid, const float *op) int PIOc_put_var_double(int ncid, int varid, const double *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var_double"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -99,7 +99,7 @@ int PIOc_put_var_double(int ncid, int varid, const double *op) int PIOc_put_var_uchar(int ncid, int varid, const unsigned char *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var_uchar"); /* Both bytes and chars are written using this interface, trying to trace/log @@ -113,7 +113,7 @@ int PIOc_put_var_uchar(int ncid, int varid, const unsigned char *op) int PIOc_put_var_ushort(int ncid, int varid, const unsigned short *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var_ushort"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -124,7 +124,7 @@ int PIOc_put_var_ushort(int ncid, int varid, const unsigned short *op) int PIOc_put_var_uint(int ncid, int varid, const unsigned int *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var_uint"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -135,7 +135,7 @@ int PIOc_put_var_uint(int ncid, int varid, const unsigned int *op) int PIOc_put_var_longlong(int ncid, int varid, const long long *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var_longlong"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -146,7 +146,7 @@ int PIOc_put_var_longlong(int ncid, int varid, const long long *op) int PIOc_put_var_ulonglong(int ncid, int varid, const unsigned long long *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_var_ulonglong"); tr.set_file_id(ncid).add_arg("ncid", ncid). diff --git a/src/clib/api/spio_put_vara_api.cpp b/src/clib/api/spio_put_vara_api.cpp index 73e4c616b7..f0c567f58b 100644 --- a/src/clib/api/spio_put_vara_api.cpp +++ b/src/clib/api/spio_put_vara_api.cpp @@ -9,7 +9,7 @@ int PIOc_put_vara(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const void *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -22,7 +22,7 @@ int PIOc_put_vara(int ncid, int varid, const PIO_Offset *start, const PIO_Offset int PIOc_put_vara_text(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const char *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara_text"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -35,7 +35,7 @@ int PIOc_put_vara_text(int ncid, int varid, const PIO_Offset *start, int PIOc_put_vara_schar(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const signed char *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara_schar"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -48,7 +48,7 @@ int PIOc_put_vara_schar(int ncid, int varid, const PIO_Offset *start, int PIOc_put_vara_short(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const short *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara_short"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -61,7 +61,7 @@ int PIOc_put_vara_short(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_put_vara_int(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const int *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara_int"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -74,7 +74,7 @@ int PIOc_put_vara_int(int ncid, int varid, const PIO_Offset *start, const PIO_Of int PIOc_put_vara_long(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const long *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara_long"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -87,7 +87,7 @@ int PIOc_put_vara_long(int ncid, int varid, const PIO_Offset *start, const PIO_O int PIOc_put_vara_float(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const float *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara_float"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -100,7 +100,7 @@ int PIOc_put_vara_float(int ncid, int varid, const PIO_Offset *start, int PIOc_put_vara_double(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const double *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara_double"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -113,7 +113,7 @@ int PIOc_put_vara_double(int ncid, int varid, const PIO_Offset *start, const PIO int PIOc_put_vara_uchar(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const unsigned char *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara_uchar"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -126,7 +126,7 @@ int PIOc_put_vara_uchar(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_put_vara_ushort(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const unsigned short *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara_ushort"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -139,7 +139,7 @@ int PIOc_put_vara_ushort(int ncid, int varid, const PIO_Offset *start, int PIOc_put_vara_uint(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const unsigned int *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara_uint"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -152,7 +152,7 @@ int PIOc_put_vara_uint(int ncid, int varid, const PIO_Offset *start, int PIOc_put_vara_longlong(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const long long *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara_longlong"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -165,7 +165,7 @@ int PIOc_put_vara_longlong(int ncid, int varid, const PIO_Offset *start, int PIOc_put_vara_ulonglong(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const unsigned long long *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vara_ulonglong"); tr.set_file_id(ncid).add_arg("ncid", ncid). diff --git a/src/clib/api/spio_put_varm_api.cpp b/src/clib/api/spio_put_varm_api.cpp index bed506b96c..036a5cb193 100644 --- a/src/clib/api/spio_put_varm_api.cpp +++ b/src/clib/api/spio_put_varm_api.cpp @@ -9,7 +9,7 @@ int PIOc_put_varm(int ncid, int varid, const PIO_Offset *start, const PIO_Offset const PIO_Offset *stride, const PIO_Offset *imap, const void *buf, PIO_Offset bufcount, MPI_Datatype buftype) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -25,7 +25,7 @@ int PIOc_put_varm_uchar(int ncid, int varid, const PIO_Offset *start, const PIO_ const PIO_Offset *stride, const PIO_Offset *imap, const unsigned char *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm_uchar"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -39,7 +39,7 @@ int PIOc_put_varm_uchar(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_put_varm_short(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, const short *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm_ushort"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -54,7 +54,7 @@ int PIOc_put_varm_text(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, const char *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm_text"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -68,7 +68,7 @@ int PIOc_put_varm_text(int ncid, int varid, const PIO_Offset *start, int PIOc_put_varm_ushort(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, const unsigned short *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm_ushort"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -83,7 +83,7 @@ int PIOc_put_varm_ulonglong(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, const unsigned long long *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm_ulonglong"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -98,7 +98,7 @@ int PIOc_put_varm_int(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, const int *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm_int"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -113,7 +113,7 @@ int PIOc_put_varm_float(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, const float *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm_float"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -128,7 +128,7 @@ int PIOc_put_varm_long(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, const long *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm_long"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -143,7 +143,7 @@ int PIOc_put_varm_uint(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, const unsigned int *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm_uint"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -157,7 +157,7 @@ int PIOc_put_varm_uint(int ncid, int varid, const PIO_Offset *start, int PIOc_put_varm_double(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, const double *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm_double"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -171,7 +171,7 @@ int PIOc_put_varm_double(int ncid, int varid, const PIO_Offset *start, const PIO int PIOc_put_varm_schar(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, const signed char *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm_schar"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -185,7 +185,7 @@ int PIOc_put_varm_schar(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_put_varm_longlong(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const PIO_Offset *imap, const long long *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_varm_longlong"); tr.set_file_id(ncid).add_arg("ncid", ncid). diff --git a/src/clib/api/spio_put_vars_api.cpp b/src/clib/api/spio_put_vars_api.cpp index f25a13d126..00667dd506 100644 --- a/src/clib/api/spio_put_vars_api.cpp +++ b/src/clib/api/spio_put_vars_api.cpp @@ -9,7 +9,7 @@ int PIOc_put_vars(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const void *buf) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -22,7 +22,7 @@ int PIOc_put_vars(int ncid, int varid, const PIO_Offset *start, const PIO_Offset int PIOc_put_vars_text(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const char *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars_text"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -36,7 +36,7 @@ int PIOc_put_vars_schar(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const signed char *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars_shcar"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -49,7 +49,7 @@ int PIOc_put_vars_schar(int ncid, int varid, const PIO_Offset *start, int PIOc_put_vars_short(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const short *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars_short"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -62,7 +62,7 @@ int PIOc_put_vars_short(int ncid, int varid, const PIO_Offset *start, int PIOc_put_vars_int(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const int *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars_int"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -75,7 +75,7 @@ int PIOc_put_vars_int(int ncid, int varid, const PIO_Offset *start, const PIO_Of int PIOc_put_vars_float(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const float *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars_float"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -88,7 +88,7 @@ int PIOc_put_vars_float(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_put_vars_double(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const double *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars_double"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -101,7 +101,7 @@ int PIOc_put_vars_double(int ncid, int varid, const PIO_Offset *start, int PIOc_put_vars_long(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const long *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars_long"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -114,7 +114,7 @@ int PIOc_put_vars_long(int ncid, int varid, const PIO_Offset *start, const PIO_O int PIOc_put_vars_uchar(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const unsigned char *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars_uchar"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -127,7 +127,7 @@ int PIOc_put_vars_uchar(int ncid, int varid, const PIO_Offset *start, const PIO_ int PIOc_put_vars_ushort(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const unsigned short *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars_ushort"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -140,7 +140,7 @@ int PIOc_put_vars_ushort(int ncid, int varid, const PIO_Offset *start, const PIO int PIOc_put_vars_uint(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const unsigned int *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars_uint"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -153,7 +153,7 @@ int PIOc_put_vars_uint(int ncid, int varid, const PIO_Offset *start, const PIO_O int PIOc_put_vars_longlong(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const long long *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars_longlong"); tr.set_file_id(ncid).add_arg("ncid", ncid). @@ -167,7 +167,7 @@ int PIOc_put_vars_ulonglong(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const unsigned long long *op) { - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("SPIO:PIOc_put_varx"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("SPIO:PIOc_put_varx"); #if SPIO_ENABLE_API_TRACING SPIO_Util::Tracer::Timed_func_call_tracer tr("PIOc_put_vars_ulonglong"); tr.set_file_id(ncid).add_arg("ncid", ncid). diff --git a/src/clib/core/pio_darray.cpp b/src/clib/core/pio_darray.cpp index 1dc918c418..b0dcd3758c 100644 --- a/src/clib/core/pio_darray.cpp +++ b/src/clib/core/pio_darray.cpp @@ -129,7 +129,7 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar int mpierr = MPI_SUCCESS; /* Return code from MPI function calls. */ int ierr = PIO_NOERR; /* Return code. */ - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer("PIO:PIOc_write_darray_multi"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer("PIO:PIOc_write_darray_multi"); /* Get the file info. */ if((ierr = pio_get_file(ncid, &file))){ return pio_err(NULL, NULL, PIO_EBADID, __FILE__, __LINE__, @@ -1983,7 +1983,7 @@ int PIOc_write_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, c int mpierr = MPI_SUCCESS; /* Return code from MPI functions. */ int ierr = PIO_NOERR; /* Return code. */ - SPIO_Util::GPTL_Util::GPTL_wrapper func_timer2("PIO:write_total"); + SPIO_Util::GPTL_Util::GPTL_timer func_timer2("PIO:write_total"); LOG((1, "PIOc_write_darray ncid = %d varid = %d ioid = %d arraylen = %d", ncid, varid, ioid, arraylen)); diff --git a/src/clib/core/rearr/pio_rearr_contig.cpp b/src/clib/core/rearr/pio_rearr_contig.cpp index 45eca0b599..4138a412eb 100644 --- a/src/clib/core/rearr/pio_rearr_contig.cpp +++ b/src/clib/core/rearr/pio_rearr_contig.cpp @@ -54,7 +54,7 @@ int SPIO::DataRearr::Contig_rearr::init(int pio_type, const int *gdimlen, int ndims, io_desc_t *iodesc) { int ret = PIO_NOERR; - SPIO_Util::GPTL_Util::GPTL_wrapper contig_init_timer("PIO:Contig_rearr::init"); + SPIO_Util::GPTL_Util::GPTL_timer contig_init_timer("PIO:Contig_rearr::init"); assert(ios_); assert(ndims > 0); @@ -362,7 +362,7 @@ int SPIO::DataRearr::Contig_rearr::aggregate_data(const void *sbuf, std::size_t void *abuf, std::size_t abuf_sz, int nvars) { int ret = PIO_NOERR; - SPIO_Util::GPTL_Util::GPTL_wrapper contig_agg_timer("PIO:Contig_rearr::aggregate_data"); + SPIO_Util::GPTL_Util::GPTL_timer contig_agg_timer("PIO:Contig_rearr::aggregate_data"); assert(is_init_); @@ -448,7 +448,7 @@ int SPIO::DataRearr::Contig_rearr::disperse_data(const void *abuf, std::size_t a void *rbuf, std::size_t rbuf_sz, int nvars) { int ret = PIO_NOERR; - SPIO_Util::GPTL_Util::GPTL_wrapper contig_dis_timer("PIO:Contig_rearr::disperse_data"); + SPIO_Util::GPTL_Util::GPTL_timer contig_dis_timer("PIO:Contig_rearr::disperse_data"); assert(is_init_); @@ -647,7 +647,7 @@ int SPIO::DataRearr::Contig_rearr::aggregate_compmap(const PIO_Offset *lcompmap, std::vector &gcompmap_displs) { int ret = PIO_NOERR; - SPIO_Util::GPTL_Util::GPTL_wrapper ftimer("PIO:Contig_rearr::aggregate_compmap"); + SPIO_Util::GPTL_Util::GPTL_timer ftimer("PIO:Contig_rearr::aggregate_compmap"); assert(ios_ && (agg_comm_ != MPI_COMM_NULL)); /* Get the compmap sizes from all procs in this aggregation comm */ @@ -768,7 +768,7 @@ int SPIO::DataRearr::Contig_rearr::setup_data_agg_info(const PIO_Offset *lcompma const std::vector &to_proc) { int ret = PIO_NOERR; - SPIO_Util::GPTL_Util::GPTL_wrapper ftimer("PIO:Contig_rearr::setup_data_agg_info"); + SPIO_Util::GPTL_Util::GPTL_timer ftimer("PIO:Contig_rearr::setup_data_agg_info"); assert(ios_); /* Setup gather scatter info for sending/receiving data from compute procs to @@ -887,7 +887,7 @@ int SPIO::DataRearr::Contig_rearr::init_agg_recv_types(const std::vector &g const std::vector &compmap_sorter) { int ret = PIO_NOERR; - SPIO_Util::GPTL_Util::GPTL_wrapper ftimer("PIO:Contig_rearr::init_agg_recv_types"); + SPIO_Util::GPTL_Util::GPTL_timer ftimer("PIO:Contig_rearr::init_agg_recv_types"); /* The compmap_sorter has the indices of the sorted data (based on to_proc & compmap) * So look for contiguous ranges in compmap_sorter array * We need to receive data in the aggregating process such that all data being sent @@ -1065,7 +1065,7 @@ int SPIO::DataRearr::Contig_rearr::setup_data_rearr_info(std::vector const int *gdimlen, int ndims) { int ret = PIO_NOERR; - SPIO_Util::GPTL_Util::GPTL_wrapper ftimer("PIO:Contig_rearr::setup_data_rearr_info"); + SPIO_Util::GPTL_Util::GPTL_timer ftimer("PIO:Contig_rearr::setup_data_rearr_info"); assert(ios_); if(!ios_->ioproc){ @@ -1199,7 +1199,7 @@ int SPIO::DataRearr::Contig_rearr::init_rearr_send_types( const std::vector &displs_counts_sent) { int ret = PIO_NOERR; - SPIO_Util::GPTL_Util::GPTL_wrapper ftimer("PIO:Contig_rearr::init_rearr_send_types"); + SPIO_Util::GPTL_Util::GPTL_timer ftimer("PIO:Contig_rearr::init_rearr_send_types"); assert(ios_ && ios_->ioproc); assert(rearr_comm_sz_ > 0); @@ -1260,7 +1260,7 @@ int SPIO::DataRearr::Contig_rearr::init_rearr_recvd_types( const std::vector &displs_counts_recvd) { int ret = PIO_NOERR; - SPIO_Util::GPTL_Util::GPTL_wrapper ftimer("PIO:Contig_rearr::init_rearr_recvd_types"); + SPIO_Util::GPTL_Util::GPTL_timer ftimer("PIO:Contig_rearr::init_rearr_recvd_types"); assert(ios_ && ios_->ioproc); assert(rearr_comm_sz_ > 0); @@ -1329,7 +1329,7 @@ int SPIO::DataRearr::Contig_rearr::rearrange_data(const void *sbuf, std::size_t void *rbuf, std::size_t rbuf_sz, int nvars, bool agg2rearr) { int ret = PIO_NOERR; - SPIO_Util::GPTL_Util::GPTL_wrapper contig_rearr_timer("PIO:Contig_rearr::rearrange_data"); + SPIO_Util::GPTL_Util::GPTL_timer contig_rearr_timer("PIO:Contig_rearr::rearrange_data"); assert(is_init_); diff --git a/src/clib/core/rearr/pio_rearr_utils.cpp b/src/clib/core/rearr/pio_rearr_utils.cpp index 4466ee002c..dc18b5b33a 100644 --- a/src/clib/core/rearr/pio_rearr_utils.cpp +++ b/src/clib/core/rearr/pio_rearr_utils.cpp @@ -35,7 +35,7 @@ int SPIO_Util::Rearr_Util::gatherw(const void *sendbuf, int sendcount, { int ret = PIO_NOERR, comm_rank = -1, comm_sz = 0; - SPIO_Util::GPTL_Util::GPTL_wrapper("PIO:SPIO_Util::Rearr_Util::gatherw"); + SPIO_Util::GPTL_Util::GPTL_timer("PIO:SPIO_Util::Rearr_Util::gatherw"); //assert((sendcount == 0) || sendbuf); @@ -187,7 +187,7 @@ int SPIO_Util::Rearr_Util::scatterw(const void *sendbuf, const std::vector { int ret = PIO_NOERR, comm_rank = -1, comm_sz = 0; - SPIO_Util::GPTL_Util::GPTL_wrapper("PIO:SPIO_Util::Rearr_Util::scatterw"); + SPIO_Util::GPTL_Util::GPTL_timer("PIO:SPIO_Util::Rearr_Util::scatterw"); ret = MPI_Comm_rank(comm, &comm_rank); if(ret != MPI_SUCCESS){ @@ -378,7 +378,7 @@ int SPIO_Util::Rearr_Util::alltoallw(const void *sendbuf, const int *sendcounts, MPI_Status status; /* Not actually used - replace with MPI_STATUSES_IGNORE. */ int mpierr; /* Return code from MPI functions. */ - SPIO_Util::GPTL_Util::GPTL_wrapper("PIO:SPIO_Util::Rearr_Util::alltoallw"); + SPIO_Util::GPTL_Util::GPTL_timer("PIO:SPIO_Util::Rearr_Util::alltoallw"); LOG((2, "pio_swapm fc->hs = %d fc->isend = %d fc->max_pend_req = %d", fc->hs, fc->isend, fc->max_pend_req)); @@ -699,7 +699,7 @@ int SPIO_Util::Rearr_Util::alltoall(const void *sendbuf, int sendcount, } } - SPIO_Util::GPTL_Util::GPTL_wrapper("PIO:SPIO_Util::Rearr_Util::alltoallw"); + SPIO_Util::GPTL_Util::GPTL_timer("PIO:SPIO_Util::Rearr_Util::alltoallw"); LOG((2, "pio_swapm fc->hs = %d fc->isend = %d fc->max_pend_req = %d", fc->hs, fc->isend, fc->max_pend_req)); From 7c0553f9fb23bf07dd20ec9b85c6d4d60c76bc4f Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 12 Mar 2026 13:06:29 -0500 Subject: [PATCH 148/194] Fix ADIOS bld issues after using interface libs Moving ADIOS util library to an object library and removing dependency to pioc lib. This avoid cyclic dependency issues between pioc and adios2pio-nm-lib libraries (CMake only allows cyclic dependencies between static libraries. Now some object libraries, that are part of pioc, and pioc depend on adios2pio-nm-lib code) Also, installing a dummy adios2pio-nm-lib.a for now since E3SM expects this library to be available (this hack will be removed once E3SM+SCORPIO build scripts are updated) --- src/clib/CMakeLists.txt | 10 ++++- tools/adios2pio-nm/CMakeLists.txt | 71 +++++++++++++++++++------------ 2 files changed, 51 insertions(+), 30 deletions(-) diff --git a/src/clib/CMakeLists.txt b/src/clib/CMakeLists.txt index f1b6422b09..a2591abf37 100644 --- a/src/clib/CMakeLists.txt +++ b/src/clib/CMakeLists.txt @@ -179,7 +179,7 @@ if (WITH_ADIOS2) # Required for symlink() support/decl in unistd.h target_compile_definitions (spio_default_private_options INTERFACE _POSIX_C_SOURCE=200112L) - target_link_libraries (spio_default_public_options INTERFACE adios2::adios2 adios2pio-nm-lib) + target_link_libraries (spio_default_public_options INTERFACE adios2::adios2) else () message(STATUS "Could not find ADIOS library, disabling support for ADIOS") set(PIO_USE_ADIOS 0) @@ -465,7 +465,7 @@ add_subdirectory (core) # FIXME : Use interface libs for subdir sources ? # Add sources for libpioc.a -add_library (pioc +set (SPIO_PIOC_OBJS $ $ $ @@ -475,6 +475,12 @@ add_library (pioc $ $) +if (ADIOS2_FOUND) + set (SPIO_PIOC_OBJS ${SPIO_PIOC_OBJS} $) +endif () + +add_library (pioc ${SPIO_PIOC_OBJS}) + # PUBLIC ${spio_default_public_libs} # PRIVATE ${spio_default_private_libs} diff --git a/tools/adios2pio-nm/CMakeLists.txt b/tools/adios2pio-nm/CMakeLists.txt index b6b6b116e6..9d8edffdf1 100644 --- a/tools/adios2pio-nm/CMakeLists.txt +++ b/tools/adios2pio-nm/CMakeLists.txt @@ -88,8 +88,16 @@ endif () #============================================================================== # DEFINE THE TARGET LIBRARY #============================================================================== +# FIXME: Remove this hack once we fix E3SM dependency for this lib +macro(create_dummy_adios_lib ) + set(spio_dummy_adios2pio_nm_lib_src "${CMAKE_CURRENT_BINARY_DIR}/spio_dummy_adios2pio_nm_lib.cxx") + file(WRITE "${spio_dummy_adios2pio_nm_lib_src}" "/* DUMMY FILE */") + add_library(adios2pio-nm-lib ${spio_dummy_adios2pio_nm_lib_src}) +endmacro() + SET(SRC ${SCORPIO_SOURCE_DIR}/util/argparser.cxx adios2pio-nm.cxx) -add_library(adios2pio-nm-lib ${SCORPIO_SOURCE_DIR}/util/spio_misc_tool_utils.cxx adios2pio-nm-lib.cxx) +add_library(adios2pio-nm-lib-objs OBJECT ${SCORPIO_SOURCE_DIR}/util/spio_misc_tool_utils.cxx adios2pio-nm-lib.cxx) +create_dummy_adios_lib() include_directories( "${PROJECT_SOURCE_DIR}" # to find foo/foo.h "${PROJECT_BINARY_DIR}") # to find foo/config.h @@ -115,8 +123,9 @@ else () set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") endif () -target_include_directories(adios2pio-nm-lib PRIVATE +target_include_directories(adios2pio-nm-lib-objs PRIVATE ${SCORPIO_SOURCE_DIR}/src/clib + ${SCORPIO_SOURCE_DIR}/src/clib/util ${SCORPIO_BINARY_DIR}/src/clib ${SCORPIO_SOURCE_DIR}/util ${PnetCDF_C_INCLUDE_DIRS} @@ -126,6 +135,7 @@ target_include_directories(adios2pio-nm-lib PRIVATE target_include_directories(adios2pio-nm.exe PRIVATE ${SCORPIO_SOURCE_DIR}/src/clib + ${SCORPIO_SOURCE_DIR}/src/clib/util ${SCORPIO_BINARY_DIR}/src/clib ${SCORPIO_SOURCE_DIR}/util ${PnetCDF_C_INCLUDE_DIRS} @@ -135,8 +145,12 @@ target_include_directories(adios2pio-nm.exe PRIVATE # Adding path to internal GPTL lib, if needed if (PIO_ENABLE_TIMING) - if (NOT GPTL_C_FOUND) - target_include_directories(adios2pio-nm-lib + if (GPTL_C_FOUND) + target_include_directories(adios2pio-nm-lib-objs + PRIVATE ${GPTL_C_INCLUDE_DIRS}) + else () + # Use internal GPTL lib + target_include_directories(adios2pio-nm-lib-objs PRIVATE ${PROJECT_SOURCE_DIR}/../src/gptl) target_include_directories(adios2pio-nm.exe PRIVATE ${PROJECT_SOURCE_DIR}/../src/gptl) @@ -144,75 +158,76 @@ if (PIO_ENABLE_TIMING) endif () # System and compiler CPP directives -target_compile_definitions (adios2pio-nm-lib +target_compile_definitions (adios2pio-nm-lib-objs PRIVATE ${CMAKE_SYSTEM_DIRECTIVE}) -target_compile_definitions (adios2pio-nm-lib +target_compile_definitions (adios2pio-nm-lib-objs PUBLIC ${CMAKE_C_COMPILER_DIRECTIVE}) # Skip MPI C++ headers/bindings for MPICH lib -target_compile_definitions (adios2pio-nm-lib +target_compile_definitions (adios2pio-nm-lib-objs PUBLIC MPICH_SKIP_MPICXX) # Skip MPI C++ headers/bindings for OpenMPI lib -target_compile_definitions (adios2pio-nm-lib +target_compile_definitions (adios2pio-nm-lib-objs PUBLIC OMPI_SKIP_MPICXX) # Skip MPI C++ headers/bindings for SGI MPT lib -target_compile_definitions (adios2pio-nm-lib +target_compile_definitions (adios2pio-nm-lib-objs PUBLIC MPI_NO_CPPBIND) # Set external lib compiler/link flags if (PnetCDF_C_FOUND) - target_include_directories (adios2pio-nm-lib + target_include_directories (adios2pio-nm-lib-objs PUBLIC ${PnetCDF_C_INCLUDE_DIRS}) - target_compile_definitions (adios2pio-nm-lib + target_compile_definitions (adios2pio-nm-lib-objs PUBLIC _PNETCDF) - target_link_libraries (adios2pio-nm-lib + target_link_libraries (adios2pio-nm-lib-objs PUBLIC ${PnetCDF_C_LIBRARIES}) else () - target_compile_definitions (adios2pio-nm-lib + target_compile_definitions (adios2pio-nm-lib-objs PUBLIC _NOPNETCDF) endif () if (NetCDF_C_FOUND) - target_include_directories (adios2pio-nm-lib + target_include_directories (adios2pio-nm-lib-objs PUBLIC ${NetCDF_C_INCLUDE_DIRS}) - target_compile_definitions (adios2pio-nm-lib + target_compile_definitions (adios2pio-nm-lib-objs PUBLIC _NETCDF) - target_link_libraries (adios2pio-nm-lib + target_link_libraries (adios2pio-nm-lib-objs PUBLIC ${NetCDF_C_LIBRARIES}) if (${NetCDF_C_HAS_PARALLEL}) - target_compile_definitions (adios2pio-nm-lib + target_compile_definitions (adios2pio-nm-lib-objs PUBLIC _NETCDF4) endif () else () - target_compile_definitions (adios2pio-nm-lib + target_compile_definitions (adios2pio-nm-lib-objs PUBLIC _NONETCDF) endif () if (ADIOS2_FOUND) - target_compile_definitions (adios2pio-nm-lib + target_compile_definitions (adios2pio-nm-lib-objs PRIVATE _ADIOS2) - target_link_libraries (adios2pio-nm-lib + target_link_libraries (adios2pio-nm-lib-objs PUBLIC adios2::adios2) else () - target_compile_definitions (adios2pio-nm-lib + target_compile_definitions (adios2pio-nm-lib-objs PUBLIC _NOADIOS) endif () # Add the extra (user-specified) compile/link options -target_include_directories (adios2pio-nm-lib +target_include_directories (adios2pio-nm-lib-objs PUBLIC ${PIO_C_EXTRA_INCLUDE_DIRS}) -target_link_libraries (adios2pio-nm-lib +target_link_libraries (adios2pio-nm-lib-objs PUBLIC ${PIO_C_EXTRA_LIBRARIES}) -target_compile_options (adios2pio-nm-lib +target_compile_options (adios2pio-nm-lib-objs PRIVATE ${PIO_C_EXTRA_COMPILE_OPTIONS}) -target_compile_definitions (adios2pio-nm-lib +target_compile_definitions (adios2pio-nm-lib-objs PUBLIC ${PIO_C_EXTRA_COMPILE_DEFINITIONS}) if (PIO_C_EXTRA_LINK_FLAGS) - set_target_properties(adios2pio-nm-lib PROPERTIES + set_target_properties(adios2pio-nm-lib-objs PROPERTIES LINK_FLAGS ${PIO_C_EXTRA_LINK_FLAGS}) endif () -TARGET_LINK_LIBRARIES(adios2pio-nm-lib PRIVATE pioc) -TARGET_LINK_LIBRARIES(adios2pio-nm.exe PRIVATE adios2pio-nm-lib) +#TARGET_LINK_LIBRARIES(adios2pio-nm-lib-objs PRIVATE pioc) +TARGET_LINK_LIBRARIES(adios2pio-nm-lib-objs PRIVATE spio_default_public_options) +TARGET_LINK_LIBRARIES(adios2pio-nm.exe PRIVATE adios2pio-nm-lib-objs) #============================================================================== # INSTALL From 752b3d821781789daad168c9098aa434a4fb3441 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 12 Mar 2026 14:30:25 -0500 Subject: [PATCH 149/194] Add asctime_r() decl is available for pnetcdf test Ensure that asctime_r() declaration (in time.h) is available by setting the POSIX standard compliance macro. --- tests/pnetcdf/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/pnetcdf/CMakeLists.txt b/tests/pnetcdf/CMakeLists.txt index 7bb8e03289..c959d54c1c 100644 --- a/tests/pnetcdf/CMakeLists.txt +++ b/tests/pnetcdf/CMakeLists.txt @@ -10,6 +10,8 @@ include(SPIOUtils) # SET THE COMPILER OPTIONS #============================================================================== include_directories("${SCORPIO_SOURCE_DIR}/tests/cunit" "${SCORPIO_SOURCE_DIR}/src/clib" "${SCORPIO_BINARY_DIR}/src/clib") +# Required for time.h to include decl of asctime_r() +add_compile_definitions(_POSIX_C_SOURCE=200112L) # Compiler-specific compiler options string (TOUPPER "${CMAKE_C_COMPILER_ID}" CMAKE_C_COMPILER_NAME) From aec8cceb178ea70029cc96af87c59aa405cc498c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 19:31:41 +0000 Subject: [PATCH 150/194] Build test_common.cpp as a CMake object library test_common.cpp was compiled redundantly into every test executable that used it. This refactors it into a single OBJECT library compiled once and linked where needed. Co-authored-by: jayeshkrishna <7873429+jayeshkrishna@users.noreply.github.com> --- cmake/SPIOUtils.cmake | 8 ++++- tests/cunit/CMakeLists.txt | 67 ++++++++++++++++++++------------------ 2 files changed, 42 insertions(+), 33 deletions(-) diff --git a/cmake/SPIOUtils.cmake b/cmake/SPIOUtils.cmake index eb2267dfdf..d8487bb314 100644 --- a/cmake/SPIOUtils.cmake +++ b/cmake/SPIOUtils.cmake @@ -9,7 +9,8 @@ # Prereq: MPI (MPI serial) & GPTL libraries are searched for (find_library() ) # prior to invoking this macro to add SCORPIO applications macro (add_spio_executable EXE_NAME IS_C_SRC EXE_LINKER_LANGUAGE) - add_executable(${EXE_NAME} ${ARGN}) + cmake_parse_arguments (_SPIO_EXE "" "" "OBJ_LIBS" ${ARGN}) + add_executable(${EXE_NAME} ${_SPIO_EXE_UNPARSED_ARGUMENTS}) if (${IS_C_SRC}) target_link_libraries(${EXE_NAME} PRIVATE pioc) else () @@ -47,5 +48,10 @@ macro (add_spio_executable EXE_NAME IS_C_SRC EXE_LINKER_LANGUAGE) if (NOT ("${EXE_LINKER_LANGUAGE}" STREQUAL "")) set_property(TARGET ${EXE_NAME} PROPERTY LINKER_LANGUAGE ${EXE_LINKER_LANGUAGE}) endif () + if (_SPIO_EXE_OBJ_LIBS) + foreach (_spio_obj_lib ${_SPIO_EXE_OBJ_LIBS}) + target_link_libraries (${EXE_NAME} PRIVATE $) + endforeach () + endif () endmacro () diff --git a/tests/cunit/CMakeLists.txt b/tests/cunit/CMakeLists.txt index a27e1c0e9c..d0e17ad27a 100644 --- a/tests/cunit/CMakeLists.txt +++ b/tests/cunit/CMakeLists.txt @@ -63,44 +63,47 @@ endif () # DEFINE THE TARGETS AND TESTS #============================================================================== +add_library (test_common_obj OBJECT test_common.cpp) +target_link_libraries (test_common_obj PRIVATE pioc) + # Exclude tests that require more than 1 procs when using the MPI serial library if (NOT PIO_USE_MPISERIAL) - add_spio_executable (test_intercomm2 TRUE "" test_intercomm2.cpp test_common.cpp) - add_spio_executable (test_async_simple TRUE "" test_async_simple.cpp test_common.cpp) - add_spio_executable (test_async_3proc TRUE "" test_async_3proc.cpp test_common.cpp) - add_spio_executable (test_async_4proc TRUE "" test_async_4proc.cpp test_common.cpp) - add_spio_executable (test_iosystem2_simple TRUE "" test_iosystem2_simple.cpp test_common.cpp) - add_spio_executable (test_iosystem2_simple2 TRUE "" test_iosystem2_simple2.cpp test_common.cpp) - add_spio_executable (test_iosystem2 TRUE "" test_iosystem2.cpp test_common.cpp) - add_spio_executable (test_iosystem3_simple TRUE "" test_iosystem3_simple.cpp test_common.cpp) - add_spio_executable (test_iosystem3_simple2 TRUE "" test_iosystem3_simple2.cpp test_common.cpp) - add_spio_executable (test_iosystem3 TRUE "" test_iosystem3.cpp test_common.cpp) - add_spio_executable (test_pioc TRUE "" test_pioc.cpp test_common.cpp test_shared.cpp) - add_spio_executable (test_pioc_unlim TRUE "" test_pioc_unlim.cpp test_common.cpp test_shared.cpp) - add_spio_executable (test_pioc_putget TRUE "" test_pioc_putget.cpp test_common.cpp test_shared.cpp) - add_spio_executable (test_pioc_fill TRUE "" test_pioc_fill.cpp test_common.cpp test_shared.cpp) - add_spio_executable (test_darray TRUE "" test_darray.cpp test_common.cpp) - add_spio_executable (test_darray_multi TRUE "" test_darray_multi.cpp test_common.cpp) - add_spio_executable (test_darray_multivar TRUE "" test_darray_multivar.cpp test_common.cpp) - add_spio_executable (test_darray_multivar2 TRUE "" test_darray_multivar2.cpp test_common.cpp) - add_spio_executable (test_darray_1d TRUE "" test_darray_1d.cpp test_common.cpp) - add_spio_executable (test_darray_3d TRUE "" test_darray_3d.cpp test_common.cpp) - add_spio_executable (test_decomp_uneven TRUE "" test_decomp_uneven.cpp test_common.cpp) - add_spio_executable (test_decomps TRUE "" test_decomps.cpp test_common.cpp) - add_spio_executable (test_rearr TRUE "" test_rearr.cpp test_common.cpp) + add_spio_executable (test_intercomm2 TRUE "" test_intercomm2.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_async_simple TRUE "" test_async_simple.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_async_3proc TRUE "" test_async_3proc.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_async_4proc TRUE "" test_async_4proc.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_iosystem2_simple TRUE "" test_iosystem2_simple.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_iosystem2_simple2 TRUE "" test_iosystem2_simple2.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_iosystem2 TRUE "" test_iosystem2.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_iosystem3_simple TRUE "" test_iosystem3_simple.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_iosystem3_simple2 TRUE "" test_iosystem3_simple2.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_iosystem3 TRUE "" test_iosystem3.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_pioc TRUE "" test_pioc.cpp test_shared.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_pioc_unlim TRUE "" test_pioc_unlim.cpp test_shared.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_pioc_putget TRUE "" test_pioc_putget.cpp test_shared.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_pioc_fill TRUE "" test_pioc_fill.cpp test_shared.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_darray TRUE "" test_darray.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_darray_multi TRUE "" test_darray_multi.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_darray_multivar TRUE "" test_darray_multivar.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_darray_multivar2 TRUE "" test_darray_multivar2.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_darray_1d TRUE "" test_darray_1d.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_darray_3d TRUE "" test_darray_3d.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_decomp_uneven TRUE "" test_decomp_uneven.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_decomps TRUE "" test_decomps.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_rearr TRUE "" test_rearr.cpp OBJ_LIBS test_common_obj) add_dependencies (tests test_intercomm2 test_async_simple test_async_3proc test_async_4proc test_iosystem2_simple test_iosystem2_simple2 test_iosystem2 test_iosystem3_simple test_iosystem3_simple2 test_iosystem3 test_pioc test_pioc_unlim test_pioc_putget test_pioc_fill test_darray test_darray_multi test_darray_multivar test_darray_multivar2 test_darray_1d test_darray_3d test_decomp_uneven test_decomps test_rearr) if (PIO_USE_MALLOC) - add_spio_executable (test_darray_async_simple TRUE "" test_darray_async_simple.cpp test_common.cpp) - add_spio_executable (test_darray_async TRUE "" test_darray_async.cpp test_common.cpp) - add_spio_executable (test_darray_async_many TRUE "" test_darray_async_many.cpp test_common.cpp) + add_spio_executable (test_darray_async_simple TRUE "" test_darray_async_simple.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_darray_async TRUE "" test_darray_async.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_darray_async_many TRUE "" test_darray_async_many.cpp OBJ_LIBS test_common_obj) add_dependencies (tests test_darray_async_simple test_darray_async test_darray_async_many) endif () endif () -add_spio_executable (test_spmd TRUE "" test_spmd.cpp test_common.cpp) +add_spio_executable (test_spmd TRUE "" test_spmd.cpp OBJ_LIBS test_common_obj) add_spio_executable (test_spio_ltimer TRUE "" test_spio_ltimer.cpp) add_spio_executable (test_spio_serializer TRUE "" test_spio_serializer.cpp) add_spio_executable (test_spio_tree TRUE "" test_spio_tree.cpp) @@ -113,8 +116,8 @@ add_spio_executable (test_spio_rearr_contig TRUE "" test_spio_rearr_contig.cpp) add_spio_executable (test_spio_rearr_contig_nvars TRUE "" test_spio_rearr_contig_nvars.cpp) add_spio_executable (test_spio_rearr_contig_fillval TRUE "" test_spio_rearr_contig_fillval.cpp) add_spio_executable (test_spio_decomp_logger TRUE "" test_spio_decomp_logger.cpp) -add_spio_executable (test_sdecomp_regex TRUE "" test_sdecomp_regex.cpp test_common.cpp) -add_spio_executable(test_req_block_wait TRUE "" test_req_block_wait.cpp test_common.cpp) +add_spio_executable (test_sdecomp_regex TRUE "" test_sdecomp_regex.cpp OBJ_LIBS test_common_obj) +add_spio_executable(test_req_block_wait TRUE "" test_req_block_wait.cpp OBJ_LIBS test_common_obj) add_spio_executable(test_spio_dt_converter TRUE "" test_spio_dt_converter.cpp) add_dependencies (tests test_spmd test_spio_ltimer test_spio_serializer test_spio_tree test_spio_file_mvcache test_spio_sort_utils test_spio_rearr_utils_gather @@ -124,9 +127,9 @@ add_dependencies (tests test_spmd test_spio_ltimer test_spio_serializer test_spi test_spio_dt_converter) if(PIO_USE_ASYNC_WR_THREAD) - add_spio_executable (test_mtq TRUE "" test_async_mtq.cpp test_common.cpp) - add_spio_executable (test_mtq_signal TRUE "" test_async_mtq_signal.cpp test_common.cpp) - add_spio_executable (test_mtq_pool TRUE "" test_async_tpool.cpp test_common.cpp) + add_spio_executable (test_mtq TRUE "" test_async_mtq.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_mtq_signal TRUE "" test_async_mtq_signal.cpp OBJ_LIBS test_common_obj) + add_spio_executable (test_mtq_pool TRUE "" test_async_tpool.cpp OBJ_LIBS test_common_obj) add_dependencies(tests test_mtq test_mtq_signal test_mtq_pool) endif() From 0b87ee510dbbc53d1fd4cd0f031c9506231bc747 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 23 Mar 2026 15:26:52 -0500 Subject: [PATCH 151/194] Moving logger to lib util Moving MPI logger from clib util to generic lib util (No source code changes, moving files and updating cmake config) --- src/clib/api/CMakeLists.txt | 2 +- src/clib/util/CMakeLists.txt | 2 +- {src/clib/util => util}/spio_logger.hpp | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename {src/clib/util => util}/spio_logger.hpp (100%) diff --git a/src/clib/api/CMakeLists.txt b/src/clib/api/CMakeLists.txt index f12965bb16..8d5368bfaa 100644 --- a/src/clib/api/CMakeLists.txt +++ b/src/clib/api/CMakeLists.txt @@ -31,7 +31,7 @@ set (pio_api_src add_library (pioc_api OBJECT ${pio_api_src}) target_include_directories(pioc_api PUBLIC . - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../util) + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../util ${SCORPIO_SOURCE_DIR}/util) target_link_libraries(pioc_api PUBLIC spio_default_public_options PRIVATE spio_default_private_options) diff --git a/src/clib/util/CMakeLists.txt b/src/clib/util/CMakeLists.txt index 9097b8e262..45adf17f61 100644 --- a/src/clib/util/CMakeLists.txt +++ b/src/clib/util/CMakeLists.txt @@ -21,7 +21,7 @@ set (spio_util_src add_library (spio_util OBJECT ${spio_util_src}) target_include_directories(spio_util PUBLIC . - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/..) + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/.. ${SCORPIO_SOURCE_DIR}/util) target_link_libraries(spio_util PUBLIC spio_default_public_options PRIVATE spio_default_private_options) diff --git a/src/clib/util/spio_logger.hpp b/util/spio_logger.hpp similarity index 100% rename from src/clib/util/spio_logger.hpp rename to util/spio_logger.hpp From 2ae824769b8de73c5fd3a4ff9c6daaab2042a573 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 25 Mar 2026 10:56:29 -0500 Subject: [PATCH 152/194] Adding log level to mpi logger Adding a log level to the MPI logger. Also adding an option to explicitly enable logging on a process --- util/spio_logger.hpp | 47 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/util/spio_logger.hpp b/util/spio_logger.hpp index 02747f876d..d92ecfc0de 100644 --- a/util/spio_logger.hpp +++ b/util/spio_logger.hpp @@ -7,13 +7,23 @@ namespace SPIO_Util{ namespace Logger{ + enum class Log_level : int{ + INVALID = 0, + TRACE, + DEBUG, + INFO, + WARN, + ERROR, + FATAL + }; + /* FIXME: Add a generic logger class */ /* FIXME : Allow logging from multiple classes */ /* An MPI logger */ template class MPI_logger{ public: - MPI_logger() : mpi_comm_(MPI_COMM_NULL), ostr_(NULL), is_io_proc_(false) {} + MPI_logger() : mpi_comm_(MPI_COMM_NULL), ostr_(NULL), is_io_proc_(false), slog_done_(false), log_lvl_(Log_level::INFO) {} MPI_logger(MPI_Comm comm, TStream *ostr); @@ -21,12 +31,21 @@ namespace SPIO_Util{ MPI_logger &operator=(const MPI_logger &other) = default; + /* Enable logging on this proc. By default logging is only enabled on rank 0 */ + MPI_logger &enable_logging(void ) { is_io_proc_ = true; return *this; } + /* Log message */ void log(const std::string &log_msg); + /* Log message, with log level */ + void log(Log_level lvl, const std::string &log_msg); + /* Singleton log : Logging is only done once - e.g. writing headers etc */ void slog(const std::string &slog_msg); + /* Singleton log with log level : Logging is only done once - e.g. writing headers etc */ + void slog(Log_level lvl, const std::string &slog_msg); + /* Explicitly flush the contents of the logger */ void flush(void ); @@ -39,22 +58,24 @@ namespace SPIO_Util{ TStream *ostr_; bool is_io_proc_; bool slog_done_; + Log_level log_lvl_; - static const int MPI_RANK_ROOT = 0; + static const int MPI_DEFAULT_ROOT = 0; static const char LOG_SEP = '\n'; }; } // namespace Logger } // namespace SPIO_Util template -SPIO_Util::Logger::MPI_logger::MPI_logger(MPI_Comm comm, TStream *ostr):mpi_comm_(comm), ostr_(ostr), is_io_proc_(false), slog_done_(false) +SPIO_Util::Logger::MPI_logger::MPI_logger(MPI_Comm comm, TStream *ostr): + mpi_comm_(comm), ostr_(ostr), is_io_proc_(false), slog_done_(false), log_lvl_(Log_level::INFO) { int rank; int ret; ret = MPI_Comm_rank(mpi_comm_, &rank); assert(ret == MPI_SUCCESS); - if(rank == MPI_RANK_ROOT){ + if(rank == MPI_DEFAULT_ROOT){ is_io_proc_ = true; } } @@ -62,16 +83,30 @@ SPIO_Util::Logger::MPI_logger::MPI_logger(MPI_Comm comm, TStream *ostr) template void SPIO_Util::Logger::MPI_logger::log(const std::string &log_msg) { - if(is_io_proc_){ + log(Log_level::INFO, log_msg); +} + +template +void SPIO_Util::Logger::MPI_logger::log(Log_level lvl, const std::string &log_msg) +{ + if(is_io_proc_ && (log_lvl_ <= lvl)){ (*ostr_) << log_msg.c_str() << LOG_SEP; } } template void SPIO_Util::Logger::MPI_logger::slog(const std::string &slog_msg) +{ + slog(Log_level::INFO, slog_msg); +} + +template +void SPIO_Util::Logger::MPI_logger::slog(Log_level lvl, const std::string &slog_msg) { if(!slog_done_){ - log(slog_msg); + if(is_io_proc_ && (log_lvl_ <= lvl)){ + log(slog_msg); + } slog_done_ = true; } } From 6ac2c006cb5afa68851fd4f698cd4dc0dc5166a8 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 25 Mar 2026 16:07:04 -0500 Subject: [PATCH 153/194] Use shared ptr for streams in logger Using a shared pointer (instead of a raw pointer) to streams in the MPI logger --- src/clib/util/spio_tracer.cpp | 5 ++--- src/clib/util/spio_tracer_mdata.cpp | 6 ++---- util/spio_logger.hpp | 11 ++++++----- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/clib/util/spio_tracer.cpp b/src/clib/util/spio_tracer.cpp index dceb67a794..a848e35d2c 100644 --- a/src/clib/util/spio_tracer.cpp +++ b/src/clib/util/spio_tracer.cpp @@ -278,7 +278,7 @@ SPIO_Util::Logger::MPI_logger &SPIO_Util::Tracer::get_iosys_trace assert(ret == MPI_SUCCESS); // FIXME: use unique_ptr - std::ofstream *fstr = new std::ofstream(); + std::shared_ptr fstr = std::make_shared(); const std::string DEV_NULL = "/dev/null"; std::string log_fname = get_trace_log_fname(iosysid, mpi_wrank); @@ -318,10 +318,9 @@ void SPIO_Util::Tracer::finalize_iosys_trace_logger(std::string iosys_key) std::map >::iterator iter = SPIO_Util::Tracer::GVars::trace_loggers_.find(iosys_key); if(iter != SPIO_Util::Tracer::GVars::trace_loggers_.end()){ (*iter).second.log(get_trace_log_footer()); - std::ofstream *fstr = (*iter).second.get_log_stream(); + std::shared_ptr fstr = (*iter).second.get_log_stream(); assert(fstr); fstr->close(); - delete fstr; SPIO_Util::Tracer::GVars::trace_loggers_.erase(iter); } diff --git a/src/clib/util/spio_tracer_mdata.cpp b/src/clib/util/spio_tracer_mdata.cpp index cb7b5839af..b20bddeaf4 100644 --- a/src/clib/util/spio_tracer_mdata.cpp +++ b/src/clib/util/spio_tracer_mdata.cpp @@ -131,8 +131,7 @@ SPIO_Util::Logger::MPI_logger &SPIO_Util::Tracer::get_iosys_trace ret = MPI_Comm_rank(comm, &rank); assert(ret == MPI_SUCCESS); - // FIXME: use unique_ptr - std::ofstream *fstr = new std::ofstream(); + std::shared_ptr fstr = std::make_shared(); const std::string DEV_NULL = "/dev/null"; std::string mdata_fname = get_trace_mdata_fname(iosysid, mpi_wrank); @@ -156,10 +155,9 @@ void SPIO_Util::Tracer::finalize_iosys_trace_mdata_logger(std::string iosys_key) std::map >::iterator iter = SPIO_Util::Tracer::GVars::trace_mdata_loggers_.find(iosys_key); if(iter != SPIO_Util::Tracer::GVars::trace_mdata_loggers_.end()){ (*iter).second.log(get_trace_mdata_footer()); - std::ofstream *fstr = (*iter).second.get_log_stream(); + std::shared_ptr fstr = (*iter).second.get_log_stream(); assert(fstr); fstr->close(); - delete fstr; SPIO_Util::Tracer::GVars::trace_mdata_loggers_.erase(iter); } diff --git a/util/spio_logger.hpp b/util/spio_logger.hpp index d92ecfc0de..bf3f8e2591 100644 --- a/util/spio_logger.hpp +++ b/util/spio_logger.hpp @@ -2,6 +2,7 @@ #define __SPIO_LOGGER_HPP__ #include +#include #include "mpi.h" @@ -25,7 +26,7 @@ namespace SPIO_Util{ public: MPI_logger() : mpi_comm_(MPI_COMM_NULL), ostr_(NULL), is_io_proc_(false), slog_done_(false), log_lvl_(Log_level::INFO) {} - MPI_logger(MPI_Comm comm, TStream *ostr); + MPI_logger(MPI_Comm comm, std::shared_ptr &ostr); MPI_logger(const MPI_logger &other) = default; @@ -50,12 +51,12 @@ namespace SPIO_Util{ void flush(void ); /* Get associated stream */ - TStream *get_log_stream(void ) const; + std::shared_ptr get_log_stream(void ) const; ~MPI_logger(){} private: MPI_Comm mpi_comm_; - TStream *ostr_; + std::shared_ptr ostr_; bool is_io_proc_; bool slog_done_; Log_level log_lvl_; @@ -67,7 +68,7 @@ namespace SPIO_Util{ } // namespace SPIO_Util template -SPIO_Util::Logger::MPI_logger::MPI_logger(MPI_Comm comm, TStream *ostr): +SPIO_Util::Logger::MPI_logger::MPI_logger(MPI_Comm comm, std::shared_ptr &ostr): mpi_comm_(comm), ostr_(ostr), is_io_proc_(false), slog_done_(false), log_lvl_(Log_level::INFO) { int rank; @@ -120,7 +121,7 @@ void SPIO_Util::Logger::MPI_logger::flush() } template -TStream *SPIO_Util::Logger::MPI_logger::get_log_stream(void ) const +std::shared_ptr SPIO_Util::Logger::MPI_logger::get_log_stream(void ) const { return ostr_; } From f47c8e5d4a7afe267d61203852b6a21cc25e8cd5 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 27 Mar 2026 16:44:18 -0500 Subject: [PATCH 154/194] Add more utils for log levels Adding utils to convert log levels to strings and back. Also adding a util to get all available log levels. --- util/spio_logger.hpp | 45 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/util/spio_logger.hpp b/util/spio_logger.hpp index bf3f8e2591..25ca35e266 100644 --- a/util/spio_logger.hpp +++ b/util/spio_logger.hpp @@ -3,6 +3,8 @@ #include #include +#include +#include #include "mpi.h" @@ -18,6 +20,49 @@ namespace SPIO_Util{ FATAL }; + inline std::string log_level_to_string(const Log_level &lvl){ + switch(lvl){ + case Logger::Log_level::INVALID : return "INVALID"; + case Logger::Log_level::TRACE : return "TRACE"; + case Logger::Log_level::DEBUG : return "DEBUG"; + case Logger::Log_level::INFO : return "INFO"; + case Logger::Log_level::WARN : return "WARN"; + case Logger::Log_level::ERROR : return "ERROR"; + case Logger::Log_level::FATAL : return "FATAL"; + default : return "INVALID"; + } + } + + inline Log_level string_to_log_level(const std::string &lvl){ + std::string ulvl(lvl); + + std::transform(ulvl.begin(), ulvl.end(), ulvl.begin(), + [](unsigned char c) { return std::toupper(c); }); + + if(ulvl == "INVALID") { return Logger::Log_level::INVALID; } + if(ulvl == "TRACE") { return Logger::Log_level::TRACE; } + if(ulvl == "DEBUG") { return Logger::Log_level::DEBUG; } + if(ulvl == "INFO") { return Logger::Log_level::INFO; } + if(ulvl == "WARN") { return Logger::Log_level::WARN; } + if(ulvl == "ERROR") { return Logger::Log_level::ERROR; } + if(ulvl == "FATAL") { return Logger::Log_level::FATAL; } + + return Logger::Log_level::INVALID; + } + + inline std::string get_available_log_levels(void ){ + std::vector log_levels = {Log_level::INVALID, + Log_level::TRACE, Log_level::DEBUG, Log_level::INFO, + Log_level::WARN, Log_level::ERROR, Log_level::FATAL}; + + std::string str_lvls("["); + std::for_each(log_levels.cbegin(), log_levels.cend(), + [&str_lvls](const Log_level &lvl) { str_lvls += log_level_to_string(lvl) + ", "; }); + + return str_lvls + "]"; + } + + /* FIXME: Add a generic logger class */ /* FIXME : Allow logging from multiple classes */ /* An MPI logger */ From 9cc97cf44b5124350d77957fed93bf3a17a987a3 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 27 Mar 2026 17:13:57 -0500 Subject: [PATCH 155/194] Log by default to stdout The MPI logger now logs by default to STDOUT --- util/spio_logger.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/util/spio_logger.hpp b/util/spio_logger.hpp index 25ca35e266..94ff87d378 100644 --- a/util/spio_logger.hpp +++ b/util/spio_logger.hpp @@ -1,6 +1,7 @@ #ifndef __SPIO_LOGGER_HPP__ #define __SPIO_LOGGER_HPP__ +#include #include #include #include @@ -99,6 +100,7 @@ namespace SPIO_Util{ std::shared_ptr get_log_stream(void ) const; ~MPI_logger(){} + private: MPI_Comm mpi_comm_; std::shared_ptr ostr_; @@ -136,7 +138,7 @@ template void SPIO_Util::Logger::MPI_logger::log(Log_level lvl, const std::string &log_msg) { if(is_io_proc_ && (log_lvl_ <= lvl)){ - (*ostr_) << log_msg.c_str() << LOG_SEP; + ((ostr_) ? (*ostr_) : std::cout) << log_msg.c_str() << LOG_SEP; } } @@ -161,7 +163,7 @@ template void SPIO_Util::Logger::MPI_logger::flush() { if(is_io_proc_){ - ostr_->flush(); + (ostr_) ? ostr_->flush() : std::cout.flush(); } } From 33305f31ca18e3b9e790a87bc3929a2f6de1839e Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 27 Mar 2026 17:30:43 -0500 Subject: [PATCH 156/194] Adding new C++ unit testing framework Adding a new C++ unit testing framework. * All initializations/finalizations (except MPI) is handled by the testing framework * Logging is supported * Users register the unit test functions when creating the testing framework * During the testing framework initialization (init()) the framework parses user arguments and initializes libs * All registered unit functions are run using the run() method of the testing framework (the framework runs each test and reports on the status) * The framework is finalized using the finalize() method * Currently "--log-file" (the file to log output) and "--log-level" (logging level) are supported as user args * --- tests/cunit/spio_test_framework.hpp | 216 ++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 tests/cunit/spio_test_framework.hpp diff --git a/tests/cunit/spio_test_framework.hpp b/tests/cunit/spio_test_framework.hpp new file mode 100644 index 0000000000..c02ef49d50 --- /dev/null +++ b/tests/cunit/spio_test_framework.hpp @@ -0,0 +1,216 @@ +#ifndef __SPIO_TEST_FRAMEWORK__ +#define __SPIO_TEST_FRAMEWORK__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pio_config.h" +#include "pio.h" +#include "argparser.h" +#include "spio_logger.hpp" + +namespace SPIO_TF{ + +class Test_framework{ + public: + Test_framework(const std::string &name, MPI_Comm comm, std::vector > > &run_funcs) : + name_(name), log_fname_(tf_name_to_log_fname(name)), + comm_(comm), comm_rank_(0), comm_root_(DEFAULT_ROOT), comm_sz_(0), + run_funcs_(run_funcs) {} + + void init(int argc, char *argv[]){ + int ret = MPI_SUCCESS; + + ret = MPI_Comm_rank(comm_, &comm_rank_); assert(ret == MPI_SUCCESS); + ret = MPI_Comm_size(comm_, &comm_sz_); assert(ret == MPI_SUCCESS); + + /* Get command line user options */ + spio_tool_utils::ArgParser ap(comm_); + init_user_options(ap); + + std::string log_fname; + SPIO_Util::Logger::Log_level log_lvl = SPIO_Util::Logger::Log_level::INVALID; + bool verbose = false; + + ret = get_user_options(ap, argc, argv, comm_rank_, comm_root_, + log_fname, log_lvl, verbose); + if(ret == PIO_NOERR){ + if(verbose) { log_lvl = SPIO_Util::Logger::Log_level::TRACE; } + } + else{ + std::cerr << "ERROR: Getting user options failed\n"; + } + + /* Set up logger - only log from comm_root_ */ + if(!log_fname.empty()){ + logger_fstr_ = std::make_shared(); + const std::string DEV_NULL = "/dev/null"; + logger_fstr_->open((comm_rank_ == comm_root_) ? log_fname_.c_str() : DEV_NULL.c_str(), + std::ofstream::out | std::ofstream::trunc); + flogger_ = SPIO_Util::Logger::MPI_logger(comm_, logger_fstr_); + } + if(comm_rank_ == comm_root_) { flogger_.enable_logging(); } + + + get_logger().log(SPIO_Util::Logger::Log_level::DEBUG, "Testing framework initialized"); +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL + ret = GPTLinitialize(); + if(ret != 0){ + get_logger().log(SPIO_Util::Logger::Log_level::ERROR, std::string("GPTLinitialize() FAILED, ret = ") + std::to_string(ret) + ")"); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + } + + void register_run_funcs(const std::vector > > &run_funcs){ + run_funcs_.insert(run_funcs.end(), run_funcs.cbegin(), run_funcs.cend()); + } + + int run(void ){ + int nerrs = 0; + + std::for_each(run_funcs_.begin(), run_funcs_.end(), + [this, &nerrs](std::pair > &f){ + int ret = PIO_NOERR; + + ret = run(f.first, f.second); + if(ret != 0) { nerrs++; } + + }); + + if(nerrs == 0){ + get_logger().log(SPIO_Util::Logger::Log_level::INFO, "All Tests PASSED"); + } + else{ + const std::string fail_msg = std::string("[") + std::to_string(nerrs) + "] Tests FAILED"; + get_logger().log(SPIO_Util::Logger::Log_level::INFO, fail_msg); + } + get_logger().flush(); + + return nerrs; + } + + template + int run(const std::string &name, std::function &f, Args&&... args){ + int ret = PIO_NOERR, mpierr = MPI_SUCCESS; + try{ + ret = f(*this, std::forward(args)...); + } catch(...){ + ret = PIO_EINTERNAL; + } + + /* Reduce the number of fails/errors across all processes */ + int num_lfail = (ret == PIO_NOERR) ? 0 : 1; + mpierr = MPI_Reduce((comm_rank_ != comm_root_) ? &num_lfail : MPI_IN_PLACE, &num_lfail, 1, MPI_INT, MPI_SUM, comm_root_, comm_); + assert(mpierr == MPI_SUCCESS); + + if(num_lfail == 0){ + get_logger().log(SPIO_Util::Logger::Log_level::INFO, name + " PASSED\n"); + } + else{ + const std::string all_proc_fail_msg("failed on all processes"); + const std::string some_proc_including_root_fail_msg = std::string("failed on ") + std::to_string(num_lfail) + " processes, including root"; + const std::string some_proc_excluding_root_fail_msg = std::string("failed on ") + std::to_string(num_lfail) + " non-root processes, passed on root"; + + + get_logger().log(SPIO_Util::Logger::Log_level::INFO, name + " FAILED (ret = " + std::to_string(ret) + ((num_lfail == comm_sz_) ? all_proc_fail_msg : ((ret != PIO_NOERR) ? some_proc_including_root_fail_msg : some_proc_excluding_root_fail_msg) + ")")); + + } + get_logger().flush(); + + return (num_lfail == 0) ? 0 : 1; + } + + SPIO_Util::Logger::MPI_logger get_logger(void ) const { + return flogger_; + } + + MPI_Comm get_comm(void ) const { return comm_; } + int get_comm_rank(void ) const { return comm_rank_; } + int get_comm_size(void ) const { return comm_sz_; } + + void finalize(void ){ + get_logger().log(SPIO_Util::Logger::Log_level::DEBUG, "Testing framework finalizing..."); +#ifdef SPIO_ENABLE_GPTL_TIMING +#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL + ret = GPTLfinalize(); + if(ret != 0){ + get_logger().log(SPIO_Util::Logger::Log_level::ERROR, std::string("GPTLfinalize() FAILED, ret = ") + std::to_string(ret) + ")"); + return ret; + } +#endif /* TIMING_INTERNAL */ +#endif /* TIMING */ + + if(logger_fstr_) { logger_fstr_->close(); } + } + + ~Test_framework() = default; + + private: + + static inline std::string tf_name_to_log_fname(const std::string &tf_name){ + return tf_name + "_log.txt"; + } + + inline bool is_comm_root(void ) const { return comm_rank_ == comm_root_; } + + static void init_user_options(spio_tool_utils::ArgParser &ap){ + ap.add_opt("log-file", "Output log file (default output is stdout)") + .add_opt("log-level", "Output log level, Valid values = " + SPIO_Util::Logger::get_available_log_levels()) + .add_opt("verbose", "Turn on verbose messages (log level = TRACE)"); + } + + static int get_user_options(spio_tool_utils::ArgParser &ap, + int argc, char *argv[], + int comm_rank, int comm_root, + std::string &log_fname, SPIO_Util::Logger::Log_level &log_lvl, + bool &verbose){ +#ifdef SPIO_NO_CXX_REGEX + ap.no_regex_parse(argc, argv); +#else + ap.parse(argc, argv); +#endif + log_fname = ""; + if(ap.has_arg("log-file")){ + log_fname = ap.get_arg("log-file"); + } + + log_lvl = SPIO_Util::Logger::Log_level::INFO; + if(ap.has_arg("log-level")){ + log_lvl = SPIO_Util::Logger::string_to_log_level(ap.get_arg("log-level")); + } + + verbose = false; + if(ap.has_arg("verbose")){ + verbose = true; + } + + return PIO_NOERR; + } + + const int DEFAULT_ROOT = 0; + + const std::string name_; + const std::string log_fname_; + MPI_Comm comm_; + int comm_rank_; + int comm_root_; + int comm_sz_; + std::vector > > run_funcs_; + std::shared_ptr logger_fstr_; + SPIO_Util::Logger::MPI_logger flogger_; +}; + +} // namespace SPIO_TF + +#endif // __SPIO_TEST_FRAMEWORK__ From 3f2056248779c91da60d0cbc2f6d2a29f40e88d4 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 27 Mar 2026 17:36:43 -0500 Subject: [PATCH 157/194] New testing framework for testing contig rearr Using the new testing framework for testing contig rearranger. * Remove custom LOG_RANK() macro. Using the testing framework logger (using get_logger()) instead * Each unit test now only accepts the testing framework as an argument * Instead of providing MPI comm, rank and size to each unit test use the testing framework to get these info. * Instead of calling the unit test functions manually in a custom test driver register the unit tests with the testing framework and use the run() method of the testing framework to run the tests * MPI is initialized and finalized as before --- tests/cunit/CMakeLists.txt | 6 +- tests/cunit/test_spio_rearr_contig.cpp | 283 ++++++++++--------------- 2 files changed, 120 insertions(+), 169 deletions(-) diff --git a/tests/cunit/CMakeLists.txt b/tests/cunit/CMakeLists.txt index d0e17ad27a..61b73b1928 100644 --- a/tests/cunit/CMakeLists.txt +++ b/tests/cunit/CMakeLists.txt @@ -10,7 +10,7 @@ include(SPIOUtils) # SET THE COMPILER OPTIONS #============================================================================== # FIXME: Use an interface lib to track these include deps -include_directories("${SCORPIO_SOURCE_DIR}/tests/cunit" "${SCORPIO_SOURCE_DIR}/src/clib" "${SCORPIO_BINARY_DIR}/src/clib" "${SCORPIO_SOURCE_DIR}/src/clib/core" "${SCORPIO_SOURCE_DIR}/src/clib/core/util" "${SCORPIO_SOURCE_DIR}/src/clib/core/rearr" "${SCORPIO_SOURCE_DIR}/src/clib/core/progress_engine" "${SCORPIO_SOURCE_DIR}/src/clib/core/iolib/hdf5" "${SCORPIO_SOURCE_DIR}/src/clib/util") +include_directories("${SCORPIO_SOURCE_DIR}/tests/cunit" "${SCORPIO_SOURCE_DIR}/util" "${SCORPIO_SOURCE_DIR}/src/clib" "${SCORPIO_BINARY_DIR}/src/clib" "${SCORPIO_SOURCE_DIR}/src/clib/core" "${SCORPIO_SOURCE_DIR}/src/clib/core/util" "${SCORPIO_SOURCE_DIR}/src/clib/core/rearr" "${SCORPIO_SOURCE_DIR}/src/clib/core/progress_engine" "${SCORPIO_SOURCE_DIR}/src/clib/core/iolib/hdf5" "${SCORPIO_SOURCE_DIR}/src/clib/util") # Compiler-specific compiler options string (TOUPPER "${CMAKE_C_COMPILER_ID}" CMAKE_C_COMPILER_NAME) @@ -63,7 +63,7 @@ endif () # DEFINE THE TARGETS AND TESTS #============================================================================== -add_library (test_common_obj OBJECT test_common.cpp) +add_library (test_common_obj OBJECT test_common.cpp ${SCORPIO_SOURCE_DIR}/util/argparser.cxx) target_link_libraries (test_common_obj PRIVATE pioc) # Exclude tests that require more than 1 procs when using the MPI serial library @@ -112,7 +112,7 @@ add_spio_executable (test_spio_sort_utils TRUE "" test_spio_sort_utils.cpp) add_spio_executable (test_spio_rearr_utils_gather TRUE "" test_spio_rearr_utils_gather.cpp) add_spio_executable (test_spio_rearr_utils_scatter TRUE "" test_spio_rearr_utils_scatter.cpp) add_spio_executable (test_spio_rearr_utils_alltoall TRUE "" test_spio_rearr_utils_alltoall.cpp) -add_spio_executable (test_spio_rearr_contig TRUE "" test_spio_rearr_contig.cpp) +add_spio_executable (test_spio_rearr_contig TRUE "" test_spio_rearr_contig.cpp OBJ_LIBS test_common_obj) add_spio_executable (test_spio_rearr_contig_nvars TRUE "" test_spio_rearr_contig_nvars.cpp) add_spio_executable (test_spio_rearr_contig_fillval TRUE "" test_spio_rearr_contig_fillval.cpp) add_spio_executable (test_spio_decomp_logger TRUE "" test_spio_decomp_logger.cpp) diff --git a/tests/cunit/test_spio_rearr_contig.cpp b/tests/cunit/test_spio_rearr_contig.cpp index 8c914ebdd5..e2ff6735e9 100644 --- a/tests/cunit/test_spio_rearr_contig.cpp +++ b/tests/cunit/test_spio_rearr_contig.cpp @@ -12,6 +12,7 @@ #include "pio.h" #include "pio_tests.h" #include "pio_rearr_contig.hpp" +#include "spio_test_framework.hpp" #ifdef SPIO_ENABLE_GPTL_TIMING #ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL @@ -19,21 +20,13 @@ #endif #endif -#define LOG_RANK0(rank, ...) \ - do{ \ - if(rank == 0){ \ - fprintf(stderr, __VA_ARGS__); \ - } \ - }while(0); - static const int FAIL = -1; template -bool cmp_result(int wrank, const std::vector &res, const std::vector &exp) +bool cmp_result(SPIO_TF::Test_framework &tf, int wrank, const std::vector &res, const std::vector &exp) { - if(res.size() != exp.size()){ - LOG_RANK0(wrank, "ERROR: The result and expected vectors are of different sizes\n"); + tf.get_logger().log(SPIO_Util::Logger::Log_level::INFO, "ERROR: The result and expected vectors are of different sizes\n"); return false; } @@ -41,8 +34,8 @@ bool cmp_result(int wrank, const std::vector &res, const std::vector &exp) if(res[i] != exp[i]){ std::ostringstream oss; oss << "ERROR: Invalid/Unexpected value, array[ " << i << "] = " << res[i] - << " (Expected array[" << i << "] = " << exp[i] << ")"; - LOG_RANK0(wrank, "ERROR: %s\n", oss.str().c_str()); + << " (Expected array[" << i << "] = " << exp[i] << ")\n"; + tf.get_logger().log(SPIO_Util::Logger::Log_level::INFO, "ERROR:" + oss.str()); return false; } } @@ -50,13 +43,13 @@ bool cmp_result(int wrank, const std::vector &res, const std::vector &exp) return true; } -iosystem_desc_t *get_iosystem(MPI_Comm comm, int wrank, int wsz, int nio_procs) +iosystem_desc_t *get_iosystem(SPIO_TF::Test_framework &tf, MPI_Comm comm, int wrank, int wsz, int nio_procs) { int ret = PIO_NOERR; static int iosysid = 1; iosystem_desc_t *ios = (iosystem_desc_t *) calloc(1, sizeof(iosystem_desc_t)); if(!ios){ - LOG_RANK0(wrank, "Unable to allocate memory for I/O system"); + tf.get_logger().log(SPIO_Util::Logger::Log_level::INFO, "Unable to allocate memory for I/O system"); return NULL; } @@ -77,7 +70,7 @@ iosystem_desc_t *get_iosystem(MPI_Comm comm, int wrank, int wsz, int nio_procs) ret = MPI_Comm_split(comm, color, 0, &(ios->io_comm)); if(ret != MPI_SUCCESS){ - LOG_RANK0(wrank, "Unable to split comm for creating I/O system"); + tf.get_logger().log(SPIO_Util::Logger::Log_level::INFO, "Unable to split comm for creating I/O system"); free(ios); return NULL; } @@ -87,7 +80,7 @@ iosystem_desc_t *get_iosystem(MPI_Comm comm, int wrank, int wsz, int nio_procs) if(ios->ioproc){ ret = MPI_Comm_rank(ios->io_comm, &(ios->io_rank)); if(ret != MPI_SUCCESS){ - LOG_RANK0(wrank, "Unable to get rank of I/O process"); + tf.get_logger().log(SPIO_Util::Logger::Log_level::INFO, "Unable to get rank of I/O process"); free(ios); return NULL; } @@ -108,13 +101,19 @@ void free_iosystem(iosystem_desc_t *ios){ free(ios); } -int test_create_block_rearr(MPI_Comm comm, int wrank, int wsz) +int test_create_block_rearr(SPIO_TF::Test_framework &tf) { + MPI_Comm comm = tf.get_comm(); + int wrank = tf.get_comm_rank(); + int wsz = tf.get_comm_size(); + SPIO_Util::Logger::MPI_logger logger = tf.get_logger(); + int ret = PIO_NOERR; + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; - iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + iosystem_desc_t *ios = get_iosystem(tf, comm, wrank, wsz, nio_procs); if(!ios){ - LOG_RANK0(wrank, "Unable to get I/O system"); + logger.log(SPIO_Util::Logger::Log_level::ERROR, "Unable to get I/O system"); return PIO_EINTERNAL; } @@ -127,18 +126,18 @@ int test_create_block_rearr(MPI_Comm comm, int wrank, int wsz) std::iota(compmap.begin(), compmap.end(), wrank * LOCAL_COMPMAP_SZ); ret = rearr.init(PIO_DOUBLE, compmap.data(), compmap.size(), &gdimlen, 1, NULL); if(ret != PIO_NOERR){ - LOG_RANK0(wrank, "Initializing contig rearranger failed"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Initializing contig rearranger failed"); return PIO_EINTERNAL; } ret = rearr.finalize(); if(ret != PIO_NOERR){ - LOG_RANK0(wrank, "Finalizing contig rearranger failed"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Finalizing contig rearranger failed"); return PIO_EINTERNAL; } } catch(...){ - LOG_RANK0(wrank, "Creating contig rearranger failed"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Creating contig rearranger failed"); return PIO_EINTERNAL; } @@ -146,13 +145,18 @@ int test_create_block_rearr(MPI_Comm comm, int wrank, int wsz) return PIO_NOERR; } -int test_c2i_block_data_rearr(MPI_Comm comm, int wrank, int wsz) +int test_c2i_block_data_rearr(SPIO_TF::Test_framework &tf) { + MPI_Comm comm = tf.get_comm(); + int wrank = tf.get_comm_rank(); + int wsz = tf.get_comm_size(); + SPIO_Util::Logger::MPI_logger logger = tf.get_logger(); int ret = PIO_NOERR; + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; - iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + iosystem_desc_t *ios = get_iosystem(tf, comm, wrank, wsz, nio_procs); if(!ios){ - LOG_RANK0(wrank, "Unable to get I/O system"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Unable to get I/O system"); return PIO_EINTERNAL; } @@ -181,29 +185,29 @@ int test_c2i_block_data_rearr(MPI_Comm comm, int wrank, int wsz) [](const PIO_Offset i){ return static_cast(i); }); ret = rearr.init(PIO_DOUBLE, compmap.data(), compmap.size(), &gdimlen, 1, NULL); if(ret != PIO_NOERR){ - LOG_RANK0(wrank, "Initializing contig rearranger failed"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Initializing contig rearranger failed"); return PIO_EINTERNAL; } ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), rdata.data(), rdata.size() * sizeof(double), 1); if(ret != PIO_NOERR){ - LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Rearranging data using contig rearranger failed"); return PIO_EINTERNAL; } - if(!cmp_result(wrank, rdata, exp_data)){ - LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement\n"); + if(!cmp_result(tf, wrank, rdata, exp_data)){ + logger.log(SPIO_Util::Logger::Log_level::INFO, "ERROR: Unexpected/invalid data received after data rearrangement\n"); return PIO_EINTERNAL; } ret = rearr.finalize(); if(ret != PIO_NOERR){ - LOG_RANK0(wrank, "Finalizing contig rearranger failed"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Finalizing contig rearranger failed"); return PIO_EINTERNAL; } } catch(...){ - LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Rearranging data using contig rearranger failed"); return PIO_EINTERNAL; } @@ -211,13 +215,18 @@ int test_c2i_block_data_rearr(MPI_Comm comm, int wrank, int wsz) return PIO_NOERR; } -int test_block_data_rearr(MPI_Comm comm, int wrank, int wsz) +int test_block_data_rearr(SPIO_TF::Test_framework &tf) { + MPI_Comm comm = tf.get_comm(); + int wrank = tf.get_comm_rank(); + int wsz = tf.get_comm_size(); + SPIO_Util::Logger::MPI_logger logger = tf.get_logger(); int ret = PIO_NOERR; + int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; - iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + iosystem_desc_t *ios = get_iosystem(tf, comm, wrank, wsz, nio_procs); if(!ios){ - LOG_RANK0(wrank, "Unable to get I/O system"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Unable to get I/O system"); return PIO_EINTERNAL; } @@ -246,7 +255,7 @@ int test_block_data_rearr(MPI_Comm comm, int wrank, int wsz) [](const PIO_Offset i){ return static_cast(i); }); ret = rearr.init(PIO_DOUBLE, compmap.data(), compmap.size(), &gdimlen, 1, NULL); if(ret != PIO_NOERR){ - LOG_RANK0(wrank, "Initializing contig rearranger failed"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Initializing contig rearranger failed"); return PIO_EINTERNAL; } @@ -254,12 +263,12 @@ int test_block_data_rearr(MPI_Comm comm, int wrank, int wsz) ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), rdata.data(), rdata.size() * sizeof(double), 1); if(ret != PIO_NOERR){ - LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Rearranging data using contig rearranger failed"); return PIO_EINTERNAL; } - if(!cmp_result(wrank, rdata, exp_data)){ - LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement (compute to I/O procs)\n"); + if(!cmp_result(tf, wrank, rdata, exp_data)){ + logger.log(SPIO_Util::Logger::Log_level::INFO, "ERROR: Unexpected/invalid data received after data rearrangement (compute to I/O procs)\n"); return PIO_EINTERNAL; } @@ -272,23 +281,23 @@ int test_block_data_rearr(MPI_Comm comm, int wrank, int wsz) ret = rearr.rearrange_io2comp(rdata.data(), rdata.size() * sizeof(double), sdata.data(), sdata.size() * sizeof(double), 1); if(ret != PIO_NOERR){ - LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Rearranging data using contig rearranger failed"); return PIO_EINTERNAL; } - if(!cmp_result(wrank, sdata, exp_data)){ - LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement (I/O to compute procs)\n"); + if(!cmp_result(tf, wrank, sdata, exp_data)){ + logger.log(SPIO_Util::Logger::Log_level::INFO, "ERROR: Unexpected/invalid data received after data rearrangement (I/O to compute procs)\n"); return PIO_EINTERNAL; } ret = rearr.finalize(); if(ret != PIO_NOERR){ - LOG_RANK0(wrank, "Finalizing contig rearranger failed"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Finalizing contig rearranger failed"); return PIO_EINTERNAL; } } catch(...){ - LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Rearranging data using contig rearranger failed"); return PIO_EINTERNAL; } @@ -296,13 +305,18 @@ int test_block_data_rearr(MPI_Comm comm, int wrank, int wsz) return PIO_NOERR; } -int test_rev_block_data_rearr(MPI_Comm comm, int wrank, int wsz) +int test_rev_block_data_rearr(SPIO_TF::Test_framework &tf) { + MPI_Comm comm = tf.get_comm(); + int wrank = tf.get_comm_rank(); + int wsz = tf.get_comm_size(); + SPIO_Util::Logger::MPI_logger logger = tf.get_logger(); + int ret = PIO_NOERR; int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; - iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + iosystem_desc_t *ios = get_iosystem(tf, comm, wrank, wsz, nio_procs); if(!ios){ - LOG_RANK0(wrank, "Unable to get I/O system"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Unable to get I/O system"); return PIO_EINTERNAL; } @@ -334,18 +348,18 @@ int test_rev_block_data_rearr(MPI_Comm comm, int wrank, int wsz) [](const PIO_Offset i){ return static_cast(i); }); ret = rearr.init(PIO_DOUBLE, compmap.data(), compmap.size(), &gdimlen, 1, NULL); if(ret != PIO_NOERR){ - LOG_RANK0(wrank, "Initializing contig rearranger failed"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Initializing contig rearranger failed"); return PIO_EINTERNAL; } ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), rdata.data(), rdata.size() * sizeof(double), 1); if(ret != PIO_NOERR){ - LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Rearranging data using contig rearranger failed"); return PIO_EINTERNAL; } - if(!cmp_result(wrank, rdata, exp_data)){ - LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement\n"); + if(!cmp_result(tf, wrank, rdata, exp_data)){ + logger.log(SPIO_Util::Logger::Log_level::INFO, "ERROR: Unexpected/invalid data received after data rearrangement\n"); return PIO_EINTERNAL; } @@ -358,23 +372,23 @@ int test_rev_block_data_rearr(MPI_Comm comm, int wrank, int wsz) ret = rearr.rearrange_io2comp(rdata.data(), rdata.size() * sizeof(double), sdata.data(), sdata.size() * sizeof(double), 1); if(ret != PIO_NOERR){ - LOG_RANK0(wrank, "Rearranging data using contig rearranger failed (I/O to compute procs)"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Rearranging data using contig rearranger failed (I/O to compute procs)"); return PIO_EINTERNAL; } - if(!cmp_result(wrank, sdata, exp_data)){ - LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement (I/O to compute procs)\n"); + if(!cmp_result(tf, wrank, sdata, exp_data)){ + logger.log(SPIO_Util::Logger::Log_level::INFO, "ERROR: Unexpected/invalid data received after data rearrangement (I/O to compute procs)\n"); return PIO_EINTERNAL; } ret = rearr.finalize(); if(ret != PIO_NOERR){ - LOG_RANK0(wrank, "Finalizing contig rearranger failed"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Finalizing contig rearranger failed"); return PIO_EINTERNAL; } } catch(...){ - LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Rearranging data using contig rearranger failed"); return PIO_EINTERNAL; } @@ -382,13 +396,18 @@ int test_rev_block_data_rearr(MPI_Comm comm, int wrank, int wsz) return PIO_NOERR; } -int test_mrange_block_data_rearr(MPI_Comm comm, int wrank, int wsz) +int test_mrange_block_data_rearr(SPIO_TF::Test_framework &tf) { + MPI_Comm comm = tf.get_comm(); + int wrank = tf.get_comm_rank(); + int wsz = tf.get_comm_size(); + SPIO_Util::Logger::MPI_logger logger = tf.get_logger(); + int ret = PIO_NOERR; int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; - iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + iosystem_desc_t *ios = get_iosystem(tf, comm, wrank, wsz, nio_procs); if(!ios){ - LOG_RANK0(wrank, "Unable to get I/O system"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Unable to get I/O system"); return PIO_EINTERNAL; } @@ -422,18 +441,18 @@ int test_mrange_block_data_rearr(MPI_Comm comm, int wrank, int wsz) [](const PIO_Offset i){ return static_cast(i); }); ret = rearr.init(PIO_DOUBLE, compmap.data(), compmap.size(), &gdimlen, 1, NULL); if(ret != PIO_NOERR){ - LOG_RANK0(wrank, "Initializing contig rearranger failed"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Initializing contig rearranger failed"); return PIO_EINTERNAL; } ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), rdata.data(), rdata.size() * sizeof(double), 1); if(ret != PIO_NOERR){ - LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Rearranging data using contig rearranger failed"); return PIO_EINTERNAL; } - if(!cmp_result(wrank, rdata, exp_data)){ - LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement\n"); + if(!cmp_result(tf, wrank, rdata, exp_data)){ + logger.log(SPIO_Util::Logger::Log_level::INFO, "ERROR: Unexpected/invalid data received after data rearrangement\n"); return PIO_EINTERNAL; } @@ -446,23 +465,23 @@ int test_mrange_block_data_rearr(MPI_Comm comm, int wrank, int wsz) ret = rearr.rearrange_io2comp(rdata.data(), rdata.size() * sizeof(double), sdata.data(), sdata.size() * sizeof(double), 1); if(ret != PIO_NOERR){ - LOG_RANK0(wrank, "Rearranging data using contig rearranger failed (I/O to compute procs)"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Rearranging data using contig rearranger failed (I/O to compute procs)"); return PIO_EINTERNAL; } - if(!cmp_result(wrank, sdata, exp_data)){ - LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement (I/O to compute procs)\n"); + if(!cmp_result(tf, wrank, sdata, exp_data)){ + logger.log(SPIO_Util::Logger::Log_level::INFO, "ERROR: Unexpected/invalid data received after data rearrangement (I/O to compute procs)\n"); return PIO_EINTERNAL; } ret = rearr.finalize(); if(ret != PIO_NOERR){ - LOG_RANK0(wrank, "Finalizing contig rearranger failed"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Finalizing contig rearranger failed"); return PIO_EINTERNAL; } } catch(...){ - LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Rearranging data using contig rearranger failed"); return PIO_EINTERNAL; } @@ -470,17 +489,22 @@ int test_mrange_block_data_rearr(MPI_Comm comm, int wrank, int wsz) return PIO_NOERR; } -int test_mrange_oddz_data_rearr(MPI_Comm comm, int wrank, int wsz) +int test_mrange_oddz_data_rearr(SPIO_TF::Test_framework &tf) { + MPI_Comm comm = tf.get_comm(); + int wrank = tf.get_comm_rank(); + int wsz = tf.get_comm_size(); + SPIO_Util::Logger::MPI_logger logger = tf.get_logger(); + bool is_odd_proc = ((wrank % 2) != 0) ? true : false; int nodd_procs = wsz/2; int neven_procs = wsz - nodd_procs; int ret = PIO_NOERR; int nio_procs = (wsz/2 > 0) ? wsz/2 : wsz; - iosystem_desc_t *ios = get_iosystem(comm, wrank, wsz, nio_procs); + iosystem_desc_t *ios = get_iosystem(tf, comm, wrank, wsz, nio_procs); if(!ios){ - LOG_RANK0(wrank, "Unable to get I/O system"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Unable to get I/O system"); return PIO_EINTERNAL; } @@ -522,18 +546,18 @@ int test_mrange_oddz_data_rearr(MPI_Comm comm, int wrank, int wsz) ret = rearr.init(PIO_DOUBLE, compmap.data(), compmap.size(), &gdimlen, 1, NULL); if(ret != PIO_NOERR){ - LOG_RANK0(wrank, "Initializing contig rearranger failed"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Initializing contig rearranger failed"); return PIO_EINTERNAL; } ret = rearr.rearrange_comp2io(sdata.data(), sdata.size() * sizeof(double), rdata.data(), rdata.size() * sizeof(double), 1); if(ret != PIO_NOERR){ - LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Rearranging data using contig rearranger failed"); return PIO_EINTERNAL; } - if(!cmp_result(wrank, rdata, exp_data)){ - LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement\n"); + if(!cmp_result(tf, wrank, rdata, exp_data)){ + logger.log(SPIO_Util::Logger::Log_level::INFO, "ERROR: Unexpected/invalid data received after data rearrangement\n"); return PIO_EINTERNAL; } @@ -552,23 +576,23 @@ int test_mrange_oddz_data_rearr(MPI_Comm comm, int wrank, int wsz) ret = rearr.rearrange_io2comp(rdata.data(), rdata.size() * sizeof(double), sdata.data(), sdata.size() * sizeof(double), 1); if(ret != PIO_NOERR){ - LOG_RANK0(wrank, "Rearranging data using contig rearranger failed (I/O to compute procs)"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Rearranging data using contig rearranger failed (I/O to compute procs)"); return PIO_EINTERNAL; } - if(!cmp_result(wrank, sdata, exp_data)){ - LOG_RANK0(wrank, "ERROR: Unexpected/invalid data received after data rearrangement (I/O to compute procs)\n"); + if(!cmp_result(tf, wrank, sdata, exp_data)){ + logger.log(SPIO_Util::Logger::Log_level::INFO, "ERROR: Unexpected/invalid data received after data rearrangement (I/O to compute procs)\n"); return PIO_EINTERNAL; } ret = rearr.finalize(); if(ret != PIO_NOERR){ - LOG_RANK0(wrank, "Finalizing contig rearranger failed"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Finalizing contig rearranger failed"); return PIO_EINTERNAL; } } catch(...){ - LOG_RANK0(wrank, "Rearranging data using contig rearranger failed"); + logger.log(SPIO_Util::Logger::Log_level::INFO, "Rearranging data using contig rearranger failed"); return PIO_EINTERNAL; } @@ -576,104 +600,31 @@ int test_mrange_oddz_data_rearr(MPI_Comm comm, int wrank, int wsz) return PIO_NOERR; } -int test_driver(MPI_Comm comm, int wrank, int wsz, int *num_errors) -{ - int nerrs = 0, ret = PIO_NOERR, mpierr = MPI_SUCCESS; - assert((comm != MPI_COMM_NULL) && (wrank >= 0) && (wsz > 0) && num_errors); - - std::vector > > test_funcs = { - {"test_create_block_rearr", test_create_block_rearr}, - {"test_c2i_block_data_rearr", test_c2i_block_data_rearr}, - {"test_block_data_rearr", test_block_data_rearr}, - {"test_rev_block_data_rearr", test_rev_block_data_rearr}, - {"test_mrange_block_data_rearr", test_mrange_block_data_rearr}, - {"test_mrange_oddz_data_rearr", test_mrange_oddz_data_rearr} - }; - - for(std::size_t tid = 0; tid < test_funcs.size(); tid++){ - try{ - ret = test_funcs[tid].second(comm, wrank, wsz); - } - catch(...){ - ret = PIO_EINTERNAL; - nerrs++; - } - int lfail = (ret == PIO_NOERR) ? 0 : 1; - mpierr = MPI_Reduce(&ret, &lfail, 1, MPI_INT, MPI_SUM, 0, comm); - if(mpierr != MPI_SUCCESS){ - LOG_RANK0(wrank, "Test Driver failed: Unable to calculate total num errors\n"); - } - if(ret != 0){ - std::string non_root_fail_msg = std::string(", failed on ") + std::to_string(ret) + std::string(" non-root processes"); - LOG_RANK0(wrank, "%s() FAILED (ret = %d%s)\n", test_funcs[tid].first.c_str(), ret, (lfail) ? "" : non_root_fail_msg.c_str()); - nerrs++; - } - else{ - LOG_RANK0(wrank, "%s() PASSED\n", test_funcs[tid].first.c_str()); - } - } - - *num_errors += nerrs; - return nerrs; -} - int main(int argc, char *argv[]) { int ret; - int wrank, wsz; - int num_errors; -#ifdef SPIO_ENABLE_GPTL_TIMING -#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL - ret = GPTLinitialize(); - if(ret != 0){ - LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); - return ret; - } -#endif /* TIMING_INTERNAL */ -#endif /* TIMING */ ret = MPI_Init(&argc, &argv); if(ret != MPI_SUCCESS){ - LOG_RANK0(wrank, "MPI_Init() FAILED, ret = %d\n", ret); + std::cerr << "MPI_Init() FAILED, ret = " << ret << "\n"; return ret; } - ret = MPI_Comm_rank(MPI_COMM_WORLD, &wrank); - if(ret != MPI_SUCCESS){ - LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); - return ret; - } - ret = MPI_Comm_size(MPI_COMM_WORLD, &wsz); - if(ret != MPI_SUCCESS){ - LOG_RANK0(wrank, "MPI_Comm_rank() FAILED, ret = %d\n", ret); - return ret; - } + std::vector > > rfuncs = { + {"test_create_block_rearr", test_create_block_rearr}, + {"test_c2i_block_data_rearr", test_c2i_block_data_rearr}, + {"test_block_data_rearr", test_block_data_rearr}, + {"test_rev_block_data_rearr", test_rev_block_data_rearr}, + {"test_mrange_block_data_rearr", test_mrange_block_data_rearr}, + {"test_mrange_oddz_data_rearr", test_mrange_oddz_data_rearr} + }; - num_errors = 0; - ret = test_driver(MPI_COMM_WORLD, wrank, wsz, &num_errors); - if(ret != 0){ - LOG_RANK0(wrank, "Test driver FAILED\n"); - return FAIL; - } - else{ - LOG_RANK0(wrank, "All tests PASSED\n"); - } + SPIO_TF::Test_framework tf("test_spio_rearr_contig", MPI_COMM_WORLD, rfuncs); + tf.init(argc, argv); + ret = tf.run(); + tf.finalize(); MPI_Finalize(); -#ifdef SPIO_ENABLE_GPTL_TIMING -#ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL - ret = GPTLfinalize(); - if(ret != 0){ - LOG_RANK0(wrank, "GPTLinitialize() FAILED, ret = %d\n", ret); - return ret; - } -#endif /* TIMING_INTERNAL */ -#endif /* TIMING */ - - if(num_errors != 0){ - LOG_RANK0(wrank, "Total errors = %d\n", num_errors); - return FAIL; - } - return 0; + return ret; } From f152a3c2517d4fb6352fd3b374749e8140fa9cd4 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 27 Mar 2026 23:43:47 -0500 Subject: [PATCH 158/194] Add config option for dim chunk info Adding a configure option to specify how dimensions are chunked for HDF5 (and in future for other iotypes) variables A new configure option, SPIO_DIM_CHUNK_INFO, is added that can be used to specify the variable dimension chunk sizes. The configure option is expected to be in the format given below, "DIM1_NAME,DIM1_CHUNK_SZ;DIM2_NAME,DIM2_CHUNK_SZ;" --- CMakeLists.txt | 6 ++ src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp | 58 ++++++++++++++++++-- src/clib/core/iolib/hdf5/spio_hdf5_utils.hpp | 2 + src/clib/core/pio_nc.cpp | 1 + src/clib/pio_config.h.in | 5 ++ src/clib/pio_types.hpp | 8 +++ 6 files changed, 76 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d7032e4db9..1f55809368 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -266,6 +266,12 @@ else() message(STATUS "Setting chunk size (in bytes) for HDF5/PnetCDF chunked variables, requested bytes = " ${PIO_CHUNK_SIZE} " (default)") endif() +# Expected format for SPIO_DIM_CHUNK_INFO = "DIM1_NAME,DIM1_CHUNK_SZ;DIM2_NAME,DIM2_CHUNK_SZ;" +# e.g. "time,1;lev,8;" ---> Each chunk has 1 time dimension (time) and 8 levels (lev) +if(DEFINED SPIO_DIM_CHUNK_INFO) + message(STATUS "Using user-specified dimension chunk info, " ${SPIO_DIM_CHUNK_INFO}) +endif() + if(WITH_ADIOS2) # Maximum number of I/O decompositions registered with ADIOS type set(DEF_SPIO_MAX_ADIOS_DECOMPS 65536) diff --git a/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp b/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp index ed6646fffb..7b364aa99c 100644 --- a/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp +++ b/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -439,8 +440,12 @@ static hid_t spio_create_hdf5_dataset_pid(iosystem_desc_t *ios, file_desc_t *fil /* Get default chunk size (no of elems) - across each dimension - for variable data. The * max chunk size (across all dimensions) is specified via PIO_CHUNK_SIZE (in bytes) */ -static inline std::vector spio_get_dim_chunk_sz(const std::vector &dim_sz, nc_type xtype) +static inline std::vector spio_get_dim_chunk_sz(const std::vector &dim_names, const std::vector &dim_sz, + const std::vector &default_dim_chunk_sz, nc_type xtype) { + const std::string dim_chunk_info(SPIO_DIM_CHUNK_INFO); + bool user_provided_dim_chunk_info = !dim_chunk_info.empty(); + std::size_t ndims = dim_sz.size(); std::vector dim_chunk_sz = dim_sz; @@ -460,8 +465,18 @@ static inline std::vector spio_get_dim_chunk_sz(const std::vector(pow(chunk_nelems, 1.0/(ndims - 1) )); for(std::size_t i = 0; i < ndims; i++){ - /* Chunk size across UNLIMITED dimension is 1 */ - dim_chunk_sz[i] = (dim_sz[i] != H5S_UNLIMITED) ? (std::min(chunk_per_dim_nelems, dim_sz[i])) : 1; + if(!user_provided_dim_chunk_info){ + /* Chunk size across UNLIMITED dimension is 1 */ + dim_chunk_sz[i] = (dim_sz[i] != H5S_UNLIMITED) ? (std::min(chunk_per_dim_nelems, dim_sz[i])) : 1; + std::cout << "DBG: DEFAULT : Chunking dim " << dim_names[i].c_str() << " : chunk sz = " << dim_chunk_sz[i] << "\n"; + } + else{ + /* User specified dim chunk info, if default_dim_chunk_sz (parsed from user provided dim chunk info) + * is 0 no chunking for that dim. + */ + if(default_dim_chunk_sz[i] != 0) { dim_chunk_sz[i] = default_dim_chunk_sz[i]; } + std::cout << "DBG: Chunking dim " << dim_names[i].c_str() << " : chunk sz = " << dim_chunk_sz[i] << "\n"; + } } return dim_chunk_sz; @@ -563,6 +578,8 @@ int spio_hdf5_def_var(iosystem_desc_t *ios, file_desc_t *file, const char *name, /* Cache the dim sizes for HDF5 calls */ std::vector dim_sz(ndims), max_dim_sz(ndims); + std::vector default_dim_chunk_sz(ndims); + std::vector dim_names(ndims); for(int i = 0; i < ndims; i++){ if(file->hdf5_dims[dimidsp[i]].len != PIO_UNLIMITED){ dim_sz[i] = max_dim_sz[i] = file->hdf5_dims[dimidsp[i]].len; @@ -571,6 +588,8 @@ int spio_hdf5_def_var(iosystem_desc_t *ios, file_desc_t *file, const char *name, dim_sz[i] = 1; max_dim_sz[i] = H5S_UNLIMITED; } + default_dim_chunk_sz[i] = file->hdf5_dims[dimidsp[i]].chunk_sz; + dim_names[i] = file->hdf5_dims[dimidsp[i]].name; } /* Create HDF5 dataset (and optionally add filters as needed) */ @@ -587,7 +606,8 @@ int spio_hdf5_def_var(iosystem_desc_t *ios, file_desc_t *file, const char *name, /* Set default chunk size for variable data */ if(ndims > 0){ - if(H5Pset_chunk(dcpl_id, ndims, spio_get_dim_chunk_sz(max_dim_sz, xtype).data()) < 0){ + std::cout << "DBG: Finding chunk dims for variable : " << name << "\n"; + if(H5Pset_chunk(dcpl_id, ndims, spio_get_dim_chunk_sz(dim_names, max_dim_sz, default_dim_chunk_sz, xtype).data()) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to set the size of the chunks used to store a chunked layout dataset", @@ -1374,4 +1394,34 @@ int spio_hdf5_set_frame(file_desc_t *file, int varid, int frame) return PIO_NOERR; } + +PIO_Offset spio_hdf5_get_dim_chunk_sz_from_chunk_info(const std::string &dim_name) +{ + const std::string dim_chunk_info(SPIO_DIM_CHUNK_INFO); + bool user_provided_dim_chunk_info = !dim_chunk_info.empty(); + + if(!user_provided_dim_chunk_info) { return 0; } + + /* FIXME: Parse it once - hdf5 init - instead of re-parsing when each dim is defined */ + /* FIXME: Since C++ regex support is limited for some compilers using streams for now */ + /* SPIO_DIM_CHUNK_INFO = "DIM1_NAME,DIM1_CHUNK_SZ;DIM2_NAME,DIM2_CHUNK_SZ;" */ + + std::istringstream istr(dim_chunk_info); + std::string dim_info_tok, dim_name_tok, dim_chunk_sz_tok; + const char dim_info_delim = ';'; + const char chunk_info_delim = ','; + + while(std::getline(istr, dim_info_tok, dim_info_delim)){ + std::size_t pos = 0; + if((pos = dim_info_tok.find(chunk_info_delim, 0)) != std::string::npos){ + dim_name_tok = dim_info_tok.substr(0, pos); + if((dim_name_tok == dim_name) && (pos + 1 < dim_info_tok.size())){ + dim_chunk_sz_tok = dim_info_tok.substr(pos + 1); + return static_cast(std::stoi(dim_chunk_sz_tok)); + } + } + } + + return 0; +} #endif diff --git a/src/clib/core/iolib/hdf5/spio_hdf5_utils.hpp b/src/clib/core/iolib/hdf5/spio_hdf5_utils.hpp index 3bf53bc73b..50fb85a90f 100644 --- a/src/clib/core/iolib/hdf5/spio_hdf5_utils.hpp +++ b/src/clib/core/iolib/hdf5/spio_hdf5_utils.hpp @@ -28,6 +28,8 @@ int spio_hdf5_put_var(iosystem_desc_t *ios, file_desc_t *file, int varid, int spio_hdf5_close(iosystem_desc_t *ios, file_desc_t *file); int spio_hdf5_set_frame(file_desc_t *file, int varid, int frame); +PIO_Offset spio_hdf5_get_dim_chunk_sz_from_chunk_info(const std::string &dim_name); + /* Inline functions */ inline hid_t spio_nc_type_to_hdf5_type(nc_type xtype) { diff --git a/src/clib/core/pio_nc.cpp b/src/clib/core/pio_nc.cpp index 4214ba9042..0fe2b315cf 100644 --- a/src/clib/core/pio_nc.cpp +++ b/src/clib/core/pio_nc.cpp @@ -3205,6 +3205,7 @@ int PIOc_def_dim_impl(int ncid, const char *name, PIO_Offset len, int *idp) } file->hdf5_dims[file->hdf5_num_dims].len = len; + file->hdf5_dims[file->hdf5_num_dims].chunk_sz = spio_hdf5_get_dim_chunk_sz_from_chunk_info(name); file->hdf5_dims[file->hdf5_num_dims].has_coord_var = false; file->hdf5_dims[file->hdf5_num_dims].hdf5_dataset_id = H5I_INVALID_HID; *idp = file->hdf5_num_dims; diff --git a/src/clib/pio_config.h.in b/src/clib/pio_config.h.in index 113cac53a9..2385cab28b 100644 --- a/src/clib/pio_config.h.in +++ b/src/clib/pio_config.h.in @@ -64,6 +64,11 @@ /** Set chunk size (in bytes) for HDF5/PnetCDF chunked variables. */ #define PIO_CHUNK_SIZE @PIO_CHUNK_SIZE@ +/** Set dimension chunk info for HDF5 chunked variables. + * Expected format: "DIM1_NAME,DIM1_CHUNK_SZ;DIM2_NAME,DIM2_CHUNK_SZ;" + */ +#define SPIO_DIM_CHUNK_INFO "@SPIO_DIM_CHUNK_INFO@" + /** Maximum number of I/O decompositions registered with ADIOS type */ #define PIO_MAX_ADIOS_DECOMPS @PIO_MAX_ADIOS_DECOMPS@ diff --git a/src/clib/pio_types.hpp b/src/clib/pio_types.hpp index 56adf48c39..2ce942c0f7 100644 --- a/src/clib/pio_types.hpp +++ b/src/clib/pio_types.hpp @@ -666,6 +666,14 @@ typedef struct hdf5_dim_desc_t /** Dimension length */ PIO_Offset len; + /** Chunk size, if specified. Default 0 + * if SPIO_DIM_CHUNK_INFO is provided by the user, + * - a Chunk size of 0 => no chunking on this dimension + * if SPIO_DIM_CHUNK_INFO is not provided by the user (empty string), + * - a Chunk size of 0 => default chunking (based on PIO_CHUNK_SIZE) + */ + PIO_Offset chunk_sz; + /** True if the dimension has a coordinate variable */ bool has_coord_var; From 7c7adf66ef765f8db8f7edb0eaf83334237e4c8c Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Sat, 28 Mar 2026 00:54:54 -0500 Subject: [PATCH 159/194] Config options to constrain chunking Adding a configure option, SPIO_ENABLE_CHUNKING_REGEX, to allow users to constrain which variables are chunked. The regex is the same as the one used for saving I/O decomps. e.g. -DSPIO_ENABLE_CHUNKING_REGEX='(VAR=\".*U.*\")&&(FILE=\".*e3sm_fgi.*\")' --- CMakeLists.txt | 16 ++++++++++++++++ src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp | 15 +++++++++++---- src/clib/core/util/pio_sdecomps_regex.cpp | 17 +++++++++++++++++ src/clib/core/util/pio_sdecomps_regex.hpp | 3 +++ src/clib/pio_config.h.in | 6 ++++++ 5 files changed, 53 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f55809368..e63b6b84aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -272,6 +272,22 @@ if(DEFINED SPIO_DIM_CHUNK_INFO) message(STATUS "Using user-specified dimension chunk info, " ${SPIO_DIM_CHUNK_INFO}) endif() +# Add more constraints on where chunking is enabled. Specify a regex that matches the variable and file name where chunking +# is enabled. Chunking will be disabled for all other variables +# The regex is same as the one used to save decompositions +# e.g. -DSPIO_ENABLE_CHUNKING_REGEX:STRING='(VAR=\".*U.*\")&&(FILE=\".*e3sm_fgi.*\")' +# Chunking is enabled only on variables with names that match ".*U.*" in files with names that match ".*e3sm_fgi.*" +if(DEFINED SPIO_ENABLE_CHUNKING_REGEX) + if(DEFINED SPIO_DIM_CHUNK_INFO) + message(STATUS "Using user-specified regex," ${SPIO_ENABLE_CHUNKING_REGEX} " to decide when to enable chunking of variables") + else() + message(STATUS "WARNING: SPIO_ENABLE_CHUNKING_REGEX was defined but SPIO_DIM_CHUNK_INFO was not defined, disabling SPIO_ENABLE_CHUNKING_REGEX") + set(SPIO_ENABLE_CHUNKING_REGEX "*") + endif() +else() + set(SPIO_ENABLE_CHUNKING_REGEX "*") +endif() + if(WITH_ADIOS2) # Maximum number of I/O decompositions registered with ADIOS type set(DEF_SPIO_MAX_ADIOS_DECOMPS 65536) diff --git a/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp b/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp index 7b364aa99c..5014250bae 100644 --- a/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp +++ b/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp @@ -31,6 +31,7 @@ #include #include "spio_hdf5_utils.hpp" +#include "pio_sdecomps_regex.hpp" /* Include headers for HDF5 compression filters */ #if PIO_USE_HDF5 #include @@ -440,7 +441,8 @@ static hid_t spio_create_hdf5_dataset_pid(iosystem_desc_t *ios, file_desc_t *fil /* Get default chunk size (no of elems) - across each dimension - for variable data. The * max chunk size (across all dimensions) is specified via PIO_CHUNK_SIZE (in bytes) */ -static inline std::vector spio_get_dim_chunk_sz(const std::vector &dim_names, const std::vector &dim_sz, +static inline std::vector spio_get_dim_chunk_sz(const std::string &fname, const std::string &vname, + const std::vector &dim_names, const std::vector &dim_sz, const std::vector &default_dim_chunk_sz, nc_type xtype) { const std::string dim_chunk_info(SPIO_DIM_CHUNK_INFO); @@ -456,6 +458,11 @@ static inline std::vector spio_get_dim_chunk_sz(const std::vector(PIO_CHUNK_SIZE)/static_cast(spio_get_nc_type_size(xtype)); /* Assuming that elements are evenly distributed across all non-unlimited dimensions, @@ -468,14 +475,14 @@ static inline std::vector spio_get_dim_chunk_sz(const std::vector 0){ std::cout << "DBG: Finding chunk dims for variable : " << name << "\n"; - if(H5Pset_chunk(dcpl_id, ndims, spio_get_dim_chunk_sz(dim_names, max_dim_sz, default_dim_chunk_sz, xtype).data()) < 0){ + if(H5Pset_chunk(dcpl_id, ndims, spio_get_dim_chunk_sz(file->fname, name, dim_names, max_dim_sz, default_dim_chunk_sz, xtype).data()) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to set the size of the chunks used to store a chunked layout dataset", diff --git a/src/clib/core/util/pio_sdecomps_regex.cpp b/src/clib/core/util/pio_sdecomps_regex.cpp index 03dd26f41f..d4c085965f 100644 --- a/src/clib/core/util/pio_sdecomps_regex.cpp +++ b/src/clib/core/util/pio_sdecomps_regex.cpp @@ -616,6 +616,12 @@ bool pio_save_decomps_regex_match(int ioid, const char *fname, const char *vname /* Match everything */ return true; } + +bool PIO_Util::spio_chunk_regex_match(int ioid, const std::string &fname, const std::string &vname) +{ + return true; +} + #else /* SPIO_NO_CXX_REGEX */ static PIO_Util::PIO_save_decomp_regex pio_sdecomp_regex(PIO_SAVE_DECOMPS_REGEX); @@ -629,4 +635,15 @@ bool pio_save_decomps_regex_match(int ioid, const char *fname, const char *vname std::string vname_str((vname) ? vname : ""); return pio_sdecomp_regex.matches(ioid, fname_str, vname_str); } + +static PIO_Util::PIO_save_decomp_regex spio_chunk_regex(SPIO_ENABLE_CHUNKING_REGEX); +bool PIO_Util::spio_chunk_regex_match(int ioid, const std::string &fname, const std::string &vname) +{ + bool ioid_is_valid = (ioid >= 0) ? true : false; + if(!ioid_is_valid && fname.empty() && vname.empty()){ + return false; + } + + return spio_chunk_regex.matches(ioid, fname, vname); +} #endif /* SPIO_NO_CXX_REGEX */ diff --git a/src/clib/core/util/pio_sdecomps_regex.hpp b/src/clib/core/util/pio_sdecomps_regex.hpp index 31e71f23d3..cc9261360e 100644 --- a/src/clib/core/util/pio_sdecomps_regex.hpp +++ b/src/clib/core/util/pio_sdecomps_regex.hpp @@ -190,6 +190,9 @@ namespace PIO_Util{ */ std::vector postfix_exp_; }; + + bool spio_chunk_regex_match(int ioid, const std::string &fname, const std::string &vname); + } // namespace PIO_Util #endif // __PIO_SDECOMPS_REGEX_HPP__ diff --git a/src/clib/pio_config.h.in b/src/clib/pio_config.h.in index 2385cab28b..adefdf8614 100644 --- a/src/clib/pio_config.h.in +++ b/src/clib/pio_config.h.in @@ -69,6 +69,12 @@ */ #define SPIO_DIM_CHUNK_INFO "@SPIO_DIM_CHUNK_INFO@" +/** Set the constraints/regex for enabling chunking of variables + * Regex format is same as the one used for PIO_SAVE_DECOMPS_REGEX + * e.g. '(VAR=\".*test_var1.*\")&&(FILE=\".*testfile1\")' + */ +#define SPIO_ENABLE_CHUNKING_REGEX "@SPIO_ENABLE_CHUNKING_REGEX@" + /** Maximum number of I/O decompositions registered with ADIOS type */ #define PIO_MAX_ADIOS_DECOMPS @PIO_MAX_ADIOS_DECOMPS@ From d28924d96cc07eef16775c42612da090623a277e Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Sat, 28 Mar 2026 01:54:40 -0500 Subject: [PATCH 160/194] Changing delim for dim chunk info Changing delimiter in dimension chunk info from comma to colon. This avoids issues with parsing of these strings in python/CIME --- CMakeLists.txt | 4 ++-- src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp | 4 ++-- src/clib/pio_config.h.in | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e63b6b84aa..2c8eb968a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -266,8 +266,8 @@ else() message(STATUS "Setting chunk size (in bytes) for HDF5/PnetCDF chunked variables, requested bytes = " ${PIO_CHUNK_SIZE} " (default)") endif() -# Expected format for SPIO_DIM_CHUNK_INFO = "DIM1_NAME,DIM1_CHUNK_SZ;DIM2_NAME,DIM2_CHUNK_SZ;" -# e.g. "time,1;lev,8;" ---> Each chunk has 1 time dimension (time) and 8 levels (lev) +# Expected format for SPIO_DIM_CHUNK_INFO = "DIM1_NAME:DIM1_CHUNK_SZ;DIM2_NAME:DIM2_CHUNK_SZ;" +# e.g. "time:1;lev:8;" ---> Each chunk has 1 time dimension (time) and 8 levels (lev) if(DEFINED SPIO_DIM_CHUNK_INFO) message(STATUS "Using user-specified dimension chunk info, " ${SPIO_DIM_CHUNK_INFO}) endif() diff --git a/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp b/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp index 5014250bae..825d70e8bb 100644 --- a/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp +++ b/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp @@ -1411,12 +1411,12 @@ PIO_Offset spio_hdf5_get_dim_chunk_sz_from_chunk_info(const std::string &dim_nam /* FIXME: Parse it once - hdf5 init - instead of re-parsing when each dim is defined */ /* FIXME: Since C++ regex support is limited for some compilers using streams for now */ - /* SPIO_DIM_CHUNK_INFO = "DIM1_NAME,DIM1_CHUNK_SZ;DIM2_NAME,DIM2_CHUNK_SZ;" */ + /* SPIO_DIM_CHUNK_INFO = "DIM1_NAME:DIM1_CHUNK_SZ;DIM2_NAME:DIM2_CHUNK_SZ;" */ std::istringstream istr(dim_chunk_info); std::string dim_info_tok, dim_name_tok, dim_chunk_sz_tok; const char dim_info_delim = ';'; - const char chunk_info_delim = ','; + const char chunk_info_delim = ':'; while(std::getline(istr, dim_info_tok, dim_info_delim)){ std::size_t pos = 0; diff --git a/src/clib/pio_config.h.in b/src/clib/pio_config.h.in index adefdf8614..3c67eec64f 100644 --- a/src/clib/pio_config.h.in +++ b/src/clib/pio_config.h.in @@ -65,7 +65,7 @@ #define PIO_CHUNK_SIZE @PIO_CHUNK_SIZE@ /** Set dimension chunk info for HDF5 chunked variables. - * Expected format: "DIM1_NAME,DIM1_CHUNK_SZ;DIM2_NAME,DIM2_CHUNK_SZ;" + * Expected format: "DIM1_NAME:DIM1_CHUNK_SZ;DIM2_NAME:DIM2_CHUNK_SZ;" */ #define SPIO_DIM_CHUNK_INFO "@SPIO_DIM_CHUNK_INFO@" From a0fe13ac4a8c50119ed49681969dec260ce07bc2 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Sat, 28 Mar 2026 18:11:04 -0500 Subject: [PATCH 161/194] Using warnings instead of dbg output for hdf5 Replacing debug prints with warnings when chunking HDF5 vars --- src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp | 25 ++++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp b/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp index 825d70e8bb..84f3937cb7 100644 --- a/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp +++ b/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp @@ -441,10 +441,12 @@ static hid_t spio_create_hdf5_dataset_pid(iosystem_desc_t *ios, file_desc_t *fil /* Get default chunk size (no of elems) - across each dimension - for variable data. The * max chunk size (across all dimensions) is specified via PIO_CHUNK_SIZE (in bytes) */ -static inline std::vector spio_get_dim_chunk_sz(const std::string &fname, const std::string &vname, +static inline std::vector spio_get_dim_chunk_sz(iosystem_desc_t *ios, file_desc_t *file, + const std::string &vname, const std::vector &dim_names, const std::vector &dim_sz, const std::vector &default_dim_chunk_sz, nc_type xtype) { + const std::string fname(file->fname); const std::string dim_chunk_info(SPIO_DIM_CHUNK_INFO); bool user_provided_dim_chunk_info = !dim_chunk_info.empty(); @@ -458,8 +460,13 @@ static inline std::vector spio_get_dim_chunk_sz(const std::string &fnam /* No chunking for scalars and 1D vars */ if(ndims <= 1) { return dim_chunk_sz; } + /* Search/Match using ioid is not required, passing -1 for ioid */ if(!PIO_Util::spio_chunk_regex_match(-1, fname, vname)){ - std::cout << "DBG: file = " << fname.c_str() << ", var = " << vname.c_str() << ", did not match regex = " << SPIO_ENABLE_CHUNKING_REGEX << "\n"; + std::string msg = std::string("Disabling chunking for variable. File name ") + + "(" + fname + ")" + " or variable name " + "(" + vname + + ") did not match chunking regex " + + "(SPIO_ENABLE_CHUNKING_REGEX = " + SPIO_ENABLE_CHUNKING_REGEX + ")"; + PIOc_warn(ios->iosysid, file->fh, __FILE__, __LINE__, msg.c_str()); return dim_chunk_sz; } @@ -475,14 +482,19 @@ static inline std::vector spio_get_dim_chunk_sz(const std::string &fnam if(!user_provided_dim_chunk_info){ /* Chunk size across UNLIMITED dimension is 1 */ dim_chunk_sz[i] = (dim_sz[i] != H5S_UNLIMITED) ? (std::min(chunk_per_dim_nelems, dim_sz[i])) : 1; - std::cout << "DBG: DEFAULT : file = " << fname.c_str() << ", var = " << vname.c_str() << ", Chunking dim " << dim_names[i].c_str() << " : chunk sz = " << dim_chunk_sz[i] << "\n"; } else{ /* User specified dim chunk info, if default_dim_chunk_sz (parsed from user provided dim chunk info) * is 0 no chunking for that dim. */ - if(default_dim_chunk_sz[i] != 0) { dim_chunk_sz[i] = default_dim_chunk_sz[i]; } - std::cout << "DBG: file = " << fname.c_str() << ", var = " << vname.c_str() << ", Chunking dim " << dim_names[i].c_str() << " : chunk sz = " << dim_chunk_sz[i] << "\n"; + if(default_dim_chunk_sz[i] != 0){ + dim_chunk_sz[i] = default_dim_chunk_sz[i]; + std::string msg = std::string("Setting user specified chunk size for variable. File name ") + + "(" + fname + ")" + ", variable name " + "(" + vname + ")" + + ", dimension name " + "(" + dim_names[i] + ")" + + ", chunk size = " + std::to_string(static_cast(dim_chunk_sz[i])); + PIOc_warn(ios->iosysid, file->fh, __FILE__, __LINE__, msg.c_str()); + } } } @@ -613,8 +625,7 @@ int spio_hdf5_def_var(iosystem_desc_t *ios, file_desc_t *file, const char *name, /* Set default chunk size for variable data */ if(ndims > 0){ - std::cout << "DBG: Finding chunk dims for variable : " << name << "\n"; - if(H5Pset_chunk(dcpl_id, ndims, spio_get_dim_chunk_sz(file->fname, name, dim_names, max_dim_sz, default_dim_chunk_sz, xtype).data()) < 0){ + if(H5Pset_chunk(dcpl_id, ndims, spio_get_dim_chunk_sz(ios, file, name, dim_names, max_dim_sz, default_dim_chunk_sz, xtype).data()) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, "Defining variable (%s, varid = %d) in file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to set the size of the chunks used to store a chunked layout dataset", From 25a97a0d1b5696431af733b8bf41d92fa851306e Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 8 Apr 2026 10:41:19 -0500 Subject: [PATCH 162/194] Enable testing workflow for all branches Enable testing workflow to run on all branches. (Github copilot has issues running the workflow on changes made in a branch without this fix) --- .github/workflows/spio_pnetcdf_testing_workflow.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/spio_pnetcdf_testing_workflow.yaml b/.github/workflows/spio_pnetcdf_testing_workflow.yaml index 8ae4b736c6..ec256c5742 100644 --- a/.github/workflows/spio_pnetcdf_testing_workflow.yaml +++ b/.github/workflows/spio_pnetcdf_testing_workflow.yaml @@ -18,10 +18,10 @@ on: # yamllint disable-line rule:truthy default: 'master' push: branches: - - master + - '**' # A "*" matches any char except "/", so use "**" to handle all branch names pull_request: branches: - - master + - '**' jobs: build_and_test: From 5df3dd5b11d362cc58a32b33c9261516b5d26bc7 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 8 Apr 2026 11:12:57 -0500 Subject: [PATCH 163/194] Fix narrowing conversions in test_darray_1d Explicitly cast when narrowing rank in test_darray_1d --- tests/cunit/test_darray_1d.cpp | 40 +++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/cunit/test_darray_1d.cpp b/tests/cunit/test_darray_1d.cpp index 304b7292fb..aabb6a0a78 100644 --- a/tests/cunit/test_darray_1d.cpp +++ b/tests/cunit/test_darray_1d.cpp @@ -186,18 +186,18 @@ int test_darray_fill(int iosysid, int ioid, int pio_type, int num_flavors, int * return ret; /* Initialize some data. */ - signed char byte_test_data[2] = {my_rank, my_rank}; - char char_test_data[2] = {my_rank, my_rank}; - short short_test_data[2] = {my_rank, my_rank}; + signed char byte_test_data[2] = {static_cast(my_rank), static_cast(my_rank)}; + char char_test_data[2] = {static_cast(my_rank), static_cast(my_rank)}; + short short_test_data[2] = {static_cast(my_rank), static_cast(my_rank)}; int int_test_data[2] = {my_rank, my_rank}; - float float_test_data[2] = {my_rank, my_rank}; - double double_test_data[2] = {my_rank, my_rank}; + float float_test_data[2] = {static_cast(my_rank), static_cast(my_rank)}; + double double_test_data[2] = {static_cast(my_rank), static_cast(my_rank)}; #ifdef _NETCDF4 - unsigned char ubyte_test_data[2] = {my_rank, my_rank}; - unsigned short ushort_test_data[2] = {my_rank, my_rank}; - unsigned int uint_test_data[2] = {my_rank, my_rank}; - long long int64_test_data[2] = {my_rank, my_rank}; - unsigned long long uint64_test_data[2] = {my_rank, my_rank}; + unsigned char ubyte_test_data[2] = {static_cast(my_rank), static_cast(my_rank)}; + unsigned short ushort_test_data[2] = {static_cast(my_rank), static_cast(my_rank)}; + unsigned int uint_test_data[2] = {static_cast(my_rank), static_cast(my_rank)}; + long long int64_test_data[2] = {static_cast(my_rank), static_cast(my_rank)}; + unsigned long long uint64_test_data[2] = {static_cast(my_rank), static_cast(my_rank)}; #endif /* _NETCDF4 */ switch (pio_type) @@ -480,18 +480,18 @@ int test_darray_fill_unlim(int iosysid, int ioid, int pio_type, int num_flavors, return ret; /* Initialize some data. */ - signed char byte_test_data[2] = {my_rank, my_rank}; - char char_test_data[2] = {my_rank, my_rank}; - short short_test_data[2] = {my_rank, my_rank}; + signed char byte_test_data[2] = {static_cast(my_rank), static_cast(my_rank)}; + char char_test_data[2] = {static_cast(my_rank), static_cast(my_rank)}; + short short_test_data[2] = {static_cast(my_rank), static_cast(my_rank)}; int int_test_data[2] = {my_rank, my_rank}; - float float_test_data[2] = {my_rank, my_rank}; - double double_test_data[2] = {my_rank, my_rank}; + float float_test_data[2] = {static_cast(my_rank), static_cast(my_rank)}; + double double_test_data[2] = {static_cast(my_rank), static_cast(my_rank)}; #ifdef _NETCDF4 - unsigned char ubyte_test_data[2] = {my_rank, my_rank}; - unsigned short ushort_test_data[2] = {my_rank, my_rank}; - unsigned int uint_test_data[2] = {my_rank, my_rank}; - long long int64_test_data[2] = {my_rank, my_rank}; - unsigned long long uint64_test_data[2] = {my_rank, my_rank}; + unsigned char ubyte_test_data[2] = {static_cast(my_rank), static_cast(my_rank)}; + unsigned short ushort_test_data[2] = {static_cast(my_rank), static_cast(my_rank)}; + unsigned int uint_test_data[2] = {static_cast(my_rank), static_cast(my_rank)}; + long long int64_test_data[2] = {static_cast(my_rank), static_cast(my_rank)}; + unsigned long long uint64_test_data[2] = {static_cast(my_rank), static_cast(my_rank)}; #endif /* _NETCDF4 */ switch (pio_type) { From 68b0389b4adf74ef610c3ce9dbf141f668399404 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 8 Apr 2026 11:16:12 -0500 Subject: [PATCH 164/194] Fix return in void func in testing fwk Fix minor bug where we return values in conditionally compiled source in void functions. --- tests/cunit/spio_test_framework.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/cunit/spio_test_framework.hpp b/tests/cunit/spio_test_framework.hpp index c02ef49d50..5cb425aabd 100644 --- a/tests/cunit/spio_test_framework.hpp +++ b/tests/cunit/spio_test_framework.hpp @@ -66,7 +66,7 @@ class Test_framework{ ret = GPTLinitialize(); if(ret != 0){ get_logger().log(SPIO_Util::Logger::Log_level::ERROR, std::string("GPTLinitialize() FAILED, ret = ") + std::to_string(ret) + ")"); - return ret; + return; } #endif /* TIMING_INTERNAL */ #endif /* TIMING */ @@ -143,10 +143,9 @@ class Test_framework{ get_logger().log(SPIO_Util::Logger::Log_level::DEBUG, "Testing framework finalizing..."); #ifdef SPIO_ENABLE_GPTL_TIMING #ifndef SPIO_ENABLE_GPTL_TIMING_INTERNAL - ret = GPTLfinalize(); + int ret = GPTLfinalize(); if(ret != 0){ get_logger().log(SPIO_Util::Logger::Log_level::ERROR, std::string("GPTLfinalize() FAILED, ret = ") + std::to_string(ret) + ")"); - return ret; } #endif /* TIMING_INTERNAL */ #endif /* TIMING */ From 9cd2a8b17dd920857dd10c71c2f5f33d6b3c471f Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 8 Apr 2026 11:29:16 -0500 Subject: [PATCH 165/194] Enable workflow explicitly for copilot Instead of enabling the workflow for push/pull on all branches, expcitly enable it on all pushes by copilot (all copilot branches are named "copilot/*") By default now workflow is only triggered on push/pull to master --- .github/workflows/spio_pnetcdf_testing_workflow.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/spio_pnetcdf_testing_workflow.yaml b/.github/workflows/spio_pnetcdf_testing_workflow.yaml index ec256c5742..216730a316 100644 --- a/.github/workflows/spio_pnetcdf_testing_workflow.yaml +++ b/.github/workflows/spio_pnetcdf_testing_workflow.yaml @@ -18,10 +18,13 @@ on: # yamllint disable-line rule:truthy default: 'master' push: branches: - - '**' # A "*" matches any char except "/", so use "**" to handle all branch names + - master + # Includes all branches starting with "copilot/" + # A "*" matches any char except "/", so use "**" to handle all branch names + - 'copilot/**' pull_request: branches: - - '**' + - master jobs: build_and_test: From ce7f453424301f19b36d02f7ceb8e11b6361747f Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 8 Apr 2026 22:58:09 -0500 Subject: [PATCH 166/194] Using C++ strings to avoid trunc of C strings Using C++ strings to avoid potentially truncating C char buffers written using snprintf * pio_create_uniq_str() now uses C++ strings (simplifies the conversion of numeric types to strings, no potential truncation of char buffers) * Using C++ strings to create/concatenate temp strings before initializing char buffers with snprintf. (Fixes "output may be truncated" warnings) --- src/clib/core/pio_darray.cpp | 40 +++---- src/clib/core/pio_nc.cpp | 18 ++-- src/clib/core/pioc.cpp | 188 ++++++++++----------------------- src/clib/core/pioc_support.cpp | 56 ++++------ src/clib/pio_internal.h | 3 +- src/clib/util/pio_timer.cpp | 17 +-- 6 files changed, 116 insertions(+), 206 deletions(-) diff --git a/src/clib/core/pio_darray.cpp b/src/clib/core/pio_darray.cpp index b0dcd3758c..70d61812b9 100644 --- a/src/clib/core/pio_darray.cpp +++ b/src/clib/core/pio_darray.cpp @@ -25,6 +25,7 @@ #include "spio_decomp_logger.hpp" #include "spio_dt_converter.hpp" #include "spio_async_utils.hpp" +#include /* uint64_t definition */ #ifdef _ADIOS2 @@ -2097,24 +2098,20 @@ int PIOc_write_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, c #if PIO_SAVE_DECOMPS if(!(iodesc->is_saved) && pio_save_decomps_regex_match(ioid, file->fname, file->varlist[varid].vname)){ - char filename[PIO_MAX_NAME]; - ierr = pio_create_uniq_str(ios, iodesc, filename, PIO_MAX_NAME, "piodecomp", ".dat"); - if(ierr != PIO_NOERR){ - if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ - GPTLstop("PIO:write_total_adios"); - } - return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Writing variable (%s, varid=%d) to file (%s, ncid=%d) failed. Saving I/O decomposition (ioid=%d) failed. Unable to create a unique file name for saving the I/O decomposition", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, ioid); - } - LOG((2, "Saving decomp map (write) to %s", filename)); - PIOc_writemap_impl(filename, ioid, iodesc->ndims, iodesc->dimlen, iodesc->maplen, iodesc->map, ios->my_comm); - char log_fname[PIO_MAX_NAME]; - ierr = pio_create_uniq_str(ios, iodesc, log_fname, PIO_MAX_NAME, "piodecomp", ".nc"); - SPIO_Util::Decomp_Util::Decomp_logger *logger = SPIO_Util::Decomp_Util::create_decomp_logger(ios->comp_comm, std::string(log_fname)); + std::string filename; + pio_create_uniq_str(ios, iodesc, filename, "piodecomp", ".dat"); + + LOG((2, "Saving decomp map (write) to %s", filename.c_str())); + PIOc_writemap_impl(filename.c_str(), ioid, iodesc->ndims, iodesc->dimlen, iodesc->maplen, iodesc->map, ios->my_comm); + + std::string log_fname; + pio_create_uniq_str(ios, iodesc, log_fname, "piodecomp", ".nc"); + SPIO_Util::Decomp_Util::Decomp_logger *logger = SPIO_Util::Decomp_Util::create_decomp_logger(ios->comp_comm, log_fname); (*logger).write_only().open().put(iodesc).close(); delete logger; + iodesc->is_saved = true; - SPIO_Util::Decomp_Util::gdpool_mgr.get_decomp_map_info_pool()->add_decomp_map_info(ioid, filename); + SPIO_Util::Decomp_Util::gdpool_mgr.get_decomp_map_info_pool()->add_decomp_map_info(ioid, filename.c_str()); } SPIO_Util::Decomp_Util::gdpool_mgr.get_decomp_map_info_pool()->add_var_info(ioid, file->pio_ncid, file->fname, varid, file->varlist[varid].vname); #endif @@ -3646,14 +3643,11 @@ int PIOc_read_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, #if PIO_SAVE_DECOMPS if(!(iodesc->is_saved) && pio_save_decomps_regex_match(ioid, file->fname, file->varlist[varid].vname)){ - char filename[PIO_MAX_NAME]; - ierr = pio_create_uniq_str(ios, iodesc, filename, PIO_MAX_NAME, "piodecomp", ".dat"); - if(ierr != PIO_NOERR){ - return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Reading variable (%s, varid=%d) from file (%s, ncid=%d) failed . Saving the I/O decomposition (ioid=%d) failed, unable to create a unique file name for saving the decomposition", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), file->pio_ncid, ioid); - } - LOG((2, "Saving decomp map (read) to %s", filename)); - PIOc_writemap_impl(filename, ioid, iodesc->ndims, iodesc->dimlen, iodesc->maplen, iodesc->map, ios->my_comm); + std::string filename; + pio_create_uniq_str(ios, iodesc, filename, "piodecomp", ".dat"); + + LOG((2, "Saving decomp map (read) to %s", filename.c_str())); + PIOc_writemap_impl(filename.c_str(), ioid, iodesc->ndims, iodesc->dimlen, iodesc->maplen, iodesc->map, ios->my_comm); iodesc->is_saved = true; } #endif diff --git a/src/clib/core/pio_nc.cpp b/src/clib/core/pio_nc.cpp index 0fe2b315cf..016a6d05be 100644 --- a/src/clib/core/pio_nc.cpp +++ b/src/clib/core/pio_nc.cpp @@ -1480,9 +1480,9 @@ int PIOc_inq_var_impl(int ncid, int varid, char *name, int namelen, nc_type *xty snprintf(timer_log_fname, PIO_MAX_NAME, "piorwinfo%010dwrank.dat", ios->ioroot); if(!mtimer_is_valid(file->varlist[varid].rd_mtimer)) { - char tmp_timer_name[PIO_MAX_NAME]; - snprintf(tmp_timer_name, PIO_MAX_NAME, "%s_%s", "rd", file->varlist[varid].vname); - file->varlist[varid].rd_mtimer = mtimer_create(tmp_timer_name, ios->my_comm, timer_log_fname); + std::string tmp_timer_name; + tmp_timer_name = std::string("rd_") + std::string(file->varlist[varid].vname); + file->varlist[varid].rd_mtimer = mtimer_create(tmp_timer_name.c_str(), ios->my_comm, timer_log_fname); if(!mtimer_is_valid(file->varlist[varid].rd_mtimer)) { spio_ltimer_stop(ios->io_fstats->tot_timer_name); @@ -1491,8 +1491,8 @@ int PIOc_inq_var_impl(int ncid, int varid, char *name, int namelen, nc_type *xty "Inquiring information of variable %s (varid=%d) failed on file %s (ncid=%d) failed. Error creating micro timer (read) for variable", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), ncid); } assert(!mtimer_is_valid(file->varlist[varid].rd_rearr_mtimer)); - snprintf(tmp_timer_name, PIO_MAX_NAME, "%s_%s", "rd_rearr", file->varlist[varid].vname); - file->varlist[varid].rd_rearr_mtimer = mtimer_create(tmp_timer_name, ios->my_comm, timer_log_fname); + tmp_timer_name = std::string("rd_rearr_") + std::string(file->varlist[varid].vname); + file->varlist[varid].rd_rearr_mtimer = mtimer_create(tmp_timer_name.c_str(), ios->my_comm, timer_log_fname); if(!mtimer_is_valid(file->varlist[varid].rd_rearr_mtimer)) { spio_ltimer_stop(ios->io_fstats->tot_timer_name); @@ -1500,8 +1500,8 @@ int PIOc_inq_var_impl(int ncid, int varid, char *name, int namelen, nc_type *xty return pio_err(ios, file, PIO_EINTERNAL, __FILE__, __LINE__, "Inquiring information of variable %s (varid=%d) failed on file %s (ncid=%d) failed. Error creating micro timer (read rearrange) for variable", pio_get_vname_from_file(file, varid), varid, pio_get_fname_from_file(file), ncid); } - snprintf(tmp_timer_name, PIO_MAX_NAME, "%s_%s", "wr", file->varlist[varid].vname); - file->varlist[varid].wr_mtimer = mtimer_create(tmp_timer_name, ios->my_comm, timer_log_fname); + tmp_timer_name = std::string("wr_") + std::string(file->varlist[varid].vname); + file->varlist[varid].wr_mtimer = mtimer_create(tmp_timer_name.c_str(), ios->my_comm, timer_log_fname); if(!mtimer_is_valid(file->varlist[varid].wr_mtimer)) { spio_ltimer_stop(ios->io_fstats->tot_timer_name); @@ -1510,8 +1510,8 @@ int PIOc_inq_var_impl(int ncid, int varid, char *name, int namelen, nc_type *xty "Inquiring information of variable %s (varid=%d) failed on file %s (ncid=%d) failed. Error creating micro timer (write) for variable", pio_get_fname_from_file(file), varid, pio_get_fname_from_file(file), ncid); } assert(!mtimer_is_valid(file->varlist[varid].wr_rearr_mtimer)); - snprintf(tmp_timer_name, PIO_MAX_NAME, "%s_%s", "wr_rearr", file->varlist[varid].vname); - file->varlist[varid].wr_rearr_mtimer = mtimer_create(tmp_timer_name, ios->my_comm, timer_log_fname); + tmp_timer_name = std::string("wr_rearr_") + std::string(file->varlist[varid].vname); + file->varlist[varid].wr_rearr_mtimer = mtimer_create(tmp_timer_name.c_str(), ios->my_comm, timer_log_fname); if(!mtimer_is_valid(file->varlist[varid].wr_rearr_mtimer)) { spio_ltimer_stop(ios->io_fstats->tot_timer_name); diff --git a/src/clib/core/pioc.cpp b/src/clib/core/pioc.cpp index e58e758b5f..cefc3abd09 100644 --- a/src/clib/core/pioc.cpp +++ b/src/clib/core/pioc.cpp @@ -39,6 +39,8 @@ #include "blosc2_filter.h" #endif #endif +#include +#include #include bool fortran_order = false; @@ -514,102 +516,30 @@ int PIOc_set_iosystem_error_handling_impl(int iosysid, int method, int *old_meth } /* Create a unique string/name using information provided by the user */ -int pio_create_uniq_str(iosystem_desc_t *ios, io_desc_t *iodesc, char *str, int len, const char *prefix, const char *suffix) +void pio_create_uniq_str(iosystem_desc_t *ios, io_desc_t *iodesc, std::string &str, const std::string &prefix, const std::string &suffix) { - static int counter = 0; - const char *DEFAULT_PREFIX = "pio"; - const char *DEFAULT_SUFFIX = ".dat"; - const int HUNDRED = 100; - const char *INT_FMT_LT_HUNDRED = "%2.2d"; - const int TEN_THOUSAND = 1000; - const char *INT_FMT_LT_TEN_THOUSAND = "%4.4d"; - const int MILLION = 1000000; - const char *INT_FMT_LT_MILLION = "%6.6d"; - - assert(str && (len > 0)); - - if(!prefix) - { - prefix = DEFAULT_PREFIX; - } - if(!suffix) - { - suffix = DEFAULT_SUFFIX; - } - - int rem_len = len; - char *sptr = str; - - /* Add prefix */ - int prefix_len = strlen(prefix); - assert(rem_len > prefix_len); - snprintf(sptr, rem_len, "%s", prefix); - rem_len -= prefix_len; - sptr += prefix_len; - - if(ios) - { - /* Add ios specific info into the str */ - assert(ios->iosysid < MILLION); - assert(ios->num_comptasks < MILLION); - assert(rem_len > 0); - const char *iosysid_fmt = (ios->iosysid < HUNDRED) ? (INT_FMT_LT_HUNDRED) : ((ios->iosysid < TEN_THOUSAND) ? (INT_FMT_LT_TEN_THOUSAND): INT_FMT_LT_MILLION); - const char *num_comptasks_fmt = (ios->num_comptasks < HUNDRED) ? (INT_FMT_LT_HUNDRED) : ((ios->num_comptasks < TEN_THOUSAND) ? (INT_FMT_LT_TEN_THOUSAND): INT_FMT_LT_MILLION); - const char *num_iotasks_fmt = num_comptasks_fmt; - - snprintf(sptr, rem_len, iosysid_fmt, ios->iosysid); - rem_len = len - strlen(str); - sptr = str + strlen(str); - snprintf(sptr, rem_len, "%s", "id"); - rem_len = len - strlen(str); - sptr = str + strlen(str); - - snprintf(sptr, rem_len, num_comptasks_fmt, ios->num_comptasks); - rem_len = len - strlen(str); - sptr = str + strlen(str); - snprintf(sptr, rem_len, "%s", "tasks"); - rem_len = len - strlen(str); - sptr = str + strlen(str); - - snprintf(sptr, rem_len, num_iotasks_fmt, ios->num_iotasks); - rem_len = len - strlen(str); - sptr = str + strlen(str); - snprintf(sptr, rem_len, "%s", "io"); - rem_len = len - strlen(str); - sptr = str + strlen(str); - } - - if(iodesc) - { - /* Add iodesc specific info into the str */ - assert(iodesc->ndims < MILLION); - assert(rem_len > 0); - const char *ndims_fmt = (iodesc->ndims < HUNDRED) ? (INT_FMT_LT_HUNDRED) : ((iodesc->ndims < TEN_THOUSAND) ? (INT_FMT_LT_TEN_THOUSAND): INT_FMT_LT_MILLION); - snprintf(sptr, rem_len, ndims_fmt, iodesc->ndims); - rem_len = len - strlen(str); - sptr = str + strlen(str); - snprintf(sptr, rem_len, "%s", "dims"); - rem_len = len - strlen(str); - sptr = str + strlen(str); - } - - /* Add counter - to make the str unique */ - assert(counter < MILLION); - const char *counter_fmt = (counter < HUNDRED) ? (INT_FMT_LT_HUNDRED) : ((counter < TEN_THOUSAND) ? (INT_FMT_LT_TEN_THOUSAND): INT_FMT_LT_MILLION); - snprintf(sptr, rem_len, counter_fmt, counter); - rem_len = len - strlen(str); - sptr = str + strlen(str); - - counter++; - - /* Add suffix */ - int suffix_len = strlen(suffix); - assert(rem_len > suffix_len); - snprintf(sptr, rem_len, "%s", suffix); - rem_len -= suffix_len; - sptr += suffix_len; + static std::atomic counter(0); + const std::string DEFAULT_PREFIX("pio"); + const std::string DEFAULT_SUFFIX(".dat"); + + /* Add prefix */ + str += (!prefix.empty()) ? prefix : DEFAULT_PREFIX; + if(ios){ + /* Add ios specific info into the str */ + str += std::to_string(ios->iosysid) + std::string("id"); + str += std::to_string(ios->num_comptasks) + std::string("tasks"); + str += std::to_string(ios->num_iotasks) + std::string("io"); + } + if(iodesc){ + /* Add iodesc specific info into the str */ + str += std::to_string(iodesc->ndims) + std::string("dims"); + } - return PIO_NOERR; + /* Add counter - to make the str unique */ + str += std::to_string(counter++); + + /* Add suffix */ + str += (!suffix.empty()) ? suffix : DEFAULT_SUFFIX; } static int subset_rearranger_init(iosystem_desc_t *ios, io_desc_t *iodesc, const PIO_Offset *iostart, const PIO_Offset *iocount) @@ -991,24 +921,21 @@ static int initdecomp(int iosysid, int pio_type, int ndims, const int *gdimlen, #if PIO_SAVE_DECOMPS if(pio_save_decomps_regex_match(*ioidp, NULL, NULL)){ - char filename[PIO_MAX_NAME]; - ierr = pio_create_uniq_str(ios, iodesc, filename, PIO_MAX_NAME, "piodecomp", ".dat"); - if(ierr != PIO_NOERR){ - return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Initializing the PIO decomposition failed. Creating a unique file name for saving the decomposition failed"); - } - LOG((2, "Saving decomp map to %s", filename)); - PIOc_writemap_impl(filename, *ioidp, ndims, gdimlen, maplen, (PIO_Offset *)compmap, ios->my_comm); + std::string filename; + pio_create_uniq_str(ios, iodesc, filename, "piodecomp", ".dat"); + + LOG((2, "Saving decomp map to %s", filename.c_str())); + PIOc_writemap_impl(filename.c_str(), *ioidp, ndims, gdimlen, maplen, (PIO_Offset *)compmap, ios->my_comm); - char log_fname[PIO_MAX_NAME]; - ierr = pio_create_uniq_str(ios, iodesc, log_fname, PIO_MAX_NAME, "piodecomp", ".nc"); - SPIO_Util::Decomp_Util::Decomp_logger *logger = SPIO_Util::Decomp_Util::create_decomp_logger(ios->comp_comm, std::string(log_fname)); + std::string log_fname; + pio_create_uniq_str(ios, iodesc, log_fname, "piodecomp", ".nc"); + SPIO_Util::Decomp_Util::Decomp_logger *logger = SPIO_Util::Decomp_Util::create_decomp_logger(ios->comp_comm, log_fname); (*logger).write_only().open().put(iodesc).close(); delete logger; iodesc->is_saved = true; - SPIO_Util::Decomp_Util::gdpool_mgr.get_decomp_map_info_pool()->add_decomp_map_info(*ioidp, filename); + SPIO_Util::Decomp_Util::gdpool_mgr.get_decomp_map_info_pool()->add_decomp_map_info(*ioidp, filename.c_str()); } #endif @@ -1660,17 +1587,15 @@ int PIOc_Init_Intracomm_impl(MPI_Comm comp_comm, int num_iotasks, int stride, in "PIO Init failed. Internal error allocating buffer space on compute processes to cache user data"); } - ret = pio_create_uniq_str(ios, NULL, ios->sname, PIO_MAX_NAME, "UNKNOWN:SPIO_COMP_", "_tmp_name"); - if(ret != PIO_NOERR) - { - /* Not a fatal error */ - LOG((0, "Creating a unique name for the iosystem (iosysid=%d) failed, ret = %d", *iosysidp, ret)); - } + std::string sname; + pio_create_uniq_str(ios, NULL, sname, "UNKNOWN:SPIO_COMP_", "_tmp_name"); + + snprintf(ios->sname, PIO_MAX_NAME, "%s", sname.c_str()); /* Set the timer names for this iosystem */ - snprintf(ios->io_fstats->wr_timer_name, SPIO_TIMER_MAX_NAME, "PIO:wr_%s", ios->sname); - snprintf(ios->io_fstats->rd_timer_name, SPIO_TIMER_MAX_NAME, "PIO:rd_%s", ios->sname); - snprintf(ios->io_fstats->tot_timer_name, SPIO_TIMER_MAX_NAME, "PIO:tot_%s", ios->sname); + snprintf(ios->io_fstats->wr_timer_name, SPIO_TIMER_MAX_NAME, "%s", (std::string("PIO:wr_") + sname).c_str()); + snprintf(ios->io_fstats->rd_timer_name, SPIO_TIMER_MAX_NAME, "%s", (std::string("PIO:rd_") + sname).c_str()); + snprintf(ios->io_fstats->tot_timer_name, SPIO_TIMER_MAX_NAME, "%s", (std::string("PIO:tot_") + sname).c_str()); LOG((2, "Init_Intracomm complete iosysid = %d", *iosysidp)); @@ -2592,16 +2517,15 @@ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_li iosysidp[cmp] = pio_add_to_iosystem_list(my_iosys, MPI_COMM_NULL); LOG((2, "new iosys ID added to iosystem_list iosysid = %d", iosysidp[cmp])); - ret = pio_create_uniq_str(my_iosys, NULL, my_iosys->sname, PIO_MAX_NAME, "UNKNOWN:SPIO_COMP_", "_tmp_name"); - if(ret != PIO_NOERR) - { - /* Not Fatal error */ - LOG((0, "Creating a unique name for the iosystem (iosysid=%d) failed,ret = %d", my_iosys->iosysid, ret)); - } + std::string sname; + pio_create_uniq_str(my_iosys, NULL, sname, "UNKNOWN:SPIO_COMP_", "_tmp_name"); + + snprintf(my_iosys->sname, PIO_MAX_NAME, "%s", sname.c_str()); + /* Set the timer names for this iosystem */ - snprintf(my_iosys->io_fstats->wr_timer_name, SPIO_TIMER_MAX_NAME, "PIO:wr_%s", my_iosys->sname); - snprintf(my_iosys->io_fstats->rd_timer_name, SPIO_TIMER_MAX_NAME, "PIO:rd_%s", my_iosys->sname); - snprintf(my_iosys->io_fstats->tot_timer_name, SPIO_TIMER_MAX_NAME, "PIO:tot_%s", my_iosys->sname); + snprintf(my_iosys->io_fstats->wr_timer_name, SPIO_TIMER_MAX_NAME, "%s", (std::string("PIO:wr_") + sname).c_str()); + snprintf(my_iosys->io_fstats->rd_timer_name, SPIO_TIMER_MAX_NAME, "%s", (std::string("PIO:rd_") + sname).c_str()); + snprintf(my_iosys->io_fstats->tot_timer_name, SPIO_TIMER_MAX_NAME, "%s", (std::string("PIO:tot_") + sname).c_str()); } /* next computational component */ /* Initialize async message signatures */ @@ -3195,16 +3119,14 @@ int PIOc_init_intercomm_impl(int component_count, const MPI_Comm peer_comm, LOG((2, "PIOc_init_intercomm : iosys[%d]->ioid=%d, iosys[%d]->uniontasks = %d, iosys[%d]->union_rank=%d, %s", i, iosys[i]->iosysid, i, iosys[i]->num_uniontasks, i, iosys[i]->union_rank, ((iosys[i]->ioproc) ? ("IS IO PROC"):((iosys[i]->compproc) ? ("IS COMPUTE PROC") : ("NEITHER IO NOR COMPUTE PROC"))) )); LOG((2, "New IOsystem added to iosystem_list iosysid = %d", iosysidps[i])); - ret = pio_create_uniq_str(iosys[i], NULL, iosys[i]->sname, PIO_MAX_NAME, "UNKNOWN:SPIO_COMP_", "_tmp_name"); - if(ret != PIO_NOERR) - { - /* Not Fatal error */ - LOG((0, "Creating a unique name for the iosystem (iosysid=%d) failed,ret = %d", iosys[i]->iosysid, ret)); - } + std::string sname; + pio_create_uniq_str(iosys[i], NULL, sname, "UNKNOWN:SPIO_COMP_", "_tmp_name"); + snprintf(iosys[i]->sname, PIO_MAX_NAME, "%s", sname.c_str()); + /* Set the timer names for this iosystem */ - snprintf(iosys[i]->io_fstats->wr_timer_name, SPIO_TIMER_MAX_NAME, "PIO:wr_%s", iosys[i]->sname); - snprintf(iosys[i]->io_fstats->rd_timer_name, SPIO_TIMER_MAX_NAME, "PIO:rd_%s", iosys[i]->sname); - snprintf(iosys[i]->io_fstats->tot_timer_name, SPIO_TIMER_MAX_NAME, "PIO:tot_%s", iosys[i]->sname); + snprintf(iosys[i]->io_fstats->wr_timer_name, SPIO_TIMER_MAX_NAME, "%s", (std::string("PIO:wr_") + sname).c_str()); + snprintf(iosys[i]->io_fstats->rd_timer_name, SPIO_TIMER_MAX_NAME, "%s", (std::string("PIO:rd_") + sname).c_str()); + snprintf(iosys[i]->io_fstats->tot_timer_name, SPIO_TIMER_MAX_NAME, "%s", (std::string("PIO:tot_") + sname).c_str()); } /* The comp_comms array is freed. The communicators will be freed internally diff --git a/src/clib/core/pioc_support.cpp b/src/clib/core/pioc_support.cpp index c42bd71744..42f00ac2bd 100644 --- a/src/clib/core/pioc_support.cpp +++ b/src/clib/core/pioc_support.cpp @@ -3074,7 +3074,7 @@ int PIO_get_avail_iotypes(char *buf, size_t sz) int spio_createfile_int(int iosysid, int *ncidp, const int *iotype, const char *filename, int mode) { - char tname[SPIO_TIMER_MAX_NAME]; + std::string tname; iosystem_desc_t *ios; /* Pointer to io system information. */ file_desc_t *file; /* Pointer to file information. */ int mpierr = MPI_SUCCESS; /* Return code from MPI function codes. */ @@ -3148,17 +3148,11 @@ int spio_createfile_int(int iosysid, int *ncidp, const int *iotype, const char * file->reserve_extra_header_space = true; /* Set to true for creating output NetCDF files only. */ file->is_reopened = false; strncpy(file->fname, filename, PIO_MAX_NAME); - ierr = pio_create_uniq_str(ios, NULL, tname, SPIO_TIMER_MAX_NAME, "tmp_", "_file"); - if(ierr != PIO_NOERR) - { - /* Not a fatal error */ - LOG((0, "Creating a unique name for the write timer for file (%s, ncid=%d) failed, ret = %d", file->fname, file->pio_ncid, ierr)); - tname[0] = '\0'; - } + pio_create_uniq_str(ios, NULL, tname, "tmp_", "_file"); - snprintf(file->io_fstats->wr_timer_name, SPIO_TIMER_MAX_NAME, "PIO:wr_%s", tname); - snprintf(file->io_fstats->rd_timer_name, SPIO_TIMER_MAX_NAME, "PIO:rd_%s", tname); - snprintf(file->io_fstats->tot_timer_name, SPIO_TIMER_MAX_NAME, "PIO:tot_%s", tname); + snprintf(file->io_fstats->wr_timer_name, SPIO_TIMER_MAX_NAME, "%s", (std::string("PIO:wr_") + tname).c_str()); + snprintf(file->io_fstats->rd_timer_name, SPIO_TIMER_MAX_NAME, "%s", (std::string("PIO:rd_") + tname).c_str()); + snprintf(file->io_fstats->tot_timer_name, SPIO_TIMER_MAX_NAME, "%s", (std::string("PIO:tot_") + tname).c_str()); spio_ltimer_start(file->io_fstats->wr_timer_name); spio_ltimer_start(file->io_fstats->tot_timer_name); @@ -4792,7 +4786,7 @@ static size_t adios_read_vars_vars(file_desc_t *file, size_t var_size, char *con int PIOc_openfile_retry_impl(int iosysid, int *ncidp, int *iotype, const char *filename, int mode, int retry) { - char tname[SPIO_TIMER_MAX_NAME]; + std::string tname; iosystem_desc_t *ios; /* Pointer to io system information. */ file_desc_t *file; /* Pointer to file information. */ int imode; /* Internal mode val for netcdf4 file open. */ @@ -4867,16 +4861,11 @@ int PIOc_openfile_retry_impl(int iosysid, int *ncidp, int *iotype, const char *f file->reserve_extra_header_space = false; /* Set to true for creating output NetCDF files only. */ file->is_reopened = true; strncpy(file->fname, filename, PIO_MAX_NAME); - ierr = pio_create_uniq_str(ios, NULL, tname, SPIO_TIMER_MAX_NAME, "tmp_", "_file"); - if(ierr != PIO_NOERR){ - /* Not a fatal error */ - LOG((0, "Creating a unique name for the write timer for file (%s, ncid=%d) failed, ret = %d", file->fname, file->pio_ncid, ierr)); - tname[0] = '\0'; - } + pio_create_uniq_str(ios, NULL, tname, "tmp_", "_file"); - snprintf(file->io_fstats->wr_timer_name, SPIO_TIMER_MAX_NAME, "PIO:wr_%s", tname); - snprintf(file->io_fstats->rd_timer_name, SPIO_TIMER_MAX_NAME, "PIO:rd_%s", tname); - snprintf(file->io_fstats->tot_timer_name, SPIO_TIMER_MAX_NAME, "PIO:tot_%s", tname); + snprintf(file->io_fstats->wr_timer_name, SPIO_TIMER_MAX_NAME, "%s", (std::string("PIO:wr_") + tname).c_str()); + snprintf(file->io_fstats->rd_timer_name, SPIO_TIMER_MAX_NAME, "%s", (std::string("PIO:rd_") + tname).c_str()); + snprintf(file->io_fstats->tot_timer_name, SPIO_TIMER_MAX_NAME, "%s", (std::string("PIO:tot_") + tname).c_str()); /* FIXME: Files can be opened for rds and writes */ spio_ltimer_start(file->io_fstats->rd_timer_name); @@ -6308,29 +6297,28 @@ const char *get_var_desc_str(int ncid, int varid, const char *desc_prefix) { iosystem_desc_t *ios; /* Pointer to io system information. */ file_desc_t *file; /* Pointer to file information. */ - static const char EMPTY_STR[] = ""; + std::string vdesc; int ierr = PIO_NOERR; ierr = pio_get_file(ncid, &file); if(ierr != PIO_NOERR) { LOG((1, "Unable to get file corresponding to ncid = %d", ncid)); - return EMPTY_STR; + return vdesc.c_str(); } ios = file->iosystem; assert(ios != NULL); - snprintf(file->varlist[varid].vdesc, PIO_MAX_NAME, - "%s %s %s %llu %llu %llu %llu %llu", - (desc_prefix)?desc_prefix:"", - file->varlist[varid].vname, - file->fname, - (unsigned long long int)file->varlist[varid].vrsize, - (unsigned long long int)file->varlist[varid].rb_pend, - (unsigned long long int)file->varlist[varid].wb_pend, - (unsigned long long int)file->rb_pend, - (unsigned long long int)file->wb_pend - ); + if(desc_prefix) { vdesc += desc_prefix; } + vdesc += std::string(file->varlist[varid].vname) + + std::string(file->fname) + + std::to_string(static_cast(file->varlist[varid].vrsize)) + + std::to_string(static_cast(file->varlist[varid].rb_pend)) + + std::to_string(static_cast(file->varlist[varid].wb_pend)) + + std::to_string(static_cast(file->rb_pend)) + + std::to_string(static_cast(file->wb_pend)); + + snprintf(file->varlist[varid].vdesc, PIO_MAX_NAME, "%s", vdesc.c_str()); return file->varlist[varid].vdesc; } diff --git a/src/clib/pio_internal.h b/src/clib/pio_internal.h index 25e3eeff8b..6a89b6b215 100644 --- a/src/clib/pio_internal.h +++ b/src/clib/pio_internal.h @@ -33,6 +33,7 @@ #include "util/bget.h" #include "util/spio_ltimer.h" #include "pio_types.hpp" +#include #if defined(__cplusplus) extern "C" { @@ -395,7 +396,7 @@ extern "C" { char *history, char *source, char *version, int *fortran_order); /* Create a unique PIO string */ - int pio_create_uniq_str(iosystem_desc_t *ios, io_desc_t *iodesc, char *str, int len, const char *prefix, const char *suffix); + void pio_create_uniq_str(iosystem_desc_t *ios, io_desc_t *iodesc, std::string &str, const std::string &prefix, const std::string &suffix); /* Set the size limit for each block of requests to wait */ int set_file_req_block_size_limit(file_desc_t *file, PIO_Offset sz); diff --git a/src/clib/util/pio_timer.cpp b/src/clib/util/pio_timer.cpp index 4eecb3fc70..90f8c178ed 100644 --- a/src/clib/util/pio_timer.cpp +++ b/src/clib/util/pio_timer.cpp @@ -1,6 +1,7 @@ #include "pio_config.h" #include "pio_timer.h" #include "pio_internal.h" +#include /* This structure stores information on a timer type * init -> The init function for the timer @@ -129,7 +130,6 @@ int mtimer_stop(mtimer_t mt, const char *log_msg) { int ret = PIO_NOERR; double elapsed_time = 0; - char tmp_log_msg[PIO_MAX_NAME]; if(mt == NULL) { LOG((3, "ERROR: Micro timer failed to stop, the timer handle is invalid")); @@ -154,10 +154,13 @@ int mtimer_stop(mtimer_t mt, const char *log_msg) /* Flush timer log message if no asynchronous events are pending */ if(!mt->is_async_event_in_progress) { - snprintf(tmp_log_msg, PIO_MAX_NAME, "%s %s time=%11.8f s", mt->name, (log_msg)?(log_msg):"", mt->total_time); if(pio_timer_type == PIO_MICRO_MPI_WTIME_ROOT) { - ret = mtimer_flush_root(mt, tmp_log_msg, mt->comm); + std::string tmp_log_msg(mt->name); + if(log_msg) { tmp_log_msg += log_msg; } + tmp_log_msg += std::string("time=") + std::to_string(mt->total_time); + + ret = mtimer_flush_root(mt, tmp_log_msg.c_str(), mt->comm); mt->total_time = 0; } else @@ -365,7 +368,6 @@ int mtimer_update(mtimer_t mt, double time) int mtimer_flush(mtimer_t mt, const char *log_msg) { int ret = PIO_NOERR; - char tmp_log_msg[PIO_MAX_NAME]; if(mt == NULL) { LOG((3, "ERROR: Flushing timer failed, invalid handle")); @@ -384,10 +386,13 @@ int mtimer_flush(mtimer_t mt, const char *log_msg) */ if(!mt->is_async_event_in_progress && (mt->total_time > 0)) { - snprintf(tmp_log_msg, PIO_MAX_NAME, "%s %s time=%11.8f s", mt->name, (log_msg)?(log_msg):"", mt->total_time); if(pio_timer_type == PIO_MICRO_MPI_WTIME_ROOT) { - ret = mtimer_flush_root(mt, tmp_log_msg, mt->comm); + std::string tmp_log_msg(mt->name); + if(log_msg) { tmp_log_msg += log_msg; } + tmp_log_msg += std::string("time=") + std::to_string(mt->total_time); + + ret = mtimer_flush_root(mt, tmp_log_msg.c_str(), mt->comm); mt->total_time = 0; } else From d6d302e8c9068381c9f64962bfd4914cb8109036 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 15 Apr 2026 15:10:40 -0500 Subject: [PATCH 167/194] Process coord hdf5 vars before non-coord ones Ensure that we process all coord variables (and associated dims) before processing non-coordinate variables since the non-coordinate variables might depend on these dimensions (associated with coord variables) --- src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp b/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp index 84f3937cb7..dd5049efea 100644 --- a/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp +++ b/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp @@ -686,6 +686,7 @@ int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) assert((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)); assert(ios->ioproc); + /* Step 1 : Process dimensions with no coordinate variables associated with it */ for(i = 0; i < file->hdf5_num_dims; i++){ /* For dimensions without an associated coordinate var, define them here. However since the * the user can call redef() multiple times define it only its not already defined/valid @@ -832,6 +833,7 @@ int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) } } + /* Step 2 : Process coordinate variables and associated dimensions */ for(i = 0; i < file->hdf5_num_vars; i++){ /* Note: For async I/O operations enddef() calls queued before * the HDF5 variable is defined will see partially initialized @@ -913,7 +915,14 @@ int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) pio_get_fname_from_file(file), file->pio_ncid); } } - else{ + } + + /* Step 3 : Process rest of the variables (These are non-coordinate variables). The coordinate + * variables and associated dimensions need to be defined (Step 2) before we start processing + * all variables. + */ + for(i = 0; i < file->hdf5_num_vars; i++){ + if(!file->hdf5_vars[i].is_coord_var){ /* Not a coordinate var */ int ndims = file->hdf5_vars[i].ndims; if(ndims > 0){ @@ -936,7 +945,6 @@ int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) } } } - return PIO_NOERR; } From 7cbd163d3260c94368de30ca31100c435f5c56c8 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 15 Apr 2026 13:07:56 -0500 Subject: [PATCH 168/194] Adding put/get with coord vars Adding tests with put/get on coordinate variables --- tests/general/ncdf_get_put.F90.in | 148 ++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/tests/general/ncdf_get_put.F90.in b/tests/general/ncdf_get_put.F90.in index 6506f306ce..d642fcf938 100644 --- a/tests/general/ncdf_get_put.F90.in +++ b/tests/general/ncdf_get_put.F90.in @@ -300,6 +300,154 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_1dvar PIO_TF_AUTO_TEST_SUB_END test_put_get_1dvar +! Put and get a single coordinate variable (dimension and variable with the same name e.g. lon[lon]) +PIO_TF_TEMPLATE +PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_1d_coord_var + Implicit none + type(file_desc_t) :: pio_file + character(len=PIO_TF_MAX_STR_LEN) :: filename + type(var_desc_t) :: pio_var + integer :: pio_dim + integer, parameter :: DIM_LEN = 100 + PIO_TF_FC_DATA_TYPE, dimension(DIM_LEN) :: pval, gval + integer, dimension(:), allocatable :: iotypes + character(len=PIO_TF_MAX_STR_LEN), dimension(:), allocatable :: iotype_descs + character(len=*), parameter :: PIO_VAR_NAME = 'dummy_coord_var' + integer :: num_iotypes + integer :: i, ret + + pval = pio_tf_world_sz_ + num_iotypes = 0 + call PIO_TF_Get_nc_iotypes(iotypes, iotype_descs, num_iotypes) + filename = "test_pio_ncdf_get_put.testfile" + do i=1,num_iotypes + PIO_TF_LOG(0,*) "Testing type :", iotype_descs(i) + ret = PIO_createfile(pio_tf_iosystem_, pio_file, iotypes(i), filename, PIO_CLOBBER) + PIO_TF_CHECK_ERR(ret, "Failed to open:" // trim(filename)) + + ! Since file is just created no need to enter redef + ret = PIO_def_dim(pio_file, PIO_VAR_NAME, DIM_LEN, pio_dim) + PIO_TF_CHECK_ERR(ret, "Failed to define dim:" // trim(filename)) + + ret = PIO_def_var(pio_file, PIO_VAR_NAME, PIO_TF_DATA_TYPE, (/pio_dim/), pio_var) + PIO_TF_CHECK_ERR(ret, "Failed to define coord var:" // trim(filename)) + + ret = PIO_enddef(pio_file) + PIO_TF_CHECK_ERR(ret, "Failed to enddef:" // trim(filename)) + + ret = PIO_put_var(pio_file, pio_var, pval); + PIO_TF_CHECK_ERR(ret, "Failed to put coord var:" // trim(filename)) + +#ifdef PIO_TEST_CLOSE_OPEN_FOR_SYNC + call PIO_closefile(pio_file) + + ret = PIO_openfile(pio_tf_iosystem_, pio_file, iotypes(i), filename, PIO_nowrite) + PIO_TF_CHECK_ERR(ret, "Failed to reopen:" // trim(filename)) + + ret = PIO_inq_varid(pio_file, PIO_VAR_NAME, pio_var) + PIO_TF_CHECK_ERR(ret, "Failed to get coord var:" // trim(filename)) +#else + call PIO_syncfile(pio_file) +#endif + + gval = 0 + ret = PIO_get_var(pio_file, pio_var, gval); + PIO_TF_CHECK_ERR(ret, "Failed to get coord var:" // trim(filename)) + + PIO_TF_CHECK_VAL((gval, pval), "Got wrong value") + + call PIO_closefile(pio_file) + call PIO_deletefile(pio_tf_iosystem_, filename); + end do + if(allocated(iotypes)) then + deallocate(iotypes) + deallocate(iotype_descs) + end if + +PIO_TF_AUTO_TEST_SUB_END test_put_get_1d_coord_var + +! Put and get multiple variables and coordinate variables +PIO_TF_TEMPLATE +PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_1d_coord_mvars + Implicit none + type(file_desc_t) :: pio_file + character(len=PIO_TF_MAX_STR_LEN) :: filename + type(var_desc_t) :: pio_var, pio_var2 + integer :: pio_dim + integer, parameter :: DIM_LEN = 100 + PIO_TF_FC_DATA_TYPE, dimension(DIM_LEN) :: pval, gval + integer, dimension(:), allocatable :: iotypes + character(len=PIO_TF_MAX_STR_LEN), dimension(:), allocatable :: iotype_descs + character(len=*), parameter :: PIO_CVAR_NAME = 'dummy_coord_var' + character(len=*), parameter :: PIO_VAR_NAME = 'dummy_var' + integer :: num_iotypes + integer :: i, ret + + pval = pio_tf_world_sz_ + num_iotypes = 0 + call PIO_TF_Get_nc_iotypes(iotypes, iotype_descs, num_iotypes) + filename = "test_pio_ncdf_get_put.testfile" + do i=1,num_iotypes + PIO_TF_LOG(0,*) "Testing type :", iotype_descs(i) + ret = PIO_createfile(pio_tf_iosystem_, pio_file, iotypes(i), filename, PIO_CLOBBER) + PIO_TF_CHECK_ERR(ret, "Failed to open:" // trim(filename)) + + ! Since file is just created no need to enter redef + ret = PIO_def_dim(pio_file, PIO_CVAR_NAME, DIM_LEN, pio_dim) + PIO_TF_CHECK_ERR(ret, "Failed to define dim:" // trim(filename)) + + ret = PIO_def_var(pio_file, PIO_VAR_NAME, PIO_TF_DATA_TYPE, (/pio_dim/), pio_var2) + PIO_TF_CHECK_ERR(ret, "Failed to define var:" // trim(filename)) + + ret = PIO_def_var(pio_file, PIO_CVAR_NAME, PIO_TF_DATA_TYPE, (/pio_dim/), pio_var) + PIO_TF_CHECK_ERR(ret, "Failed to define coord var:" // trim(filename)) + + ret = PIO_enddef(pio_file) + PIO_TF_CHECK_ERR(ret, "Failed to enddef:" // trim(filename)) + + ret = PIO_put_var(pio_file, pio_var, pval); + PIO_TF_CHECK_ERR(ret, "Failed to put coord var:" // trim(filename)) + + ret = PIO_put_var(pio_file, pio_var2, pval); + PIO_TF_CHECK_ERR(ret, "Failed to put var:" // trim(filename)) + +#ifdef PIO_TEST_CLOSE_OPEN_FOR_SYNC + call PIO_closefile(pio_file) + + ret = PIO_openfile(pio_tf_iosystem_, pio_file, iotypes(i), filename, PIO_nowrite) + PIO_TF_CHECK_ERR(ret, "Failed to reopen:" // trim(filename)) + + ret = PIO_inq_varid(pio_file, PIO_CVAR_NAME, pio_var) + PIO_TF_CHECK_ERR(ret, "Failed to get coord var:" // trim(filename)) + + ret = PIO_inq_varid(pio_file, PIO_VAR_NAME, pio_var2) + PIO_TF_CHECK_ERR(ret, "Failed to get var:" // trim(filename)) +#else + call PIO_syncfile(pio_file) +#endif + + gval = 0 + ret = PIO_get_var(pio_file, pio_var, gval); + PIO_TF_CHECK_ERR(ret, "Failed to get coord var:" // trim(filename)) + + PIO_TF_CHECK_VAL((gval, pval), "Got wrong value") + + gval = 0 + ret = PIO_get_var(pio_file, pio_var2, gval); + PIO_TF_CHECK_ERR(ret, "Failed to get var:" // trim(filename)) + + PIO_TF_CHECK_VAL((gval, pval), "Got wrong value") + + call PIO_closefile(pio_file) + call PIO_deletefile(pio_tf_iosystem_, filename); + end do + if(allocated(iotypes)) then + deallocate(iotypes) + deallocate(iotype_descs) + end if + +PIO_TF_AUTO_TEST_SUB_END test_put_get_1d_coord_mvars + ! Put and get variables with large/small (compared to the variable size) user buffers PIO_TF_TEMPLATE PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_1dvar_ls_buf From 8c60a568b2e156d771b799728cc5cb13f1d0330e Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 22 Apr 2026 10:14:26 -0500 Subject: [PATCH 169/194] Skip adios for rd/wr with diff decomps Since the ADIOS I/O type does not support reading and writing with different I/O decompositions, skipping these tests in 1d decomp tests --- tests/general/pio_decomp_tests2_1d.F90.in | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/general/pio_decomp_tests2_1d.F90.in b/tests/general/pio_decomp_tests2_1d.F90.in index 2a384717d1..e836a81624 100644 --- a/tests/general/pio_decomp_tests2_1d.F90.in +++ b/tests/general/pio_decomp_tests2_1d.F90.in @@ -173,6 +173,10 @@ PIO_TF_AUTO_TEST_SUB_BEGIN nc_wr_rd_a2a filename = "test_pio_decomp_simple_tests.testfile" do i=1,num_iotypes PIO_TF_LOG(0,*) "Testing : PIO_TF_DATA_TYPE : ", iotype_descs(i) + if((iotypes(i) == PIO_IOTYPE_ADIOS) .OR. (iotypes(i) == PIO_IOTYPE_ADIOSC)) then + PIO_TF_LOG(0,*) "Skipping (Read/Writes with different I/O decomps is not supported) : ", iotype_descs(i) + cycle + end if ierr = PIO_createfile(pio_tf_iosystem_, pio_file, iotypes(i), filename, PIO_CLOBBER) PIO_TF_CHECK_ERR(ierr, "Could not create file " // trim(filename)) @@ -294,6 +298,10 @@ PIO_TF_AUTO_TEST_SUB_BEGIN nc_wr_rev_rd filename = "test_pio_decomp_simple_tests.testfile" do i=1,num_iotypes PIO_TF_LOG(0,*) "Testing : PIO_TF_DATA_TYPE : ", iotype_descs(i) + if((iotypes(i) == PIO_IOTYPE_ADIOS) .OR. (iotypes(i) == PIO_IOTYPE_ADIOSC)) then + PIO_TF_LOG(0,*) "Skipping (Read/Writes with different I/O decomps is not supported) : ", iotype_descs(i) + cycle + end if ierr = PIO_createfile(pio_tf_iosystem_, pio_file, iotypes(i), filename, PIO_CLOBBER) PIO_TF_CHECK_ERR(ierr, "Could not create file " // trim(filename)) From cac99c1b948e4964f37813bf766f6bfb31fdd044 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 23 Apr 2026 12:58:13 -0500 Subject: [PATCH 170/194] Avoid appending in get/put tests Since ADIOS does not support appending data avoid appending in get/put tests. Modify test to write all variables after creating the file, instead of writing it in multiple phases by appending data. --- tests/general/ncdf_get_put.F90.in | 101 +++++++++++++++--------------- 1 file changed, 50 insertions(+), 51 deletions(-) diff --git a/tests/general/ncdf_get_put.F90.in b/tests/general/ncdf_get_put.F90.in index d642fcf938..52cce701b4 100644 --- a/tests/general/ncdf_get_put.F90.in +++ b/tests/general/ncdf_get_put.F90.in @@ -454,7 +454,7 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_1dvar_ls_buf Implicit none type(file_desc_t) :: pio_file character(len=PIO_TF_MAX_STR_LEN) :: filename - type(var_desc_t) :: pio_var, pio_cvar + type(var_desc_t) :: pio_svar, pio_lvar, pio_scvar, pio_lcvar integer :: pio_dim integer, parameter :: DIM_LEN = 200 @@ -469,8 +469,10 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_1dvar_ls_buf integer, dimension(:), allocatable :: iotypes character(len=PIO_TF_MAX_STR_LEN), dimension(:), allocatable :: iotype_descs - character(len=*), parameter :: PIO_VAR_NAME = 'dummy_var_put_val' - character(len=*), parameter :: PIO_CVAR_NAME = 'dummy_var_put_cval' + character(len=*), parameter :: PIO_SVAR_NAME = 'dummy_svar_put_val' + character(len=*), parameter :: PIO_LVAR_NAME = 'dummy_lvar_put_val' + character(len=*), parameter :: PIO_SCVAR_NAME = 'dummy_svar_put_cval' + character(len=*), parameter :: PIO_LCVAR_NAME = 'dummy_lvar_put_cval' integer :: num_iotypes integer :: i, j, ret @@ -509,34 +511,54 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_1dvar_ls_buf ret = PIO_def_dim(pio_file, 'dummy_dim_put_val', DIM_LEN, pio_dim) PIO_TF_CHECK_ERR(ret, "Failed to define dim:" // trim(filename)) - ret = PIO_def_var(pio_file, PIO_VAR_NAME, PIO_TF_DATA_TYPE, (/pio_dim/), pio_var) - PIO_TF_CHECK_ERR(ret, "Failed to define var:" // trim(filename)) + ret = PIO_def_var(pio_file, PIO_SVAR_NAME, PIO_TF_DATA_TYPE, (/pio_dim/), pio_svar) + PIO_TF_CHECK_ERR(ret, "Failed to define var (smaller than user buffer):" // trim(filename)) - ret = PIO_def_var(pio_file, PIO_CVAR_NAME, PIO_char, (/pio_dim/), pio_cvar) - PIO_TF_CHECK_ERR(ret, "Failed to define char var:" // trim(filename)) + ret = PIO_def_var(pio_file, PIO_LVAR_NAME, PIO_TF_DATA_TYPE, (/pio_dim/), pio_lvar) + PIO_TF_CHECK_ERR(ret, "Failed to define var (larger than user buffer):" // trim(filename)) + + ret = PIO_def_var(pio_file, PIO_SCVAR_NAME, PIO_char, (/pio_dim/), pio_scvar) + PIO_TF_CHECK_ERR(ret, "Failed to define char var (smaller than user buffer):" // trim(filename)) + + ret = PIO_def_var(pio_file, PIO_LCVAR_NAME, PIO_char, (/pio_dim/), pio_lcvar) + PIO_TF_CHECK_ERR(ret, "Failed to define char var (larger than user buffer):" // trim(filename)) ret = PIO_enddef(pio_file) PIO_TF_CHECK_ERR(ret, "Failed to enddef:" // trim(filename)) ! Put and get the values using a user buffer that is larger than the ! variable - ret = PIO_put_var(pio_file, pio_var, lpval); - PIO_TF_CHECK_ERR(ret, "Failed to put var:" // trim(filename)) + ret = PIO_put_var(pio_file, pio_svar, lpval); + PIO_TF_CHECK_ERR(ret, "Failed to put var (smaller than user buffer)):" // trim(filename)) - ret = PIO_put_var(pio_file, pio_cvar, lpcval); - PIO_TF_CHECK_ERR(ret, "Failed to put char var:" // trim(filename)) + ret = PIO_put_var(pio_file, pio_scvar, lpcval); + PIO_TF_CHECK_ERR(ret, "Failed to put char var (smaller than user buffer):" // trim(filename)) + + ! Put the values using a user buffer that is smaller than the + ! variable and get it with a larger buffer + ret = PIO_put_var(pio_file, pio_lvar, spval); + PIO_TF_CHECK_ERR(ret, "Failed to put var (larger than user buffer):" // trim(filename)) + + ret = PIO_put_var(pio_file, pio_lcvar, spcval); + PIO_TF_CHECK_ERR(ret, "Failed to put char var (larger than user buffer):" // trim(filename)) #ifdef PIO_TEST_CLOSE_OPEN_FOR_SYNC call PIO_closefile(pio_file) - ret = PIO_openfile(pio_tf_iosystem_, pio_file, iotypes(i), filename, PIO_write) + ret = PIO_openfile(pio_tf_iosystem_, pio_file, iotypes(i), filename, PIO_nowrite) PIO_TF_CHECK_ERR(ret, "Failed to reopen:" // trim(filename)) - ret = PIO_inq_varid(pio_file, PIO_VAR_NAME, pio_var) - PIO_TF_CHECK_ERR(ret, "Failed to get scalar var:" // trim(filename)) + ret = PIO_inq_varid(pio_file, PIO_SVAR_NAME, pio_svar) + PIO_TF_CHECK_ERR(ret, "Failed to get var (smaller than user buffer):" // trim(filename)) - ret = PIO_inq_varid(pio_file, PIO_CVAR_NAME, pio_cvar) - PIO_TF_CHECK_ERR(ret, "Failed to get scalar char var:" // trim(filename)) + ret = PIO_inq_varid(pio_file, PIO_LVAR_NAME, pio_lvar) + PIO_TF_CHECK_ERR(ret, "Failed to get var (larger than user buffer):" // trim(filename)) + + ret = PIO_inq_varid(pio_file, PIO_SCVAR_NAME, pio_scvar) + PIO_TF_CHECK_ERR(ret, "Failed to get char var (smaller than user buffer):" // trim(filename)) + + ret = PIO_inq_varid(pio_file, PIO_LCVAR_NAME, pio_lcvar) + PIO_TF_CHECK_ERR(ret, "Failed to get char var (larger than user buffer):" // trim(filename)) #else call PIO_syncfile(pio_file) #endif @@ -546,38 +568,15 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_1dvar_ls_buf lgcval(j:j) = '' end do - ret = PIO_get_var(pio_file, pio_var, lgval); - PIO_TF_CHECK_ERR(ret, "Failed to get var:" // trim(filename)) - - PIO_TF_CHECK_VAL((lgval, lpval), "Get with large user buffer : Got wrong value") - - ret = PIO_get_var(pio_file, pio_cvar, lgcval); - PIO_TF_CHECK_ERR(ret, "Failed to get char var:" // trim(filename)) - - PIO_TF_CHECK_VAL((lgcval, lpcval), "Get with large user buffer : Got wrong value") - - ! Put the values using a user buffer that is smaller than the - ! variable and get it with a larger buffer - ret = PIO_put_var(pio_file, pio_var, spval); - PIO_TF_CHECK_ERR(ret, "Failed to put var:" // trim(filename)) - - ret = PIO_put_var(pio_file, pio_cvar, spcval); - PIO_TF_CHECK_ERR(ret, "Failed to put char var:" // trim(filename)) - -#ifdef PIO_TEST_CLOSE_OPEN_FOR_SYNC - call PIO_closefile(pio_file) + ret = PIO_get_var(pio_file, pio_svar, lgval); + PIO_TF_CHECK_ERR(ret, "Failed to get var (smaller than user buffer):" // trim(filename)) - ret = PIO_openfile(pio_tf_iosystem_, pio_file, iotypes(i), filename, PIO_nowrite) - PIO_TF_CHECK_ERR(ret, "Failed to reopen:" // trim(filename)) + PIO_TF_CHECK_VAL((lgval, lpval), "Get variable written with large user buffer : Got wrong value") - ret = PIO_inq_varid(pio_file, PIO_VAR_NAME, pio_var) - PIO_TF_CHECK_ERR(ret, "Failed to get scalar var:" // trim(filename)) + ret = PIO_get_var(pio_file, pio_scvar, lgcval); + PIO_TF_CHECK_ERR(ret, "Failed to get char var (smaller than user buffer):" // trim(filename)) - ret = PIO_inq_varid(pio_file, PIO_CVAR_NAME, pio_cvar) - PIO_TF_CHECK_ERR(ret, "Failed to get scalar char var:" // trim(filename)) -#else - call PIO_syncfile(pio_file) -#endif + PIO_TF_CHECK_VAL((lgcval, lpcval), "Get variable written with large user buffer : Got wrong value") do j=1,DIM_SMALL_LEN lpcval(j:j) = spcval(j:j) @@ -600,13 +599,13 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_1dvar_ls_buf ! Note: Getting a variable with a buffer smaller than the size of the variable ! is an error, so use a large buffer for reading this data - ret = PIO_get_var(pio_file, pio_var, lgval); - PIO_TF_CHECK_ERR(ret, "Failed to get var:" // trim(filename)) + ret = PIO_get_var(pio_file, pio_lvar, lgval); + PIO_TF_CHECK_ERR(ret, "Failed to get var (larger than user buffer):" // trim(filename)) - PIO_TF_CHECK_VAL((lgval, lpval), "Get with large user buffer : Got wrong value") + PIO_TF_CHECK_VAL((lgval, lpval), "Get variable written with small user buffer : Got wrong value") - ret = PIO_get_var(pio_file, pio_cvar, lgcval); - PIO_TF_CHECK_ERR(ret, "Failed to get char var:" // trim(filename)) + ret = PIO_get_var(pio_file, pio_lcvar, lgcval); + PIO_TF_CHECK_ERR(ret, "Failed to get char var (larger than user buffer):" // trim(filename)) ! Since the variable is written out with a smaller buffer (than the size of the ! variable), the rest of the variable might contain invalid/uninitialized @@ -614,7 +613,7 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_1dvar_ls_buf ! results lgcval(DIM_SMALL_LEN+1:DIM_LARGE_LEN) = '' - PIO_TF_CHECK_VAL((lgcval, lpcval), "Get with large user buffer : Got wrong value") + PIO_TF_CHECK_VAL((lgcval, lpcval), "Get variable written with small user buffer : Got wrong value") call PIO_closefile(pio_file) call PIO_deletefile(pio_tf_iosystem_, filename); From 0210c79878d8db7150fce8da0581f168109360c9 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 23 Apr 2026 15:54:02 -0500 Subject: [PATCH 171/194] Skip put of 4d vars for ADIOS Since ADIOS (ADIOS support in SCORPIO) does not support "put" of 4D Vars skipping these tests for ADIOS --- tests/general/ncdf_get_put.F90.in | 32 +++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/tests/general/ncdf_get_put.F90.in b/tests/general/ncdf_get_put.F90.in index 52cce701b4..5e274591a6 100644 --- a/tests/general/ncdf_get_put.F90.in +++ b/tests/general/ncdf_get_put.F90.in @@ -939,9 +939,13 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_md2mdplus1_var start(4) = tstep count(4) = 1 pval_start = (tstep - 1) * (MAX_ROWS * MAX_COLS * MAX_LEVS) - ret = PIO_put_var(pio_file, pio_4dvar, start, count,& - pval_3d(:,:,:)+pval_start) - PIO_TF_CHECK_ERR(ret, "Failed to put 4d var:" // trim(filename)) + if((iotypes(i) == PIO_IOTYPE_ADIOS) .or. (iotypes(i) == PIO_IOTYPE_ADIOSC)) then + PIO_TF_LOG(0,*) "Skipping write/put of 4d var (NOT SUPPORTED) :", iotype_descs(i) + else + ret = PIO_put_var(pio_file, pio_4dvar, start, count,& + pval_3d(:,:,:)+pval_start) + PIO_TF_CHECK_ERR(ret, "Failed to put 4d var:" // trim(filename)) + end if end do #ifdef PIO_TEST_CLOSE_OPEN_FOR_SYNC @@ -974,15 +978,19 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_md2mdplus1_var PIO_TF_CHECK_VAL((gval_3d, exp_val_3d), "Got wrong value (3d var)") - gval_4d = 0 - ret = PIO_get_var(pio_file, pio_4dvar, gval_4d) - PIO_TF_CHECK_ERR(ret, "Failed to get 4d var:" // trim(filename)) - - ! Special code to handle 4d vals is required since the framework - ! currently does not support comparing 4d arrays - do tstep=1,MAX_TIMES - PIO_TF_CHECK_VAL((gval_4d(:,:,:,tstep), exp_val_4d(:,:,:,tstep)), "Got wrong value (4d var)") - end do + if((iotypes(i) == PIO_IOTYPE_ADIOS) .or. (iotypes(i) == PIO_IOTYPE_ADIOSC)) then + PIO_TF_LOG(0,*) "Skipping read/get of 4d var (WRITE/PUT NOT SUPPORTED) :", iotype_descs(i) + else + gval_4d = 0 + ret = PIO_get_var(pio_file, pio_4dvar, gval_4d) + PIO_TF_CHECK_ERR(ret, "Failed to get 4d var:" // trim(filename)) + + ! Special code to handle 4d vals is required since the framework + ! currently does not support comparing 4d arrays + do tstep=1,MAX_TIMES + PIO_TF_CHECK_VAL((gval_4d(:,:,:,tstep), exp_val_4d(:,:,:,tstep)), "Got wrong value (4d var)") + end do + end if call PIO_closefile(pio_file) call PIO_deletefile(pio_tf_iosystem_, filename); From b4a28990805ea1803528263195f9858e712a184b Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 23 Apr 2026 16:04:20 -0500 Subject: [PATCH 172/194] Skip put of 6D vars for ADIOS Since ADIOS (ADIOS support in SCORPIO) currently supports "put" of vars upto 3D skipping the 6D var test for ADIOS --- tests/general/ncdf_get_put.F90.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/general/ncdf_get_put.F90.in b/tests/general/ncdf_get_put.F90.in index 5e274591a6..684e2b4401 100644 --- a/tests/general/ncdf_get_put.F90.in +++ b/tests/general/ncdf_get_put.F90.in @@ -1032,6 +1032,10 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_6d_var filename = "test_pio_ncdf_get_put_6d_slice.testfile" do iotype_idx=1,num_iotypes PIO_TF_LOG(0,*) "Testing type :", iotype_descs(iotype_idx) + if((iotypes(iotype_idx) == PIO_IOTYPE_ADIOS) .or. (iotypes(iotype_idx) == PIO_IOTYPE_ADIOSC)) then + PIO_TF_LOG(0,*) "Skipping (Put/Write of 6D vars NOT SUPPORTED) :", iotype_descs(iotype_idx) + cycle + end if ret = PIO_createfile(pio_tf_iosystem_, pio_file, iotypes(iotype_idx), filename, PIO_CLOBBER) PIO_TF_CHECK_ERR(ret, "Failed to open:" // trim(filename)) From 7422e7f403520bbf7aeadf9411f6d98680015d81 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 27 Apr 2026 13:11:29 -0500 Subject: [PATCH 173/194] Skip more ADIOS put tests:4d cvar, multiple writes Skipping more ADIOS tests. Skipping puts/writes of 4d character variables (NOT SUPPORTED with ADIOS in SCORPIO) Skipping multple hyperslab writes (with reads in between to verify the data written out that requires syncing data to the file), since ADIOS does not support appending data. --- tests/general/ncdf_get_put.F90.in | 95 ++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 33 deletions(-) diff --git a/tests/general/ncdf_get_put.F90.in b/tests/general/ncdf_get_put.F90.in index 684e2b4401..6e06955e73 100644 --- a/tests/general/ncdf_get_put.F90.in +++ b/tests/general/ncdf_get_put.F90.in @@ -1925,8 +1925,12 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_misc_str PIO_TF_CHECK_ERR(ret, "Failed to put 2d array of strings in file " // trim(filename)) ! This calls put_var_3d_text() - ret = PIO_put_var(pio_file, var3d, exp_str3d); - PIO_TF_CHECK_ERR(ret, "Failed to put 3d array of strings in file " // trim(filename)) + if((iotypes(i) == PIO_IOTYPE_ADIOS) .or. (iotypes(i) == PIO_IOTYPE_ADIOSC)) then + PIO_TF_LOG(0,*) "Skipping put/write of 3d string (NOT SUPPORTED for 4d char vars) :", iotype_descs(i) + else + ret = PIO_put_var(pio_file, var3d, exp_str3d); + PIO_TF_CHECK_ERR(ret, "Failed to put 3d array of strings in file " // trim(filename)) + end if ! Sync data to disk #ifdef PIO_TEST_CLOSE_OPEN_FOR_SYNC @@ -1972,11 +1976,15 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_misc_str PIO_TF_CHECK_VAL((gstr2d, exp_str2d), "Got wrong value for 2d char var") ! This calls get_var_3d_text() - gstr3d = '' - ret = PIO_get_var(pio_file, var3d, gstr3d); - PIO_TF_CHECK_ERR(ret, "Failed to get 3d char var in file " // trim(filename)) - - PIO_TF_CHECK_VAL((gstr3d, exp_str3d), "Got wrong value for 3d char var") + ! Skip for ADIOS since we currently don't support put/write of + ! 4D char variables with ADIOS + if((iotypes(i) /= PIO_IOTYPE_ADIOS) .and. (iotypes(i) /= PIO_IOTYPE_ADIOSC)) then + gstr3d = '' + ret = PIO_get_var(pio_file, var3d, gstr3d); + PIO_TF_CHECK_ERR(ret, "Failed to get 3d char var in file " // trim(filename)) + + PIO_TF_CHECK_VAL((gstr3d, exp_str3d), "Got wrong value for 3d char var") + end if ! Re-write the variables in the file with a smaller (than the variable size) ! buffer @@ -2085,8 +2093,14 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_misc_str cnt(4) = NUM_STEPS ! This calls put_vara_3d_text() - ret = PIO_put_var(pio_file, var3d, strt, cnt, exp_str3d); - PIO_TF_CHECK_ERR(ret, "Failed to put hslab of 3d array of strings in file " // trim(filename)) + ! Skip for ADIOS since we currently don't support put/write of + ! 4D char variables with ADIOS + if((iotypes(i) == PIO_IOTYPE_ADIOS) .or. (iotypes(i) == PIO_IOTYPE_ADIOSC)) then + PIO_TF_LOG(0,*) "Skipping put/write of 3d string (NOT SUPPORTED for 4d char vars) :", iotype_descs(i) + else + ret = PIO_put_var(pio_file, var3d, strt, cnt, exp_str3d); + PIO_TF_CHECK_ERR(ret, "Failed to put hslab of 3d array of strings in file " // trim(filename)) + end if ! Sync data to disk #ifdef PIO_TEST_CLOSE_OPEN_FOR_SYNC @@ -2122,9 +2136,13 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_misc_str PIO_TF_CHECK_VAL((gstr2d, exp_str2d), "Got wrong value for 2d char var written with hslab put") ! This calls get_var_3d_text() - gstr3d = '' - ret = PIO_get_var(pio_file, var3d, gstr3d); - PIO_TF_CHECK_ERR(ret, "Failed to get 3d char var in file " // trim(filename)) + ! Skip for ADIOS since we currently don't support put/write of + ! 4D char variables with ADIOS + if((iotypes(i) /= PIO_IOTYPE_ADIOS) .and. (iotypes(i) /= PIO_IOTYPE_ADIOSC)) then + gstr3d = '' + ret = PIO_get_var(pio_file, var3d, gstr3d); + PIO_TF_CHECK_ERR(ret, "Failed to get 3d char var in file " // trim(filename)) + end if PIO_TF_CHECK_VAL((gstr3d, exp_str3d), "Got wrong value for 3d char var written with hslab put") @@ -2271,23 +2289,27 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_str_frames end do ! Write the 3d text variable, 1 2d array (row x col) of strings at a time - do step=1,NUM_STEPS - strt = 1 - cnt = 0 - strt(1) = 1 - strt(2) = 1 - strt(3) = 1 - strt(4) = step - cnt(1) = STR_LEN - cnt(2) = NUM_ROWS - cnt(3) = NUM_COLS - cnt(4) = 1 - - frame_str3d(:,:,1) = exp_str3d(:,:,step) - ! This calls put_vara_3d_text() - ret = PIO_put_var(pio_file, var3d, strt, cnt, frame_str3d); - PIO_TF_CHECK_ERR(ret, "Failed to put 3d array of strings 1 frame at a time in file " // trim(filename)) - end do + if((iotypes(i) /= PIO_IOTYPE_ADIOS) .and. (iotypes(i) /= PIO_IOTYPE_ADIOSC)) then + do step=1,NUM_STEPS + strt = 1 + cnt = 0 + strt(1) = 1 + strt(2) = 1 + strt(3) = 1 + strt(4) = step + cnt(1) = STR_LEN + cnt(2) = NUM_ROWS + cnt(3) = NUM_COLS + cnt(4) = 1 + + frame_str3d(:,:,1) = exp_str3d(:,:,step) + ! This calls put_vara_3d_text() + ret = PIO_put_var(pio_file, var3d, strt, cnt, frame_str3d); + PIO_TF_CHECK_ERR(ret, "Failed to put 3d array of strings 1 frame at a time in file " // trim(filename)) + end do + else + PIO_TF_LOG(0,*) "Skipping put/write of 4d char vars (NOT SUPPORTED), type :", iotype_descs(i) + end if ! Sync data to disk #ifdef PIO_TEST_CLOSE_OPEN_FOR_SYNC @@ -2323,11 +2345,14 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_str_frames PIO_TF_CHECK_VAL((gstr2d, exp_str2d), "Got wrong value for 2d char var") ! This calls get_var_3d_text() - gstr3d = '' - ret = PIO_get_var(pio_file, var3d, gstr3d); - PIO_TF_CHECK_ERR(ret, "Failed to get 3d char var in file " // trim(filename)) + ! Skip for ADIOS since put/write of 4D vars is not supported right now + if((iotypes(i) /= PIO_IOTYPE_ADIOS) .and. (iotypes(i) /= PIO_IOTYPE_ADIOSC)) then + gstr3d = '' + ret = PIO_get_var(pio_file, var3d, gstr3d); + PIO_TF_CHECK_ERR(ret, "Failed to get 3d char var in file " // trim(filename)) - PIO_TF_CHECK_VAL((gstr3d, exp_str3d), "Got wrong value for 3d char var") + PIO_TF_CHECK_VAL((gstr3d, exp_str3d), "Got wrong value for 3d char var") + end if call PIO_closefile(pio_file) call PIO_deletefile(pio_tf_iosystem_, filename); @@ -2722,6 +2747,10 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_str_hslabs end do PIO_TF_LOG(0,*) "Testing type :", iotype_descs(i) + if((iotypes(i) == PIO_IOTYPE_ADIOS) .or. (iotypes(i) == PIO_IOTYPE_ADIOSC)) then + PIO_TF_LOG(0,*) "Skipping writing hyperslabs of strings in phases (Appending to files is not SUPPORTED), type :", iotype_descs(i) + cycle + end if ret = PIO_createfile(pio_tf_iosystem_, pio_file, iotypes(i), filename, PIO_CLOBBER) PIO_TF_CHECK_ERR(ret, "Failed to open:" // trim(filename)) From dddcebf1135a7c8fb3ff715232a3f672e5d57ad3 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 29 Apr 2026 11:34:20 -0500 Subject: [PATCH 174/194] Avoid append in misc str tests Avoid appending (since ADIOS does not support appending to a file) by writing all variables after creating the file (instead of appending variables to the file for each case). --- tests/general/ncdf_get_put.F90.in | 299 +++++++++++++++++------------- 1 file changed, 166 insertions(+), 133 deletions(-) diff --git a/tests/general/ncdf_get_put.F90.in b/tests/general/ncdf_get_put.F90.in index 6e06955e73..9ea54469ca 100644 --- a/tests/general/ncdf_get_put.F90.in +++ b/tests/general/ncdf_get_put.F90.in @@ -1813,10 +1813,22 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_misc_str type(file_desc_t) :: pio_file character(len=*), parameter :: filename = "test_pio_ncdf_get_put_misc_str.testfile" type(var_desc_t) :: var0d, var1d, var2d, var3d + type(var_desc_t) :: svar0d, svar1d, svar2d, svar3d + type(var_desc_t) :: hsvar0d, hsvar1d, hsvar2d, hsvar3d character(len=*), parameter :: var0d_name = "var0d" character(len=*), parameter :: var1d_name = "var1d" character(len=*), parameter :: var2d_name = "var2d" character(len=*), parameter :: var3d_name = "var3d" + ! Small variables : Puts with buffers smaller than the variable, Gets with larger buf + character(len=*), parameter :: svar0d_name = "svr0d" + character(len=*), parameter :: svar1d_name = "svr1d" + character(len=*), parameter :: svar2d_name = "svr2d" + character(len=*), parameter :: svar3d_name = "svr3d" + ! Variables with data written to it in hyperslabs + character(len=*), parameter :: hsvar0d_name = "hvr0d" + character(len=*), parameter :: hsvar1d_name = "hvr1d" + character(len=*), parameter :: hsvar2d_name = "hvr2d" + character(len=*), parameter :: hsvar3d_name = "hvr3d" integer, parameter :: SHORT_STR_LEN = 32 integer, parameter :: LONG_STR_LEN = 128 @@ -1835,12 +1847,19 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_misc_str character(len=STR_LEN) :: exp_str0d, exp_str1d(NUM_ROWS) character(len=STR_LEN) :: exp_str2d(NUM_ROWS, NUM_COLS) character(len=STR_LEN) :: exp_str3d(NUM_ROWS, NUM_COLS, NUM_STEPS) + character(len=STR_LEN) :: exp_hstr1d(NUM_ROWS) + character(len=STR_LEN) :: exp_hstr2d(NUM_ROWS, NUM_COLS) + character(len=STR_LEN) :: exp_hstr3d(NUM_ROWS, NUM_COLS, NUM_STEPS) + character(len=STR_LEN) :: gstr0d, gstr1d(NUM_ROWS) character(len=STR_LEN) :: gstr2d(NUM_ROWS, NUM_COLS) character(len=STR_LEN) :: gstr3d(NUM_ROWS, NUM_COLS, NUM_STEPS) character(len=SHORT_STR_LEN) :: exp_sstr0d, exp_sstr1d(NUM_ROWS) character(len=SHORT_STR_LEN) :: exp_sstr2d(NUM_ROWS, NUM_COLS) + character(len=SHORT_STR_LEN) :: exp_hsstr1d(NUM_ROWS) + character(len=SHORT_STR_LEN) :: exp_hsstr2d(NUM_ROWS, NUM_COLS) + character(len=LONG_STR_LEN) :: glstr0d, glstr1d(NUM_ROWS) character(len=LONG_STR_LEN) :: glstr2d(NUM_ROWS, NUM_COLS) @@ -1868,23 +1887,44 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_misc_str do i=1,num_iotypes ! Initialize the buffers written out to the variable exp_str0d = var0d_name - exp_sstr0d = var0d_name do row=1,NUM_ROWS write(exp_str1d(row), VNAME_WITH_1D_IDX_FMT1) var1d_name, row - write(exp_sstr1d(row), VNAME_WITH_1D_IDX_FMT1) var1d_name, row do col=1,NUM_COLS write(exp_str2d(row,col), VNAME_WITH_2D_IDX_FMT1) var2d_name, row, col - write(exp_sstr2d(row,col), VNAME_WITH_2D_IDX_FMT1) var2d_name, row, col do step=1,NUM_STEPS write(exp_str3d(row,col,step), VNAME_WITH_3D_IDX_FMT1) var2d_name, row, col, step end do end do end do + ! Write the variables in the file with a smaller (than the variable size) + ! buffer + exp_sstr0d = svar0d_name // "_" + do row=1,NUM_ROWS + write(exp_sstr1d(row), VNAME_WITH_1D_IDX_FMT2) svar1d_name, row + do col=1,NUM_COLS + write(exp_sstr2d(row,col), VNAME_WITH_2D_IDX_FMT2) svar2d_name, row, col + end do + end do + + ! Write the variables in the file to test hyperslab puts + do row=1,NUM_ROWS + write(exp_hstr1d(row), VNAME_WITH_1D_IDX_FMT1) hsvar1d_name, row + write(exp_hsstr1d(row), VNAME_WITH_1D_IDX_FMT1) hsvar1d_name, row + do col=1,NUM_COLS + write(exp_hstr2d(row,col), VNAME_WITH_2D_IDX_FMT1) hsvar2d_name, row, col + write(exp_hsstr2d(row,col), VNAME_WITH_2D_IDX_FMT1) hsvar2d_name, row, col + do step=1,NUM_STEPS + write(exp_hstr3d(row,col,step), VNAME_WITH_3D_IDX_FMT1) hsvar3d_name, row, col, step + end do + end do + end do + PIO_TF_LOG(0,*) "Testing type :", iotype_descs(i) ret = PIO_createfile(pio_tf_iosystem_, pio_file, iotypes(i), filename, PIO_CLOBBER) PIO_TF_CHECK_ERR(ret, "Failed to open:" // trim(filename)) + ! ========== DIMENSIONS ============== ret = PIO_def_dim(pio_file, dim0_name, STR_LEN, pio_dims(1)) PIO_TF_CHECK_ERR(ret, "Failed to define dim 0:" // trim(filename)) @@ -1897,6 +1937,7 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_misc_str ret = PIO_def_dim(pio_file, dim3_name, NUM_STEPS, pio_dims(4)) PIO_TF_CHECK_ERR(ret, "Failed to define dim 3:" // trim(filename)) + ! ========== VARIABLES ============== ret = PIO_def_var(pio_file, var0d_name, PIO_char, (/pio_dims(1)/), var0d) PIO_TF_CHECK_ERR(ret, "Failed to define 0 dim char array or string in file " // trim(filename)) @@ -1909,9 +1950,36 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_misc_str ret = PIO_def_var(pio_file, var3d_name, PIO_char, pio_dims, var3d) PIO_TF_CHECK_ERR(ret, "Failed to define 3 dim char array or 3d array of strings in file " // trim(filename)) + ! ========== SMALL VARIABLES (Buffers used are smaller than variable) ============== + ret = PIO_def_var(pio_file, svar0d_name, PIO_char, (/pio_dims(1)/), svar0d) + PIO_TF_CHECK_ERR(ret, "Failed to define 0 dim char array or string in file (small var) " // trim(filename)) + + ret = PIO_def_var(pio_file, svar1d_name, PIO_char, (/pio_dims(1), pio_dims(2)/), svar1d) + PIO_TF_CHECK_ERR(ret, "Failed to define 1 dim char array or 1d array of strings in file (small var)" // trim(filename)) + + ret = PIO_def_var(pio_file, svar2d_name, PIO_char, (/pio_dims(1), pio_dims(2), pio_dims(3)/), svar2d) + PIO_TF_CHECK_ERR(ret, "Failed to define 2 dim char array or 2d array of strings in file (small var)" // trim(filename)) + + ret = PIO_def_var(pio_file, svar3d_name, PIO_char, pio_dims, svar3d) + PIO_TF_CHECK_ERR(ret, "Failed to define 3 dim char array or 3d array of strings in file (small var)" // trim(filename)) + + ! ========== HYPERSLAB VARIABLES (Operations are on hyperslabs of this variable) ============== + ret = PIO_def_var(pio_file, hsvar0d_name, PIO_char, (/pio_dims(1)/), hsvar0d) + PIO_TF_CHECK_ERR(ret, "Failed to define 0 dim char array or string in file (hyperslab var) " // trim(filename)) + + ret = PIO_def_var(pio_file, hsvar1d_name, PIO_char, (/pio_dims(1), pio_dims(2)/), hsvar1d) + PIO_TF_CHECK_ERR(ret, "Failed to define 1 dim char array or 1d array of strings in file (hyperslab var)" // trim(filename)) + + ret = PIO_def_var(pio_file, hsvar2d_name, PIO_char, (/pio_dims(1), pio_dims(2), pio_dims(3)/), hsvar2d) + PIO_TF_CHECK_ERR(ret, "Failed to define 2 dim char array or 2d array of strings in file (hyperslab var)" // trim(filename)) + + ret = PIO_def_var(pio_file, hsvar3d_name, PIO_char, pio_dims, hsvar3d) + PIO_TF_CHECK_ERR(ret, "Failed to define 3 dim char array or 3d array of strings in file (hyperslab var)" // trim(filename)) + ret = PIO_enddef(pio_file) PIO_TF_CHECK_ERR(ret, "Failed to enddef:" // trim(filename)) + ! ========== WRITE VARIABLES ================= ! This calls put_var_0d_text() ret = PIO_put_var(pio_file, var0d, exp_str0d); PIO_TF_CHECK_ERR(ret, "Failed to put 0 dim char array or string in file " // trim(filename)) @@ -1932,11 +2000,62 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_misc_str PIO_TF_CHECK_ERR(ret, "Failed to put 3d array of strings in file " // trim(filename)) end if + ! ========== WRITE VARIABLES WITH SMALL BUFFERS ================= + ! This calls put_var_0d_text() + ret = PIO_put_var(pio_file, svar0d, exp_sstr0d); + PIO_TF_CHECK_ERR(ret, "Failed to put 0 dim char array or string with small buf in file (small var)" // trim(filename)) + + ! This calls put_var_1d_text() + ret = PIO_put_var(pio_file, svar1d, exp_sstr1d); + PIO_TF_CHECK_ERR(ret, "Failed to put 1d array of strings with small buf in file (small var)" // trim(filename)) + + ! This calls put_var_2d_text() + ret = PIO_put_var(pio_file, svar2d, exp_sstr2d); + PIO_TF_CHECK_ERR(ret, "Failed to put 2d array of strings with small buf in file (small var)" // trim(filename)) + + ! ========== WRITE VARIABLES IN HYPERSLABS ================= + strt = 1 + cnt = 0 + cnt(1) = STR_LEN + cnt(2) = NUM_ROWS + + ! This calls put_vara_1d_text() + ret = PIO_put_var(pio_file, hsvar1d, strt, cnt, exp_hstr1d); + PIO_TF_CHECK_ERR(ret, "Failed to put hslab of 1d array of strings in file (hyperslab var)" // trim(filename)) + + strt = 1 + cnt = 0 + cnt(1) = STR_LEN + cnt(2) = NUM_ROWS + cnt(3) = NUM_COLS + + ! This calls put_vara_2d_text() + ret = PIO_put_var(pio_file, hsvar2d, strt, cnt, exp_hstr2d); + PIO_TF_CHECK_ERR(ret, "Failed to put hslab of 2d array of strings in file (hyperslab var)" // trim(filename)) + + strt = 1 + cnt = 0 + cnt(1) = STR_LEN + cnt(2) = NUM_ROWS + cnt(3) = NUM_COLS + cnt(4) = NUM_STEPS + + ! This calls put_vara_3d_text() + ! Skip for ADIOS since we currently don't support put/write of + ! 4D char variables with ADIOS + if((iotypes(i) == PIO_IOTYPE_ADIOS) .or. (iotypes(i) == PIO_IOTYPE_ADIOSC)) then + PIO_TF_LOG(0,*) "Skipping put/write of 3d string (NOT SUPPORTED for 4d char vars) :", iotype_descs(i) + else + ret = PIO_put_var(pio_file, hsvar3d, strt, cnt, exp_hstr3d); + PIO_TF_CHECK_ERR(ret, "Failed to put hslab of 3d array of strings in file (hyperslab var)" // trim(filename)) + end if + + ! ========== SYNC Data ================= ! Sync data to disk #ifdef PIO_TEST_CLOSE_OPEN_FOR_SYNC call PIO_closefile(pio_file) - ret = PIO_openfile(pio_tf_iosystem_, pio_file, iotypes(i), filename, PIO_write) + ret = PIO_openfile(pio_tf_iosystem_, pio_file, iotypes(i), filename, PIO_nowrite) PIO_TF_CHECK_ERR(ret, "Failed to reopen:" // trim(filename)) ret = PIO_inq_varid(pio_file, var0d_name, var0d) @@ -1950,10 +2069,35 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_misc_str ret = PIO_inq_varid(pio_file, var3d_name, var3d) PIO_TF_CHECK_ERR(ret, "Failed to inquire 3d array of strings var in file " // trim(filename)) + + ret = PIO_inq_varid(pio_file, svar0d_name, svar0d) + PIO_TF_CHECK_ERR(ret, "Failed to inquire 0d char or string var in file (small var)" // trim(filename)) + + ret = PIO_inq_varid(pio_file, svar1d_name, svar1d) + PIO_TF_CHECK_ERR(ret, "Failed to inquire 1d array of strings var in file (small var)" // trim(filename)) + + ret = PIO_inq_varid(pio_file, svar2d_name, svar2d) + PIO_TF_CHECK_ERR(ret, "Failed to inquire 2d array of strings var in file (small var)" // trim(filename)) + + ret = PIO_inq_varid(pio_file, svar3d_name, svar3d) + PIO_TF_CHECK_ERR(ret, "Failed to inquire 3d array of strings var in file (small var)" // trim(filename)) + + ret = PIO_inq_varid(pio_file, hsvar0d_name, hsvar0d) + PIO_TF_CHECK_ERR(ret, "Failed to inquire 0d char or string var in file (hyperslab var)" // trim(filename)) + + ret = PIO_inq_varid(pio_file, hsvar1d_name, hsvar1d) + PIO_TF_CHECK_ERR(ret, "Failed to inquire 1d array of strings var in file (hyperslab var)" // trim(filename)) + + ret = PIO_inq_varid(pio_file, hsvar2d_name, hsvar2d) + PIO_TF_CHECK_ERR(ret, "Failed to inquire 2d array of strings var in file (hyperslab var)" // trim(filename)) + + ret = PIO_inq_varid(pio_file, hsvar3d_name, hsvar3d) + PIO_TF_CHECK_ERR(ret, "Failed to inquire 3d array of strings var in file (hyperslab var)" // trim(filename)) #else call PIO_syncfile(pio_file) #endif + ! ========== READ & VERIFY : VARIABLES ================= ! This calls get_var_0d_text() gstr0d = '' ret = PIO_get_var(pio_file, var0d, gstr0d); @@ -1986,165 +2130,54 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_misc_str PIO_TF_CHECK_VAL((gstr3d, exp_str3d), "Got wrong value for 3d char var") end if - ! Re-write the variables in the file with a smaller (than the variable size) - ! buffer - exp_sstr0d = var0d_name // "_" - do row=1,NUM_ROWS - write(exp_sstr1d(row), VNAME_WITH_1D_IDX_FMT2) var1d_name, row - do col=1,NUM_COLS - write(exp_sstr2d(row,col), VNAME_WITH_2D_IDX_FMT2) var2d_name, row, col - end do - end do - - ! This calls put_var_0d_text() - ret = PIO_put_var(pio_file, var0d, exp_sstr0d); - PIO_TF_CHECK_ERR(ret, "Failed to put 0 dim char array or string with small buf in file " // trim(filename)) - - ! This calls put_var_1d_text() - ret = PIO_put_var(pio_file, var1d, exp_sstr1d); - PIO_TF_CHECK_ERR(ret, "Failed to put 1d array of strings with small buf in file " // trim(filename)) - - ! This calls put_var_2d_text() - ret = PIO_put_var(pio_file, var2d, exp_sstr2d); - PIO_TF_CHECK_ERR(ret, "Failed to put 2d array of strings with small buf in file " // trim(filename)) - - ! Sync data to disk -#ifdef PIO_TEST_CLOSE_OPEN_FOR_SYNC - call PIO_closefile(pio_file) - - ret = PIO_openfile(pio_tf_iosystem_, pio_file, iotypes(i), filename, PIO_write) - PIO_TF_CHECK_ERR(ret, "Failed to reopen:" // trim(filename)) - - ret = PIO_inq_varid(pio_file, var0d_name, var0d) - PIO_TF_CHECK_ERR(ret, "Failed to inquire 0d char or string var in file " // trim(filename)) - - ret = PIO_inq_varid(pio_file, var1d_name, var1d) - PIO_TF_CHECK_ERR(ret, "Failed to inquire 1d array of strings var in file " // trim(filename)) - - ret = PIO_inq_varid(pio_file, var2d_name, var2d) - PIO_TF_CHECK_ERR(ret, "Failed to inquire 2d array of strings var in file " // trim(filename)) - - ret = PIO_inq_varid(pio_file, var3d_name, var3d) - PIO_TF_CHECK_ERR(ret, "Failed to inquire 3d array of strings var in file " // trim(filename)) - -#else - call PIO_syncfile(pio_file) -#endif - + ! ========== READ & VERIFY : SMALL (puts with small buffer) VARIABLES ================= ! Read data back with a larger (than the size of the variable) buffer ! This calls get_var_0d_text() glstr0d = '' - ret = PIO_get_var(pio_file, var0d, glstr0d); - PIO_TF_CHECK_ERR(ret, "Failed to get 0d char var with large buf in file " // trim(filename)) + ret = PIO_get_var(pio_file, svar0d, glstr0d); + PIO_TF_CHECK_ERR(ret, "Failed to get 0d char var with large buf in file (small var)" // trim(filename)) PIO_TF_CHECK_VAL((glstr0d, exp_sstr0d), "Got wrong value for 0d char var with large buf") ! This calls get_var_1d_text() glstr1d = '' - ret = PIO_get_var(pio_file, var1d, glstr1d); - PIO_TF_CHECK_ERR(ret, "Failed to get 1d char var with large buf in file " // trim(filename)) + ret = PIO_get_var(pio_file, svar1d, glstr1d); + PIO_TF_CHECK_ERR(ret, "Failed to get 1d char var with large buf in file (small var)" // trim(filename)) PIO_TF_CHECK_VAL((glstr1d, exp_sstr1d), "Got wrong value for 1d char var with large buf") ! This calls get_var_2d_text() glstr2d = '' - ret = PIO_get_var(pio_file, var2d, glstr2d); - PIO_TF_CHECK_ERR(ret, "Failed to get 2d char var with large buf in file " // trim(filename)) + ret = PIO_get_var(pio_file, svar2d, glstr2d); + PIO_TF_CHECK_ERR(ret, "Failed to get 2d char var with large buf in file (small var)" // trim(filename)) PIO_TF_CHECK_VAL((glstr2d, exp_sstr2d), "Got wrong value for 2d char var with large buf") - ! Re-write the variables in the file to test hyperslab puts - do row=1,NUM_ROWS - write(exp_str1d(row), VNAME_WITH_1D_IDX_FMT1) var1d_name, row - write(exp_sstr1d(row), VNAME_WITH_1D_IDX_FMT1) var1d_name, row - do col=1,NUM_COLS - write(exp_str2d(row,col), VNAME_WITH_2D_IDX_FMT1) var2d_name, row, col - write(exp_sstr2d(row,col), VNAME_WITH_2D_IDX_FMT1) var2d_name, row, col - do step=1,NUM_STEPS - write(exp_str3d(row,col,step), VNAME_WITH_3D_IDX_FMT1) var3d_name, row, col, step - end do - end do - end do - - strt = 1 - cnt = 0 - cnt(1) = STR_LEN - cnt(2) = NUM_ROWS - - ! This calls put_vara_1d_text() - ret = PIO_put_var(pio_file, var1d, strt, cnt, exp_str1d); - PIO_TF_CHECK_ERR(ret, "Failed to put hslab of 1d array of strings in file " // trim(filename)) - - strt = 1 - cnt = 0 - cnt(1) = STR_LEN - cnt(2) = NUM_ROWS - cnt(3) = NUM_COLS - - ! This calls put_vara_2d_text() - ret = PIO_put_var(pio_file, var2d, strt, cnt, exp_str2d); - PIO_TF_CHECK_ERR(ret, "Failed to put hslab of 2d array of strings in file " // trim(filename)) - - strt = 1 - cnt = 0 - cnt(1) = STR_LEN - cnt(2) = NUM_ROWS - cnt(3) = NUM_COLS - cnt(4) = NUM_STEPS - - ! This calls put_vara_3d_text() - ! Skip for ADIOS since we currently don't support put/write of - ! 4D char variables with ADIOS - if((iotypes(i) == PIO_IOTYPE_ADIOS) .or. (iotypes(i) == PIO_IOTYPE_ADIOSC)) then - PIO_TF_LOG(0,*) "Skipping put/write of 3d string (NOT SUPPORTED for 4d char vars) :", iotype_descs(i) - else - ret = PIO_put_var(pio_file, var3d, strt, cnt, exp_str3d); - PIO_TF_CHECK_ERR(ret, "Failed to put hslab of 3d array of strings in file " // trim(filename)) - end if - - ! Sync data to disk -#ifdef PIO_TEST_CLOSE_OPEN_FOR_SYNC - call PIO_closefile(pio_file) - - ret = PIO_openfile(pio_tf_iosystem_, pio_file, iotypes(i), filename, PIO_nowrite) - PIO_TF_CHECK_ERR(ret, "Failed to reopen:" // trim(filename)) - - ret = PIO_inq_varid(pio_file, var1d_name, var1d) - PIO_TF_CHECK_ERR(ret, "Failed to inquire 1d array of strings var in file " // trim(filename)) - - ret = PIO_inq_varid(pio_file, var2d_name, var2d) - PIO_TF_CHECK_ERR(ret, "Failed to inquire 2d array of strings var in file " // trim(filename)) - - ret = PIO_inq_varid(pio_file, var3d_name, var3d) - PIO_TF_CHECK_ERR(ret, "Failed to inquire 3d array of strings var in file " // trim(filename)) -#else - call PIO_syncfile(pio_file) -#endif - + ! ========== READ & VERIFY : HYPERSLAB (puts in hyperslabs) VARIABLES ================= ! This calls get_var_1d_text() gstr1d = '' - ret = PIO_get_var(pio_file, var1d, gstr1d); - PIO_TF_CHECK_ERR(ret, "Failed to get 1d char var in file " // trim(filename)) + ret = PIO_get_var(pio_file, hsvar1d, gstr1d); + PIO_TF_CHECK_ERR(ret, "Failed to get 1d char var in file (hyperslab var)" // trim(filename)) - PIO_TF_CHECK_VAL((gstr1d, exp_str1d), "Got wrong value for 1d char var written with hslab put") + PIO_TF_CHECK_VAL((gstr1d, exp_hstr1d), "Got wrong value for 1d char var written with hslab put") ! This calls get_var_2d_text() gstr2d = '' - ret = PIO_get_var(pio_file, var2d, gstr2d); - PIO_TF_CHECK_ERR(ret, "Failed to get 2d char var in file " // trim(filename)) + ret = PIO_get_var(pio_file, hsvar2d, gstr2d); + PIO_TF_CHECK_ERR(ret, "Failed to get 2d char var in file (hyperslab var)" // trim(filename)) - PIO_TF_CHECK_VAL((gstr2d, exp_str2d), "Got wrong value for 2d char var written with hslab put") + PIO_TF_CHECK_VAL((gstr2d, exp_hstr2d), "Got wrong value for 2d char var written with hslab put") ! This calls get_var_3d_text() ! Skip for ADIOS since we currently don't support put/write of ! 4D char variables with ADIOS if((iotypes(i) /= PIO_IOTYPE_ADIOS) .and. (iotypes(i) /= PIO_IOTYPE_ADIOSC)) then gstr3d = '' - ret = PIO_get_var(pio_file, var3d, gstr3d); - PIO_TF_CHECK_ERR(ret, "Failed to get 3d char var in file " // trim(filename)) - end if + ret = PIO_get_var(pio_file, hsvar3d, gstr3d); + PIO_TF_CHECK_ERR(ret, "Failed to get 3d char var in file (hyperslab var)" // trim(filename)) - PIO_TF_CHECK_VAL((gstr3d, exp_str3d), "Got wrong value for 3d char var written with hslab put") + PIO_TF_CHECK_VAL((gstr3d, exp_hstr3d), "Got wrong value for 3d char var written with hslab put") + end if call PIO_closefile(pio_file) call PIO_deletefile(pio_tf_iosystem_, filename); From 9d513f269d827f2986d3c83bcbc66b52cc5021ce Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 29 Apr 2026 12:39:48 -0500 Subject: [PATCH 175/194] Skip modifying string at idx for ADIOS Since ADIOS does not support appending/modifying data, skip the test that modifies strings at specific indices for ADIOS --- tests/general/ncdf_get_put.F90.in | 73 ++++++++++++++++++------------- 1 file changed, 43 insertions(+), 30 deletions(-) diff --git a/tests/general/ncdf_get_put.F90.in b/tests/general/ncdf_get_put.F90.in index 9ea54469ca..8bc0663bb6 100644 --- a/tests/general/ncdf_get_put.F90.in +++ b/tests/general/ncdf_get_put.F90.in @@ -2590,7 +2590,13 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_str_idx #ifdef PIO_TEST_CLOSE_OPEN_FOR_SYNC call PIO_closefile(pio_file) - ret = PIO_openfile(pio_tf_iosystem_, pio_file, iotypes(i), filename, PIO_write) + if((iotypes(i) /= PIO_IOTYPE_ADIOS) .and. (iotypes(i) /= PIO_IOTYPE_ADIOSC)) then + ! Re-open in write mode for modifying "var1d_midx" var + ret = PIO_openfile(pio_tf_iosystem_, pio_file, iotypes(i), filename, PIO_write) + else + ! ADIOS does not support appending data + ret = PIO_openfile(pio_tf_iosystem_, pio_file, iotypes(i), filename, PIO_nowrite) + end if PIO_TF_CHECK_ERR(ret, "Failed to reopen:" // trim(filename)) ret = PIO_inq_varid(pio_file, var1d_name, var1d) @@ -2611,42 +2617,46 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_str_idx call PIO_syncfile(pio_file) #endif - do row=1,NUM_ROWS - ! Change the variable name to "vname_mdix" by writing at the index for the variable name - ! vname_midx(i) = "Index is: vname_midx(i)" - strt = 1 - strt(1) = VNAME_IDX_IN_VNAME_WITH_1D_IDX_FMT2 - strt(2) = row + ! Skip overwriting variables (varid_midx) for ADIOS iotypes. ADIOS does not support + ! appending/modifying data + if((iotypes(i) /= PIO_IOTYPE_ADIOS) .and. (iotypes(i) /= PIO_IOTYPE_ADIOSC)) then + do row=1,NUM_ROWS + ! Change the variable name to "vname_mdix" by writing at the index for the variable name + ! vname_midx(i) = "Index is: vname_midx(i)" + strt = 1 + strt(1) = VNAME_IDX_IN_VNAME_WITH_1D_IDX_FMT2 + strt(2) = row - ! This calls put_vara_1d_text() - ret = PIO_put_var(pio_file, var1d_midx, strt, var1d_midx_name); - PIO_TF_CHECK_ERR(ret, "Failed to put 1d array of long strings 1 string at a time to file " // trim(filename)) - end do + ! This calls put_vara_1d_text() + ret = PIO_put_var(pio_file, var1d_midx, strt, var1d_midx_name); + PIO_TF_CHECK_ERR(ret, "Failed to put 1d array of long strings 1 string at a time to file " // trim(filename)) + end do - ! Sync data to disk + ! Sync data to disk #ifdef PIO_TEST_CLOSE_OPEN_FOR_SYNC - call PIO_closefile(pio_file) + call PIO_closefile(pio_file) - ret = PIO_openfile(pio_tf_iosystem_, pio_file, iotypes(i), filename, PIO_nowrite) - PIO_TF_CHECK_ERR(ret, "Failed to reopen:" // trim(filename)) + ret = PIO_openfile(pio_tf_iosystem_, pio_file, iotypes(i), filename, PIO_nowrite) + PIO_TF_CHECK_ERR(ret, "Failed to reopen:" // trim(filename)) - ret = PIO_inq_varid(pio_file, var1d_name, var1d) - PIO_TF_CHECK_ERR(ret, "Failed to inquire 1d array of strings var in file " // trim(filename)) + ret = PIO_inq_varid(pio_file, var1d_name, var1d) + PIO_TF_CHECK_ERR(ret, "Failed to inquire 1d array of strings var in file " // trim(filename)) - ret = PIO_inq_varid(pio_file, var1d_shrt_name, var1d_shrt) - PIO_TF_CHECK_ERR(ret, "Failed to inquire 1d array of strings var in file " // trim(filename)) + ret = PIO_inq_varid(pio_file, var1d_shrt_name, var1d_shrt) + PIO_TF_CHECK_ERR(ret, "Failed to inquire 1d array of strings var in file " // trim(filename)) - ret = PIO_inq_varid(pio_file, var1d_long_name, var1d_long) - PIO_TF_CHECK_ERR(ret, "Failed to inquire 1d array of strings var in file " // trim(filename)) + ret = PIO_inq_varid(pio_file, var1d_long_name, var1d_long) + PIO_TF_CHECK_ERR(ret, "Failed to inquire 1d array of strings var in file " // trim(filename)) - ret = PIO_inq_varid(pio_file, var1d_trnc_name, var1d_trnc) - PIO_TF_CHECK_ERR(ret, "Failed to inquire 1d array of strings var in file " // trim(filename)) + ret = PIO_inq_varid(pio_file, var1d_trnc_name, var1d_trnc) + PIO_TF_CHECK_ERR(ret, "Failed to inquire 1d array of strings var in file " // trim(filename)) - ret = PIO_inq_varid(pio_file, var1d_midx_name, var1d_midx) - PIO_TF_CHECK_ERR(ret, "Failed to inquire 1d array of strings var in file " // trim(filename)) + ret = PIO_inq_varid(pio_file, var1d_midx_name, var1d_midx) + PIO_TF_CHECK_ERR(ret, "Failed to inquire 1d array of strings var in file " // trim(filename)) #else - call PIO_syncfile(pio_file) + call PIO_syncfile(pio_file) #endif + end if ! This calls get_var_1d_text() gstr1d = '' @@ -2673,11 +2683,14 @@ PIO_TF_AUTO_TEST_SUB_BEGIN test_put_get_str_idx PIO_TF_CHECK_VAL((gstr1d, exp_trnc_str1d), "Got wrong value for truncatable 1d char var") - gstr1d = '' - ret = PIO_get_var(pio_file, var1d_midx, gstr1d); - PIO_TF_CHECK_ERR(ret, "Failed to get 1d char var in file " // trim(filename)) + ! Skip for ADIOS - ADIOS does not support appending/modifying data + if((iotypes(i) /= PIO_IOTYPE_ADIOS) .and. (iotypes(i) /= PIO_IOTYPE_ADIOSC)) then + gstr1d = '' + ret = PIO_get_var(pio_file, var1d_midx, gstr1d); + PIO_TF_CHECK_ERR(ret, "Failed to get 1d char var in file " // trim(filename)) - PIO_TF_CHECK_VAL((gstr1d, exp_midx_str1d), "Got wrong value for index write of 1d char var") + PIO_TF_CHECK_VAL((gstr1d, exp_midx_str1d), "Got wrong value for index write of 1d char var") + end if call PIO_closefile(pio_file) call PIO_deletefile(pio_tf_iosystem_, filename); From 791a3cde2190cd0763e16f7da65ebbfa13b2fc6b Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 30 Apr 2026 11:12:21 -0500 Subject: [PATCH 176/194] Rm obsolete func to close soft closed files Remove obsolete function (empty function) that was used to close multiple soft closed files. (spio_close_soft_closed_file() is now used to close these files) --- src/clib/core/pioc.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/clib/core/pioc.cpp b/src/clib/core/pioc.cpp index cefc3abd09..5caba6d0ba 100644 --- a/src/clib/core/pioc.cpp +++ b/src/clib/core/pioc.cpp @@ -1702,10 +1702,6 @@ int PIOc_set_hint_impl(int iosysid, const char *hint, const char *hintval) return PIO_NOERR; } -int spio_close_soft_closed_files(iosystem_desc_t *iosys) -{ -} - /** * Clean up internal data structures, free MPI resources, and exit the * pio library. From 3df6110e96b46c9d46658a6e26b4d2f2bc013c29 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 30 Apr 2026 11:27:15 -0500 Subject: [PATCH 177/194] Fix warning in bget : missing const in char* Fixing warning in bget where "char *" was used to point to const strings. (Warning : "ISO C++ forbids converting a string constant to 'char*' ") The code was refactored to avoid these assignments --- src/clib/util/bget.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/clib/util/bget.cpp b/src/clib/util/bget.cpp index 46352a92dc..e6f03f6f19 100644 --- a/src/clib/util/bget.cpp +++ b/src/clib/util/bget.cpp @@ -1348,17 +1348,16 @@ void bpoold(void *buf, int dumpalloc, int dumpfree) bufdump((void *) (((char *) b) + sizeof(struct bhead))); } } else { - char *lerr = ""; - assert(bs > 0); if ((b->ql.blink->ql.flink != b) || (b->ql.flink->ql.blink != b)) { - lerr = " (Bad free list links)"; + LOG((0, "Free block: size %6ld bytes. (Bad free list links)", (long) bs)); + } + else{ + LOG((0, "Free block: size %6ld bytes.", (long) bs)); } - LOG((0, "Free block: size %6ld bytes.%s", - (long) bs, lerr)); #ifdef FreeWipe - lerr = ((char *) b) + sizeof(struct bfhead); + char *lerr = ((char *) b) + sizeof(struct bfhead); if ((bs > sizeof(struct bfhead)) && ((*lerr != 0x55) || (memcmp(lerr, lerr + 1, (MemSize) (bs - (sizeof(struct bfhead) + 1))) != 0))) { @@ -1391,21 +1390,18 @@ int bpoolv(void *buf) if (bs < 0) { bs = -bs; } else { - char *lerr = ""; - assert(bs > 0); if (bs <= 0) { return 0; } if ((b->ql.blink->ql.flink != b) || (b->ql.flink->ql.blink != b)) { - LOG((0, "Free block: size %6ld bytes. (Bad free list links)", - (long) bs)); + LOG((0, "Free block: size %6ld bytes. (Bad free list links)", (long) bs)); assert(0); return 0; } #ifdef FreeWipe - lerr = ((char *) b) + sizeof(struct bfhead); + char *lerr = ((char *) b) + sizeof(struct bfhead); if ((bs > sizeof(struct bfhead)) && ((*lerr != 0x55) || (memcmp(lerr, lerr + 1, (MemSize) (bs - (sizeof(struct bfhead) + 1))) != 0))) { From b5eebfc483f54c4e2eb584201e75663f4b7d4330 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 30 Apr 2026 12:17:58 -0500 Subject: [PATCH 178/194] Fix warning in bget : set bufsize to size_t Define bufsize in bget to size_t. This avoids warnings due to comparison of bufsize (which was defined as long) to size of objects (which would be size_t) Also refactoring the buffer report function to pass in args with the correct type (instead of assuming longs pass in args of type bufsize as needed) and use the appropriate casts (and inits) --- src/clib/core/pio_darray_int.cpp | 15 +++++++++++---- src/clib/util/bget.cpp | 4 ++-- src/clib/util/bget.h | 4 +++- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/clib/core/pio_darray_int.cpp b/src/clib/core/pio_darray_int.cpp index 7621af7e91..b1fb410c38 100644 --- a/src/clib/core/pio_darray_int.cpp +++ b/src/clib/core/pio_darray_int.cpp @@ -2374,11 +2374,18 @@ void cn_buffer_report(iosystem_desc_t *ios, bool collective) LOG((2, "cn_buffer_report ios->iossysid = %d collective = %d", ios->iosysid, collective)); - long bget_stats[5]; - long bget_mins[5]; - long bget_maxs[5]; + bufsize curalloc = 0, totfree = 0, maxfree = 0; + long nget = 0, nrel = 0; + + bstats(&curalloc, &totfree, &maxfree, &nget, &nrel); + + long bget_stats[5] = {static_cast(curalloc), + static_cast(totfree), + static_cast(maxfree), + nget, nrel}; + long bget_mins[5] = {0}; + long bget_maxs[5] = {0}; - bstats(bget_stats, bget_stats+1,bget_stats+2,bget_stats+3,bget_stats+4); if (collective) { LOG((3, "cn_buffer_report calling MPI_Reduce ios->comp_comm = %d", ios->comp_comm)); diff --git a/src/clib/util/bget.cpp b/src/clib/util/bget.cpp index e6f03f6f19..885db7e267 100644 --- a/src/clib/util/bget.cpp +++ b/src/clib/util/bget.cpp @@ -1292,8 +1292,8 @@ void bufdump(void *buf) } while (bdlen > 0) { - int i, dupes = 0; - bufsize l = bdlen; + int dupes = 0; + bufsize i = 0, l = bdlen; char bhex[50], bascii[20]; if (l > 16) { diff --git a/src/clib/util/bget.h b/src/clib/util/bget.h index 9929b31cb0..43467c5bd0 100644 --- a/src/clib/util/bget.h +++ b/src/clib/util/bget.h @@ -11,7 +11,9 @@ //#undef NDEBUG //#endif -typedef long bufsize; +#include + +typedef size_t bufsize; #if defined(__cplusplus) extern "C" { From 89779dcaf69a71b506f8d769fe71e7eb6c630cab Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 30 Apr 2026 12:58:11 -0500 Subject: [PATCH 179/194] Missing free for mtx when open/create fails Add missing free() for pointer to mutex when file create/open fails --- src/clib/core/pioc_support.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/clib/core/pioc_support.cpp b/src/clib/core/pioc_support.cpp index 42f00ac2bd..1913877387 100644 --- a/src/clib/core/pioc_support.cpp +++ b/src/clib/core/pioc_support.cpp @@ -3139,6 +3139,7 @@ int spio_createfile_int(int iosysid, int *ncidp, const int *iotype, const char * file->io_fstats = (spio_io_fstats_summary_t *) calloc(sizeof(spio_io_fstats_summary_t), 1); if(!(file->io_fstats)) { + delete(file->pmtx); return pio_err(ios, NULL, PIO_ENOMEM, __FILE__, __LINE__, "Creating file (%s) failed. Out of memory allocating %lld bytes for caching file I/O statistics", filename, (unsigned long long) (sizeof(spio_io_fstats_summary_t))); } @@ -3844,6 +3845,7 @@ int spio_createfile_int(int iosysid, int *ncidp, const int *iotype, const char * #endif spio_ltimer_stop(file->io_fstats->wr_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); + delete(file->pmtx); free(file->io_fstats); free(file); return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); @@ -3865,6 +3867,7 @@ int spio_createfile_int(int iosysid, int *ncidp, const int *iotype, const char * #endif spio_ltimer_stop(file->io_fstats->wr_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); + delete(file->pmtx); free(file->io_fstats); free(file); return pio_err(ios, NULL, ierr, __FILE__, __LINE__, @@ -5418,6 +5421,7 @@ int PIOc_openfile_retry_impl(int iosysid, int *ncidp, int *iotype, const char *f spio_ltimer_stop(file->io_fstats->rd_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); + delete(file->pmtx); free(file->io_fstats); free(file); PIO_get_avail_iotypes(avail_iotypes, PIO_MAX_NAME); @@ -5491,6 +5495,7 @@ int PIOc_openfile_retry_impl(int iosysid, int *ncidp, int *iotype, const char *f spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); + delete(file->pmtx); free(file->io_fstats); free(file); return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); @@ -5503,6 +5508,7 @@ int PIOc_openfile_retry_impl(int iosysid, int *ncidp, int *iotype, const char *f spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); + delete(file->pmtx); free(file->io_fstats); free(file); return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); @@ -5517,6 +5523,7 @@ int PIOc_openfile_retry_impl(int iosysid, int *ncidp, int *iotype, const char *f spio_ltimer_stop(ios->io_fstats->tot_timer_name); spio_ltimer_stop(file->io_fstats->rd_timer_name); spio_ltimer_stop(file->io_fstats->tot_timer_name); + delete(file->pmtx); free(file->io_fstats); free(file); LOG((1, "PIOc_openfile_retry failed, ierr = %d", ierr)); From 99846362484ea93f03e9f934eba72c86b1c09592 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 30 Apr 2026 19:58:40 -0500 Subject: [PATCH 180/194] Global check on fail in create/open Ensure that we always check the error globally (across all procs in the comm) with create/open calls, instead of using the error handler set by the user. This prevents dangling internal structs related to files that fail to open (or create) --- src/clib/core/pioc_support.cpp | 99 ++++++++++++++++++++-------------- src/clib/pio_internal.h | 2 + 2 files changed, 60 insertions(+), 41 deletions(-) diff --git a/src/clib/core/pioc_support.cpp b/src/clib/core/pioc_support.cpp index 1913877387..2eabf926cd 100644 --- a/src/clib/core/pioc_support.cpp +++ b/src/clib/core/pioc_support.cpp @@ -1202,69 +1202,42 @@ int check_mpi(iosystem_desc_t *ios, file_desc_t *file, int mpierr, return PIO_NOERR; } -/** - * Check the result of a netCDF API call. - * (Collective call for file/ios with error handler != PIO_RETURN_ERROR) - * - * PIO_INTERNAL_ERROR : Abort (inside PIO) on error from any MPI process - * PIO_RETURN_ERROR : Return error back to the user (Allow the user to - * handle the error. Each MPI process just returns the error code back - * to the user) - * PIO_BCAST_ERROR : Broadcast error code from I/O process with rank 0 - * (in the I/O communicator) to all processes. - * PIO_REDUCE_ERROR : Reduce error codes across all processes (and log - * the error codes from each process). This error handler detects error - * in any process. - * - * @param ios pointer to the iosystem description struct. Ignored if NULL. - * @param file pointer to the PIO structure describing this file. Ignored if NULL. - * @param status the return value from the netCDF call. - * @param fname the name of the code file. - * @param line the line number of the netCDF call in the code. - * @return the error code - */ -int check_netcdf(iosystem_desc_t *ios, file_desc_t *file, int status, - const char *fname, int line) +int spio_handle_err(iosystem_desc_t *ios, file_desc_t *file, int eh, + int status, const char *fname, int line) { - int eh = default_error_handler; /* Error handler that will be used. */ char errmsg[PIO_MAX_NAME + 1]; /* Error message. */ - int ioroot; - MPI_Comm comm; + int ioroot = 0; + MPI_Comm comm = MPI_COMM_NULL; int mpierr = MPI_SUCCESS; /* User must provide this. */ assert(ios || file); assert(fname); - LOG((1, "check_netcdf status = %d fname = %s line = %d", status, fname, line)); + LOG((1, "spio_handle_err status = %d fname = %s line = %d", status, fname, line)); - /* Find the error handler. Error handlers associated with file has - * priority over ios error handlers. - */ + assert( (eh == PIO_INTERNAL_ERROR) || + (eh == PIO_BCAST_ERROR) || + (eh == PIO_RETURN_ERROR) || + (eh == PIO_REDUCE_ERROR) ); + + LOG((2, "spio_handle_err chose error handler = %d", eh)); if(file){ - eh = file->iosystem->error_handler; ioroot = file->iosystem->ioroot; comm = file->iosystem->my_comm; } else{ assert(ios); - eh = ios->error_handler; ioroot = ios->ioroot; comm = ios->my_comm; } - assert( (eh == PIO_INTERNAL_ERROR) || - (eh == PIO_BCAST_ERROR) || - (eh == PIO_RETURN_ERROR) || - (eh == PIO_REDUCE_ERROR) ); - LOG((2, "check_netcdf chose error handler = %d", eh)); - /* Get an error message. */ if(status != PIO_NOERR){ if(eh == PIO_INTERNAL_ERROR){ int ret = PIOc_strerror_impl(status, errmsg, PIO_MAX_NAME); assert(ret == PIO_NOERR); - LOG((1, "check_netcdf errmsg = %s", errmsg)); + LOG((1, "spio_handle_err errmsg = %s", errmsg)); piodie(fname, line, "FATAL ERROR: %s (file = %s)", errmsg, (file)?(file->fname):"UNKNOWN"); } } @@ -1345,6 +1318,44 @@ int check_netcdf(iosystem_desc_t *ios, file_desc_t *file, int status, return status; } +/** + * Check the result of a netCDF API call. + * (Collective call for file/ios with error handler != PIO_RETURN_ERROR) + * + * PIO_INTERNAL_ERROR : Abort (inside PIO) on error from any MPI process + * PIO_RETURN_ERROR : Return error back to the user (Allow the user to + * handle the error. Each MPI process just returns the error code back + * to the user) + * PIO_BCAST_ERROR : Broadcast error code from I/O process with rank 0 + * (in the I/O communicator) to all processes. + * PIO_REDUCE_ERROR : Reduce error codes across all processes (and log + * the error codes from each process). This error handler detects error + * in any process. + * + * @param ios pointer to the iosystem description struct. Ignored if NULL. + * @param file pointer to the PIO structure describing this file. Ignored if NULL. + * @param status the return value from the netCDF call. + * @param fname the name of the code file. + * @param line the line number of the netCDF call in the code. + * @return the error code + */ +int check_netcdf(iosystem_desc_t *ios, file_desc_t *file, int status, + const char *fname, int line) +{ + /* User must provide this. */ + assert(ios || file); + assert(fname); + + LOG((1, "check_netcdf status = %d fname = %s line = %d", status, fname, line)); + + /* Find the error handler. Error handlers associated with file has + * priority over ios error handlers. + */ + int eh = (file) ? (file->iosystem->error_handler) : (ios->error_handler); + + return spio_handle_err(ios, file, eh, status, fname, line); +} + /** * Handle an error in PIO. This will consult the error handler * settings and either call MPI_Abort() or return an error code. @@ -3851,7 +3862,10 @@ int spio_createfile_int(int iosysid, int *ncidp, const int *iotype, const char * return check_mpi(NULL, file, mpierr, __FILE__, __LINE__); } - ierr = check_netcdf(ios, file, ierr, __FILE__, __LINE__); + /* Ensure that we handle all errors, irrespective of what error handle is + * set by the user, when creating files + */ + ierr = spio_handle_err(ios, file, PIO_REDUCE_ERROR, ierr, __FILE__, __LINE__); /* If there was an error, free the memory we allocated and handle error. */ if (ierr != PIO_NOERR) { @@ -5515,7 +5529,10 @@ int PIOc_openfile_retry_impl(int iosysid, int *ncidp, int *iotype, const char *f } } - ierr = check_netcdf(ios, file, ierr, __FILE__, __LINE__); + /* Ensure that we handle all errors, irrespective of the error handler + * set by the user, when opening a file + */ + ierr = spio_handle_err(ios, file, PIO_REDUCE_ERROR, ierr, __FILE__, __LINE__); /* If there was an error, free allocated memory and deal with the error. */ if(ierr != PIO_NOERR){ int tmp_iotype = file->iotype; diff --git a/src/clib/pio_internal.h b/src/clib/pio_internal.h index 6a89b6b215..d51cd26783 100644 --- a/src/clib/pio_internal.h +++ b/src/clib/pio_internal.h @@ -152,6 +152,8 @@ extern "C" { int pio_add_to_iosystem_list(iosystem_desc_t *ios, MPI_Comm comm); /* Check the return code from a netCDF call, with ios pointer. */ + int spio_handle_err(iosystem_desc_t *ios, file_desc_t *file, int eh, + int status, const char *fname, int line); int check_netcdf(iosystem_desc_t *ios, file_desc_t *file, int status, const char *fname, int line); From 85cb4f8a2ccedef05945880853eaf187fd0957d1 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 30 Apr 2026 20:22:51 -0500 Subject: [PATCH 181/194] Avoid memset of file_desc since it has C++ ds Removing memset() of the dummy file_desc_t struct in mvcache test since it now contains C++ data structures. --- tests/cunit/test_spio_file_mvcache.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/cunit/test_spio_file_mvcache.cpp b/tests/cunit/test_spio_file_mvcache.cpp index 55be72eecd..21c2ef9beb 100644 --- a/tests/cunit/test_spio_file_mvcache.cpp +++ b/tests/cunit/test_spio_file_mvcache.cpp @@ -199,8 +199,6 @@ int test_cint_mvcache(int wrank) { file_desc_t file; - std::memset(&file, 0, sizeof(file_desc_t)); - /* Initialize the mvcache associated with this dummy file */ spio_file_mvcache_init(&file); From 8612f47ae158fa6e85a47cef5c31b7fbd4d4dd0d Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Thu, 30 Apr 2026 22:11:37 -0500 Subject: [PATCH 182/194] Rm invalid file if unlim dim chk fails Remove invalid file from the global file list when check for unlimited dimensions fail. --- src/clib/core/pioc_support.cpp | 44 ++++++++++++++++------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/src/clib/core/pioc_support.cpp b/src/clib/core/pioc_support.cpp index 2eabf926cd..1ae8c4fea2 100644 --- a/src/clib/core/pioc_support.cpp +++ b/src/clib/core/pioc_support.cpp @@ -5581,46 +5581,42 @@ int PIOc_openfile_retry_impl(int iosysid, int *ncidp, int *iotype, const char *f #endif } + spio_ltimer_stop(ios->io_fstats->rd_timer_name); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->rd_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + /* Check if the file has unlimited dimensions */ if(!ios->async || !ios->ioproc){ - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - ierr = PIOc_inq_unlimdims_impl(*ncidp, &(file->num_unlim_dimids), NULL); if(ierr != PIO_NOERR){ - spio_file_mvcache_finalize(file); - return pio_err(ios, file, ierr, __FILE__, __LINE__, + ierr = pio_err(ios, file, ierr, __FILE__, __LINE__, "Opening file (%s) failed. Although the file was opened successfully, querying the number of unlimited dimensions in the file failed", filename); } - if(file->num_unlim_dimids > 0){ + if((ierr == PIO_NOERR) && (file->num_unlim_dimids > 0)){ file->unlim_dimids = (int *)malloc(file->num_unlim_dimids * sizeof(int)); if(!file->unlim_dimids){ - spio_file_mvcache_finalize(file); - return pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, + ierr = pio_err(ios, file, PIO_ENOMEM, __FILE__, __LINE__, "Opening file (%s) failed. Out of memory allocating %lld bytes for caching the unlimited dimension ids", filename, (unsigned long long) (file->num_unlim_dimids * sizeof(int))); } - ierr = PIOc_inq_unlimdims_impl(*ncidp, NULL, file->unlim_dimids); - if(ierr != PIO_NOERR){ - spio_file_mvcache_finalize(file); - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Opening file (%s) failed. Although the file was opened successfully, querying the unlimited dimensions in the file failed", filename); + if(ierr == PIO_NOERR){ + ierr = PIOc_inq_unlimdims_impl(*ncidp, NULL, file->unlim_dimids); + if(ierr != PIO_NOERR){ + ierr = pio_err(ios, file, ierr, __FILE__, __LINE__, + "Opening file (%s) failed. Although the file was opened successfully, querying the unlimited dimensions in the file failed", filename); + } } } - spio_ltimer_start(ios->io_fstats->rd_timer_name); - spio_ltimer_start(ios->io_fstats->tot_timer_name); - spio_ltimer_start(file->io_fstats->rd_timer_name); - spio_ltimer_start(file->io_fstats->tot_timer_name); - LOG((3, "File has %d unlimited dimensions", file->num_unlim_dimids)); + if(ierr != PIO_NOERR){ + pio_delete_file_from_list(file->pio_ncid); + } + else{ + LOG((3, "File has %d unlimited dimensions", file->num_unlim_dimids)); + } } - spio_ltimer_stop(ios->io_fstats->rd_timer_name); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->rd_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); return ierr; } From b2850d330717c0f74fefa93fb8f4cb805ddaa1e3 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 1 May 2026 09:34:27 -0500 Subject: [PATCH 183/194] Add fillval support for HDF5 Adding support for writing out fillvalues with the HDF5 iotypes --- src/clib/core/pio_darray.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/clib/core/pio_darray.cpp b/src/clib/core/pio_darray.cpp index 70d61812b9..b22d740ebc 100644 --- a/src/clib/core/pio_darray.cpp +++ b/src/clib/core/pio_darray.cpp @@ -502,6 +502,23 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar } break; /* FIXME: Handle fillvalues for HDF5 */ + case PIO_IOTYPE_HDF5: + case PIO_IOTYPE_HDF5C: + #if PIO_USE_ASYNC_WR_THREAD + ierr = pio_iosys_async_hdf5_write_op_add(file, nvars, fndims, varids, iodesc, + DARRAY_FILL, frame); + if(ierr != PIO_NOERR){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Writing multiple variables to file (%s, ncid=%d) failed. Internal error queing async task to write variable fillvalues in parallel (iotype = %s)", pio_get_fname_from_file(file), ncid, pio_iotype_to_string(file->iotype)); + } + #else + if((ierr = write_darray_multi_par(file, nvars, fndims, varids, iodesc, + DARRAY_FILL, frame))){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Writing multiple variables to file (%s, ncid=%d) failed. Internal error writing variable fillvalues in parallel (iotype = %s)", pio_get_fname_from_file(file), ncid, pio_iotype_to_string(file->iotype)); + } + #endif + break; case PIO_IOTYPE_NETCDF4C: case PIO_IOTYPE_NETCDF: if((ierr = write_darray_multi_serial(file, nvars, fndims, varids, iodesc, @@ -522,6 +539,12 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar brel(vdesc0->fillbuf); vdesc0->fillbuf = NULL; } + #if !PIO_USE_ASYNC_WR_THREAD + if((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)){ + assert(file->dt_converter); + static_cast(file->dt_converter)->free(ioid); + } + #endif } } From 1cc1ba29f9acc733dc090dec1d63faf0c63807bc Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 1 May 2026 09:35:31 -0500 Subject: [PATCH 184/194] Increasing default timeout for tests to 30m With a new data rearranger and new I/O types tests can potentially take much longer to run. Increasing the default timeout for tests to 1800s --- tests/general/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/general/CMakeLists.txt b/tests/general/CMakeLists.txt index 454930e7f6..a676362843 100644 --- a/tests/general/CMakeLists.txt +++ b/tests/general/CMakeLists.txt @@ -151,7 +151,7 @@ endif () #============================================================================== # Test Timeout (16 min = 960 sec) -set (DEFAULT_TEST_TIMEOUT 960) +set (DEFAULT_TEST_TIMEOUT 1800) set (DEFAULT_TEST_MAXNUMPROCS 4) # Use environment variable PIO_TF_MAXNUMPROCS to set the maximum number From d1f2c19763af1fdff556292719d30421366a81f0 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 1 May 2026 11:30:42 -0500 Subject: [PATCH 185/194] Refactor spio_change_def() util function The spio_change_def() function handled both enddef and redef calls and was getting harder to read/maintain. Splitting the spio_change_def() to separate functions for handling enddef and redef calls. Also move this code back to PIOc__impl() functions and getting rid of the common spio_change_def() function Also refactoring the code for handling enddef() calls to make it easier to read/maintain. The code for handling redef() call was also refactored as needed. --- src/clib/core/pio_nc.cpp | 259 ++++++++++++++++++++++++++++++++- src/clib/core/pioc_support.cpp | 206 -------------------------- src/clib/pio_internal.h | 3 - 3 files changed, 257 insertions(+), 211 deletions(-) diff --git a/src/clib/core/pio_nc.cpp b/src/clib/core/pio_nc.cpp index 016a6d05be..45663f675c 100644 --- a/src/clib/core/pio_nc.cpp +++ b/src/clib/core/pio_nc.cpp @@ -3005,7 +3005,186 @@ int PIOc_set_fill_impl(int ncid, int fillmode, int *old_modep) */ int PIOc_enddef_impl(int ncid) { - return spio_change_def(ncid, 1); + iosystem_desc_t *ios; /* Pointer to io system information. */ + file_desc_t *file; /* Pointer to file information. */ + int ierr = PIO_NOERR; /* Return code from function calls. */ + + LOG((2, "PIOc_enddef_impl ncid = %d", ncid)); + + /* Find the info about this file. When I check the return code + * here, some tests fail. ???*/ + if((ierr = pio_get_file(ncid, &file))){ + return pio_err(NULL, NULL, ierr, __FILE__, __LINE__, + "Ending the define mode for file (ncid = %d) failed. Invalid file id", ncid); + } + assert(file); + ios = file->iosystem; + assert(ios); + spio_ltimer_start(ios->io_fstats->tot_timer_name); + spio_ltimer_start(file->io_fstats->tot_timer_name); + + /* If async is in use, and this is not an IO task, bcast the parameters. */ + if(ios->async){ + int msg = PIO_MSG_ENDDEF; + + PIO_SEND_ASYNC_MSG(ios, msg, &ierr, ncid); + if(ierr != PIO_NOERR){ + LOG((1, "Error sending async msg for PIO_MSG_ENDDEF")); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + return pio_err(ios, NULL, ierr, __FILE__, __LINE__, + "Ending the define mode for file (%s) failed. Error sending async msg, PIO_MSG_ENDDEF, on iosystem (iosysid=%d)", pio_get_fname_from_file(file), ios->iosysid); + } + } + +#if PIO_USE_ASYNC_WR_THREAD + /* FIXME: Relax this wait */ + /* + ierr = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ierr != PIO_NOERR){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Error waiting on all pending asynchronous HDF5 ops", + pio_get_fname_from_file(file), file->pio_ncid); + } + */ +#endif + + /* If this is an IO task, then call the netCDF function. */ + LOG((3, "PIOc_enddef_impl ios->ioproc = %d", ios->ioproc)); + if(ios->ioproc){ + LOG((3, "PIOc_enddef_impl calling netcdf function file->fh = %d file->do_io = %d iotype = %d", + file->fh, file->do_io, file->iotype)); + + /* NetCDF and PnetCDF by default do not reserve any extra space in + * the NetCDF file headers (compactness etc). However this can be a + * problem (performance related) when renaming variables etc since + * this information is stored in the NetCDF header. Adding more + * information into the header requires the libraries to resize the + * file, extend the header space and copy the contents of the file + * (similar to realloc). + * + * The solution for the performance issue is to reserve some extra + * space in the header when creating NetCDF files. The current calls + * to nc_enddef()/ncmpi_enddef() need to be replaced with nc__enddef + * ()/ncmpi__enddef() (note the double underscore). + * + * This reservation should be made only once: after the header section + * is expanded, a new reservation may involve moving (shifting) data, + * which can be very expensive if the data sections are huge. + */ +#ifdef _PNETCDF + if(file->iotype == PIO_IOTYPE_PNETCDF){ + /* ncmpi__enddef has been available since PnetCDF 1.5.0 (PNETCDF_MIN_VER_REQD is currently 1.8.1): + int ncmpi__enddef(int ncid, + MPI_Offset h_minfree, + MPI_Offset v_align, + MPI_Offset v_minfree, + MPI_Offset r_align); + + The usual call of ncmpi_enddef(ncid) is equivalent to ncmpi__enddef(ncid, 0, 0, 0, 0). + + Call ncmpi__enddef with appropriate arguments instead of ncmpi_enddef: + - To reserve a sufficiently large space for the file header if it is expected + to expand (set h_minfree > 0 explicitly). + See https://github.com/E3SM-Project/scorpio/issues/436 + + - To prevent PnetCDF (versions prior to 1.13.0) from implicitly selecting the + file striping size to align the header extent (set v_align > 0 explicitly). + See https://github.com/E3SM-Project/scorpio/issues/566 + */ + + /* Sets the pad at the end of the "header" section. */ + MPI_Offset h_minfree = 0; /* Unless extra header space is requested, this can be left as default (0) */ + + /* Controls the alignment of the beginning of the data section for fixed-size/record variables. */ + const MPI_Offset v_align = 4; /* For fixed-size variables, needs to be left as the default (4 bytes) */ + const MPI_Offset r_align = 4; /* For record variables, needs to be left as the default (4 bytes) */ + + /* Sets the pad at the end of the data section for fixed-size variables. */ + const MPI_Offset v_minfree = 0; /* This can be left as default (0) */ + + if(file->reserve_extra_header_space){ + /* The recommended size by Charlie Zender (NCO developer) is 10 KB */ + assert(PIO_RESERVED_FILE_HEADER_SIZE >= 0); + h_minfree = PIO_RESERVED_FILE_HEADER_SIZE; + + file->reserve_extra_header_space = false; + } + + ierr = ncmpi__enddef(file->fh, h_minfree, v_align, v_minfree, r_align); + } +#endif /* _PNETCDF */ +#ifdef _NETCDF + if(((file->iotype == PIO_IOTYPE_NETCDF) || (file->iotype == PIO_IOTYPE_NETCDF4C) || + (file->iotype == PIO_IOTYPE_NETCDF4P) || (file->iotype == PIO_IOTYPE_NETCDF4P_NCZARR)) && + file->do_io){ + LOG((3, "PIOc_enddef_impl calling nc_enddef file->fh = %d", file->fh)); + + /* We only reserve header space for CLASSIC NetCDF files */ + bool reserve_extra_header_space = (file->iotype == PIO_IOTYPE_NETCDF) && + file->reserve_extra_header_space; + bool enddef_complete = false; + + /* CAUTION: nc__enddef may not be available on future NetCDF implementations. */ +#ifdef NETCDF_C_NC__ENDDEF_EXISTS + if(reserve_extra_header_space){ + /* Sets the pad at the end of the "header" section. + * The recommended size by Charlie Zender (NCO developer) is 10 KB */ + assert(PIO_RESERVED_FILE_HEADER_SIZE >= 0); + const MPI_Offset h_minfree = PIO_RESERVED_FILE_HEADER_SIZE; + + /* Controls the alignment of the beginning of the data section for fixed-size/record variables. */ + const size_t v_align = 4; /* For fixed-size variables, needs to be left as the default (4 bytes) */ + const size_t r_align = 4; /* For record variables, needs to be left as the default (4 bytes) */ + + /* Sets the pad at the end of the data section for fixed-size variables. */ + const size_t v_minfree = 0; /* This can be left as default (0) */ + + /* nc__enddef has been available since NetCDF 3.x (NETCDF_C_MIN_VER_REQD is currently 4.3.3) */ + ierr = nc__enddef(file->fh, h_minfree, v_align, v_minfree, r_align); + + file->reserve_extra_header_space = false; + + enddef_complete = true; + } +#endif + + if(!enddef_complete){ + /* The default method for enddef for all NetCDF4 I/O types (and also for PIO_IOTYPE_NETCDF when we + * don't require header expansion OR when nc__enddef() is unavailable to expand the header + * According to NCO user guide, nc__enddef will improve speed of future metadata expansion with + * classic and 64bit NetCDF files, though not necessarily with NetCDF4 files. + */ + ierr = nc_enddef(file->fh); + } + } +#endif /* _NETCDF */ +#ifdef _HDF5 + if((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)){ +#if PIO_USE_ASYNC_WR_THREAD + ierr = spio_iosys_async_hdf5_enddef_op_add(file); +#else + ierr = spio_hdf5_enddef(ios, file); +#endif /* PIO_USE_ASYNC_WR_THREAD */ + } +#endif /* _HDF5 */ + + /* Do nothing for ADIOS I/O types */ + } + + ierr = check_netcdf(NULL, file, ierr, __FILE__, __LINE__); + if(ierr != PIO_NOERR){ + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Ending the define mode for file (%s) failed. Low-level I/O library API failed", pio_get_fname_from_file(file)); + } + LOG((3, "PIOc_enddef_impl succeeded")); + + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + return ierr; } /** @@ -3024,7 +3203,83 @@ int PIOc_enddef_impl(int ncid) */ int PIOc_redef_impl(int ncid) { - return spio_change_def(ncid, 0); + iosystem_desc_t *ios; /* Pointer to io system information. */ + file_desc_t *file; /* Pointer to file information. */ + int ierr = PIO_NOERR; /* Return code from function calls. */ + + LOG((2, "PIOc_redef_impl ncid = %d ", ncid)); + + /* Find the info about this file. When I check the return code + * here, some tests fail. ???*/ + if((ierr = pio_get_file(ncid, &file))){ + return pio_err(NULL, NULL, ierr, __FILE__, __LINE__, + "Changing the define mode (redef) for file (ncid = %d) failed. Invalid file id", ncid); + } + assert(file); + ios = file->iosystem; + assert(ios); + spio_ltimer_start(ios->io_fstats->tot_timer_name); + spio_ltimer_start(file->io_fstats->tot_timer_name); + + /* If async is in use, and this is not an IO task, bcast the parameters. */ + if(ios->async){ + int msg = PIO_MSG_REDEF; + + PIO_SEND_ASYNC_MSG(ios, msg, &ierr, ncid); + if(ierr != PIO_NOERR){ + LOG((1, "Error sending async msg for PIO_MSG_REDEF")); + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + return pio_err(ios, NULL, ierr, __FILE__, __LINE__, + "Changing the define mode (redef) for file (%s) failed. Error sending async msg, PIO_MSG_REDEF, on iosystem (iosysid=%d)", pio_get_fname_from_file(file), ios->iosysid); + } + } + +#if PIO_USE_ASYNC_WR_THREAD + /* FIXME: Relax this wait */ + /* + ierr = spio_wait_all_hdf5_async_ops(ios->iosysid); + if(ierr != PIO_NOERR){ + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Error waiting on all pending asynchronous HDF5 ops", + pio_get_fname_from_file(file), file->pio_ncid); + } + */ +#endif + + /* If this is an IO task, then call the netCDF function. */ + LOG((3, "PIOc_redef_impl ios->ioproc = %d", ios->ioproc)); + if(ios->ioproc){ + LOG((3, "PIOc_redef calling netcdf function file->fh = %d file->do_io = %d iotype = %d", + file->fh, file->do_io, file->iotype)); + switch(file->iotype){ +#ifdef _PNETCDF + case PIO_IOTYPE_PNETCDF: ierr = ncmpi_redef(file->fh); break; +#endif +#ifdef _NETCDF + case PIO_IOTYPE_NETCDF: + case PIO_IOTYPE_NETCDF4C: + case PIO_IOTYPE_NETCDF4P: + case PIO_IOTYPE_NETCDF4P_NCZARR: + if(file->do_io) { ierr = nc_redef(file->fh); break; } +#endif /* _NETCDF */ + default: /* Do nothing : PIO_IOTYPE_ADIOS, PIO_IOTYPE_ADIOSC, PIO_IOTYPE_HDF5, PIO_IOTYPE_HDF5C */ break; + } + } + + ierr = check_netcdf(NULL, file, ierr, __FILE__, __LINE__); + if(ierr != PIO_NOERR){ + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + return pio_err(ios, file, ierr, __FILE__, __LINE__, + "Changing the define mode (redef) for file (%s) failed. Low-level I/O library API failed", pio_get_fname_from_file(file)); + } + LOG((3, "PIOc_redef_impl succeeded")); + + spio_ltimer_stop(ios->io_fstats->tot_timer_name); + spio_ltimer_stop(file->io_fstats->tot_timer_name); + return ierr; } /** diff --git a/src/clib/core/pioc_support.cpp b/src/clib/core/pioc_support.cpp index 1ae8c4fea2..7a160258e5 100644 --- a/src/clib/core/pioc_support.cpp +++ b/src/clib/core/pioc_support.cpp @@ -5711,212 +5711,6 @@ int spio_pnetcdf_inq_type(int ncid, nc_type xtype, char *name, return PIO_NOERR; } -/** - * This is an internal function that handles both PIOc_enddef and - * PIOc_redef. - * - * @param ncid the ncid of the file to enddef or redef - * @param is_enddef set to non-zero for enddef, 0 for redef. - * @returns PIO_NOERR on success, error code on failure. */ -int spio_change_def(int ncid, int is_enddef) -{ - iosystem_desc_t *ios; /* Pointer to io system information. */ - file_desc_t *file; /* Pointer to file information. */ - int ierr = PIO_NOERR; /* Return code from function calls. */ - - LOG((2, "spio_change_def ncid = %d is_enddef = %d", ncid, is_enddef)); - - /* Find the info about this file. When I check the return code - * here, some tests fail. ???*/ - if ((ierr = pio_get_file(ncid, &file))) - { - return pio_err(NULL, NULL, ierr, __FILE__, __LINE__, - "Changing the define mode for file (ncid = %d) failed. Invalid file id", ncid); - } - assert(file); - ios = file->iosystem; - assert(ios); - spio_ltimer_start(ios->io_fstats->tot_timer_name); - spio_ltimer_start(file->io_fstats->tot_timer_name); - - /* If async is in use, and this is not an IO task, bcast the parameters. */ - if (ios->async) - { - int msg = is_enddef ? PIO_MSG_ENDDEF : PIO_MSG_REDEF; - - PIO_SEND_ASYNC_MSG(ios, msg, &ierr, ncid); - if(ierr != PIO_NOERR) - { - LOG((1, "Error sending async msg for PIO_MSG_ENDDEF/PIO_MSG_REDEF")); - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - return pio_err(ios, NULL, ierr, __FILE__, __LINE__, - "Changing the define mode for file (%s) failed. Error sending async msg, PIO_MSG_ENDDEF/PIO_MSG_REDEF, on iosystem (iosysid=%d)", pio_get_fname_from_file(file), ios->iosysid); - } - } - -#if PIO_USE_ASYNC_WR_THREAD - /* FIXME: Relax this wait */ - /* - ierr = spio_wait_all_hdf5_async_ops(ios->iosysid); - if(ierr != PIO_NOERR){ - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " - "Error waiting on all pending asynchronous HDF5 ops", - pio_get_fname_from_file(file), file->pio_ncid); - } - */ -#endif - - /* If this is an IO task, then call the netCDF function. */ - LOG((3, "spio_change_def ios->ioproc = %d", ios->ioproc)); - if (ios->ioproc) - { - LOG((3, "spio_change_def calling netcdf function file->fh = %d file->do_io = %d iotype = %d", - file->fh, file->do_io, file->iotype)); - - /* NetCDF and PnetCDF by default do not reserve any extra space in - * the NetCDF file headers (compactness etc). However this can be a - * problem (performance related) when renaming variables etc since - * this information is stored in the NetCDF header. Adding more - * information into the header requires the libraries to resize the - * file, extend the header space and copy the contents of the file - * (similar to realloc). - * - * The solution for the performance issue is to reserve some extra - * space in the header when creating NetCDF files. The current calls - * to nc_enddef()/ncmpi_enddef() need to be replaced with nc__enddef - * ()/ncmpi__enddef() (note the double underscore). - * - * This reservation should be made only once: after the header section - * is expanded, a new reservation may involve moving (shifting) data, - * which can be very expensive if the data sections are huge. - */ -#ifdef _PNETCDF - if (file->iotype == PIO_IOTYPE_PNETCDF) - { - if (is_enddef) - { - /* ncmpi__enddef has been available since PnetCDF 1.5.0 (PNETCDF_MIN_VER_REQD is currently 1.8.1): - int ncmpi__enddef(int ncid, - MPI_Offset h_minfree, - MPI_Offset v_align, - MPI_Offset v_minfree, - MPI_Offset r_align); - - The usual call of ncmpi_enddef(ncid) is equivalent to ncmpi__enddef(ncid, 0, 0, 0, 0). - - Call ncmpi__enddef with appropriate arguments instead of ncmpi_enddef: - - To reserve a sufficiently large space for the file header if it is expected - to expand (set h_minfree > 0 explicitly). - See https://github.com/E3SM-Project/scorpio/issues/436 - - - To prevent PnetCDF (versions prior to 1.13.0) from implicitly selecting the - file striping size to align the header extent (set v_align > 0 explicitly). - See https://github.com/E3SM-Project/scorpio/issues/566 - */ - - /* Sets the pad at the end of the "header" section. */ - MPI_Offset h_minfree = 0; /* Unless extra header space is requested, this can be left as default (0) */ - - /* Controls the alignment of the beginning of the data section for fixed-size/record variables. */ - const MPI_Offset v_align = 4; /* For fixed-size variables, needs to be left as the default (4 bytes) */ - const MPI_Offset r_align = 4; /* For record variables, needs to be left as the default (4 bytes) */ - - /* Sets the pad at the end of the data section for fixed-size variables. */ - const MPI_Offset v_minfree = 0; /* This can be left as default (0) */ - - if (file->reserve_extra_header_space) - { - /* The recommended size by Charlie Zender (NCO developer) is 10 KB */ - assert(PIO_RESERVED_FILE_HEADER_SIZE >= 0); - h_minfree = PIO_RESERVED_FILE_HEADER_SIZE; - - file->reserve_extra_header_space = false; - } - - ierr = ncmpi__enddef(file->fh, h_minfree, v_align, v_minfree, r_align); - } - else - ierr = ncmpi_redef(file->fh); - } -#endif /* _PNETCDF */ -#ifdef _NETCDF - if (file->iotype != PIO_IOTYPE_PNETCDF && - file->iotype != PIO_IOTYPE_ADIOS && file->iotype != PIO_IOTYPE_ADIOSC && - file->iotype != PIO_IOTYPE_HDF5 && file->iotype != PIO_IOTYPE_HDF5C && file->do_io) - { - if (is_enddef) - { - LOG((3, "spio_change_def calling nc_enddef file->fh = %d", file->fh)); - if (file->iotype == PIO_IOTYPE_NETCDF) - { -#ifdef NETCDF_C_NC__ENDDEF_EXISTS - if (file->reserve_extra_header_space) - { - /* Sets the pad at the end of the "header" section. - * The recommended size by Charlie Zender (NCO developer) is 10 KB */ - assert(PIO_RESERVED_FILE_HEADER_SIZE >= 0); - const MPI_Offset h_minfree = PIO_RESERVED_FILE_HEADER_SIZE; - - /* Controls the alignment of the beginning of the data section for fixed-size/record variables. */ - const size_t v_align = 4; /* For fixed-size variables, needs to be left as the default (4 bytes) */ - const size_t r_align = 4; /* For record variables, needs to be left as the default (4 bytes) */ - - /* Sets the pad at the end of the data section for fixed-size variables. */ - const size_t v_minfree = 0; /* This can be left as default (0) */ - - /* nc__enddef has been available since NetCDF 3.x (NETCDF_C_MIN_VER_REQD is currently 4.3.3) */ - ierr = nc__enddef(file->fh, h_minfree, v_align, v_minfree, r_align); - - file->reserve_extra_header_space = false; - } - else - ierr = nc_enddef(file->fh); -#else - /* CAUTION: nc__enddef may not be available on future NetCDF implementations, switch back to nc_enddef. */ - ierr = nc_enddef(file->fh); -#endif - } - else - { - /* We still call nc_enddef for NetCDF4 type. According to NCO user guide, nc__enddef will improve speed of - * future metadata expansion with classic and 64bit NetCDF files, though not necessarily with NetCDF4 files. - */ - ierr = nc_enddef(file->fh); - } - } - else - ierr = nc_redef(file->fh); - } -#endif /* _NETCDF */ -#ifdef _HDF5 - if((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)){ - if(is_enddef){ -#if PIO_USE_ASYNC_WR_THREAD - ierr = spio_iosys_async_hdf5_enddef_op_add(file); -#else - ierr = spio_hdf5_enddef(ios, file); -#endif - } - } -#endif /* _HDF5 */ - } - - ierr = check_netcdf(NULL, file, ierr, __FILE__, __LINE__); - if(ierr != PIO_NOERR){ - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - return pio_err(ios, file, ierr, __FILE__, __LINE__, - "Changing the define mode for file (%s) failed. Low-level I/O library API failed", pio_get_fname_from_file(file)); - } - LOG((3, "spio_change_def succeeded")); - - spio_ltimer_stop(ios->io_fstats->tot_timer_name); - spio_ltimer_stop(file->io_fstats->tot_timer_name); - return ierr; -} - /** * Check whether an IO type is valid for the build. * diff --git a/src/clib/pio_internal.h b/src/clib/pio_internal.h index d51cd26783..3d71674189 100644 --- a/src/clib/pio_internal.h +++ b/src/clib/pio_internal.h @@ -367,9 +367,6 @@ extern "C" { int spio_pnetcdf_inq_type(int ncid, nc_type xtype, char *name, PIO_Offset *sizep); - /* Handle end and re-defs. */ - int spio_change_def(int ncid, int is_enddef); - /* Remove a directory in the filesystem */ int spio_remove_directory(const char *path); From 3d51844a2be5a6e8a10fa71f45e985eeae49ca89 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Fri, 1 May 2026 13:03:01 -0500 Subject: [PATCH 186/194] Explicit check for define mode for non-PnetCDF Adding explicit check for "define mdoe "in redef/enddef calls for NetCDF, HDF5 and ADIOS I/O types. Redef calls in "define mode" only fail for PnetCDF lib calls --- src/clib/core/pio_nc.cpp | 41 +++++++++++++++++++++++++++++----- src/clib/core/pioc_support.cpp | 2 ++ src/clib/pio_types.hpp | 3 +++ 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/clib/core/pio_nc.cpp b/src/clib/core/pio_nc.cpp index 45663f675c..39b67fc606 100644 --- a/src/clib/core/pio_nc.cpp +++ b/src/clib/core/pio_nc.cpp @@ -3160,17 +3160,33 @@ int PIOc_enddef_impl(int ncid) } } #endif /* _NETCDF */ + + /* For NetCDF I/O types whether "this file is in define mode before enddef() is called" is + * handled by the low-level NetCDF enddef() calls. For HDF5 and ADIOS we handle it explicitly + */ #ifdef _HDF5 if((file->iotype == PIO_IOTYPE_HDF5) || (file->iotype == PIO_IOTYPE_HDF5C)){ + if(file->in_def_mode){ #if PIO_USE_ASYNC_WR_THREAD - ierr = spio_iosys_async_hdf5_enddef_op_add(file); + ierr = spio_iosys_async_hdf5_enddef_op_add(file); #else - ierr = spio_hdf5_enddef(ios, file); + ierr = spio_hdf5_enddef(ios, file); #endif /* PIO_USE_ASYNC_WR_THREAD */ + } + else{ + ierr = pio_err(ios, file, PIO_EINTERNAL, __FILE__, __LINE__, + "Ending the define mode for file (%s) failed. The file is not in define mode.", pio_get_fname_from_file(file)); + } } #endif /* _HDF5 */ - /* Do nothing for ADIOS I/O types */ + if((file->iotype == PIO_IOTYPE_ADIOS) || (file->iotype == PIO_IOTYPE_ADIOSC)){ + /* Do nothing - no "enddef" - for ADIOS I/O types. Just a sanity check here */ + if(!file->in_def_mode){ + ierr = pio_err(ios, file, PIO_EINTERNAL, __FILE__, __LINE__, + "Ending the define mode for file (%s) failed. The file is not in define mode.", pio_get_fname_from_file(file)); + } + } } ierr = check_netcdf(NULL, file, ierr, __FILE__, __LINE__); @@ -3180,6 +3196,9 @@ int PIOc_enddef_impl(int ncid) return pio_err(ios, file, ierr, __FILE__, __LINE__, "Ending the define mode for file (%s) failed. Low-level I/O library API failed", pio_get_fname_from_file(file)); } + + /* File no longer in "define mode" */ + file->in_def_mode = false; LOG((3, "PIOc_enddef_impl succeeded")); spio_ltimer_stop(ios->io_fstats->tot_timer_name); @@ -3262,9 +3281,18 @@ int PIOc_redef_impl(int ncid) case PIO_IOTYPE_NETCDF4C: case PIO_IOTYPE_NETCDF4P: case PIO_IOTYPE_NETCDF4P_NCZARR: - if(file->do_io) { ierr = nc_redef(file->fh); break; } + if(file->do_io) { ierr = nc_redef(file->fh); } + /* Unlike PnetCDF ncmpi_redef() call, NetCDF does not fail for multiple redef() calls + * So perform the sanity checks in the "default:" case for NetCDF I/O types */ + /* break; */ #endif /* _NETCDF */ - default: /* Do nothing : PIO_IOTYPE_ADIOS, PIO_IOTYPE_ADIOSC, PIO_IOTYPE_HDF5, PIO_IOTYPE_HDF5C */ break; + default: + /* Do nothing : Just some sanity checks */ + if(file->in_def_mode){ + ierr = pio_err(ios, file, PIO_EINTERNAL, __FILE__, __LINE__, + "Changing the define mode (redef) for file (%s) failed. The file is already in define mode.", pio_get_fname_from_file(file)); + } + break; } } @@ -3275,6 +3303,9 @@ int PIOc_redef_impl(int ncid) return pio_err(ios, file, ierr, __FILE__, __LINE__, "Changing the define mode (redef) for file (%s) failed. Low-level I/O library API failed", pio_get_fname_from_file(file)); } + + file->in_def_mode = true; + LOG((3, "PIOc_redef_impl succeeded")); spio_ltimer_stop(ios->io_fstats->tot_timer_name); diff --git a/src/clib/core/pioc_support.cpp b/src/clib/core/pioc_support.cpp index 7a160258e5..275e6da110 100644 --- a/src/clib/core/pioc_support.cpp +++ b/src/clib/core/pioc_support.cpp @@ -3158,6 +3158,7 @@ int spio_createfile_int(int iosysid, int *ncidp, const int *iotype, const char * /* Fill in some file values. */ file->fh = -1; file->reserve_extra_header_space = true; /* Set to true for creating output NetCDF files only. */ + file->in_def_mode = true; /* The file is in "define mode" when created */ file->is_reopened = false; strncpy(file->fname, filename, PIO_MAX_NAME); pio_create_uniq_str(ios, NULL, tname, "tmp_", "_file"); @@ -4876,6 +4877,7 @@ int PIOc_openfile_retry_impl(int iosysid, int *ncidp, int *iotype, const char *f /* Fill in some file values. */ file->fh = -1; file->reserve_extra_header_space = false; /* Set to true for creating output NetCDF files only. */ + file->in_def_mode = false; /* The file is NOT in "define mode" when opened */ file->is_reopened = true; strncpy(file->fname, filename, PIO_MAX_NAME); pio_create_uniq_str(ios, NULL, tname, "tmp_", "_file"); diff --git a/src/clib/pio_types.hpp b/src/clib/pio_types.hpp index 2ce942c0f7..7d15526516 100644 --- a/src/clib/pio_types.hpp +++ b/src/clib/pio_types.hpp @@ -938,6 +938,9 @@ typedef struct file_desc_t * creating NetCDF files to accommodate anticipated changes. */ bool reserve_extra_header_space; + /** True if the file is in "define mode", false otherwise */ + bool in_def_mode; + /** True if this is an existing file reopened */ bool is_reopened; } file_desc_t; From 05c9c2560b7c01cd0e6060c8ca62b60eaba4ad3a Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Mon, 4 May 2026 11:01:06 -0500 Subject: [PATCH 187/194] Handle hdf5 close without enddef Handle cases where close() is called without an enddef() for HDF5 I/O types (by explicitly calling enddef() before a close()) --- src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp b/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp index dd5049efea..aad30b1bce 100644 --- a/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp +++ b/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp @@ -1309,11 +1309,23 @@ int spio_hdf5_put_var(iosystem_desc_t *ios, file_desc_t *file, int varid, int spio_hdf5_close(iosystem_desc_t *ios, file_desc_t *file) { int i = 0; + int ierr = PIO_NOERR; assert(ios && file); assert((file->iotype == PIO_IOTYPE_HDF5) || ((file->iotype == PIO_IOTYPE_HDF5C))); assert(ios->ioproc); + /* Handle pending defines here + * e.g. If user calls close() without an enddef() + */ + ierr = spio_hdf5_enddef(ios, file); + if(ierr != PIO_NOERR){ + return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, + "Closing file (%s, ncid=%d) using HDF5 iotype failed. " + "Processing pending defines (variables, dimensions) failed", + pio_get_fname_from_file(file), file->pio_ncid); + } + /* Since close is always an async op, when async thread is used, we do not need * to explicitly wait for async ops to complete * i.e., we don't need spio_wait_all_hdf5_async_ops() here From d19b4250ab87ad0c6a0edd1ec35ecf9a117e1ff0 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 5 May 2026 11:05:16 -0500 Subject: [PATCH 188/194] Avoid wr mode when checking file in iosystem tests In I/O system tests avoid opening the file in write mode when checking the contents --- tests/general/pio_iosystem_tests.F90.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/general/pio_iosystem_tests.F90.in b/tests/general/pio_iosystem_tests.F90.in index 4d4da46f27..a98ccd4a0a 100644 --- a/tests/general/pio_iosystem_tests.F90.in +++ b/tests/general/pio_iosystem_tests.F90.in @@ -153,7 +153,7 @@ SUBROUTINE open_and_check_file(comm, iosys, iotype, pio_file, fname, & logical, intent(in) :: disable_fclose integer, intent(inout) :: ret - ret = PIO_openfile(iosys, pio_file, iotype, fname, PIO_write) + ret = PIO_openfile(iosys, pio_file, iotype, fname, PIO_nowrite) PIO_TF_CHECK_ERR(ret, comm, "Failed to open:" // fname) call check_file(comm, pio_file, fname, attname, dimname, ret) From b36f099ceb7a2d928a5bb2faade34c7d1cb38157 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 5 May 2026 11:06:29 -0500 Subject: [PATCH 189/194] Adding support for copying HDF5 atts Adding support for PIO_copy_att() for HDF5 I/O types. * The spio_hdf5_enddef() function was refactored to move the sync of definitions to a separate function * A new function, spio_hdf5_copy_att(), was added to support copying HDF5 attributes between files * A minor fix in default case for PIOc_copy_att() impl : Using the user supplied file ids instead of using file->fh --- src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp | 122 +++++++++++++++---- src/clib/core/iolib/hdf5/spio_hdf5_utils.hpp | 3 + src/clib/core/pio_nc.cpp | 27 +++- 3 files changed, 125 insertions(+), 27 deletions(-) diff --git a/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp b/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp index aad30b1bce..bdf37945da 100644 --- a/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp +++ b/src/clib/core/iolib/hdf5/spio_hdf5_utils.cpp @@ -678,7 +678,7 @@ int spio_hdf5_def_var(iosystem_desc_t *ios, file_desc_t *file, const char *name, return PIO_NOERR; } -int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) +static int spio_hdf5_sync_defs(iosystem_desc_t *ios, file_desc_t *file) { int i = 0, ret = PIO_NOERR; @@ -698,7 +698,7 @@ int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) dcpl_id = H5Pcreate(H5P_DATASET_CREATE); if(dcpl_id == H5I_INVALID_HID){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Syncing definitions of variables/attributes in file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to create a new dataset creation property list", pio_get_fname_from_file(file), file->pio_ncid); } @@ -709,7 +709,7 @@ int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) #if 0 if(H5Pset_attr_creation_order(dcpl_id, H5P_CRT_ORDER_TRACKED | H5P_CRT_ORDER_INDEXED) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Syncing definitions of variables/attributes in file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to set tracking and indexing of attribute creation order", pio_get_fname_from_file(file), file->pio_ncid); } @@ -724,7 +724,7 @@ int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) if(H5Pset_chunk(dcpl_id, 1, chunk_dims) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Syncing definitions of variables/attributes in file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to set the size of the chunks used to store a chunked layout dataset", pio_get_fname_from_file(file), file->pio_ncid); } @@ -733,7 +733,7 @@ int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) space_id = H5Screate_simple(1, dims, max_dims); if(space_id == H5I_INVALID_HID){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Syncing definitions of variables/attributes in file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to create a new simple dataspace", pio_get_fname_from_file(file), file->pio_ncid); } @@ -743,7 +743,7 @@ int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) space_id, H5P_DEFAULT, dcpl_id, H5P_DEFAULT); if(dimscale_id < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Syncing definitions of variables/attributes in file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to create a new dataset (%s) that will be converted to a dimension scale", pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_dims[i].name); } @@ -753,7 +753,7 @@ int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) if(H5DSset_scale(dimscale_id, dimscale_name) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Syncing definitions of variables/attributes in file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to convert a dataset (for dimension %s) to a dimension scale", pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_dims[i].name); } @@ -767,7 +767,7 @@ int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) hid_t dimid_space_id = H5Screate(H5S_SCALAR); if(dimid_space_id == H5I_INVALID_HID){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Syncing definitions of variables/attributes in file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to create a new scalar dataspace", pio_get_fname_from_file(file), file->pio_ncid); } @@ -783,7 +783,7 @@ int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) H5T_NATIVE_INT, dimid_space_id, H5P_DEFAULT, H5P_DEFAULT); if(dimid_att_id == H5I_INVALID_HID){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Syncing definitions of variables/attributes in file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to create a new attribute (%s) attached to a dimension scale (%s)", pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_dims[i].name); } @@ -791,42 +791,42 @@ int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) else{ /* Error determining whether an attribute with a given name exists on an object */ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Syncing definitions of variables/attributes in file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to determine whether an attribute (%s) exists on a dimension scale (%s)", pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_dims[i].name); } if(H5Awrite(dimid_att_id, H5T_NATIVE_INT, &i) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Syncing definitions of variables/attributes in file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to write an attribute (%s) attached to a dimension scale (%s)", pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_dims[i].name); } if(H5Sclose(dimid_space_id) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Syncing definitions of variables/attributes in file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to release a scalar dataspace", pio_get_fname_from_file(file), file->pio_ncid); } if(H5Aclose(dimid_att_id) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Syncing definitions of variables/attributes in file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to close an attribute (%s) attached to a dimension scale (%s)", pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_dims[i].name); } if(H5Sclose(space_id) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Syncing definitions of variables/attributes in file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to release a simple dataspace", pio_get_fname_from_file(file), file->pio_ncid); } if(H5Pclose(dcpl_id) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Syncing definitions of variables/attributes in file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to close a dataset creation property list", pio_get_fname_from_file(file), file->pio_ncid); } @@ -854,7 +854,7 @@ int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) if(attr_exists < 0){ /* Error determining whether an attribute with a given name exists on an object */ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Syncing definitions of variables/attributes in file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to determine whether an attribute (%s) exists on a dimension scale (%s)", pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); } @@ -868,7 +868,7 @@ int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) if(H5DSset_scale(file->hdf5_vars[i].hdf5_dataset_id, file->hdf5_vars[i].name) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Syncing definitions of variables/attributes in file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to convert a dataset (for coordinate variable %s) to a dimension scale", pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_vars[i].name); } @@ -880,7 +880,7 @@ int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) hid_t dimid_space_id = H5Screate(H5S_SCALAR); if(dimid_space_id == H5I_INVALID_HID){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Syncing definitions of variables/attributes in file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to create a new scalar dataspace", pio_get_fname_from_file(file), file->pio_ncid); } @@ -889,28 +889,28 @@ int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) H5T_NATIVE_INT, dimid_space_id, H5P_DEFAULT, H5P_DEFAULT); if(dimid_att_id == H5I_INVALID_HID){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Syncing definitions of variables/attributes in file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to create a new attribute (%s) attached to a dimension scale (%s)", pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); } if(H5Awrite(dimid_att_id, H5T_NATIVE_INT, &dimid) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Syncing definitions of variables/attributes in file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to write an attribute (%s) attached to a dimension scale (%s)", pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); } if(H5Aclose(dimid_att_id) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Syncing definitions of variables/attributes in file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to close an attribute (%s) attached to a dimension scale (%s)", pio_get_fname_from_file(file), file->pio_ncid, attr_name, file->hdf5_vars[i].name); } if(H5Sclose(dimid_space_id) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Syncing definitions of variables/attributes in file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to release a scalar dataspace", pio_get_fname_from_file(file), file->pio_ncid); } @@ -930,7 +930,7 @@ int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) for(int j = 0; j < ndims; j++){ if(H5DSattach_scale(file->hdf5_vars[i].hdf5_dataset_id, file->hdf5_dims[dimids[j]].hdf5_dataset_id, j) < 0){ return pio_err(ios, file, PIO_EHDF5ERR, __FILE__, __LINE__, - "Ending the define mode for file (%s, ncid=%d) using HDF5 iotype failed. " + "Syncing definitions of variables/attributes in file (%s, ncid=%d) using HDF5 iotype failed. " "The low level (HDF5) I/O library call failed to attach a dimension scale (for dimension %s) to %dth dimension of a dataset (for variable %s)", pio_get_fname_from_file(file), file->pio_ncid, file->hdf5_dims[dimids[j]].name, j, file->hdf5_vars[i].name); } @@ -948,6 +948,82 @@ int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) return PIO_NOERR; } +int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file) +{ + return spio_hdf5_sync_defs(ios, file); +} + +int spio_hdf5_copy_att(iosystem_desc_t *ios, file_desc_t *ifile, int ivarid, const char *name, + file_desc_t *ofile, int ovarid) +{ + int ret = PIO_NOERR; + + assert(ios && ifile && ofile && name); + assert((ifile->iotype == PIO_IOTYPE_HDF5) || (ifile->iotype == PIO_IOTYPE_HDF5C)); + assert((ofile->iotype == PIO_IOTYPE_HDF5) || (ofile->iotype == PIO_IOTYPE_HDF5C)); + assert(ios->ioproc); + + /* Error message template */ + const std::string err_msg = std::string("Copying attribute (") + name + ") associated with variable (varid=" + std::to_string(ivarid) + " in input file (" + pio_get_fname_from_file(ifile) + ", ncid=" + std::to_string(ifile->pio_ncid) + ") to variable (varid=" + std::to_string(ovarid) + ") in file (" + pio_get_fname_from_file(ofile) + ", ncid=" + std::to_string(ofile->pio_ncid) + ") using HDF5 iotype failed."; + + /* Sync any pending defs (attributes) */ + ret = spio_hdf5_sync_defs(ios, ifile); + if(ret == PIO_NOERR){ ret = spio_hdf5_sync_defs(ios, ofile); } + + /* Read attribute from the input file */ + hid_t iloc_id = (ivarid == PIO_GLOBAL) ? ifile->hdf5_file_id : ifile->hdf5_vars[ivarid].hdf5_dataset_id; + + hid_t iattr_id = H5Aopen(iloc_id, name, H5P_DEFAULT); + if(iattr_id == H5I_INVALID_HID){ + const std::string lerr_msg = " The low level (HDF5) I/O library call failed to open attribute in input file"; + return pio_err(ios, ifile, PIO_EHDF5ERR, __FILE__, __LINE__, "%s", (err_msg + lerr_msg).c_str()); + } + + hsize_t asize = H5Aget_storage_size(iattr_id); + hid_t h5_space = H5Aget_space(iattr_id); + hid_t h5_xtype = H5Aget_type(iattr_id); + if((asize <= 0) || (h5_space == H5I_INVALID_HID) || (h5_xtype == H5I_INVALID_HID)){ + const std::string lerr_msg = std::string(" The low level (HDF5) I/O library call to ") + ((asize <= 0) ? " get storage size failed" : ((h5_space == H5I_INVALID_HID) ? " get dataspace of attribute failed" : " get type of attribute failed")); + if(h5_xtype != H5I_INVALID_HID) { H5Tclose(h5_xtype); } + if(h5_space != H5I_INVALID_HID) { H5Sclose(h5_space); } + H5Aclose(iattr_id); + return pio_err(ios, ifile, PIO_EHDF5ERR, __FILE__, __LINE__, "%s", (err_msg + lerr_msg).c_str()); + } + + void *abuf = malloc(static_cast(asize)); + if(!abuf){ + const std::string lerr_msg = std::string(" Allocating ") + std::to_string(static_cast(asize)) + " bytes for reading attribute failed"; + H5Tclose(h5_xtype); H5Sclose(h5_space); H5Aclose(iattr_id); + return pio_err(ios, ifile, PIO_ENOMEM, __FILE__, __LINE__, "%s", (err_msg + lerr_msg).c_str()); + } + + if(H5Aread(iattr_id, h5_xtype, abuf) < 0){ + const std::string lerr_msg = " Reading attribute from input file failed"; + free(abuf); H5Tclose(h5_xtype); H5Sclose(h5_space); H5Aclose(iattr_id); + return pio_err(ios, ifile, PIO_ENOMEM, __FILE__, __LINE__, "%s", (err_msg + lerr_msg).c_str()); + } + + /* Create attribute in output file and write to it */ + hid_t oloc_id = (ovarid == PIO_GLOBAL) ? ofile->hdf5_file_id : ofile->hdf5_vars[ovarid].hdf5_dataset_id; + + hid_t oattr_id = H5Acreate2(oloc_id, name, h5_xtype, h5_space, H5P_DEFAULT, H5P_DEFAULT); + if(oattr_id == H5I_INVALID_HID){ + const std::string lerr_msg = " Creating attribute in ouput file failed"; + free(abuf); H5Tclose(h5_xtype); H5Sclose(h5_space); H5Aclose(iattr_id); + return pio_err(ios, ofile, PIO_ENOMEM, __FILE__, __LINE__, "%s", (err_msg + lerr_msg).c_str()); + } + + if(H5Awrite(oattr_id, h5_xtype, abuf) < 0){ + const std::string lerr_msg = " Writing attribute to output file failed"; + H5Aclose(oattr_id); free(abuf); H5Tclose(h5_xtype); H5Sclose(h5_space); H5Aclose(iattr_id); + return pio_err(ios, ofile, PIO_ENOMEM, __FILE__, __LINE__, "%s", (err_msg + lerr_msg).c_str()); + } + + H5Aclose(oattr_id); free(abuf); H5Tclose(h5_xtype); H5Sclose(h5_space); H5Aclose(iattr_id); + + return PIO_NOERR; +} + int spio_hdf5_put_att(iosystem_desc_t *ios, file_desc_t *file, int varid, const char *name, nc_type atttype, PIO_Offset len, const void *op) { diff --git a/src/clib/core/iolib/hdf5/spio_hdf5_utils.hpp b/src/clib/core/iolib/hdf5/spio_hdf5_utils.hpp index 50fb85a90f..0fff055878 100644 --- a/src/clib/core/iolib/hdf5/spio_hdf5_utils.hpp +++ b/src/clib/core/iolib/hdf5/spio_hdf5_utils.hpp @@ -18,6 +18,9 @@ int spio_hdf5_def_var(iosystem_desc_t *ios, file_desc_t *file, const char *name, int spio_hdf5_enddef(iosystem_desc_t *ios, file_desc_t *file); +int spio_hdf5_copy_att(iosystem_desc_t *ios, file_desc_t *ifile, int ivarid, const char *name, + file_desc_t *ofile, int ovarid); + int spio_hdf5_put_att(iosystem_desc_t *ios, file_desc_t *file, int varid, const char *name, nc_type atttype, PIO_Offset len, const void *op); diff --git a/src/clib/core/pio_nc.cpp b/src/clib/core/pio_nc.cpp index 39b67fc606..93703e9437 100644 --- a/src/clib/core/pio_nc.cpp +++ b/src/clib/core/pio_nc.cpp @@ -5177,6 +5177,15 @@ int PIOc_copy_att_impl(int incid, int ivarid, const char *name, } ierr = check_netcdf(ios, ifile, ierr, __FILE__, __LINE__); break; +#endif +#ifdef _HDF5 + case PIO_IOTYPE_HDF5: + case PIO_IOTYPE_HDF5C: + if(ios->ioproc){ + ierr = spio_hdf5_copy_att(ifile->iosystem, ifile, ivarid, name, ofile, ovarid); + } + ierr = check_netcdf(ios, ifile, ierr, __FILE__, __LINE__); + break; #endif default: { @@ -5187,32 +5196,42 @@ int PIOc_copy_att_impl(int incid, int ivarid, const char *name, PIO_Offset att_len = 0, type_sz = 0; spio_ltimer_stop(ios->io_fstats->tot_timer_name); GPTLstop(ifile->io_fstats->tot_timer_name); - ierr = PIOc_inq_att_impl(ifile->fh, ivarid, name, &att_type, &att_len); + ierr = PIOc_inq_att_impl(incid, ivarid, name, &att_type, &att_len); if(ierr != PIO_NOERR){ + spio_ltimer_start(ios->io_fstats->tot_timer_name); + GPTLstart(ifile->io_fstats->tot_timer_name); ierr = pio_err(ios, ifile, ierr, __FILE__, __LINE__, "Copying attribute, %s, associated with variable %s (varid=%d) in file %s (ncid=%d) to file %s (ncid=%d) failed. Inquiring attribute type and length in file %s (ncid=%d) failed", name, pio_get_vname_from_file(ifile, ivarid), ivarid, pio_get_fname_from_file(ifile), incid, pio_get_fname_from_file(ofile), oncid, pio_get_fname_from_file(ifile), incid); break; } - ierr = PIOc_inq_type_impl(ifile->fh, att_type, NULL, &type_sz); + ierr = PIOc_inq_type_impl(incid, att_type, NULL, &type_sz); if(ierr != PIO_NOERR){ + spio_ltimer_start(ios->io_fstats->tot_timer_name); + GPTLstart(ifile->io_fstats->tot_timer_name); ierr = pio_err(ios, ifile, ierr, __FILE__, __LINE__, "Copying attribute, %s, associated with variable %s (varid=%d) in file %s (ncid=%d) to file %s (ncid=%d) failed. Inquiring attribute type size (attribute type = %x) failed", name, pio_get_vname_from_file(ifile, ivarid), ivarid, pio_get_fname_from_file(ifile), incid, pio_get_fname_from_file(ofile), oncid, att_type); break; } void *pbuf = malloc(type_sz * att_len); if(!pbuf){ + spio_ltimer_start(ios->io_fstats->tot_timer_name); + GPTLstart(ifile->io_fstats->tot_timer_name); ierr = pio_err(ios, ifile, PIO_ENOMEM, __FILE__, __LINE__, "Copying attribute, %s, associated with variable %s (varid=%d) in file %s (ncid=%d) to file %s (ncid=%d) failed. Unable to allocate %lld bytes to temporarily cache the attribute for copying", name, pio_get_vname_from_file(ifile, ivarid), ivarid, pio_get_fname_from_file(ifile), incid, pio_get_fname_from_file(ofile), oncid, (long long int) (type_sz * att_len)); break; } - ierr = PIOc_get_att_impl(ifile->fh, ivarid, name, pbuf); + ierr = PIOc_get_att_impl(incid, ivarid, name, pbuf); if(ierr != PIO_NOERR){ + spio_ltimer_start(ios->io_fstats->tot_timer_name); + GPTLstart(ifile->io_fstats->tot_timer_name); ierr = pio_err(ios, ifile, ierr, __FILE__, __LINE__, "Copying attribute, %s, associated with variable %s (varid=%d) in file %s (ncid=%d) to file %s (ncid=%d) failed. Getting attribute from file %s (ncid=%d) failed", name, pio_get_vname_from_file(ifile, ivarid), ivarid, pio_get_fname_from_file(ifile), incid, pio_get_fname_from_file(ofile), oncid, pio_get_fname_from_file(ifile), incid); break; } - ierr = PIOc_put_att_impl(ofile->fh, ovarid, name, att_type, att_len, pbuf); + ierr = PIOc_put_att_impl(oncid, ovarid, name, att_type, att_len, pbuf); if(ierr != PIO_NOERR){ + spio_ltimer_start(ios->io_fstats->tot_timer_name); + GPTLstart(ifile->io_fstats->tot_timer_name); ierr = pio_err(ios, ifile, ierr, __FILE__, __LINE__, "Copying attribute, %s, associated with variable %s (varid=%d) in file %s (ncid=%d) to file %s (ncid=%d) failed. Putting/Writing attribute to file %s (ncid=%d, varid=%d) failed", name, pio_get_vname_from_file(ifile, ivarid), ivarid, pio_get_fname_from_file(ifile), incid, pio_get_fname_from_file(ofile), oncid, pio_get_fname_from_file(ofile), oncid, ovarid); break; From cf75043e06c9fcfd357ec5b1c94621b68a0c7a85 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 5 May 2026 15:33:10 -0500 Subject: [PATCH 190/194] Increasing timelimit for hdf5 test Increasing timeout for HDF5 test from 1m to 3m --- examples/c/CMakeLists.txt | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt index ea35771d41..fa2a221b4b 100644 --- a/examples/c/CMakeLists.txt +++ b/examples/c/CMakeLists.txt @@ -72,6 +72,9 @@ endif () #============================================================================== # DEFINE THE TARGETS AND TESTS #============================================================================== +# Test timeout to 180s +set (DEFAULT_TEST_TIMEOUT 180) + add_spio_executable(examplePio TRUE "" examplePio.c) add_spio_executable(example1 TRUE "" example1.c) add_spio_executable(darray_no_async TRUE "" darray_no_async.c) @@ -101,18 +104,18 @@ if (PIO_USE_MPISERIAL) add_test(NAME example1 COMMAND example1) add_test(NAME put_var COMMAND put_var) else () - add_mpi_test(examplePio EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/examplePio NUMPROCS 4 TIMEOUT 60) - add_mpi_test(example1 EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/example1 NUMPROCS 4 TIMEOUT 60) - add_mpi_test(put_var EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/put_var NUMPROCS 4 TIMEOUT 60) - #add_mpi_test(darray_async EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/darray_async NUMPROCS 5 TIMEOUT 60) - add_mpi_test(darray_no_async EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/darray_no_async NUMPROCS 4 TIMEOUT 60) + add_mpi_test(examplePio EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/examplePio NUMPROCS 4 TIMEOUT ${DEFAULT_TEST_TIMEOUT}) + add_mpi_test(example1 EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/example1 NUMPROCS 4 TIMEOUT ${DEFAULT_TEST_TIMEOUT}) + add_mpi_test(put_var EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/put_var NUMPROCS 4 TIMEOUT ${DEFAULT_TEST_TIMEOUT}) + #add_mpi_test(darray_async EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/darray_async NUMPROCS 5 TIMEOUT ${DEFAULT_TEST_TIMEOUT}) + add_mpi_test(darray_no_async EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/darray_no_async NUMPROCS 4 TIMEOUT ${DEFAULT_TEST_TIMEOUT}) if (WITH_HDF5) - add_mpi_test(test_hdf5 EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/test_hdf5 NUMPROCS 4 TIMEOUT 60) + add_mpi_test(test_hdf5 EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/test_hdf5 NUMPROCS 4 TIMEOUT ${DEFAULT_TEST_TIMEOUT}) endif () if (WITH_ADIOS2) - add_mpi_test(test_adios EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/test_adios NUMPROCS 4 TIMEOUT 60) + add_mpi_test(test_adios EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/test_adios NUMPROCS 4 TIMEOUT ${DEFAULT_TEST_TIMEOUT}) endif () if (WITH_NETCDF) - add_mpi_test(test_netcdf4p EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/test_netcdf4p NUMPROCS 4 TIMEOUT 60) + add_mpi_test(test_netcdf4p EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/test_netcdf4p NUMPROCS 4 TIMEOUT ${DEFAULT_TEST_TIMEOUT}) endif () endif () From b4dca5ca1e82e33d2a4d37db970106b18c61a320 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 5 May 2026 20:24:59 -0500 Subject: [PATCH 191/194] Add an AUTHORS.md file Create an AUTHORS.md file and include list of major contributors --- AUTHORS.md | 14 ++++++ src/clib/core/pio_darray.cpp | 5 --- src/clib/core/pio_darray_int.cpp | 15 ------- src/clib/core/pio_file.cpp | 8 ---- src/clib/core/pio_get_nc.cpp | 55 ----------------------- src/clib/core/pio_getput_int.cpp | 11 ----- src/clib/core/pio_msg.cpp | 40 ----------------- src/clib/core/pio_nc.cpp | 64 --------------------------- src/clib/core/pio_nc4.cpp | 11 ----- src/clib/core/pio_put_nc.cpp | 55 ----------------------- src/clib/core/pio_spmd.cpp | 6 --- src/clib/core/pioc.cpp | 22 --------- src/clib/core/pioc_sc.cpp | 2 - src/clib/core/pioc_support.cpp | 3 -- src/clib/core/rearr/pio_rearrange.cpp | 18 -------- src/clib/core/util/pio_lists.cpp | 1 - src/clib/pio.h | 3 -- src/clib/pio_internal.h | 3 -- tests/cunit/pio_tests.h | 2 - 19 files changed, 14 insertions(+), 324 deletions(-) create mode 100644 AUTHORS.md diff --git a/AUTHORS.md b/AUTHORS.md new file mode 100644 index 0000000000..d32c01235c --- /dev/null +++ b/AUTHORS.md @@ -0,0 +1,14 @@ +# Authors +** Current Authors ** + +* Jayesh Krishna [email](jayesh@anl.gov) +* Danqing Wu [email](DanqingWu@hotmail.com) + +** Past Contributors ** + +* Norbert Podhorszki +* Tahsin Kurc +* Dmitry Ganyushin +* Jim Edwards +* Ed Hartnett + diff --git a/src/clib/core/pio_darray.cpp b/src/clib/core/pio_darray.cpp index b22d740ebc..bd582f4e68 100644 --- a/src/clib/core/pio_darray.cpp +++ b/src/clib/core/pio_darray.cpp @@ -6,7 +6,6 @@ * array. Only by combining the distributed arrays from all processor * can the full array be obtained. * - * @author Jim Edwards */ #include #include @@ -115,7 +114,6 @@ PIO_Offset PIOc_set_buffer_size_limit_impl(PIO_Offset limit) * @param flushtodisk non-zero to cause buffers to be flushed to disk. * @return 0 for success, error code otherwise. * @ingroup PIO_write_darray - * @author Jim Edwards, Ed Hartnett */ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvars, PIO_Offset arraylen, const void *array, const int *frame, @@ -583,7 +581,6 @@ int PIOc_write_darray_multi_impl(int ncid, const int *varids, int ioid, int nvar * @param vdesc pointer to var_desc_t info for this var. * @returns 0 for success, non-zero error code for failure. * @ingroup PIO_write_darray - * @author Ed Hartnett */ int find_var_fillvalue(file_desc_t *file, int varid, var_desc_t *vdesc) { @@ -1986,7 +1983,6 @@ static int PIOc_write_darray_adios(file_desc_t *file, int varid, int ioid, * data. * @returns 0 for success, non-zero error code for failure. * @ingroup PIO_write_darray - * @author Jim Edwards, Ed Hartnett */ int PIOc_write_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, const void *array, const void *fillvalue) @@ -3462,7 +3458,6 @@ static int PIOc_read_darray_adios(file_desc_t *file, int fndims, io_desc_t *iode * processor. * @return 0 for success, error code otherwise. * @ingroup PIO_read_darray - * @author Jim Edwards, Ed Hartnett */ int PIOc_read_darray_impl(int ncid, int varid, int ioid, PIO_Offset arraylen, void *array) diff --git a/src/clib/core/pio_darray_int.cpp b/src/clib/core/pio_darray_int.cpp index b1fb410c38..4649566c5a 100644 --- a/src/clib/core/pio_darray_int.cpp +++ b/src/clib/core/pio_darray_int.cpp @@ -6,7 +6,6 @@ * array. Only by combining the distributed arrays from all processor * can the full array be obtained. * - * @author Jim Edwards */ #include @@ -55,7 +54,6 @@ void *bpool_alloc(bufsize sz) * @param ios pointer to the iosystem descriptor which will use the * new buffer. * @returns 0 for success, error code otherwise. - * @author Jim Edwards */ int compute_buffer_init(iosystem_desc_t *ios) { @@ -89,7 +87,6 @@ int compute_buffer_init(iosystem_desc_t *ios) * values. * @return 0 for success, error code otherwise. * @ingroup PIO_write_darray - * @author Ed Hartnett */ int spio_find_start_count(int ndims, const int *dimlen, int fndims, var_desc_t *vdesc, io_region *region, size_t *start, size_t *count) @@ -167,7 +164,6 @@ int spio_find_start_count(int ndims, const int *dimlen, int fndims, var_desc_t * * in iobuf. NULL if this iodesc contains non-record vars. * @return 0 for success, error code otherwise. * @ingroup PIO_write_darray - * @author Jim Edwards, Ed Hartnett */ int write_darray_multi_par(file_desc_t *file, int nvars, int fndims, const int *varids, io_desc_t *iodesc, int fill, const int *frame) @@ -708,7 +704,6 @@ int write_darray_multi_par(file_desc_t *file, int nvars, int fndims, const int * * regions. * @returns 0 for success, error code otherwise. * @ingroup PIO_read_darray - * @author Jim Edwards, Ed Hartnett **/ int find_all_start_count(io_region *region, int maxregions, int fndims, int iodesc_ndims, const int *dimlen, var_desc_t *vdesc, @@ -785,7 +780,6 @@ int find_all_start_count(io_region *region, int maxregions, int fndims, * * @return 0 for success, error code otherwise. * @ingroup PIO_write_darray - * @author Jim Edwards, Ed Hartnett */ int send_all_start_count(iosystem_desc_t *ios, io_desc_t *iodesc, PIO_Offset llen, int maxregions, int nvars, int fndims, size_t *tmp_start, @@ -864,7 +858,6 @@ int send_all_start_count(iosystem_desc_t *ios, io_desc_t *iodesc, PIO_Offset lle * iobuf. * @return 0 for success, error code otherwise. * @ingroup PIO_write_darray - * @author Jim Edwards, Ed Hartnett */ int recv_and_write_data(file_desc_t *file, const int *varids, const int *frame, io_desc_t *iodesc, PIO_Offset llen, int maxregions, int nvars, @@ -1068,7 +1061,6 @@ int recv_and_write_data(file_desc_t *file, const int *varids, const int *frame, * in iobuf. NULL if this iodesc contains non-record vars. * @return 0 for success, error code otherwise. * @ingroup PIO_write_darray - * @author Jim Edwards, Ed Hartnett */ int write_darray_multi_serial(file_desc_t *file, int nvars, int fndims, const int *varids, io_desc_t *iodesc, int fill, const int *frame) @@ -1178,7 +1170,6 @@ int write_darray_multi_serial(file_desc_t *file, int nvars, int fndims, const in * iobuf. * @return 0 on success, error code otherwise. * @ingroup PIO_read_darray - * @author Jim Edwards, Ed Hartnett */ int pio_read_darray_nc(file_desc_t *file, int fndims, io_desc_t *iodesc, int vid, void *iobuf) { @@ -1434,7 +1425,6 @@ int pio_read_darray_nc(file_desc_t *file, int fndims, io_desc_t *iodesc, int vid * iobuf. * @returns 0 for success, error code otherwise. * @ingroup PIO_read_darray - * @author Jim Edwards, Ed Hartnett */ int pio_read_darray_nc_serial(file_desc_t *file, int fndims, io_desc_t *iodesc, int vid, void *iobuf) @@ -1821,7 +1811,6 @@ int set_file_req_block_size_limit(file_desc_t *file, PIO_Offset sz) * @param nreq_blocks Pointer to integer that will contain the * number of block ranges * - * @author Jayesh Krishna */ int get_file_req_blocks(file_desc_t *file, @@ -2068,7 +2057,6 @@ int get_file_req_blocks(file_desc_t *file, * @param addsize additional size to add to buffer (in bytes) * @return 0 for success, error code otherwise. * @ingroup PIO_write_darray - * @author Jim Edwards, Jayesh Krishna, Ed Hartnett */ int flush_output_buffer(file_desc_t *file, bool force, PIO_Offset addsize) { @@ -2366,7 +2354,6 @@ int flush_output_buffer(file_desc_t *file, bool force, PIO_Offset addsize) * @param ios pointer to the IO system structure * @param collective true if collective report is desired * @ingroup PIO_write_darray - * @author Jim Edwards */ void cn_buffer_report(iosystem_desc_t *ios, bool collective) { @@ -2421,7 +2408,6 @@ void cn_buffer_report(iosystem_desc_t *ios, bool collective) * @param flushtodisk if true, then flush data to disk. * @returns 0 for success, error code otherwise. * @ingroup PIO_write_darray - * @author Jim Edwards, Ed Hartnett */ int flush_buffer(int ncid, wmulti_buffer *wmb, bool flushtodisk) { @@ -2531,7 +2517,6 @@ int flush_buffer(int ncid, wmulti_buffer *wmb, bool flushtodisk) * @param ios pointer to the IO system structure. * @param iodesc a pointer to decomposition description. * @returns 0 for success, error code otherwise. - * @author Jim Edwards */ int compute_maxaggregate_bytes(iosystem_desc_t *ios, io_desc_t *iodesc) { diff --git a/src/clib/core/pio_file.cpp b/src/clib/core/pio_file.cpp index f9e7e822aa..8e9cb48e89 100644 --- a/src/clib/core/pio_file.cpp +++ b/src/clib/core/pio_file.cpp @@ -37,7 +37,6 @@ * @param mode : The netcdf mode for the open operation * @return 0 for success, error code otherwise. * @ingroup PIO_openfile - * @author Jim Edwards, Ed Hartnett */ int PIOc_openfile_impl(int iosysid, int *ncidp, int *iotype, const char *filename, int mode) @@ -62,7 +61,6 @@ int PIOc_openfile_impl(int iosysid, int *ncidp, int *iotype, const char *filenam * @param mode : The netcdf mode for the open operation * @return 0 for success, error code otherwise. * @ingroup PIO_openfile - * @author Ed Hartnett */ int PIOc_openfile2_impl(int iosysid, int *ncidp, int *iotype, const char *filename, int mode) @@ -81,7 +79,6 @@ int PIOc_openfile2_impl(int iosysid, int *ncidp, int *iotype, const char *filena * @param ncidp pointer to int where ncid will go * @return 0 for success, error code otherwise. * @ingroup PIO_openfile - * @author Ed Hartnett */ int PIOc_open_impl(int iosysid, const char *path, int mode, int *ncidp) { @@ -136,7 +133,6 @@ int PIOc_open_impl(int iosysid, const char *path, int mode, int *ncidp) * @param mode The netcdf mode for the create operation. * @returns 0 for success, error code otherwise. * @ingroup PIO_createfile - * @author Jim Edwards, Ed Hartnett */ int PIOc_createfile_impl(int iosysid, int *ncidp, const int *iotype, const char *filename, int mode) @@ -225,7 +221,6 @@ int PIOc_createfile_impl(int iosysid, int *ncidp, const int *iotype, const char * @param ncidp : A pio file descriptor (output) * @return 0 for success, error code otherwise. * @ingroup PIO_create - * @author Ed Hartnett */ int PIOc_create_impl(int iosysid, const char *filename, int cmode, int *ncidp) { @@ -876,7 +871,6 @@ int spio_soft_closefile(iosystem_desc_t *ios, file_desc_t *file) * * @param ncid: the file pointer * @returns PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_closefile_impl(int ncid) { @@ -1052,7 +1046,6 @@ int PIOc_closefile_impl(int ncid) * @param iosysid a pio system handle. * @param filename a filename. * @returns PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_deletefile_impl(int iosysid, const char *filename) { @@ -1167,7 +1160,6 @@ int PIOc_deletefile_impl(int iosysid, const char *filename) * * @param ncid the ncid of the file to sync. * @returns PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_sync_impl(int ncid) { diff --git a/src/clib/core/pio_get_nc.cpp b/src/clib/core/pio_get_nc.cpp index 854a08532c..6de4e073d2 100644 --- a/src/clib/core/pio_get_nc.cpp +++ b/src/clib/core/pio_get_nc.cpp @@ -2,10 +2,7 @@ * @file * PIO functions to get data (excluding varm functions). * - * @author Ed Hartnett - * @date 2016 * - * @see http://code.google.com/p/parallelio/ */ #include @@ -31,7 +28,6 @@ * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vars_text_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, char *buf) @@ -58,7 +54,6 @@ int PIOc_get_vars_text_impl(int ncid, int varid, const PIO_Offset *start, const * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vars_uchar_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, unsigned char *buf) @@ -85,7 +80,6 @@ int PIOc_get_vars_uchar_impl(int ncid, int varid, const PIO_Offset *start, * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vars_schar_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, signed char *buf) @@ -113,7 +107,6 @@ int PIOc_get_vars_schar_impl(int ncid, int varid, const PIO_Offset *start, * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vars_ushort_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, unsigned short *buf) @@ -140,7 +133,6 @@ int PIOc_get_vars_ushort_impl(int ncid, int varid, const PIO_Offset *start, * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vars_short_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, short *buf) @@ -167,7 +159,6 @@ int PIOc_get_vars_short_impl(int ncid, int varid, const PIO_Offset *start, * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vars_uint_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, unsigned int *buf) @@ -194,7 +185,6 @@ int PIOc_get_vars_uint_impl(int ncid, int varid, const PIO_Offset *start, * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vars_int_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, int *buf) @@ -221,7 +211,6 @@ int PIOc_get_vars_int_impl(int ncid, int varid, const PIO_Offset *start, const P * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vars_long_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, long *buf) @@ -248,7 +237,6 @@ int PIOc_get_vars_long_impl(int ncid, int varid, const PIO_Offset *start, * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vars_float_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, float *buf) @@ -276,7 +264,6 @@ int PIOc_get_vars_float_impl(int ncid, int varid, const PIO_Offset *start, * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vars_double_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, double *buf) @@ -304,7 +291,6 @@ int PIOc_get_vars_double_impl(int ncid, int varid, const PIO_Offset *start, * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vars_ulonglong_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, @@ -332,7 +318,6 @@ int PIOc_get_vars_ulonglong_impl(int ncid, int varid, const PIO_Offset *start, * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vars_longlong_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, long long *buf) @@ -356,7 +341,6 @@ int PIOc_get_vars_longlong_impl(int ncid, int varid, const PIO_Offset *start, * the variable will be used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vara_text_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, char *buf) @@ -380,7 +364,6 @@ int PIOc_get_vara_text_impl(int ncid, int varid, const PIO_Offset *start, * the variable will be used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vara_uchar_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, unsigned char *buf) @@ -404,7 +387,6 @@ int PIOc_get_vara_uchar_impl(int ncid, int varid, const PIO_Offset *start, * the variable will be used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vara_schar_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, signed char *buf) @@ -429,7 +411,6 @@ int PIOc_get_vara_schar_impl(int ncid, int varid, const PIO_Offset *start, * the variable will be used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vara_ushort_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, unsigned short *buf) @@ -453,7 +434,6 @@ int PIOc_get_vara_ushort_impl(int ncid, int varid, const PIO_Offset *start, * the variable will be used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vara_short_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, short *buf) @@ -477,7 +457,6 @@ int PIOc_get_vara_short_impl(int ncid, int varid, const PIO_Offset *start, * the variable will be used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vara_long_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, long *buf) @@ -501,7 +480,6 @@ int PIOc_get_vara_long_impl(int ncid, int varid, const PIO_Offset *start, * the variable will be used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vara_uint_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, unsigned int *buf) @@ -525,7 +503,6 @@ int PIOc_get_vara_uint_impl(int ncid, int varid, const PIO_Offset *start, * the variable will be used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vara_int_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, int *buf) @@ -549,7 +526,6 @@ int PIOc_get_vara_int_impl(int ncid, int varid, const PIO_Offset *start, * the variable will be used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vara_float_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, float *buf) @@ -573,7 +549,6 @@ int PIOc_get_vara_float_impl(int ncid, int varid, const PIO_Offset *start, * the variable will be used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vara_double_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, double *buf) @@ -598,7 +573,6 @@ int PIOc_get_vara_double_impl(int ncid, int varid, const PIO_Offset *start, * the variable will be used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vara_ulonglong_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, unsigned long long *buf) @@ -622,7 +596,6 @@ int PIOc_get_vara_ulonglong_impl(int ncid, int varid, const PIO_Offset *start, * the variable will be used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vara_longlong_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, long long *buf) @@ -640,7 +613,6 @@ int PIOc_get_vara_longlong_impl(int ncid, int varid, const PIO_Offset *start, * @param varid the variable ID number * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var_text_impl(int ncid, int varid, char *buf) { @@ -657,7 +629,6 @@ int PIOc_get_var_text_impl(int ncid, int varid, char *buf) * @param varid the variable ID number * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var_uchar_impl(int ncid, int varid, unsigned char *buf) { @@ -674,7 +645,6 @@ int PIOc_get_var_uchar_impl(int ncid, int varid, unsigned char *buf) * @param varid the variable ID number * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var_schar_impl(int ncid, int varid, signed char *buf) { @@ -691,7 +661,6 @@ int PIOc_get_var_schar_impl(int ncid, int varid, signed char *buf) * @param varid the variable ID number * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var_ushort_impl(int ncid, int varid, unsigned short *buf) { @@ -708,7 +677,6 @@ int PIOc_get_var_ushort_impl(int ncid, int varid, unsigned short *buf) * @param varid the variable ID number * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var_short_impl(int ncid, int varid, short *buf) { @@ -725,7 +693,6 @@ int PIOc_get_var_short_impl(int ncid, int varid, short *buf) * @param varid the variable ID number * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var_uint_impl(int ncid, int varid, unsigned int *buf) { @@ -742,7 +709,6 @@ int PIOc_get_var_uint_impl(int ncid, int varid, unsigned int *buf) * @param varid the variable ID number * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var_int_impl(int ncid, int varid, int *buf) { @@ -759,7 +725,6 @@ int PIOc_get_var_int_impl(int ncid, int varid, int *buf) * @param varid the variable ID number * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var_long_impl(int ncid, int varid, long *buf) { @@ -776,7 +741,6 @@ int PIOc_get_var_long_impl(int ncid, int varid, long *buf) * @param varid the variable ID number * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var_float_impl(int ncid, int varid, float *buf) { @@ -793,7 +757,6 @@ int PIOc_get_var_float_impl(int ncid, int varid, float *buf) * @param varid the variable ID number * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var_double_impl(int ncid, int varid, double *buf) { @@ -810,7 +773,6 @@ int PIOc_get_var_double_impl(int ncid, int varid, double *buf) * @param varid the variable ID number * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var_ulonglong_impl(int ncid, int varid, unsigned long long *buf) { @@ -827,7 +789,6 @@ int PIOc_get_var_ulonglong_impl(int ncid, int varid, unsigned long long *buf) * @param varid the variable ID number * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var_longlong_impl(int ncid, int varid, long long *buf) { @@ -847,7 +808,6 @@ int PIOc_get_var_longlong_impl(int ncid, int varid, long long *buf) * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var1_text_impl(int ncid, int varid, const PIO_Offset *index, char *buf) { @@ -867,7 +827,6 @@ int PIOc_get_var1_text_impl(int ncid, int varid, const PIO_Offset *index, char * * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var1_uchar_impl(int ncid, int varid, const PIO_Offset *index, unsigned char *buf) { @@ -887,7 +846,6 @@ int PIOc_get_var1_uchar_impl(int ncid, int varid, const PIO_Offset *index, unsig * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var1_schar_impl(int ncid, int varid, const PIO_Offset *index, signed char *buf) { @@ -907,7 +865,6 @@ int PIOc_get_var1_schar_impl(int ncid, int varid, const PIO_Offset *index, signe * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var1_ushort_impl(int ncid, int varid, const PIO_Offset *index, unsigned short *buf) { @@ -927,7 +884,6 @@ int PIOc_get_var1_ushort_impl(int ncid, int varid, const PIO_Offset *index, unsi * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var1_short_impl(int ncid, int varid, const PIO_Offset *index, short *buf) { @@ -949,7 +905,6 @@ int PIOc_get_var1_short_impl(int ncid, int varid, const PIO_Offset *index, short * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var1_uint_impl(int ncid, int varid, const PIO_Offset *index, unsigned int *buf) { @@ -969,7 +924,6 @@ int PIOc_get_var1_uint_impl(int ncid, int varid, const PIO_Offset *index, unsign * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var1_long_impl(int ncid, int varid, const PIO_Offset *index, long *buf) { @@ -989,7 +943,6 @@ int PIOc_get_var1_long_impl(int ncid, int varid, const PIO_Offset *index, long * * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var1_int_impl(int ncid, int varid, const PIO_Offset *index, int *buf) { @@ -1009,7 +962,6 @@ int PIOc_get_var1_int_impl(int ncid, int varid, const PIO_Offset *index, int *bu * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var1_float_impl(int ncid, int varid, const PIO_Offset *index, float *buf) { @@ -1029,7 +981,6 @@ int PIOc_get_var1_float_impl(int ncid, int varid, const PIO_Offset *index, float * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var1_double_impl(int ncid, int varid, const PIO_Offset *index, double *buf) { @@ -1049,7 +1000,6 @@ int PIOc_get_var1_double_impl(int ncid, int varid, const PIO_Offset *index, doub * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var1_ulonglong_impl(int ncid, int varid, const PIO_Offset *index, unsigned long long *buf) @@ -1070,7 +1020,6 @@ int PIOc_get_var1_ulonglong_impl(int ncid, int varid, const PIO_Offset *index, * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var1_longlong_impl(int ncid, int varid, const PIO_Offset *index, long long *buf) @@ -1089,7 +1038,6 @@ int PIOc_get_var1_longlong_impl(int ncid, int varid, const PIO_Offset *index, * @param varid the variable ID number * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var_impl(int ncid, int varid, void *buf) { @@ -1110,7 +1058,6 @@ int PIOc_get_var_impl(int ncid, int varid, void *buf) * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_var1_impl(int ncid, int varid, const PIO_Offset *index, void *buf) { @@ -1134,7 +1081,6 @@ int PIOc_get_var1_impl(int ncid, int varid, const PIO_Offset *index, void *buf) * the variable will be used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vara_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, void *buf) @@ -1162,7 +1108,6 @@ int PIOc_get_vara_impl(int ncid, int varid, const PIO_Offset *start, const PIO_O * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_get_vars_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, void *buf) diff --git a/src/clib/core/pio_getput_int.cpp b/src/clib/core/pio_getput_int.cpp index 9f947ed6e9..43a9686db5 100644 --- a/src/clib/core/pio_getput_int.cpp +++ b/src/clib/core/pio_getput_int.cpp @@ -3,10 +3,7 @@ * Internal PIO functions to get and put attributes and data * (excluding varm functions). * - * @author Ed Hartnett - * @date 2016 * - * @see http://code.google.com/p/parallelio/ */ #include @@ -31,7 +28,6 @@ * @param len the length of the attribute array. * @param op a pointer with the attribute data. * @return PIO_NOERR for success, error code otherwise. - * @author Ed Hartnett */ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, PIO_Offset len, nc_type memtype, const void *op) @@ -569,7 +565,6 @@ int spio_put_att_tc(int ncid, int varid, const char *name, nc_type atttype, * of type memtype. * @param ip a pointer that will get the attribute value. * @return PIO_NOERR for success, error code otherwise. - * @author Ed Hartnett */ int spio_get_att_tc(int ncid, int varid, const char *name, nc_type memtype, void *ip) { @@ -992,7 +987,6 @@ int spio_get_att_tc(int ncid, int varid, const char *name, nc_type memtype, void * will be used. Use special PIO_LONG_INTERNAL for _long() functions. * @param buf pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, nc_type xtype, void *buf) @@ -2223,7 +2217,6 @@ int spio_get_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off * @param xtype the netcdf type of the variable. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int spio_get_var1_tc(int ncid, int varid, const PIO_Offset *index, nc_type xtype, void *buf) @@ -2270,7 +2263,6 @@ int spio_get_var1_tc(int ncid, int varid, const PIO_Offset *index, nc_type xtype * @param xtype the netcdf type of the variable. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int spio_get_var_tc(int ncid, int varid, nc_type xtype, void *buf) { @@ -2371,7 +2363,6 @@ int spio_get_var_tc(int ncid, int varid, nc_type xtype, void *buf) * @param buf pointer to the data to be written. * * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, nc_type xtype, const void *buf) @@ -3439,7 +3430,6 @@ int spio_put_vars_tc(int ncid, int varid, const PIO_Offset *start, const PIO_Off * @param op pointer to the data to be written. * * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int spio_put_var1_tc(int ncid, int varid, const PIO_Offset *index, nc_type xtype, const void *op) @@ -3496,7 +3486,6 @@ int spio_put_var1_tc(int ncid, int varid, const PIO_Offset *index, nc_type xtype * @param op pointer to the data to be written. * * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int spio_put_var_tc(int ncid, int varid, nc_type xtype, const void *op) { diff --git a/src/clib/core/pio_msg.cpp b/src/clib/core/pio_msg.cpp index 648da01c5c..8337f62e1f 100644 --- a/src/clib/core/pio_msg.cpp +++ b/src/clib/core/pio_msg.cpp @@ -5,7 +5,6 @@ * messages from the computation nodes, and responds to messages by * running the appropriate netCDF function. * - * @author Ed Hartnett */ #include @@ -1076,7 +1075,6 @@ int recv_async_msg(iosystem_desc_t *ios, int msg, ...) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int inq_type_handler(iosystem_desc_t *ios) { @@ -1126,7 +1124,6 @@ int inq_type_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int inq_format_handler(iosystem_desc_t *ios) { @@ -1172,7 +1169,6 @@ int inq_format_handler(iosystem_desc_t *ios) * @param ios pointer to the iosystem info. * @returns 0 for success, error code otherwise. * @internal - * @author Ed Hartnett */ int set_fill_handler(iosystem_desc_t *ios) { @@ -1220,7 +1216,6 @@ int set_fill_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int create_file_handler(iosystem_desc_t *ios) { @@ -1261,7 +1256,6 @@ int create_file_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int close_file_handler(iosystem_desc_t *ios) { @@ -1301,7 +1295,6 @@ int close_file_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int inq_handler(iosystem_desc_t *ios) { @@ -1357,7 +1350,6 @@ int inq_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int inq_unlimdims_handler(iosystem_desc_t *ios) { @@ -1409,7 +1401,6 @@ int inq_unlimdims_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int inq_dim_handler(iosystem_desc_t *ios, int msg) { @@ -1460,7 +1451,6 @@ int inq_dim_handler(iosystem_desc_t *ios, int msg) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int inq_dimid_handler(iosystem_desc_t *ios) { @@ -1507,7 +1497,6 @@ int inq_dimid_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int inq_att_handler(iosystem_desc_t *ios) { @@ -1557,7 +1546,6 @@ int inq_att_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int inq_attname_handler(iosystem_desc_t *ios) { @@ -1605,7 +1593,6 @@ int inq_attname_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int inq_attid_handler(iosystem_desc_t *ios) { @@ -1652,7 +1639,6 @@ int inq_attid_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int att_put_handler(iosystem_desc_t *ios) { @@ -1709,7 +1695,6 @@ int att_put_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Jayesh Krishna */ int att_copy_handler(iosystem_desc_t *ios) { @@ -1751,7 +1736,6 @@ int att_copy_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int att_get_handler(iosystem_desc_t *ios) { @@ -1813,7 +1797,6 @@ int att_get_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int put_vars_handler(iosystem_desc_t *ios) { @@ -1933,7 +1916,6 @@ int put_vars_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int get_vars_handler(iosystem_desc_t *ios) { @@ -2328,7 +2310,6 @@ int inq_var_deflate_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int inq_varid_handler(iosystem_desc_t *ios) { @@ -2366,7 +2347,6 @@ int inq_varid_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int sync_file_handler(iosystem_desc_t *ios) { @@ -2405,7 +2385,6 @@ int sync_file_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int setframe_handler(iosystem_desc_t *ios) { @@ -2447,7 +2426,6 @@ int setframe_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int advanceframe_handler(iosystem_desc_t *ios) { @@ -2487,7 +2465,6 @@ int advanceframe_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int change_def_file_handler(iosystem_desc_t *ios, int msg) { @@ -2530,7 +2507,6 @@ int change_def_file_handler(iosystem_desc_t *ios, int msg) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int def_var_handler(iosystem_desc_t *ios) { @@ -2805,7 +2781,6 @@ int set_var_chunk_cache_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int def_dim_handler(iosystem_desc_t *ios) { @@ -2848,7 +2823,6 @@ int def_dim_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int rename_dim_handler(iosystem_desc_t *ios) { @@ -2892,7 +2866,6 @@ int rename_dim_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int rename_var_handler(iosystem_desc_t *ios) { @@ -2936,7 +2909,6 @@ int rename_var_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int rename_att_handler(iosystem_desc_t *ios) { @@ -2980,7 +2952,6 @@ int rename_att_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int delete_att_handler(iosystem_desc_t *ios) { @@ -3024,7 +2995,6 @@ int delete_att_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int open_file_handler(iosystem_desc_t *ios) { @@ -3070,7 +3040,6 @@ int open_file_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int delete_file_handler(iosystem_desc_t *ios) { @@ -3191,7 +3160,6 @@ int initdecomp_dof_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int write_darray_multi_handler(iosystem_desc_t *ios) { @@ -3297,7 +3265,6 @@ int write_darray_multi_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int readdarray_handler(iosystem_desc_t *ios) { @@ -3336,7 +3303,6 @@ int readdarray_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int seterrorhandling_handler(iosystem_desc_t *ios) { @@ -3382,7 +3348,6 @@ int seterrorhandling_handler(iosystem_desc_t *ios) * @param ios pointer to the iosystem_desc_t data. * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. - * @author Ed Hartnett */ int set_chunk_cache_handler(iosystem_desc_t *ios) { @@ -3426,7 +3391,6 @@ int set_chunk_cache_handler(iosystem_desc_t *ios) * @param ios pointer to the iosystem_desc_t data. * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. - * @author Ed Hartnett */ int get_chunk_cache_handler(iosystem_desc_t *ios) { @@ -3480,7 +3444,6 @@ int get_chunk_cache_handler(iosystem_desc_t *ios) * @param ios pointer to the iosystem_desc_t data. * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. - * @author Ed Hartnett */ int get_var_chunk_cache_handler(iosystem_desc_t *ios) { @@ -3533,7 +3496,6 @@ int get_var_chunk_cache_handler(iosystem_desc_t *ios) * @param ios pointer to the iosystem_desc_t data. * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. - * @author Ed Hartnett */ int freedecomp_handler(iosystem_desc_t *ios) { @@ -3574,7 +3536,6 @@ int freedecomp_handler(iosystem_desc_t *ios) * @returns 0 for success, PIO_EIO for MPI Bcast errors, or error code * from netCDF base function. * @internal - * @author Ed Hartnett */ int finalize_handler(iosystem_desc_t *ios, int index) { @@ -3616,7 +3577,6 @@ int finalize_handler(iosystem_desc_t *ios, int index) * @param iosys pointer to pointer to iosystem info * @param io_comm MPI communicator for IO * @returns 0 for success, error code otherwise. - * @author Ed Hartnett */ int pio_msg_handler2(int io_rank, int component_count, iosystem_desc_t **iosys, MPI_Comm io_comm) diff --git a/src/clib/core/pio_nc.cpp b/src/clib/core/pio_nc.cpp index 93703e9437..8b7fe03d7e 100644 --- a/src/clib/core/pio_nc.cpp +++ b/src/clib/core/pio_nc.cpp @@ -11,8 +11,6 @@ * tasks (io_comm). Each routine must be called collectively from * union_comm. * - * @author Jim Edwards (jedwards@ucar.edu), Ed Hartnett - * @date Feburary 2014, April 2016 */ #include #include @@ -86,7 +84,6 @@ int get_adios2_type_size(adios2_type type, const void *var) * * @return PIO_NOERR for success, error code otherwise. See * PIOc_Set_File_Error_Handling - * @author Jim Edwards, Ed Hartnett */ int PIOc_inq_impl(int ncid, int *ndimsp, int *nvarsp, int *ngattsp, int *unlimdimidp) { @@ -296,7 +293,6 @@ int PIOc_inq_impl(int ncid, int *ndimsp, int *nvarsp, int *ngattsp, int *unlimdi * @param ncid the ncid of the open file. * @param ndimsp a pointer that will get the number of dimensions. * @returns 0 for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_inq_ndims_impl(int ncid, int *ndimsp) { @@ -311,7 +307,6 @@ int PIOc_inq_ndims_impl(int ncid, int *ndimsp) * @param ncid the ncid of the open file. * @param nvarsp a pointer that will get the number of variables. * @returns 0 for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_inq_nvars_impl(int ncid, int *nvarsp) { @@ -325,7 +320,6 @@ int PIOc_inq_nvars_impl(int ncid, int *nvarsp) * @param ncid the ncid of the open file. * @param nattsp a pointer that will get the number of attributes. * @returns 0 for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_inq_natts_impl(int ncid, int *ngattsp) { @@ -340,7 +334,6 @@ int PIOc_inq_natts_impl(int ncid, int *ngattsp) * @param unlimdimidp a pointer that will the ID of the unlimited * dimension, or -1 if there is no unlimited dimension. * @returns 0 for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_inq_unlimdim_impl(int ncid, int *unlimdimidp) { @@ -359,7 +352,6 @@ int PIOc_inq_unlimdim_impl(int ncid, int *unlimdimidp) * dimension IDs. * @returns 0 for success, error code otherwise. * @ingroup PIO_inq_unlimdim - * @author Jim Edwards, Ed Hartnett */ int PIOc_inq_unlimdims_impl(int ncid, int *nunlimdimsp, int *unlimdimidsp) { @@ -527,7 +519,6 @@ int PIOc_inq_unlimdims_impl(int ncid, int *nunlimdimsp, int *unlimdimidsp) * @param name pointer that will get the name of the type. * @param sizep pointer that will get the size of the type in bytes. * @returns 0 for success, error code otherwise. - * @author Ed Hartnett */ int PIOc_inq_type_impl(int ncid, nc_type xtype, char *name, PIO_Offset *sizep) { @@ -684,7 +675,6 @@ int PIOc_inq_type_impl(int ncid, nc_type xtype, char *name, PIO_Offset *sizep) * @param ncid the ncid of an open file. * @param formatp a pointer that will get the format. * @returns 0 for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_inq_format_impl(int ncid, int *formatp) { @@ -785,7 +775,6 @@ int PIOc_inq_format_impl(int ncid, int *formatp) * PIOc_openfile() or PIOc_createfile(). * @param lenp a pointer that will get the number of values * @return PIO_NOERR for success, error code otherwise. See PIOc_Set_File_Error_Handling - * @author Jim Edwards, Ed Hartnett */ int PIOc_inq_dim_impl(int ncid, int dimid, char *name, PIO_Offset *lenp) { @@ -985,7 +974,6 @@ int PIOc_inq_dim_impl(int ncid, int dimid, char *name, PIO_Offset *lenp) * @param name a pointer that gets the name of the dimension. Igorned * if NULL. * @returns 0 for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_inq_dimname_impl(int ncid, int dimid, char *name) { @@ -1002,7 +990,6 @@ int PIOc_inq_dimname_impl(int ncid, int dimid, char *name) * @param lenp a pointer that gets the length of the dimension. Igorned * if NULL. * @returns 0 for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_inq_dimlen_impl(int ncid, int dimid, PIO_Offset *lenp) { @@ -1022,7 +1009,6 @@ int PIOc_inq_dimlen_impl(int ncid, int dimid, PIO_Offset *lenp) * PIOc_openfile() or PIOc_createfile(). * @param idp a pointer that will get the id of the variable or attribute. * @return PIO_NOERR for success, error code otherwise. See PIOc_Set_File_Error_Handling - * @author Jim Edwards, Ed Hartnett */ int PIOc_inq_dimid_impl(int ncid, const char *name, int *idp) { @@ -1204,7 +1190,6 @@ int PIOc_inq_dimid_impl(int ncid, const char *name, int *idp) * @param xtypep a pointer that will get the type of the attribute. * @param nattsp a pointer that will get the number of attributes * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_inq_var_impl(int ncid, int varid, char *name, int namelen, nc_type *xtypep, int *ndimsp, int *dimidsp, int *nattsp) @@ -1593,7 +1578,6 @@ int PIOc_inq_var_impl(int ncid, int varid, char *name, int namelen, nc_type *xty * @param name a pointer that will get the variable name. * @param namelen the size of the user buffer pointed by name. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_inq_varname_impl(int ncid, int varid, char *name, int namelen) { @@ -1609,7 +1593,6 @@ int PIOc_inq_varname_impl(int ncid, int varid, char *name, int namelen) * @param xtypep a pointer that will get the type of the * attribute. Ignored if NULL. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_inq_vartype_impl(int ncid, int varid, nc_type *xtypep) { @@ -1625,7 +1608,6 @@ int PIOc_inq_vartype_impl(int ncid, int varid, nc_type *xtypep) * @param ndimsp a pointer that will get the number of * dimensions. Ignored if NULL. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_inq_varndims_impl(int ncid, int varid, int *ndimsp) { @@ -1641,7 +1623,6 @@ int PIOc_inq_varndims_impl(int ncid, int varid, int *ndimsp) * @param dimidsp a pointer that will get an array of dimids. Ignored * if NULL. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_inq_vardimid_impl(int ncid, int varid, int *dimidsp) { @@ -1657,7 +1638,6 @@ int PIOc_inq_vardimid_impl(int ncid, int varid, int *dimidsp) * @param nattsp a pointer that will get the number of attriburtes. Ignored * if NULL. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_inq_varnatts_impl(int ncid, int varid, int *nattsp) { @@ -1678,7 +1658,6 @@ int PIOc_inq_varnatts_impl(int ncid, int varid, int *nattsp) * @param varid the variable ID. * @param varidp a pointer that will get the variable id * @return PIO_NOERR for success, error code otherwise. See PIOc_Set_File_Error_Handling - * @author Jim Edwards, Ed Hartnett */ int PIOc_inq_varid_impl(int ncid, const char *name, int *varidp) { @@ -1895,7 +1874,6 @@ int PIOc_inq_varid_impl(int ncid, const char *name, int *varidp) * @param xtypep a pointer that will get the type of the attribute. * @param lenp a pointer that will get the number of values * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_inq_att_impl(int ncid, int varid, const char *name, nc_type *xtypep, PIO_Offset *lenp) @@ -2084,7 +2062,6 @@ int PIOc_inq_att_impl(int ncid, int varid, const char *name, nc_type *xtypep, * @param lenp a pointer that gets the lenght of the attribute * array. Ignored if NULL. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_inq_attlen_impl(int ncid, int varid, const char *name, PIO_Offset *lenp) { @@ -2101,7 +2078,6 @@ int PIOc_inq_attlen_impl(int ncid, int varid, const char *name, PIO_Offset *lenp * @param xtypep a pointer that gets the type of the * attribute. Ignored if NULL. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_inq_atttype_impl(int ncid, int varid, const char *name, nc_type *xtypep) { @@ -2122,7 +2098,6 @@ int PIOc_inq_atttype_impl(int ncid, int varid, const char *name, nc_type *xtypep * @param varid the variable ID. * @param attnum the attribute ID. * @return PIO_NOERR for success, error code otherwise. See PIOc_Set_File_Error_Handling - * @author Jim Edwards, Ed Hartnett */ int PIOc_inq_attname_impl(int ncid, int varid, int attnum, char *name) { @@ -2295,7 +2270,6 @@ int PIOc_inq_attname_impl(int ncid, int varid, int attnum, char *name) * @param varid the variable ID. * @param idp a pointer that will get the id of the variable or attribute. * @return PIO_NOERR for success, error code otherwise. See PIOc_Set_File_Error_Handling - * @author Jim Edwards, Ed Hartnett */ int PIOc_inq_attid_impl(int ncid, int varid, const char *name, int *idp) { @@ -2465,7 +2439,6 @@ int PIOc_inq_attid_impl(int ncid, int varid, const char *name, int *idp) * @param ncid the ncid of the open file, obtained from * PIOc_openfile() or PIOc_createfile(). * @return PIO_NOERR for success, error code otherwise. See PIOc_Set_File_Error_Handling - * @author Jim Edwards, Ed Hartnett */ int PIOc_rename_dim_impl(int ncid, int dimid, const char *name) { @@ -2566,7 +2539,6 @@ int PIOc_rename_dim_impl(int ncid, int dimid, const char *name) * PIOc_openfile() or PIOc_createfile(). * @param varid the variable ID. * @return PIO_NOERR for success, error code otherwise. See PIOc_Set_File_Error_Handling - * @author Jim Edwards, Ed Hartnett */ int PIOc_rename_var_impl(int ncid, int varid, const char *name) { @@ -2668,7 +2640,6 @@ int PIOc_rename_var_impl(int ncid, int varid, const char *name) * @param varid the variable ID. * @return PIO_NOERR for success, error code otherwise. See * PIOc_Set_File_Error_Handling - * @author Jim Edwards, Ed Hartnett */ int PIOc_rename_att_impl(int ncid, int varid, const char *name, const char *newname) @@ -2779,7 +2750,6 @@ int PIOc_rename_att_impl(int ncid, int varid, const char *name, * @param varid the variable ID. * @param name of the attribute to delete. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_del_att_impl(int ncid, int varid, const char *name) { @@ -2880,7 +2850,6 @@ int PIOc_del_att_impl(int ncid, int varid, const char *name) * @param old_modep a pointer to an int that gets the old setting. * @return PIO_NOERR for success, error code otherwise. * @ingroup PIO_set_fill - * @author Jim Edwards, Ed Hartnett */ int PIOc_set_fill_impl(int ncid, int fillmode, int *old_modep) { @@ -3001,7 +2970,6 @@ int PIOc_set_fill_impl(int ncid, int fillmode, int *old_modep) * @param ncid the ncid of the open file, obtained from * PIOc_openfile() or PIOc_createfile(). * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_enddef_impl(int ncid) { @@ -3218,7 +3186,6 @@ int PIOc_enddef_impl(int ncid) * @param ncid the ncid of the open file, obtained from * PIOc_openfile() or PIOc_createfile(). * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_redef_impl(int ncid) { @@ -3326,7 +3293,6 @@ int PIOc_redef_impl(int ncid) * PIOc_openfile() or PIOc_createfile(). * @param idp a pointer that will get the id of the variable or attribute. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_def_dim_impl(int ncid, const char *name, PIO_Offset len, int *idp) { @@ -3569,7 +3535,6 @@ int PIOc_def_dim_impl(int ncid, const char *name, PIO_Offset len, int *idp) * @param varidp a pointer that will get the variable id * @return PIO_NOERR for success, error code otherwise. * @ingroup PIO_def_var - * @author Jim Edwards, Ed Hartnett */ int PIOc_def_var_impl(int ncid, const char *name, nc_type xtype, int ndims, const int *dimidsp, int *varidp) @@ -4110,7 +4075,6 @@ int PIOc_def_var_impl(int ncid, const char *name, nc_type xtype, int ndims, * @param fill_value pointer to the fill value to be used if fill_mode is set to NC_FILL. * @return PIO_NOERR for success, otherwise an error code. * @ingroup PIO_def_var - * @author Jim Edwards, Ed Hartnett */ int PIOc_def_var_fill_impl(int ncid, int varid, int fill_mode, const void *fill_valuep) { @@ -4277,7 +4241,6 @@ int PIOc_def_var_fill_impl(int ncid, int varid, int fill_mode, const void *fill_ * this variable. Ignored if NULL. * @return PIO_NOERR for success, error code otherwise. * @ingroup PIO_inq_var_fill - * @author Jim Edwards, Ed Hartnett */ int PIOc_inq_var_fill_impl(int ncid, int varid, int *no_fill, void *fill_valuep) { @@ -4485,7 +4448,6 @@ int PIOc_inq_var_fill_impl(int ncid, int varid, int *no_fill, void *fill_valuep) * @param ip a pointer that will get the attribute value. * @return PIO_NOERR for success, error code otherwise. * @ingroup PIO_get_att - * @author Jim Edwards, Ed Hartnett */ int PIOc_get_att_impl(int ncid, int varid, const char *name, void *ip) { @@ -4543,7 +4505,6 @@ int PIOc_get_att_impl(int ncid, int varid, const char *name, void *ip) * @param len the length of the attribute array. * @param op a pointer with the attribute data. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_put_att_impl(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const void *op) @@ -4564,7 +4525,6 @@ int PIOc_put_att_impl(int ncid, int varid, const char *name, nc_type xtype, * @param name the name of the attribute to get * @param ip a pointer that will get the attribute value. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_get_att_double_impl(int ncid, int varid, const char *name, double *ip) { @@ -4584,7 +4544,6 @@ int PIOc_get_att_double_impl(int ncid, int varid, const char *name, double *ip) * @param name the name of the attribute to get * @param ip a pointer that will get the attribute value. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_get_att_uchar_impl(int ncid, int varid, const char *name, unsigned char *ip) { @@ -4604,7 +4563,6 @@ int PIOc_get_att_uchar_impl(int ncid, int varid, const char *name, unsigned char * @param name the name of the attribute to get * @param ip a pointer that will get the attribute value. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_get_att_ushort_impl(int ncid, int varid, const char *name, unsigned short *ip) { @@ -4624,7 +4582,6 @@ int PIOc_get_att_ushort_impl(int ncid, int varid, const char *name, unsigned sho * @param ip a pointer that will get the attribute value. * @return PIO_NOERR for success, error code otherwise. * @ingroup PIO_get_att - * @author Jim Edwards, Ed Hartnett */ int PIOc_get_att_uint_impl(int ncid, int varid, const char *name, unsigned int *ip) { @@ -4644,7 +4601,6 @@ int PIOc_get_att_uint_impl(int ncid, int varid, const char *name, unsigned int * * @param name the name of the attribute to get * @param ip a pointer that will get the attribute value. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_get_att_long_impl(int ncid, int varid, const char *name, long *ip) { @@ -4666,7 +4622,6 @@ int PIOc_get_att_long_impl(int ncid, int varid, const char *name, long *ip) * @param ip a pointer that will get the attribute value. * @return PIO_NOERR for success, error code otherwise. * @ingroup PIO_get_att - * @author Jim Edwards, Ed Hartnett */ int PIOc_get_att_text_impl(int ncid, int varid, const char *name, char *ip) { @@ -4686,7 +4641,6 @@ int PIOc_get_att_text_impl(int ncid, int varid, const char *name, char *ip) * @param name the name of the attribute to get * @param ip a pointer that will get the attribute value. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_get_att_schar_impl(int ncid, int varid, const char *name, signed char *ip) { @@ -4706,7 +4660,6 @@ int PIOc_get_att_schar_impl(int ncid, int varid, const char *name, signed char * * @param name the name of the attribute to get * @param ip a pointer that will get the attribute value. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_get_att_ulonglong_impl(int ncid, int varid, const char *name, unsigned long long *ip) { @@ -4726,7 +4679,6 @@ int PIOc_get_att_ulonglong_impl(int ncid, int varid, const char *name, unsigned * @param name the name of the attribute to get * @param ip a pointer that will get the attribute value. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_get_att_short_impl(int ncid, int varid, const char *name, short *ip) { @@ -4746,7 +4698,6 @@ int PIOc_get_att_short_impl(int ncid, int varid, const char *name, short *ip) * @param name the name of the attribute to get * @param ip a pointer that will get the attribute value. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_get_att_int_impl(int ncid, int varid, const char *name, int *ip) { @@ -4766,7 +4717,6 @@ int PIOc_get_att_int_impl(int ncid, int varid, const char *name, int *ip) * @param name the name of the attribute to get * @param ip a pointer that will get the attribute value. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_get_att_longlong_impl(int ncid, int varid, const char *name, long long *ip) { @@ -4786,7 +4736,6 @@ int PIOc_get_att_longlong_impl(int ncid, int varid, const char *name, long long * @param name the name of the attribute to get * @param ip a pointer that will get the attribute value. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_get_att_float_impl(int ncid, int varid, const char *name, float *ip) { @@ -4808,7 +4757,6 @@ int PIOc_get_att_float_impl(int ncid, int varid, const char *name, float *ip) * @param len the length of the attribute array. * @param op a pointer with the attribute data. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_put_att_schar_impl(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const signed char *op) @@ -4831,7 +4779,6 @@ int PIOc_put_att_schar_impl(int ncid, int varid, const char *name, nc_type xtype * @param len the length of the attribute array. * @param op a pointer with the attribute data. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_put_att_long_impl(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const long *op) @@ -4854,7 +4801,6 @@ int PIOc_put_att_long_impl(int ncid, int varid, const char *name, nc_type xtype, * @param len the length of the attribute array. * @param op a pointer with the attribute data. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_put_att_int_impl(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const int *op) @@ -4877,7 +4823,6 @@ int PIOc_put_att_int_impl(int ncid, int varid, const char *name, nc_type xtype, * @param len the length of the attribute array. * @param op a pointer with the attribute data. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_put_att_uchar_impl(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const unsigned char *op) @@ -4900,7 +4845,6 @@ int PIOc_put_att_uchar_impl(int ncid, int varid, const char *name, nc_type xtype * @param len the length of the attribute array. * @param op a pointer with the attribute data. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_put_att_longlong_impl(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const long long *op) @@ -4923,7 +4867,6 @@ int PIOc_put_att_longlong_impl(int ncid, int varid, const char *name, nc_type xt * @param len the length of the attribute array. * @param op a pointer with the attribute data. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_put_att_uint_impl(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const unsigned int *op) @@ -4946,7 +4889,6 @@ int PIOc_put_att_uint_impl(int ncid, int varid, const char *name, nc_type xtype, * @param len the length of the attribute array. * @param op a pointer with the attribute data. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_put_att_float_impl(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const float *op) @@ -4969,7 +4911,6 @@ int PIOc_put_att_float_impl(int ncid, int varid, const char *name, nc_type xtype * @param len the length of the attribute array. * @param op a pointer with the attribute data. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_put_att_ulonglong_impl(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const unsigned long long *op) @@ -4992,7 +4933,6 @@ int PIOc_put_att_ulonglong_impl(int ncid, int varid, const char *name, nc_type x * @param len the length of the attribute array. * @param op a pointer with the attribute data. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_put_att_ushort_impl(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const unsigned short *op) @@ -5015,7 +4955,6 @@ int PIOc_put_att_ushort_impl(int ncid, int varid, const char *name, nc_type xtyp * @param len the length of the attribute array. * @param op a pointer with the attribute data. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_put_att_text_impl(int ncid, int varid, const char *name, PIO_Offset len, const char *op) @@ -5038,7 +4977,6 @@ int PIOc_put_att_text_impl(int ncid, int varid, const char *name, * @param len the length of the attribute array. * @param op a pointer with the attribute data. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_put_att_short_impl(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const short *op) @@ -5061,7 +4999,6 @@ int PIOc_put_att_short_impl(int ncid, int varid, const char *name, nc_type xtype * @param len the length of the attribute array. * @param op a pointer with the attribute data. * @return PIO_NOERR for success, error code otherwise. - * @author Jim Edwards, Ed Hartnett */ int PIOc_put_att_double_impl(int ncid, int varid, const char *name, nc_type xtype, PIO_Offset len, const double *op) @@ -5086,7 +5023,6 @@ int PIOc_put_att_double_impl(int ncid, int varid, const char *name, nc_type xtyp * @param ovarid the ID of the variable to copy the attribute * to in the output file. * @return PIO_NOERR for success, error code otherwise. - * @author Jayesh Krishna */ int PIOc_copy_att_impl(int incid, int ivarid, const char *name, int oncid, int ovarid) diff --git a/src/clib/core/pio_nc4.cpp b/src/clib/core/pio_nc4.cpp index 56ca7ec788..cd2d1f35b8 100644 --- a/src/clib/core/pio_nc4.cpp +++ b/src/clib/core/pio_nc4.cpp @@ -2,7 +2,6 @@ * * Functions to wrap netCDF-4 functions for PIO. * - * @author Ed Hartnett */ #include #include @@ -30,7 +29,6 @@ * compressed. * @return PIO_NOERR for success, otherwise an error code. * @ingroup PIO_def_var - * @author Ed Hartnett */ int PIOc_def_var_deflate_impl(int ncid, int varid, int shuffle, int deflate, int deflate_level) @@ -129,7 +127,6 @@ int PIOc_def_var_deflate_impl(int ncid, int varid, int shuffle, int deflate, * if NULL. * @return PIO_NOERR for success, otherwise an error code. * @ingroup PIO_inq_var - * @author Ed Hartnett */ int PIOc_inq_var_deflate_impl(int ncid, int varid, int *shufflep, int *deflatep, int *deflate_levelp) @@ -251,7 +248,6 @@ int PIOc_inq_var_deflate_impl(int ncid, int varid, int *shufflep, int *deflatep, * @param chunksizep an array of chunksizes. Must have a chunksize for * every variable dimension. * @return PIO_NOERR for success, otherwise an error code. - * @author Ed Hartnett */ int PIOc_def_var_chunking_impl(int ncid, int varid, int storage, const PIO_Offset *chunksizesp) { @@ -394,7 +390,6 @@ int PIOc_def_var_chunking_impl(int ncid, int varid, int storage, const PIO_Offse * dimensions. * @return PIO_NOERR for success, otherwise an error code. * @ingroup PIO_inq_var - * @author Ed Hartnett */ int PIOc_inq_var_chunking_impl(int ncid, int varid, int *storagep, PIO_Offset *chunksizesp) { @@ -551,7 +546,6 @@ int PIOc_inq_var_chunking_impl(int ncid, int varid, int *storagep, PIO_Offset *c * every variable dimension. * @return PIO_NOERR for success, otherwise an error code. * @ingroup PIO_def_var - * @author Ed Hartnett */ int PIOc_def_var_endian_impl(int ncid, int varid, int endian) { @@ -632,7 +626,6 @@ int PIOc_def_var_endian_impl(int ncid, int varid, int endian) * endianness. Ignored if NULL. * @return PIO_NOERR for success, otherwise an error code. * @ingroup PIO_inq_var - * @author Ed Hartnett */ int PIOc_inq_var_endian_impl(int ncid, int varid, int *endianp) { @@ -734,7 +727,6 @@ int PIOc_inq_var_endian_impl(int ncid, int varid, int *endianp) * @param preemption preemption setting for file cache. * @return PIO_NOERR for success, otherwise an error code. * @ingroup PIO_def_var - * @author Ed Hartnett */ int PIOc_set_chunk_cache_impl(int iosysid, int iotype, PIO_Offset size, PIO_Offset nelems, float preemption) @@ -831,7 +823,6 @@ int PIOc_set_chunk_cache_impl(int iosysid, int iotype, PIO_Offset size, PIO_Offs * @param preemptionp gets the preemption setting for file cache. * @return PIO_NOERR for success, otherwise an error code. * @ingroup PIO_def_var - * @author Ed Hartnett */ int PIOc_get_chunk_cache_impl(int iosysid, int iotype, PIO_Offset *sizep, PIO_Offset *nelemsp, float *preemptionp) @@ -953,7 +944,6 @@ int PIOc_get_chunk_cache_impl(int iosysid, int iotype, PIO_Offset *sizep, PIO_Of * every variable dimension. * @return PIO_NOERR for success, otherwise an error code. * @ingroup PIO_def_var - * @author Ed Hartnett */ int PIOc_set_var_chunk_cache_impl(int ncid, int varid, PIO_Offset size, PIO_Offset nelems, float preemption) @@ -1040,7 +1030,6 @@ int PIOc_set_var_chunk_cache_impl(int ncid, int varid, PIO_Offset size, PIO_Offs * @param preemptionp will get the cache preemption value. Ignored if NULL. * @return PIO_NOERR for success, otherwise an error code. * @ingroup PIO_inq_var - * @author Ed Hartnett */ int PIOc_get_var_chunk_cache_impl(int ncid, int varid, PIO_Offset *sizep, PIO_Offset *nelemsp, float *preemptionp) diff --git a/src/clib/core/pio_put_nc.cpp b/src/clib/core/pio_put_nc.cpp index a68e558ad6..0624612c25 100644 --- a/src/clib/core/pio_put_nc.cpp +++ b/src/clib/core/pio_put_nc.cpp @@ -2,9 +2,6 @@ * @file * PIO functions to write data. * - * @author Ed Hartnett - * @date 2016 - * @see http://code.google.com/p/parallelio/ */ #include @@ -30,7 +27,6 @@ * used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vars_text_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const char *op) @@ -57,7 +53,6 @@ int PIOc_put_vars_text_impl(int ncid, int varid, const PIO_Offset *start, const * used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vars_uchar_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, @@ -85,7 +80,6 @@ int PIOc_put_vars_uchar_impl(int ncid, int varid, const PIO_Offset *start, * used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vars_schar_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const signed char *op) @@ -113,7 +107,6 @@ int PIOc_put_vars_schar_impl(int ncid, int varid, const PIO_Offset *start, const * used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vars_ushort_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const unsigned short *op) @@ -140,7 +133,6 @@ int PIOc_put_vars_ushort_impl(int ncid, int varid, const PIO_Offset *start, cons * used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vars_short_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const short *op) @@ -168,7 +160,6 @@ int PIOc_put_vars_short_impl(int ncid, int varid, const PIO_Offset *start, * used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vars_uint_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const unsigned int *op) @@ -195,7 +186,6 @@ int PIOc_put_vars_uint_impl(int ncid, int varid, const PIO_Offset *start, const * used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vars_int_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const int *op) @@ -222,7 +212,6 @@ int PIOc_put_vars_int_impl(int ncid, int varid, const PIO_Offset *start, const P * used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vars_long_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const long *op) @@ -249,7 +238,6 @@ int PIOc_put_vars_long_impl(int ncid, int varid, const PIO_Offset *start, const * used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vars_float_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const float *op) @@ -277,7 +265,6 @@ int PIOc_put_vars_float_impl(int ncid, int varid, const PIO_Offset *start, const * used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vars_longlong_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const long long *op) @@ -305,7 +292,6 @@ int PIOc_put_vars_longlong_impl(int ncid, int varid, const PIO_Offset *start, co * used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vars_double_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const double *op) @@ -333,7 +319,6 @@ int PIOc_put_vars_double_impl(int ncid, int varid, const PIO_Offset *start, cons * used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vars_ulonglong_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const unsigned long long *op) @@ -354,7 +339,6 @@ int PIOc_put_vars_ulonglong_impl(int ncid, int varid, const PIO_Offset *start, c * used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var1_text_impl(int ncid, int varid, const PIO_Offset *index, const char *op) { @@ -374,7 +358,6 @@ int PIOc_put_var1_text_impl(int ncid, int varid, const PIO_Offset *index, const * used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var1_uchar_impl(int ncid, int varid, const PIO_Offset *index, const unsigned char *op) @@ -395,7 +378,6 @@ int PIOc_put_var1_uchar_impl(int ncid, int varid, const PIO_Offset *index, * used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var1_schar_impl(int ncid, int varid, const PIO_Offset *index, const signed char *op) @@ -416,7 +398,6 @@ int PIOc_put_var1_schar_impl(int ncid, int varid, const PIO_Offset *index, * used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var1_ushort_impl(int ncid, int varid, const PIO_Offset *index, const unsigned short *op) @@ -437,7 +418,6 @@ int PIOc_put_var1_ushort_impl(int ncid, int varid, const PIO_Offset *index, * used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var1_short_impl(int ncid, int varid, const PIO_Offset *index, const short *op) @@ -458,7 +438,6 @@ int PIOc_put_var1_short_impl(int ncid, int varid, const PIO_Offset *index, * used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var1_uint_impl(int ncid, int varid, const PIO_Offset *index, const unsigned int *op) @@ -479,7 +458,6 @@ int PIOc_put_var1_uint_impl(int ncid, int varid, const PIO_Offset *index, * used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var1_int_impl(int ncid, int varid, const PIO_Offset *index, const int *op) { @@ -499,7 +477,6 @@ int PIOc_put_var1_int_impl(int ncid, int varid, const PIO_Offset *index, const i * used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var1_float_impl(int ncid, int varid, const PIO_Offset *index, const float *op) { @@ -519,7 +496,6 @@ int PIOc_put_var1_float_impl(int ncid, int varid, const PIO_Offset *index, const * used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var1_long_impl(int ncid, int varid, const PIO_Offset *index, const long *op) { @@ -539,7 +515,6 @@ int PIOc_put_var1_long_impl(int ncid, int varid, const PIO_Offset *index, const * used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var1_double_impl(int ncid, int varid, const PIO_Offset *index, const double *op) @@ -560,7 +535,6 @@ int PIOc_put_var1_double_impl(int ncid, int varid, const PIO_Offset *index, * used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var1_ulonglong_impl(int ncid, int varid, const PIO_Offset *index, const unsigned long long *op) @@ -581,7 +555,6 @@ int PIOc_put_var1_ulonglong_impl(int ncid, int varid, const PIO_Offset *index, * used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var1_longlong_impl(int ncid, int varid, const PIO_Offset *index, const long long *op) @@ -605,7 +578,6 @@ int PIOc_put_var1_longlong_impl(int ncid, int varid, const PIO_Offset *index, * the variable will be used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vara_text_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const char *op) @@ -629,7 +601,6 @@ int PIOc_put_vara_text_impl(int ncid, int varid, const PIO_Offset *start, * the variable will be used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vara_uchar_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const unsigned char *op) @@ -653,7 +624,6 @@ int PIOc_put_vara_uchar_impl(int ncid, int varid, const PIO_Offset *start, * the variable will be used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vara_schar_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const signed char *op) @@ -677,7 +647,6 @@ int PIOc_put_vara_schar_impl(int ncid, int varid, const PIO_Offset *start, * the variable will be used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vara_ushort_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const unsigned short *op) @@ -701,7 +670,6 @@ int PIOc_put_vara_ushort_impl(int ncid, int varid, const PIO_Offset *start, * the variable will be used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vara_short_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const short *op) @@ -725,7 +693,6 @@ int PIOc_put_vara_short_impl(int ncid, int varid, const PIO_Offset *start, * the variable will be used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vara_uint_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const unsigned int *op) @@ -749,7 +716,6 @@ int PIOc_put_vara_uint_impl(int ncid, int varid, const PIO_Offset *start, * the variable will be used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vara_int_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const int *op) @@ -773,7 +739,6 @@ int PIOc_put_vara_int_impl(int ncid, int varid, const PIO_Offset *start, * the variable will be used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vara_long_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const long *op) @@ -797,7 +762,6 @@ int PIOc_put_vara_long_impl(int ncid, int varid, const PIO_Offset *start, * the variable will be used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vara_float_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const float *op) @@ -821,7 +785,6 @@ int PIOc_put_vara_float_impl(int ncid, int varid, const PIO_Offset *start, * the variable will be used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vara_ulonglong_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const unsigned long long *op) @@ -845,7 +808,6 @@ int PIOc_put_vara_ulonglong_impl(int ncid, int varid, const PIO_Offset *start, * the variable will be used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vara_longlong_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const long long *op) @@ -869,7 +831,6 @@ int PIOc_put_vara_longlong_impl(int ncid, int varid, const PIO_Offset *start, * the variable will be used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vara_double_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const double *op) @@ -893,7 +854,6 @@ int PIOc_put_vara_double_impl(int ncid, int varid, const PIO_Offset *start, * the variable will be used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var_text_impl(int ncid, int varid, const char *op) { @@ -916,7 +876,6 @@ int PIOc_put_var_text_impl(int ncid, int varid, const char *op) * the variable will be used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var_uchar_impl(int ncid, int varid, const unsigned char *op) { @@ -939,7 +898,6 @@ int PIOc_put_var_uchar_impl(int ncid, int varid, const unsigned char *op) * the variable will be used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var_schar_impl(int ncid, int varid, const signed char *op) { @@ -962,7 +920,6 @@ int PIOc_put_var_schar_impl(int ncid, int varid, const signed char *op) * the variable will be used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var_ushort_impl(int ncid, int varid, const unsigned short *op) { @@ -985,7 +942,6 @@ int PIOc_put_var_ushort_impl(int ncid, int varid, const unsigned short *op) * the variable will be used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var_short_impl(int ncid, int varid, const short *op) { @@ -1008,7 +964,6 @@ int PIOc_put_var_short_impl(int ncid, int varid, const short *op) * the variable will be used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var_uint_impl(int ncid, int varid, const unsigned int *op) { @@ -1031,7 +986,6 @@ int PIOc_put_var_uint_impl(int ncid, int varid, const unsigned int *op) * the variable will be used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var_int_impl(int ncid, int varid, const int *op) { @@ -1054,7 +1008,6 @@ int PIOc_put_var_int_impl(int ncid, int varid, const int *op) * the variable will be used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var_long_impl(int ncid, int varid, const long *op) { @@ -1077,7 +1030,6 @@ int PIOc_put_var_long_impl(int ncid, int varid, const long *op) * the variable will be used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var_float_impl(int ncid, int varid, const float *op) { @@ -1100,7 +1052,6 @@ int PIOc_put_var_float_impl(int ncid, int varid, const float *op) * the variable will be used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var_ulonglong_impl(int ncid, int varid, const unsigned long long *op) { @@ -1123,7 +1074,6 @@ int PIOc_put_var_ulonglong_impl(int ncid, int varid, const unsigned long long *o * the variable will be used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var_longlong_impl(int ncid, int varid, const long long *op) { @@ -1146,7 +1096,6 @@ int PIOc_put_var_longlong_impl(int ncid, int varid, const long long *op) * the variable will be used. * @param op pointer to the data to be written. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var_double_impl(int ncid, int varid, const double *op) { @@ -1163,7 +1112,6 @@ int PIOc_put_var_double_impl(int ncid, int varid, const double *op) * @param varid the variable ID number * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var_impl(int ncid, int varid, const void *op) { @@ -1183,7 +1131,6 @@ int PIOc_put_var_impl(int ncid, int varid, const void *op) * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_var1_impl(int ncid, int varid, const PIO_Offset *index, const void *op) { @@ -1206,7 +1153,6 @@ int PIOc_put_var1_impl(int ncid, int varid, const PIO_Offset *index, const void * the variable will be used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vara_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const void *op) @@ -1233,7 +1179,6 @@ int PIOc_put_vara_impl(int ncid, int varid, const PIO_Offset *start, const PIO_O * used. * @param buf pointer that will get the data. * @return PIO_NOERR on success, error code otherwise. - * @author Ed Hartnett */ int PIOc_put_vars_impl(int ncid, int varid, const PIO_Offset *start, const PIO_Offset *count, const PIO_Offset *stride, const void *op) diff --git a/src/clib/core/pio_spmd.cpp b/src/clib/core/pio_spmd.cpp index 8aaa4e5637..77b3babfb4 100644 --- a/src/clib/core/pio_spmd.cpp +++ b/src/clib/core/pio_spmd.cpp @@ -4,8 +4,6 @@ * Atmosphere Model; C translation. This includes MPI_Gather, * MPI_Gatherv, and MPI_Alltoallw with flow control options. * - * @author Jim Edwards - * @date 2014 */ #include #include @@ -19,7 +17,6 @@ * @param i input number * @returns the smallest power of 2 greater than * or equal to i. - * @author Jim Edwards */ int ceil2(int i) { @@ -38,7 +35,6 @@ int ceil2(int i) * @param p integer between 0 and np - 1. * @param k integer between 0 and np - 1. * @returns (p + 1) ^ k else -1. - * @author Jim Edwards */ int pair(int np, int p, int k) { @@ -72,7 +68,6 @@ int pair(int np, int p, int k) * @param comm MPI communicator for the MPI_Alltoallw call. * @param fc pointer to the struct that provided flow control options. * @returns 0 for success, error code otherwise. - * @author Jim Edwards */ int pio_swapm(const void *sendbuf, const int *sendcounts, const int *sdispls, const MPI_Datatype *sendtypes, void *recvbuf, const int *recvcounts, const int *rdispls, const MPI_Datatype *recvtypes, @@ -576,7 +571,6 @@ void pio_swapm_req_free(void *p) * @param comm communicator. * @param flow_cntl if non-zero, flow control will be used. * @returns 0 for success, error code otherwise. - * @author Jim Edwards */ int pio_fc_gatherv(const void *sendbuf, int sendcnt, MPI_Datatype sendtype, void *recvbuf, const int *recvcnts, const int *displs, diff --git a/src/clib/core/pioc.cpp b/src/clib/core/pioc.cpp index 5caba6d0ba..195567931a 100644 --- a/src/clib/core/pioc.cpp +++ b/src/clib/core/pioc.cpp @@ -1,10 +1,7 @@ /** * @file * Some initialization and support functions. - * @author Jim Edwards - * @date 2014 * - * @see http://code.google.com/p/parallelio/ */ #include @@ -59,7 +56,6 @@ extern int blocksize; * @param active pointer that gets true if IO system is active, false * otherwise. * @returns 0 on success, error code otherwise - * @author Jim Edwards */ int PIOc_iosystem_is_active_impl(int iosysid, bool *active) { @@ -86,7 +82,6 @@ int PIOc_iosystem_is_active_impl(int iosysid, bool *active) * * @param ncid the ncid of an open file * @returns 1 if file is open, 0 otherwise. - * @author Jim Edwards */ int PIOc_File_is_Open_impl(int ncid) { @@ -153,7 +148,6 @@ static const char *PIO_error_handler_to_string(int eh) * @param method the error handling method * @returns old error handler * @ingroup PIO_error_method - * @author Jim Edwards */ int PIOc_Set_File_Error_Handling_impl(int ncid, int method) { @@ -186,7 +180,6 @@ int PIOc_Set_File_Error_Handling_impl(int ncid, int method) * @param ncid the ncid of the open file * @param varid the variable ID * @returns 0 on success, error code otherwise - * @author Jim Edwards, Ed Hartnett */ int PIOc_advanceframe_impl(int ncid, int varid) { @@ -240,7 +233,6 @@ int PIOc_advanceframe_impl(int ncid, int varid) * first record, 1 for the second * @return PIO_NOERR for no error, or error code. * @ingroup PIO_setframe - * @author Jim Edwards, Ed Hartnett */ int PIOc_setframe_impl(int ncid, int varid, int frame) { @@ -379,7 +371,6 @@ int PIOc_setframe_impl(int ncid, int varid, int frame) * @param numiotasks a pointer taht gets the number of IO * tasks. Ignored if NULL. * @returns 0 on success, error code otherwise - * @author Ed Hartnett */ int PIOc_get_numiotasks_impl(int iosysid, int *numiotasks) { @@ -405,7 +396,6 @@ int PIOc_get_numiotasks_impl(int iosysid, int *numiotasks) * @param ioid IO description ID of an IO decomposition that represents the * variable layout. * @returns the local size (size on the local process) of the variable. - * @author Jim Edwards */ int PIOc_get_local_array_size_impl(int ioid) { @@ -429,7 +419,6 @@ int PIOc_get_local_array_size_impl(int ioid) * @param method the error handling method * @returns old error handler * @ingroup PIO_error_method - * @author Jim Edwards */ int PIOc_Set_IOSystem_Error_Handling_impl(int iosysid, int method) { @@ -461,7 +450,6 @@ int PIOc_Set_IOSystem_Error_Handling_impl(int iosysid, int method) * if NULL. * @returns 0 for success, error code otherwise. * @ingroup PIO_error_method - * @author Jim Edwards, Ed Hartnett */ int PIOc_set_iosystem_error_handling_impl(int iosysid, int method, int *old_method) { @@ -1046,7 +1034,6 @@ int PIOc_init_decomp_impl(int iosysid, int pio_type, int ndims, const int *gdiml * @param pointer that gets the IO ID. * @returns 0 for success, error code otherwise * @ingroup PIO_initdecomp - * @author Jim Edwards */ int PIOc_InitDecomp_bc_impl(int iosysid, int pio_type, int ndims, const int *gdimlen, const long int *start, const long int *count, int *ioidp) @@ -1260,7 +1247,6 @@ static int init_adios_comm(iosystem_desc_t *ios) * @param iosysidp index of the defined system descriptor. * @return 0 on success, otherwise a PIO error code. * @ingroup PIO_init - * @author Jim Edwards, Ed Hartnett */ int PIOc_Init_Intracomm_impl(MPI_Comm comp_comm, int num_iotasks, int stride, int base, int rearr, int *iosysidp) @@ -1613,7 +1599,6 @@ int PIOc_Init_Intracomm_impl(MPI_Comm comp_comm, int num_iotasks, int stride, in * @param rearr_opts the rearranger options * @param iosysidp a pointer that gets the IO system ID * @returns 0 for success, error code otherwise - * @author Jim Edwards */ int PIOc_Init_Intracomm_from_F90_impl(int f90_comp_comm, const int num_iotasks, const int stride, @@ -1658,7 +1643,6 @@ int PIOc_Init_Intracomm_from_F90_impl(int f90_comp_comm, * @param hint the hint for MPI * @param hintval the value of the hint * @returns 0 for success, or PIO_BADID if iosysid can't be found. - * @author Jim Edwards, Ed Hartnett */ int PIOc_set_hint_impl(int iosysid, const char *hint, const char *hintval) { @@ -1709,7 +1693,6 @@ int PIOc_set_hint_impl(int iosysid, const char *hint, const char *hintval) * @param iosysid: the io system ID provided by PIOc_Init_Intracomm(). * @returns 0 for success or non-zero for error. * @ingroup PIO_finalize - * @author Jim Edwards, Ed Hartnett */ int PIOc_finalize_impl(int iosysid) { @@ -1926,7 +1909,6 @@ int PIOc_finalize_impl(int iosysid) * @param ioproc a pointer that gets 1 if task is an IO task, 0 * otherwise. Ignored if NULL. * @returns 0 for success, or PIO_BADID if iosysid can't be found. - * @author Jim Edwards */ int PIOc_iam_iotask_impl(int iosysid, bool *ioproc) { @@ -1952,7 +1934,6 @@ int PIOc_iam_iotask_impl(int iosysid, bool *ioproc) * @param iorank a pointer that gets the io rank, or -1 if task is not * in the IO communicator. Ignored if NULL. * @returns 0 for success, or PIO_BADID if iosysid can't be found. - * @author Jim Edwards */ int PIOc_iotask_rank_impl(int iosysid, int *iorank) { @@ -1975,7 +1956,6 @@ int PIOc_iotask_rank_impl(int iosysid, int *iorank) * * @param iotype the io type to check * @returns 1 if iotype is in build, 0 if not. - * @author Jim Edwards */ int PIOc_iotype_available_impl(int iotype) { @@ -2078,7 +2058,6 @@ int PIOc_iotype_available_impl(int iotype) * * @return PIO_NOERR on success, error code otherwise. * @ingroup PIO_init - * @author Ed Hartnett */ int PIOc_init_async_impl(MPI_Comm world, int num_io_procs, const int *io_proc_list, int component_count, const int *num_procs_per_comp, const int **proc_list, @@ -3235,7 +3214,6 @@ int PIOc_Init_Intercomm_from_F90_impl(int component_count, int f90_peer_comm, * @param newblocksize the new blocksize. * @returns 0 for success. * @ingroup PIO_set_blocksize - * @author Jim Edwards */ int PIOc_set_blocksize_impl(int newblocksize) { diff --git a/src/clib/core/pioc_sc.cpp b/src/clib/core/pioc_sc.cpp index fc080a0380..15e1f7dbac 100644 --- a/src/clib/core/pioc_sc.cpp +++ b/src/clib/core/pioc_sc.cpp @@ -2,8 +2,6 @@ * @file * Compute start and count arrays for the box rearranger * - * @author Jim Edwards - * @date 2014 */ #include #include diff --git a/src/clib/core/pioc_support.cpp b/src/clib/core/pioc_support.cpp index 275e6da110..25f3d03310 100644 --- a/src/clib/core/pioc_support.cpp +++ b/src/clib/core/pioc_support.cpp @@ -3933,7 +3933,6 @@ int spio_createfile_int(int iosysid, int *ncidp, const int *iotype, const char * * @param ncid the file->fh for this file (the real netCDF ncid, not * the pio_ncid). * @returns 0 if file is OK, error code otherwise. - * @author Ed Hartnett */ int check_unlim_use(int ncid) { @@ -4799,7 +4798,6 @@ static size_t adios_read_vars_vars(file_desc_t *file, size_t var_size, char *con * * @return 0 for success, error code otherwise. * @ingroup PIO_openfile - * @author Jim Edwards, Ed Hartnett */ int PIOc_openfile_retry_impl(int iosysid, int *ncidp, int *iotype, const char *filename, int mode, int retry) @@ -5639,7 +5637,6 @@ int PIOc_openfile_retry_impl(int iosysid, int *ncidp, int *iotype, const char *f * * @return 0 for success, error code otherwise. * @ingroup PIO_openfile - * @author Ed Hartnett */ int openfile_int(int iosysid, int *ncidp, int *iotype, const char *filename, int mode, int retry) diff --git a/src/clib/core/rearr/pio_rearrange.cpp b/src/clib/core/rearr/pio_rearrange.cpp index ad5b68125d..514594d221 100644 --- a/src/clib/core/rearr/pio_rearrange.cpp +++ b/src/clib/core/rearr/pio_rearrange.cpp @@ -1,7 +1,6 @@ /** @file * Code to map IO to model decomposition. * - * @author Jim Edwards */ #include #include @@ -45,7 +44,6 @@ void init_rearr_opts(iosystem_desc_t *iosys) * of data. * @param dim_list array of length ndims that will get the dimensions * corresponding to this index. - * @author Jim Edwards, Ed Hartnett */ inline void idx_to_dim_list(int ndims, const int *gdimlen, PIO_Offset idx, PIO_Offset *dim_list) @@ -91,7 +89,6 @@ inline void idx_to_dim_list(int ndims, const int *gdimlen, PIO_Offset idx, * @param max_size array of size dim + 1 that contains the maximum * sizes along that dimension. * @param count array of size dim + 1 that gets the new counts. - * @author Jim Edwards */ void expand_region(int dim, const int *gdimlen, int maplen, const PIO_Offset *map, int region_size, int region_stride, const int *max_size, @@ -168,7 +165,6 @@ void expand_region(int dim, const int *gdimlen, int maplen, const PIO_Offset *ma * @param count array (length ndims) that will get counts of found * region. * @returns length of the region found. - * @author Jim Edwards */ PIO_Offset find_region(int ndims, const int *gdimlen, int maplen, const PIO_Offset *map, PIO_Offset *start, PIO_Offset *count) @@ -215,7 +211,6 @@ PIO_Offset find_region(int ndims, const int *gdimlen, int maplen, const PIO_Offs * @param lcoord pointer to an offset. * @param count array of counts. * @returns the local array index. - * @author Jim Edwards */ inline PIO_Offset coord_to_lindex(int ndims, const PIO_Offset *lcoord, const PIO_Offset *count) { @@ -242,7 +237,6 @@ inline PIO_Offset coord_to_lindex(int ndims, const PIO_Offset *lcoord, const PIO * @param io_comm the IO communicator * @param iodesc a pointer to the io_desc_t struct. * @returns 0 for success, error code otherwise. - * @author Jim Edwards */ int compute_maxIObuffersize(MPI_Comm io_comm, io_desc_t *iodesc) { @@ -292,7 +286,6 @@ int compute_maxIObuffersize(MPI_Comm io_comm, io_desc_t *iodesc) * @param mtype pointer to an array (length msgcnt) which gets the * created datatypes. Will be NULL when iodesc->nrecvs == 0. * @returns 0 on success, error code otherwise. - * @author Jim Edwards */ int create_mpi_datatypes(MPI_Datatype mpitype, int msgcnt, const PIO_Offset *mindex, const int *mcount, int *mfrom, @@ -442,7 +435,6 @@ int create_mpi_datatypes(MPI_Datatype mpitype, int msgcnt, * @param ios pointer to the iosystem_desc_t struct. * @param iodesc a pointer to the io_desc_t struct. * @returns 0 on success, error code otherwise. - * @author Jim Edwards */ int define_iodesc_datatypes(iosystem_desc_t *ios, io_desc_t *iodesc) { @@ -561,7 +553,6 @@ int define_iodesc_datatypes(iosystem_desc_t *ios, io_desc_t *iodesc) * @param dest_ioproc an array (length maplen) of IO task numbers. * @param dest_ioindex an array (length maplen) of IO indicies. * @returns 0 on success, error code otherwise. - * @author Jim Edwards */ int compute_counts(iosystem_desc_t *ios, io_desc_t *iodesc, const int *dest_ioproc, const PIO_Offset *dest_ioindex) @@ -846,7 +837,6 @@ int compute_counts(iosystem_desc_t *ios, io_desc_t *iodesc, * @param rbuf receive buffer. May be NULL. * @param nvars number of variables. * @returns 0 on success, error code otherwise. - * @author Jim Edwards */ int rearrange_comp2io(iosystem_desc_t *ios, io_desc_t *iodesc, file_desc_t *file, const void *sbuf, void *rbuf, int nvars) @@ -1085,7 +1075,6 @@ int rearrange_comp2io(iosystem_desc_t *ios, io_desc_t *iodesc, file_desc_t *file * @param sbuf send buffer. * @param rbuf receive buffer. * @returns 0 on success, error code otherwise. - * @author Jim Edwards */ int rearrange_io2comp(iosystem_desc_t *ios, io_desc_t *iodesc, const void *sbuf, void *rbuf) @@ -1220,7 +1209,6 @@ int rearrange_io2comp(iosystem_desc_t *ios, io_desc_t *iodesc, const void *sbuf, * entire var (for non-record vars). * @param compmap only used for the box communicator. * @returns 0 on success, error code otherwise. - * @author Jim Edwards */ int determine_fill(iosystem_desc_t *ios, io_desc_t *iodesc, const int *gdimlen, const PIO_Offset *compmap) @@ -1302,7 +1290,6 @@ int determine_fill(iosystem_desc_t *ios, io_desc_t *iodesc, const int *gdimlen, * @param iodesc a pointer to the io_desc_t struct, which must be * allocated before this function is called. * @returns 0 on success, error code otherwise. - * @author Jim Edwards */ int box_rearrange_create(iosystem_desc_t *ios, int maplen, const PIO_Offset *compmap, const int *gdimlen, int ndims, io_desc_t *iodesc) @@ -1956,7 +1943,6 @@ int box_rearrange_create_with_holes(iosystem_desc_t *ios, int maplen, const PIO_ * @param a pointer to an offset. * @param b pointer to another offset. * @returns 0 if offsets are the same or either pointer is NULL. - * @author Jim Edwards */ int compare_offsets(const void *a, const void *b) { @@ -1987,7 +1973,6 @@ int compare_offsets(const void *a, const void *b) * @param maxregions * @param firstregion pointer to the first region. * @returns 0 on success, error code otherwise. - * @author Jim Edwards */ int get_regions(int ndims, const int *gdimlen, int maplen, const PIO_Offset *map, int *maxregions, io_region *firstregion) @@ -2074,7 +2059,6 @@ int get_regions(int ndims, const int *gdimlen, int maplen, const PIO_Offset *map * @param ios pointer to the iosystem_desc_t struct. * @param iodesc a pointer to the io_desc_t struct. * @returns 0 on success, error code otherwise. - * @author Jim Edwards */ int default_subset_partition(iosystem_desc_t *ios, io_desc_t *iodesc) { @@ -2199,7 +2183,6 @@ int default_subset_partition(iosystem_desc_t *ios, io_desc_t *iodesc) * @param ndims the number of dimensions. * @param iodesc a pointer to the io_desc_t struct. * @returns 0 on success, error code otherwise. - * @author Jim Edwards */ int subset_rearrange_create(iosystem_desc_t *ios, int maplen, PIO_Offset *compmap, const int *gdimlen, int ndims, io_desc_t *iodesc) @@ -2731,7 +2714,6 @@ int subset_rearrange_create(iosystem_desc_t *ios, int maplen, PIO_Offset *compma * @param ios pointer to the iosystem description struct. * @param iodesc pointer to the IO description struct. * @returns 0 on success, error code otherwise. - * @author Jim Edwards */ void performance_tune_rearranger(iosystem_desc_t *ios, io_desc_t *iodesc) { diff --git a/src/clib/core/util/pio_lists.cpp b/src/clib/core/util/pio_lists.cpp index 4112d9e99d..0e0507002d 100644 --- a/src/clib/core/util/pio_lists.cpp +++ b/src/clib/core/util/pio_lists.cpp @@ -473,7 +473,6 @@ io_desc_t *pio_get_iodesc_from_id(int ioid) * * @param ioid The id of the I/O descriptor (io_desc_t) to delete * @returns 0 on success, error code otherwise. - * @author Jayesh Krishna */ int pio_delete_iodesc_from_list(int ioid) { diff --git a/src/clib/pio.h b/src/clib/pio.h index 44f97b68cf..a88ae6ff76 100644 --- a/src/clib/pio.h +++ b/src/clib/pio.h @@ -1,10 +1,7 @@ /** * @file * Public headers for the PIO C interface. - * @author Jim Edwards - * @date 2014 * - * @see http://code.google.com/p/parallelio/ */ #ifndef _PIO_H_ diff --git a/src/clib/pio_internal.h b/src/clib/pio_internal.h index 3d71674189..8d0f46b24d 100644 --- a/src/clib/pio_internal.h +++ b/src/clib/pio_internal.h @@ -1,10 +1,7 @@ /** * @file * Private headers and defines for the PIO C interface. - * @author Jim Edwards - * @date 2014 * - * @see http://code.google.com/p/parallelio/ */ #ifndef __PIO_INTERNAL__ diff --git a/tests/cunit/pio_tests.h b/tests/cunit/pio_tests.h index 4e9d22c293..6d8909fcca 100644 --- a/tests/cunit/pio_tests.h +++ b/tests/cunit/pio_tests.h @@ -1,8 +1,6 @@ /** * @file * Include file for tests for the Parallel IO library. - * @author Ed Hartnett - * @date 9/13/2016 */ #ifndef _PIO_TESTS_H From 2bf2036ee6230b174d3a0d3852edf2a51c133081 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Tue, 5 May 2026 22:00:45 -0500 Subject: [PATCH 192/194] Adding a simple AGENTS.md Adding a simple AGENTS.md for the library --- AGENTS.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..e5d9e0c0d4 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,49 @@ +# AGENTS.md + +SCORPIO (Software for Caching Output and Reads for Parallel I/O) is a high-level Parallel I/O Library for structured grid applications. + +## Project Overview + +SCORPIO (Software for Caching Output and Reads for Parallel I/O) is a high-level Parallel I/O Library. The library is used by the E3SM (Energy Exascale Earth System Model) earth system model for all I/O. + +- **Website:** https://github.com/E3SM-Project/scorpio +- **Documentation:** https://docs.e3sm.org/scorpio/ +- **DOI:** https://www.osti.gov/doecode/biblio/36752 + +## Architecture + +- The Fortran interface library source is in src/flib directory +- The C (main/core library) library source is in src/clib directory +- The tests are in tests/general and tests/cunit directories +- The examples are in the examples directory + +## Build Commands + +SCORPIO uses CMake for configuring the library. The library requires a C, C++ and Fortran compiler and an MPI library. SCORPIO uses low-level I/O libraries like PnetCDF (https://parallel-netcdf.github.io), NetCDF (https://www.unidata.ucar.edu/software/netcdf), HDF5 (https://www.hdfgroup.org/solutions/hdf5/) and ADIOS (https://adios2.readthedocs.io/en/latest/) for I/O. + +To configure SCORPIO (source in /path/to/scorpio/source directory) using CMake with the PnetCDF library (installed at /path/to/pnetcdf) use the command below, + +``` +CC=mpicc CXX=mpicxx FC=mpif90 cmake -DPnetCDF_PATH=/path/to/pnetcdf /path/to/scorpio/source +``` + +After configuring the library to build it use make, + +``` +make +``` + +## Development Workflow +- All changes are made on a development branch off master +- The development branches are named using the pattern : ```/``` +- The changes in a branch are merged to the develop branch for nightly testing (Run using Jenkins and results published on CDASH at http://my.cdash.org/index.php?project=E3SM\_SCORPIO) +- Once the nightly testing is successful the PR is manually merged to the master branch +- Code formatting for C++ sources is mentioned in the library documentation (https://docs.e3sm.org/scorpio/html/contributing_code.html) + +## Testing instructions +- Find the CI (Github Actions workflow) plan in the .github/workflows directory +- Add/update tests for the code that you change + +## PR instructions +- Run the CI workflow (SCORPIO + PnetCDF - build and test) in the .github/workflows directory before committing any changes +- Do not automatically merge PRs to master or develop branch From 1e893c230a78a4873a121efb37507aa7ce4a1a51 Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 6 May 2026 11:04:25 -0500 Subject: [PATCH 193/194] ifdef pnetcdf calls in async utils Add ifdefs (HAVE_PNETCDF) around pnetcdf async util functions --- src/clib/core/progress_engine/spio_async_utils.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/clib/core/progress_engine/spio_async_utils.cpp b/src/clib/core/progress_engine/spio_async_utils.cpp index b2bed720ea..44fd924923 100644 --- a/src/clib/core/progress_engine/spio_async_utils.cpp +++ b/src/clib/core/progress_engine/spio_async_utils.cpp @@ -276,6 +276,7 @@ void pio_viobuf_free(void *p) */ int pio_async_pnetcdf_write_kwait(void *f) { +#ifdef HAVE_PNETCDF int ret; file_desc_t *file = (file_desc_t *)f; assert(file); @@ -363,6 +364,9 @@ int pio_async_pnetcdf_write_kwait(void *f) } return PIO_NOERR; +#else + assert(0); +#endif } /* Wait only for rearr async ops on a file */ From 637acf12a576cb8a50bd6e9af7f70b9e977fb81e Mon Sep 17 00:00:00 2001 From: jayeshkrishna Date: Wed, 6 May 2026 12:33:20 -0500 Subject: [PATCH 194/194] Disable pnetcdf tests if its not available Add pnetcdf tests only if pnetcdf lib is found/available --- tests/pnetcdf/CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/pnetcdf/CMakeLists.txt b/tests/pnetcdf/CMakeLists.txt index c959d54c1c..d9e7429551 100644 --- a/tests/pnetcdf/CMakeLists.txt +++ b/tests/pnetcdf/CMakeLists.txt @@ -79,11 +79,12 @@ endif () #============================================================================== # Exclude tests that require more than 1 procs when using the MPI serial library -if (WITH_PNETCDF) +if (WITH_PNETCDF AND PnetCDF_FOUND) add_spio_executable (test_pnetcdf TRUE "" test_pnetcdf.c) add_spio_executable (test_pnetcdf_4d TRUE "" test_pnetcdf_4d.cpp) + + add_dependencies (tests test_pnetcdf test_pnetcdf_4d) endif () -add_dependencies (tests test_pnetcdf test_pnetcdf_4d) set (SPIO_TEST_MAX_NPROCS 4)