[Darshan-commits] [Git][darshan/darshan][dev-daos-dfs-module] first cut at entire dfs runtime/util code

Shane Snyder xgitlab at cels.anl.gov
Wed Jan 27 13:29:25 CST 2021



Shane Snyder pushed to branch dev-daos-dfs-module at darshan / darshan


Commits:
520301c3 by Shane Snyder at 2021-01-27T19:28:49+00:00
first cut at entire dfs runtime/util code

- - - - -


9 changed files:

- darshan-daos-log-format.h
- darshan-log-format.h
- darshan-runtime/Makefile.in
- darshan-runtime/lib/darshan-daos.c
- + darshan-runtime/share/ld-opts/darshan-daos-ld-opts
- darshan-util/Makefile.in
- + darshan-util/darshan-daos-logutils.c
- + darshan-util/darshan-daos-logutils.h
- darshan-util/darshan-logutils.h


Changes:

=====================================
darshan-daos-log-format.h
=====================================
@@ -18,20 +18,110 @@
     X(DFS_LOOKUPS) \
     /* count of dfs dups */\
     X(DFS_DUPS) \
+    /* count of dfs reads */\
+    X(DFS_READS) \
+    /* count of dfs readxs */\
+    X(DFS_READXS) \
+    /* count of dfs writes */\
+    X(DFS_WRITES) \
+    /* count of dfs writexs */\
+    X(DFS_WRITEXS) \
+    /* count of total non-blocking dfs reads (including read/readx) */\
+    X(DFS_NB_READS) \
+    /* count of total non-blocking dfs writes (including write/writex) */\
+    X(DFS_NB_WRITES) \
+    /* count of dfs get sizes */\
+    X(DFS_GET_SIZES) \
+    /* count of dfs punches */\
+    X(DFS_PUNCHES) \
+    /* count of dfs moves */\
+    X(DFS_MOVES) \
+    /* count of dfs exchanges */\
+    X(DFS_EXCHANGES) \
+    /* count of dfs stats */\
+    X(DFS_STATS) \
+    /* total bytes read */\
+    X(DFS_BYTES_READ) \
+    /* total bytes written */\
+    X(DFS_BYTES_WRITTEN) \
+    /* number of times switched between read and write */\
+    X(DFS_RW_SWITCHES) \
+    /* dfs file chunk size */\
+    X(DFS_CHUNK_SIZE) \
+    /* whether dfs distributed transactions are used */\
+    X(DFS_USE_DTX) \
+    X(DFS_MAX_READ_TIME_SIZE) \
+    X(DFS_MAX_WRITE_TIME_SIZE) \
+    /* buckets for dfs read size ranges */\
+    X(DFS_SIZE_READ_0_100) \
+    X(DFS_SIZE_READ_100_1K) \
+    X(DFS_SIZE_READ_1K_10K) \
+    X(DFS_SIZE_READ_10K_100K) \
+    X(DFS_SIZE_READ_100K_1M) \
+    X(DFS_SIZE_READ_1M_4M) \
+    X(DFS_SIZE_READ_4M_10M) \
+    X(DFS_SIZE_READ_10M_100M) \
+    X(DFS_SIZE_READ_100M_1G) \
+    X(DFS_SIZE_READ_1G_PLUS) \
+    /* buckets for dfs write size ranges */\
+    X(DFS_SIZE_WRITE_0_100) \
+    X(DFS_SIZE_WRITE_100_1K) \
+    X(DFS_SIZE_WRITE_1K_10K) \
+    X(DFS_SIZE_WRITE_10K_100K) \
+    X(DFS_SIZE_WRITE_100K_1M) \
+    X(DFS_SIZE_WRITE_1M_4M) \
+    X(DFS_SIZE_WRITE_4M_10M) \
+    X(DFS_SIZE_WRITE_10M_100M) \
+    X(DFS_SIZE_WRITE_100M_1G) \
+    X(DFS_SIZE_WRITE_1G_PLUS) \
+    /* the four most frequently appearing access sizes */\
+    X(DFS_ACCESS1_ACCESS) \
+    X(DFS_ACCESS2_ACCESS) \
+    X(DFS_ACCESS3_ACCESS) \
+    X(DFS_ACCESS4_ACCESS) \
+    /* count of each of the most frequent access sizes */\
+    X(DFS_ACCESS1_COUNT) \
+    X(DFS_ACCESS2_COUNT) \
+    X(DFS_ACCESS3_COUNT) \
+    X(DFS_ACCESS4_COUNT) \
+    /* rank and number of bytes moved for fastest/slowest ranks */\
+    X(DFS_FASTEST_RANK) \
+    X(DFS_FASTEST_RANK_BYTES) \
+    X(DFS_SLOWEST_RANK) \
+    X(DFS_SLOWEST_RANK_BYTES) \
     /* end of counters */\
     X(DFS_NUM_INDICES)
 
 #define DFS_F_COUNTERS \
     /* timestamp of first open */\
     X(DFS_F_OPEN_START_TIMESTAMP) \
+    /* timestamp of first read */\
+    X(DFS_F_READ_START_TIMESTAMP) \
+    /* timestamp of first write */\
+    X(DFS_F_WRITE_START_TIMESTAMP) \
     /* timestamp of first close */\
     X(DFS_F_CLOSE_START_TIMESTAMP) \
     /* timestamp of last open */\
     X(DFS_F_OPEN_END_TIMESTAMP) \
+    /* timestamp of last read */\
+    X(DFS_F_READ_END_TIMESTAMP) \
+    /* timestamp of last write */\
+    X(DFS_F_WRITE_END_TIMESTAMP) \
     /* timestamp of last close */\
     X(DFS_F_CLOSE_END_TIMESTAMP) \
+    /* cumulative dfs read time */\
+    X(DFS_F_READ_TIME) \
+    /* cumulative dfs write time */\
+    X(DFS_F_WRITE_TIME) \
     /* cumulative dfs meta time */\
     X(DFS_F_META_TIME) \
+    /* maximum dfs read duration */\
+    X(DFS_F_MAX_READ_TIME) \
+    /* maximum dfs write duration */\
+    X(DFS_F_MAX_WRITE_TIME) \
+    /* total i/o and meta time consumed for fastest/slowest ranks */\
+    X(DFS_F_FASTEST_RANK_TIME) \
+    X(DFS_F_SLOWEST_RANK_TIME) \
     /* end of counters */\
     X(DFS_F_NUM_INDICES)
 


=====================================
darshan-log-format.h
=====================================
@@ -120,6 +120,7 @@ struct darshan_base_record
 /* DXT */
 #include "darshan-dxt-log-format.h"
 #include "darshan-mdhim-log-format.h"
+#include "darshan-daos-log-format.h"
 
 /* X-macro for keeping module ordering consistent */
 /* NOTE: first val used to define module enum values, 
@@ -144,7 +145,8 @@ struct darshan_base_record
     /* DXT */ \
     X(DXT_POSIX_MOD,       "DXT_POSIX",  DXT_POSIX_VER,         &dxt_posix_logutils) \
     X(DXT_MPIIO_MOD,       "DXT_MPIIO",  DXT_MPIIO_VER,         &dxt_mpiio_logutils) \
-    X(DARSHAN_MDHIM_MOD,   "MDHIM",      DARSHAN_MDHIM_VER,     &mdhim_logutils)
+    X(DARSHAN_MDHIM_MOD,   "MDHIM",      DARSHAN_MDHIM_VER,     &mdhim_logutils) \
+    X(DARSHAN_DFS_MOD,     "DFS",        DARSHAN_DFS_VER,       &dfs_logutils)
 
 
 /* unique identifiers to distinguish between available darshan modules */


=====================================
darshan-runtime/Makefile.in
=====================================
@@ -261,6 +261,7 @@ endif
 ifdef BUILD_MDHIM_MODULE
 	install -m 644 $(srcdir)/share/ld-opts/darshan-mdhim-ld-opts $(DESTDIR)$(datarootdir)/ld-opts/darshan-mdhim-ld-opts
 endif
+	install -m 644 $(srcdir)/share/ld-opts/darshan-daos-ld-opts $(DESTDIR)$(datarootdir)/ld-opts/darshan-daos-ld-opts
 ifdef ENABLE_MMAP_LOGS
 	install -m 755 share/darshan-mmap-epilog.sh $(DESTDIR)$(datarootdir)/darshan-mmap-epilog.sh
 endif


=====================================
darshan-runtime/lib/darshan-daos.c
=====================================
@@ -35,28 +35,294 @@
 #include <daos_array.h>
 #include <daos_fs.h>
 
-
 DARSHAN_FORWARD_DECL(dfs_mount, int, (daos_handle_t poh, daos_handle_t coh, int flags, dfs_t **dfs));
+DARSHAN_FORWARD_DECL(dfs_global2local, int, (daos_handle_t poh, daos_handle_t coh, int flags, d_iov_t glob, dfs_t **dfs));
+DARSHAN_FORWARD_DECL(dfs_umount, int, (dfs_t *dfs));
 DARSHAN_FORWARD_DECL(dfs_lookup, int, (dfs_t *dfs, const char *path, int flags, dfs_obj_t **obj, mode_t *mode, struct stat *stbuf));
 DARSHAN_FORWARD_DECL(dfs_lookup_rel, int, (dfs_t *dfs, dfs_obj_t *parent, const char *name, int flags, dfs_obj_t **obj, mode_t *mode, struct stat *stbuf));
 DARSHAN_FORWARD_DECL(dfs_open, int, (dfs_t *dfs, dfs_obj_t *parent, const char *name, mode_t mode, int flags, daos_oclass_id_t cid, daos_size_t chunk_size, const char *value, dfs_obj_t **obj));
 DARSHAN_FORWARD_DECL(dfs_dup, int, (dfs_t *dfs, dfs_obj_t *obj, int flags, dfs_obj_t **new_obj));
 DARSHAN_FORWARD_DECL(dfs_obj_global2local, int, (dfs_t *dfs, int flags, d_iov_t glob, dfs_obj_t **obj));
 DARSHAN_FORWARD_DECL(dfs_release, int, (dfs_obj_t *obj));
+DARSHAN_FORWARD_DECL(dfs_read, int, (dfs_t *dfs, dfs_obj_t *obj, d_sg_list_t *sgl, daos_off_t off, daos_size_t *read_size, daos_event_t *ev));
+DARSHAN_FORWARD_DECL(dfs_readx, int, (dfs_t *dfs, dfs_obj_t *obj, dfs_iod_t *iod, d_sg_list_t *sgl, daos_size_t *read_size, daos_event_t *ev));
+DARSHAN_FORWARD_DECL(dfs_write, int, (dfs_t *dfs, dfs_obj_t *obj, d_sg_list_t *sgl, daos_off_t off, daos_event_t *ev));
+DARSHAN_FORWARD_DECL(dfs_writex, int, (dfs_t *dfs, dfs_obj_t *obj, dfs_iod_t *iod, d_sg_list_t *sgl, daos_event_t *ev));
+DARSHAN_FORWARD_DECL(dfs_get_size, int, (dfs_t *dfs, dfs_obj_t *obj, daos_size_t *size));
+DARSHAN_FORWARD_DECL(dfs_punch, int, (dfs_t *dfs, dfs_obj_t *obj, daos_off_t offset, daos_size_t len));
+DARSHAN_FORWARD_DECL(dfs_move, int, (dfs_t *dfs, dfs_obj_t *parent, char *name, dfs_obj_t *new_parent, char *new_name, daos_obj_id_t *oid));
+DARSHAN_FORWARD_DECL(dfs_exchange, int, (dfs_t *dfs, dfs_obj_t *parent1, char *name1, dfs_obj_t *parent2, char *name2));
+DARSHAN_FORWARD_DECL(dfs_stat, int, (dfs_t *dfs, dfs_obj_t *parent, const char *name, struct stat *stbuf));
+DARSHAN_FORWARD_DECL(dfs_ostat, int, (dfs_t *dfs, dfs_obj_t *obj, struct stat *stbuf));
+DARSHAN_FORWARD_DECL(dfs_osetattr, int, (dfs_t *dfs, dfs_obj_t *obj, struct stat *stbuf, int flags));
+
+/* The dfs_file_record_ref structure maintains necessary runtime metadata
+ * for the DFS file record (darshan_dfs_file structure, defined in
+ * darshan-daos-log-format.h) pointed to by 'file_rec'. This metadata
+ * assists with the instrumenting of specific statistics in the file record.
+ *
+ * RATIONALE: the DFS module needs to track some stateful, volatile 
+ * information about each open file (like the current file offset, most recent 
+ * access time, etc.) to aid in instrumentation, but this information can't be
+ * stored in the darshan_dfs_file struct because we don't want it to appear in
+ * the final darshan log file. We therefore associate a dfs_file_record_ref
+ * struct with each darshan_dfs_file struct in order to track this information
+ * (i.e., the mapping between dfs_file_record_ref structs to darshan_dfs_file
+ * structs is one-to-one).
+ *
+ * NOTE: we use the 'darshan_record_ref' interface (in darshan-common) to
+ * associate different types of handles with this dfs_file_record_ref struct.
+ * This allows us to index this struct (and the underlying file record) by using
+ * either the corresponding Darshan record identifier (derived from the filename)
+ * or by a DFS file object, for instance. Note that, while there should
+ * only be a single Darshan record identifier that indexes a dfs_file_record_ref,
+ * there could be multiple open file objects that index it.
+ */
+struct dfs_file_record_ref
+{
+    struct darshan_dfs_file *file_rec;
+    enum darshan_io_type last_io_type;
+    double last_meta_end;
+    double last_read_end;
+    double last_write_end;
+    void *access_root;
+    int access_count;
+};
 
 struct dfs_mount_info
 {
+    /* XXX needed uuids? or just strs? */
     uuid_t pool_uuid;
     uuid_t cont_uuid;
+    char pool_uuid_str[64];
+    char cont_uuid_str[64];
     UT_hash_handle hlink;
 };
 
 struct dfs_runtime
 {
     struct dfs_mount_info *mount_hash;
+    void *rec_id_hash;
+    void *file_obj_hash;
+    int file_rec_count;
 };
 
+static void dfs_runtime_initialize();
+static struct dfs_file_record_ref *dfs_track_new_file_record(
+    darshan_record_id rec_id, const char *path);
+static void dfs_finalize_file_records(
+    void *rec_ref_p, void *user_ptr);
+static void dfs_cleanup_runtime();
+#ifdef HAVE_MPI
+static void dfs_record_reduction_op(
+    void* infile_v, void* inoutfile_v, int *len, MPI_Datatype *datatype);
+static void dfs_mpi_redux(
+    void *dfs_buf, MPI_Comm mod_comm,
+    darshan_record_id *shared_recs, int shared_rec_count);
+#endif
+static void dfs_shutdown(
+    void **dfs_buf, int *dfs_buf_sz);
+
 static struct dfs_runtime *dfs_runtime = NULL;
+static pthread_mutex_t daos_runtime_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+static int my_rank = -1;
+
+#define DAOS_LOCK() pthread_mutex_lock(&daos_runtime_mutex)
+#define DAOS_UNLOCK() pthread_mutex_unlock(&daos_runtime_mutex)
+
+#define DFS_PRE_RECORD() do { \
+    if(ret) return(ret); \
+    DAOS_LOCK(); \
+    if(!darshan_core_disabled_instrumentation()) { \
+        if(!dfs_runtime) { \
+            dfs_runtime_initialize(); \
+        } \
+        if(dfs_runtime) break; \
+    } \
+    DAOS_UNLOCK(); \
+    return(ret); \
+} while(0)
+
+#define DFS_POST_RECORD() do { \
+    DAOS_UNLOCK(); \
+} while(0)
+
+#define DFS_STORE_MOUNT_INFO(__poh, __coh, __dfs_p) do { \
+    int __query_ret, __success=0; \
+    daos_pool_info_t __pool_info; \
+    daos_cont_info_t __cont_info; \
+    struct dfs_mount_info *__mnt_info; \
+    __query_ret = daos_pool_query(__poh, NULL, &__pool_info, NULL, NULL); \
+    if(__query_ret == 0) { \
+        __query_ret = daos_cont_query(__coh, &__cont_info, NULL, NULL); \
+        if(__query_ret == 0) __success = 1; \
+    } \
+    if(__success) { \
+        __mnt_info = malloc(sizeof(*__mnt_info)); \
+        if(__mnt_info) { \
+            uuid_copy(__mnt_info->pool_uuid, __pool_info.pi_uuid); \
+            uuid_copy(__mnt_info->cont_uuid, __cont_info.ci_uuid); \
+            uuid_unparse(__mnt_info->pool_uuid, __mnt_info->pool_uuid_str); \
+            uuid_unparse(__mnt_info->cont_uuid, __mnt_info->cont_uuid_str); \
+            HASH_ADD_KEYPTR(hlink, dfs_runtime->mount_hash, *__dfs_p, sizeof(*__dfs_p), __mnt_info); \
+        } \
+    } \
+} while(0)
+
+#define DFS_GET_MOUNT_INFO(__dfs, __mnt_info) \
+    HASH_FIND(hlink, dfs_runtime->mount_hash, __dfs, sizeof(__dfs), __mnt_info)
+
+#define DFS_FREE_MOUNT_INFO(__mnt_info) do { \
+        HASH_DELETE(hlink, dfs_runtime->mount_hash, __mnt_info); \
+        free(__mnt_info); \
+} while(0)
+
+#define DFS_RESOLVE_PARENT_REC_NAME(__dfs, __parent_obj, __parent_rec_name) do { \
+    struct dfs_mount_info *__mnt_info; \
+    struct dfs_file_record_ref *__parent_rec_ref; \
+    int __parent_rec_name_len; \
+    __parent_rec_name = NULL; \
+    if (__parent_obj) { \
+        __parent_rec_ref = darshan_lookup_record_ref(dfs_runtime->file_obj_hash, \
+            &__parent_obj, sizeof(__parent_obj)); \
+        if(!__parent_rec_ref) break; \
+        __parent_rec_name = darshan_core_lookup_record_name(__parent_rec_ref->file_rec->base_rec.id); \
+    } \
+    else { \
+        DFS_GET_MOUNT_INFO(__dfs, __mnt_info); \
+        if(!__mnt_info) break; \
+        __parent_rec_name_len = strlen(__mnt_info->pool_uuid_str) + strlen(__mnt_info->pool_uuid_str) + 4; \
+        __parent_rec_name = malloc(__parent_rec_name_len); \
+        if(!__parent_rec_name) break; \
+        memset(__parent_rec_name, 0, __parent_rec_name_len); \
+        strcat(__parent_rec_name, __mnt_info->pool_uuid_str); \
+        strcat(__parent_rec_name, ":"); \
+        strcat(__parent_rec_name, __mnt_info->cont_uuid_str); \
+        strcat(__parent_rec_name, ":"); \
+        strcat(__parent_rec_name, "/"); \
+    } \
+} while(0)
+
+/* XXX is it right to attribute lookup timing to open? */
+#define DFS_RECORD_FILE_OBJ_OPEN(__dfs, __parent_name, __obj_name, __counter, __obj_p, __tm1, __tm2) do { \
+    struct dfs_mount_info *__mnt_info; \
+    char *__rec_name; \
+    int __rec_name_len; \
+    darshan_record_id __rec_id; \
+    struct dfs_file_record_ref *__rec_ref; \
+    __rec_name_len = strlen(__obj_name) + 1; \
+    if(__parent_name) { \
+        __rec_name_len += strlen(__parent_name); \
+        __rec_name = malloc(__rec_name_len); \
+        if(!__rec_name) break; \
+        memset(__rec_name, 0, __rec_name_len); \
+        strcat(__rec_name, __parent_name); \
+        strcat(__rec_name, __obj_name); \
+    } \
+    else { \
+        DFS_GET_MOUNT_INFO(__dfs, __mnt_info); \
+        if(!__mnt_info) break; \
+        __rec_name_len += (strlen(__mnt_info->pool_uuid_str) + strlen(__mnt_info->pool_uuid_str) + 2); \
+        __rec_name = malloc(__rec_name_len); \
+        if(!__rec_name) break; \
+        memset(__rec_name, 0, __rec_name_len); \
+        strcat(__rec_name, __mnt_info->pool_uuid_str); \
+        strcat(__rec_name, ":"); \
+        strcat(__rec_name, __mnt_info->cont_uuid_str); \
+        strcat(__rec_name, ":"); \
+        strcat(__rec_name, __obj_name); \
+    } \
+    __rec_id = darshan_core_gen_record_id(__rec_name); \
+    __rec_ref = darshan_lookup_record_ref(dfs_runtime->rec_id_hash, &__rec_id, sizeof(__rec_id)); \
+    if(!__rec_ref) __rec_ref = dfs_track_new_file_record(__rec_id, __rec_name); \
+    free(__rec_name); \
+    DFS_RECORD_FILE_OBJREF_OPEN(__rec_ref, __counter, __obj_p, __tm1, __tm2); \
+} while(0)
+
+#define DFS_RECORD_FILE_OBJREF_OPEN(__rec_ref, __counter, __obj_p, __tm1, __tm2) do { \
+    if(!__rec_ref) break; \
+    __rec_ref->file_rec->counters[__counter] += 1; \
+    if(getenv("DFS_USE_DTX")) __rec_ref->file_rec->counters[DFS_USE_DTX] = 1; \
+    if(__rec_ref->file_rec->fcounters[DFS_F_OPEN_START_TIMESTAMP] == 0 || \
+         __rec_ref->file_rec->fcounters[DFS_F_OPEN_START_TIMESTAMP] > __tm1) \
+            __rec_ref->file_rec->fcounters[DFS_F_OPEN_START_TIMESTAMP] = __tm1; \
+        __rec_ref->file_rec->fcounters[DFS_F_OPEN_END_TIMESTAMP] = __tm2; \
+        DARSHAN_TIMER_INC_NO_OVERLAP(__rec_ref->file_rec->fcounters[DFS_F_META_TIME], \
+            __tm1, __tm2, __rec_ref->last_meta_end); \
+    darshan_add_record_ref(&(dfs_runtime->file_obj_hash), __obj_p, sizeof(*__obj_p), __rec_ref); \
+} while(0)
+
+#define DFS_RECORD_READ(__obj, __read_size, __counter, __ev, __tm1, __tm2) do { \
+    struct dfs_file_record_ref *__rec_ref; \
+    struct darshan_common_val_counter *__cvc; \
+    double __elapsed = __tm2-__tm1; \
+    daos_size_t __chunk_size; \
+    __rec_ref = darshan_lookup_record_ref(dfs_runtime->file_obj_hash, &__obj, sizeof(obj)); \
+    if(!__rec_ref) break; \
+    __rec_ref->file_rec->counters[__counter] += 1; \
+    if(__ev) \
+        __rec_ref->file_rec->counters[DFS_NB_READS] += 1; \
+    __rec_ref->file_rec->counters[DFS_BYTES_READ] += __read_size; \
+    DARSHAN_BUCKET_INC(&(__rec_ref->file_rec->counters[DFS_SIZE_READ_0_100]), __read_size); \
+    __cvc = darshan_track_common_val_counters(&__rec_ref->access_root, &__read_size, 1, \
+        &__rec_ref->access_count); \
+    if(__cvc) DARSHAN_UPDATE_COMMON_VAL_COUNTERS( \
+        &(__rec_ref->file_rec->counters[DFS_ACCESS1_ACCESS]), \
+        &(__rec_ref->file_rec->counters[DFS_ACCESS1_COUNT]), \
+        __cvc->vals, 1, __cvc->freq, 0); \
+    if(__rec_ref->last_io_type == DARSHAN_IO_WRITE) \
+        __rec_ref->file_rec->counters[DFS_RW_SWITCHES] += 1; \
+    __rec_ref->last_io_type = DARSHAN_IO_READ; \
+    if(__rec_ref->file_rec->counters[DFS_CHUNK_SIZE] == 0) \
+        if(dfs_get_chunk_size(__obj, &__chunk_size) == 0) \
+            __rec_ref->file_rec->counters[DFS_CHUNK_SIZE] = __chunk_size; \
+    if(__rec_ref->file_rec->fcounters[DFS_F_READ_START_TIMESTAMP] == 0 || \
+     __rec_ref->file_rec->fcounters[DFS_F_READ_START_TIMESTAMP] > __tm1) \
+        __rec_ref->file_rec->fcounters[DFS_F_READ_START_TIMESTAMP] = __tm1; \
+    __rec_ref->file_rec->fcounters[DFS_F_READ_END_TIMESTAMP] = __tm2; \
+    if(__rec_ref->file_rec->fcounters[DFS_F_MAX_READ_TIME] < __elapsed) { \
+        __rec_ref->file_rec->fcounters[DFS_F_MAX_READ_TIME] = __elapsed; \
+        __rec_ref->file_rec->counters[DFS_MAX_READ_TIME_SIZE] = __read_size; \
+    } \
+    DARSHAN_TIMER_INC_NO_OVERLAP(__rec_ref->file_rec->fcounters[DFS_F_READ_TIME], \
+        __tm1, __tm2, __rec_ref->last_read_end); \
+} while(0)
+
+#define DFS_RECORD_WRITE(__obj, __write_size, __counter, __ev, __tm1, __tm2) do { \
+    struct dfs_file_record_ref *__rec_ref; \
+    struct darshan_common_val_counter *__cvc; \
+    double __elapsed = __tm2-__tm1; \
+    daos_size_t __chunk_size; \
+    __rec_ref = darshan_lookup_record_ref(dfs_runtime->file_obj_hash, &__obj, sizeof(obj)); \
+    if(!__rec_ref) break; \
+    __rec_ref->file_rec->counters[__counter] += 1; \
+    if(__ev) \
+        __rec_ref->file_rec->counters[DFS_NB_WRITES] += 1; \
+    __rec_ref->file_rec->counters[DFS_BYTES_WRITTEN] += __write_size; \
+    DARSHAN_BUCKET_INC(&(__rec_ref->file_rec->counters[DFS_SIZE_WRITE_0_100]), __write_size); \
+    __cvc = darshan_track_common_val_counters(&__rec_ref->access_root, &__write_size, 1, \
+        &__rec_ref->access_count); \
+    if(__cvc) DARSHAN_UPDATE_COMMON_VAL_COUNTERS( \
+        &(__rec_ref->file_rec->counters[DFS_ACCESS1_ACCESS]), \
+        &(__rec_ref->file_rec->counters[DFS_ACCESS1_COUNT]), \
+        __cvc->vals, 1, __cvc->freq, 0); \
+    if(__rec_ref->last_io_type == DARSHAN_IO_READ) \
+        __rec_ref->file_rec->counters[DFS_RW_SWITCHES] += 1; \
+    __rec_ref->last_io_type = DARSHAN_IO_WRITE; \
+    if(__rec_ref->file_rec->counters[DFS_CHUNK_SIZE] == 0) \
+        if(dfs_get_chunk_size(__obj, &__chunk_size) == 0) \
+            __rec_ref->file_rec->counters[DFS_CHUNK_SIZE] = __chunk_size; \
+    if(__rec_ref->file_rec->fcounters[DFS_F_WRITE_START_TIMESTAMP] == 0 || \
+     __rec_ref->file_rec->fcounters[DFS_F_WRITE_START_TIMESTAMP] > __tm1) \
+        __rec_ref->file_rec->fcounters[DFS_F_WRITE_START_TIMESTAMP] = __tm1; \
+    __rec_ref->file_rec->fcounters[DFS_F_WRITE_END_TIMESTAMP] = __tm2; \
+    if(__rec_ref->file_rec->fcounters[DFS_F_MAX_WRITE_TIME] < __elapsed) { \
+        __rec_ref->file_rec->fcounters[DFS_F_MAX_WRITE_TIME] = __elapsed; \
+        __rec_ref->file_rec->counters[DFS_MAX_WRITE_TIME_SIZE] = __write_size; \
+    } \
+    DARSHAN_TIMER_INC_NO_OVERLAP(__rec_ref->file_rec->fcounters[DFS_F_WRITE_TIME], \
+        __tm1, __tm2, __rec_ref->last_write_end); \
+} while(0)
 
 /*****************************************************
  *      Wrappers for DAOS functions of interest      * 
@@ -64,45 +330,48 @@ static struct dfs_runtime *dfs_runtime = NULL;
 
 int DARSHAN_DECL(dfs_mount)(daos_handle_t poh, daos_handle_t coh, int flags, dfs_t **dfs)
 {
-    int ret, query_ret;
-    int success=0;
-    daos_pool_info_t pool_info;
-    daos_cont_info_t cont_info;
-    struct dfs_mount_info  *mnt_info;
-
-    fprintf(stderr, "***********DFS_MOUNT INTERCEPT\n");
+    int ret;
 
     MAP_OR_FAIL(dfs_mount);
 
     ret = __real_dfs_mount(poh, coh, flags, dfs);
 
-    /* TODO: Make sure we are init */
-    if(ret == 0)
-    {
-        /* query pool UUID from open handle */
-        query_ret = daos_pool_query(poh, NULL, &pool_info, NULL, NULL);
-        if(query_ret == 0)
-        {
-            query_ret = daos_cont_query(coh, &cont_info, NULL, NULL);
-            if(query_ret == 0)
-                success = 1;
-        }
+    DFS_PRE_RECORD();
+    DFS_STORE_MOUNT_INFO(poh, coh, dfs);
+    DFS_POST_RECORD();
 
-        if(success)
-        {
-            /* create mapping from DFS mount to pool & container UUIDs */
-            printf("**************FOUND\n");
-            mnt_info = malloc(sizeof(*mnt_info));
-            if(mnt_info)
-            {
-                uuid_copy(mnt_info->pool_uuid, pool_info.pi_uuid);
-                uuid_copy(mnt_info->cont_uuid, cont_info.ci_uuid);
-                HASH_ADD_KEYPTR(hlink, dfs_runtime->mount_hash, dfs, sizeof(dfs), mnt_info);
-            }
-        }
-    }
+    return(ret);
+}
+
+int DARSHAN_DECL(dfs_global2local)(daos_handle_t poh, daos_handle_t coh, int flags, d_iov_t glob, dfs_t **dfs)
+{
+    int ret;
+
+    MAP_OR_FAIL(dfs_global2local);
+
+    ret = __real_dfs_global2local(poh, coh, flags, glob, dfs);
+
+    DFS_PRE_RECORD();
+    DFS_STORE_MOUNT_INFO(poh, coh, dfs);
+    DFS_POST_RECORD();
+
+    return(ret);
+}
+
+int DARSHAN_DECL(dfs_umount)(dfs_t *dfs)
+{
+    int ret = 0;
+    struct dfs_mount_info *mnt_info;
+
+    MAP_OR_FAIL(dfs_umount);
+
+    DFS_PRE_RECORD();
+    DFS_GET_MOUNT_INFO(dfs, mnt_info);
+    if(mnt_info)
+        DFS_FREE_MOUNT_INFO(mnt_info);
+    DFS_POST_RECORD();
 
-    fprintf(stderr, "***********DFS_MOUNT INTERCEPT RETURN %d\n", ret);
+    ret = __real_dfs_umount(dfs);
 
     return(ret);
 }
@@ -118,6 +387,10 @@ int DARSHAN_DECL(dfs_lookup)(dfs_t *dfs, const char *path, int flags, dfs_obj_t
     ret = __real_dfs_lookup(dfs, path, flags, obj, mode, stbuf);
     tm2 = darshan_core_wtime();
 
+    DFS_PRE_RECORD();
+    DFS_RECORD_FILE_OBJ_OPEN(dfs, NULL, path, DFS_LOOKUPS, obj, tm1, tm2);
+    DFS_POST_RECORD();
+
     return(ret);
 }
 
@@ -125,6 +398,7 @@ int DARSHAN_DECL(dfs_lookup_rel)(dfs_t *dfs, dfs_obj_t *parent, const char *name
 {
     int ret;
     double tm1, tm2;
+    char *parent_rec_name;
 
     MAP_OR_FAIL(dfs_lookup_rel);
 
@@ -132,6 +406,15 @@ int DARSHAN_DECL(dfs_lookup_rel)(dfs_t *dfs, dfs_obj_t *parent, const char *name
     ret = __real_dfs_lookup_rel(dfs, parent, name, flags, obj, mode, stbuf);
     tm2 = darshan_core_wtime();
 
+    DFS_PRE_RECORD();
+    DFS_RESOLVE_PARENT_REC_NAME(dfs, parent, parent_rec_name);
+    if(parent_rec_name)
+    {
+        DFS_RECORD_FILE_OBJ_OPEN(dfs, parent_rec_name, name, DFS_LOOKUPS, obj, tm1, tm2);
+        if(!parent) free(parent_rec_name);
+    }
+    DFS_POST_RECORD();
+
     return(ret);
 }
 
@@ -139,6 +422,7 @@ int DARSHAN_DECL(dfs_open)(dfs_t *dfs, dfs_obj_t *parent, const char *name, mode
 {
     int ret;
     double tm1, tm2;
+    char *parent_rec_name;
 
     MAP_OR_FAIL(dfs_open);
 
@@ -146,6 +430,15 @@ int DARSHAN_DECL(dfs_open)(dfs_t *dfs, dfs_obj_t *parent, const char *name, mode
     ret = __real_dfs_open(dfs, parent, name, mode, flags, cid, chunk_size, value, obj);
     tm2 = darshan_core_wtime();
 
+    DFS_PRE_RECORD();
+    DFS_RESOLVE_PARENT_REC_NAME(dfs, parent, parent_rec_name);
+    if(parent_rec_name)
+    {
+        DFS_RECORD_FILE_OBJ_OPEN(dfs, parent_rec_name, name, DFS_OPENS, obj, tm1, tm2);
+        if(!parent) free(parent_rec_name);
+    }
+    DFS_POST_RECORD();
+
     return(ret);
 }
 
@@ -153,6 +446,7 @@ int DARSHAN_DECL(dfs_dup)(dfs_t *dfs, dfs_obj_t *obj, int flags, dfs_obj_t **new
 {
     int ret;
     double tm1, tm2;
+    struct dfs_file_record_ref *rec_ref = NULL;
 
     MAP_OR_FAIL(dfs_dup);
 
@@ -160,6 +454,11 @@ int DARSHAN_DECL(dfs_dup)(dfs_t *dfs, dfs_obj_t *obj, int flags, dfs_obj_t **new
     ret = __real_dfs_dup(dfs, obj, flags, new_obj);
     tm2 = darshan_core_wtime();
 
+    DFS_PRE_RECORD();
+    rec_ref = darshan_lookup_record_ref(dfs_runtime->file_obj_hash, &obj, sizeof(obj));
+    DFS_RECORD_FILE_OBJREF_OPEN(rec_ref, DFS_DUPS, new_obj, tm1, tm2);
+    DFS_POST_RECORD();
+
     return(ret);
 }
 
@@ -174,6 +473,10 @@ int DARSHAN_DECL(dfs_obj_global2local)(dfs_t *dfs, int flags, d_iov_t glob, dfs_
     ret = __real_dfs_obj_global2local(dfs, flags, glob, obj);
     tm2 = darshan_core_wtime();
 
+    DFS_PRE_RECORD();
+    // XXX need help here, no way to convert args to object name
+    DFS_POST_RECORD();
+
     return(ret);
 }
 
@@ -181,6 +484,7 @@ int DARSHAN_DECL(dfs_release)(dfs_obj_t *obj)
 {
     int ret;
     double tm1, tm2;
+    struct dfs_file_record_ref *rec_ref = NULL;
 
     MAP_OR_FAIL(dfs_release);
 
@@ -188,9 +492,808 @@ int DARSHAN_DECL(dfs_release)(dfs_obj_t *obj)
     ret = __real_dfs_release(obj);
     tm2 = darshan_core_wtime();
 
+    DFS_PRE_RECORD();
+    rec_ref = darshan_lookup_record_ref(dfs_runtime->file_obj_hash, &obj, sizeof(obj));
+    if(rec_ref)
+    {
+        if(rec_ref->file_rec->fcounters[DFS_F_CLOSE_START_TIMESTAMP] == 0 ||
+         rec_ref->file_rec->fcounters[DFS_F_CLOSE_START_TIMESTAMP] > tm1)
+           rec_ref->file_rec->fcounters[DFS_F_CLOSE_START_TIMESTAMP] = tm1;
+        rec_ref->file_rec->fcounters[DFS_F_CLOSE_END_TIMESTAMP] = tm2;
+        DARSHAN_TIMER_INC_NO_OVERLAP(
+            rec_ref->file_rec->fcounters[DFS_F_META_TIME],
+            tm1, tm2, rec_ref->last_meta_end);
+        darshan_delete_record_ref(&(dfs_runtime->file_obj_hash), &obj, sizeof(obj));
+    }
+    DFS_POST_RECORD();
+
     return(ret);
 }
 
+int DARSHAN_DECL(dfs_read)(dfs_t *dfs, dfs_obj_t *obj, d_sg_list_t *sgl, daos_off_t off, daos_size_t *read_size, daos_event_t *ev)
+{
+    int ret;
+    double tm1, tm2;
+    daos_size_t rdsize;
+
+    MAP_OR_FAIL(dfs_read);
+
+    tm1 = darshan_core_wtime();
+    ret = __real_dfs_read(dfs, obj, sgl, off, read_size, ev);
+    tm2 = darshan_core_wtime();
+
+    DFS_PRE_RECORD();
+    /* no need to calculate read_size, it's returned to user */
+    rdsize = *read_size;
+    DFS_RECORD_READ(obj, rdsize, DFS_READS, ev, tm1, tm2);
+    DFS_POST_RECORD();
+
+    return(ret);
+}
+
+int DARSHAN_DECL(dfs_readx)(dfs_t *dfs, dfs_obj_t *obj, dfs_iod_t *iod, d_sg_list_t *sgl, daos_size_t *read_size, daos_event_t *ev)
+{
+    int ret;
+    double tm1, tm2;
+    daos_size_t rdsize;
+
+    MAP_OR_FAIL(dfs_readx);
+
+    tm1 = darshan_core_wtime();
+    ret = __real_dfs_readx(dfs, obj, iod, sgl, read_size, ev);
+    tm2 = darshan_core_wtime();
+
+    DFS_PRE_RECORD();
+    rdsize = *read_size;
+    DFS_RECORD_READ(obj, rdsize, DFS_READXS, ev, tm1, tm2);
+    DFS_POST_RECORD();
+
+    return(ret);
+}
+
+int DARSHAN_DECL(dfs_write)(dfs_t *dfs, dfs_obj_t *obj, d_sg_list_t *sgl, daos_off_t off, daos_event_t *ev)
+{
+    int ret;
+    double tm1, tm2;
+    daos_size_t wrsize;
+    int i;
+
+    MAP_OR_FAIL(dfs_write);
+
+    tm1 = darshan_core_wtime();
+    ret = __real_dfs_write(dfs, obj, sgl, off, ev);
+    tm2 = darshan_core_wtime();
+
+    DFS_PRE_RECORD();
+    /* calculate write size first */
+    for (i = 0, wrsize = 0; i < sgl->sg_nr; i++)
+        wrsize += sgl->sg_iovs[i].iov_len;
+    DFS_RECORD_WRITE(obj, wrsize, DFS_WRITES, ev, tm1, tm2);
+    DFS_POST_RECORD();
+
+    return(ret);
+}
+
+int DARSHAN_DECL(dfs_writex)(dfs_t *dfs, dfs_obj_t *obj, dfs_iod_t *iod, d_sg_list_t *sgl, daos_event_t *ev)
+{
+    int ret;
+    double tm1, tm2;
+    daos_size_t wrsize;
+    int i;
+
+    MAP_OR_FAIL(dfs_writex);
+
+    tm1 = darshan_core_wtime();
+    ret = __real_dfs_writex(dfs, obj, iod, sgl, ev);
+    tm2 = darshan_core_wtime();
+
+    DFS_PRE_RECORD();
+    /* calculate write size first */
+    for (i = 0, wrsize = 0; i < sgl->sg_nr; i++)
+        wrsize += sgl->sg_iovs[i].iov_len;
+    DFS_RECORD_WRITE(obj, wrsize, DFS_WRITEXS, ev, tm1, tm2);
+    DFS_POST_RECORD();
+
+    return(ret);
+}
+
+int DARSHAN_DECL(dfs_get_size)(dfs_t *dfs, dfs_obj_t *obj, daos_size_t *size)
+{
+    int ret;
+    double tm1, tm2;
+    struct dfs_file_record_ref *rec_ref = NULL;
+
+    MAP_OR_FAIL(dfs_get_size);
+
+    tm1 = darshan_core_wtime();
+    ret = __real_dfs_get_size(dfs, obj, size);
+    tm2 = darshan_core_wtime();
+
+    DFS_PRE_RECORD();
+    rec_ref = darshan_lookup_record_ref(dfs_runtime->file_obj_hash, &obj, sizeof(obj));
+    if(rec_ref)
+    {
+        rec_ref->file_rec->counters[DFS_GET_SIZES] += 1;
+        DARSHAN_TIMER_INC_NO_OVERLAP(
+            rec_ref->file_rec->fcounters[DFS_F_META_TIME],
+            tm1, tm2, rec_ref->last_meta_end);
+    }
+    DFS_POST_RECORD();
+
+    return(ret);
+}
+
+int DARSHAN_DECL(dfs_punch)(dfs_t *dfs, dfs_obj_t *obj, daos_off_t offset, daos_size_t len)
+{
+    int ret;
+    double tm1, tm2;
+    struct dfs_file_record_ref *rec_ref = NULL;
+
+    MAP_OR_FAIL(dfs_punch);
+
+    tm1 = darshan_core_wtime();
+    ret = __real_dfs_punch(dfs, obj, offset, len);
+    tm2 = darshan_core_wtime();
+
+    DFS_PRE_RECORD();
+    rec_ref = darshan_lookup_record_ref(dfs_runtime->file_obj_hash, &obj, sizeof(obj));
+    if(rec_ref)
+    {
+        rec_ref->file_rec->counters[DFS_PUNCHES] += 1;
+        DARSHAN_TIMER_INC_NO_OVERLAP(
+            rec_ref->file_rec->fcounters[DFS_F_META_TIME],
+            tm1, tm2, rec_ref->last_meta_end);
+    }
+    DFS_POST_RECORD();
+
+    return(ret);
+}
+
+int DARSHAN_DECL(dfs_move)(dfs_t *dfs, dfs_obj_t *parent, char *name, dfs_obj_t *new_parent, char *new_name, daos_obj_id_t *oid)
+{
+    int ret;
+    double tm1, tm2;
+    struct dfs_file_record_ref *rec_ref = NULL;
+    char *parent_rec_name, *rec_name;
+    int rec_len;
+    darshan_record_id rec_id;
+
+    MAP_OR_FAIL(dfs_move);
+
+    tm1 = darshan_core_wtime();
+    ret = __real_dfs_move(dfs, parent, name, new_parent, new_name, oid);
+    tm2 = darshan_core_wtime();
+
+    DFS_PRE_RECORD();
+    DFS_RESOLVE_PARENT_REC_NAME(dfs, parent, parent_rec_name);
+    if(parent_rec_name)
+    {
+        rec_len = strlen(parent_rec_name) + strlen(name) + 1;
+        rec_name = malloc(rec_len);
+        if(rec_name)
+        {
+            memset(rec_name, 0, rec_len);
+            strcat(rec_name, parent_rec_name);
+            strcat(rec_name, name);
+            rec_id = darshan_core_gen_record_id(rec_name);
+            rec_ref = darshan_lookup_record_ref(dfs_runtime->rec_id_hash, &rec_id, sizeof(rec_id));
+            if(rec_ref)
+            {
+                rec_ref->file_rec->counters[DFS_MOVES] += 1;
+                DARSHAN_TIMER_INC_NO_OVERLAP(
+                    rec_ref->file_rec->fcounters[DFS_F_META_TIME],
+                    tm1, tm2, rec_ref->last_meta_end);
+            }
+            free(rec_name);
+        }
+        if(!parent) free(parent_rec_name);
+    }
+    DFS_POST_RECORD();
+
+    return(ret);
+}
+
+int DARSHAN_DECL(dfs_exchange)(dfs_t *dfs, dfs_obj_t *parent1, char *name1, dfs_obj_t *parent2, char *name2)
+{
+    int ret;
+    double tm1, tm2;
+    struct dfs_file_record_ref *rec_ref = NULL;
+    char *parent_rec_name, *rec_name;
+    int rec_len;
+    darshan_record_id rec_id;
+
+    MAP_OR_FAIL(dfs_exchange);
+
+    tm1 = darshan_core_wtime();
+    ret = __real_dfs_exchange(dfs, parent1, name1, parent2, name2);
+    tm2 = darshan_core_wtime();
+
+    DFS_PRE_RECORD();
+    /* increment exchange counter for both file records */
+    /* NOTE: only increment metadata time on first record, to avoid double counting */
+    DFS_RESOLVE_PARENT_REC_NAME(dfs, parent1, parent_rec_name);
+    if(parent_rec_name)
+    {
+        rec_len = strlen(parent_rec_name) + strlen(name1) + 1;
+        rec_name = malloc(rec_len);
+        if(rec_name)
+        {
+            memset(rec_name, 0, rec_len);
+            strcat(rec_name, parent_rec_name);
+            strcat(rec_name, name1);
+            rec_id = darshan_core_gen_record_id(rec_name);
+            rec_ref = darshan_lookup_record_ref(dfs_runtime->rec_id_hash, &rec_id, sizeof(rec_id));
+            if(rec_ref)
+            {
+                rec_ref->file_rec->counters[DFS_EXCHANGES] += 1;
+                DARSHAN_TIMER_INC_NO_OVERLAP(
+                    rec_ref->file_rec->fcounters[DFS_F_META_TIME],
+                    tm1, tm2, rec_ref->last_meta_end);
+            }
+            free(rec_name);
+        }
+        if(!parent1) free(parent_rec_name);
+    }
+    DFS_RESOLVE_PARENT_REC_NAME(dfs, parent2, parent_rec_name);
+    if(parent_rec_name)
+    {
+        rec_len = strlen(parent_rec_name) + strlen(name2) + 1;
+        rec_name = malloc(rec_len);
+        if(rec_name)
+        {
+            memset(rec_name, 0, rec_len);
+            strcat(rec_name, parent_rec_name);
+            strcat(rec_name, name1);
+            rec_id = darshan_core_gen_record_id(rec_name);
+            rec_ref = darshan_lookup_record_ref(dfs_runtime->rec_id_hash, &rec_id, sizeof(rec_id));
+            if(rec_ref)
+                rec_ref->file_rec->counters[DFS_EXCHANGES] += 1;
+            free(rec_name);
+        }
+        if(!parent2) free(parent_rec_name);
+    }
+    DFS_POST_RECORD();
+
+    return(ret);
+}
+
+int DARSHAN_DECL(dfs_stat)(dfs_t *dfs, dfs_obj_t *parent, const char *name, struct stat *stbuf)
+{
+    int ret;
+    double tm1, tm2;
+    struct dfs_file_record_ref *rec_ref = NULL;
+    char *parent_rec_name, *rec_name;
+    int rec_len;
+    darshan_record_id rec_id;
+
+    MAP_OR_FAIL(dfs_stat);
+
+    tm1 = darshan_core_wtime();
+    ret = __real_dfs_stat(dfs, parent, name, stbuf);
+    tm2 = darshan_core_wtime();
+
+    DFS_PRE_RECORD();
+    DFS_RESOLVE_PARENT_REC_NAME(dfs, parent, parent_rec_name);
+    if(parent_rec_name)
+    {
+        rec_len = strlen(parent_rec_name) + strlen(name) + 1;
+        rec_name = malloc(rec_len);
+        if(rec_name)
+        {
+            memset(rec_name, 0, rec_len);
+            strcat(rec_name, parent_rec_name);
+            strcat(rec_name, name);
+            rec_id = darshan_core_gen_record_id(rec_name);
+            rec_ref = darshan_lookup_record_ref(dfs_runtime->rec_id_hash, &rec_id, sizeof(rec_id));
+            if(!rec_ref) rec_ref = dfs_track_new_file_record(rec_id, rec_name);
+            if(rec_ref)
+            {
+                rec_ref->file_rec->counters[DFS_STATS] += 1;
+                DARSHAN_TIMER_INC_NO_OVERLAP(
+                    rec_ref->file_rec->fcounters[DFS_F_META_TIME],
+                    tm1, tm2, rec_ref->last_meta_end);
+            }
+            free(rec_name);
+        }
+        if(!parent) free(parent_rec_name);
+    }
+    DFS_POST_RECORD();
+
+    return(ret);
+}
+
+int DARSHAN_DECL(dfs_ostat)(dfs_t *dfs, dfs_obj_t *obj, struct stat *stbuf)
+{
+    int ret;
+    double tm1, tm2;
+    struct dfs_file_record_ref *rec_ref = NULL;
+
+    MAP_OR_FAIL(dfs_ostat);
+
+    tm1 = darshan_core_wtime();
+    ret = __real_dfs_ostat(dfs, obj, stbuf);
+    tm2 = darshan_core_wtime();
+
+    DFS_PRE_RECORD();
+    rec_ref = darshan_lookup_record_ref(dfs_runtime->file_obj_hash, &obj, sizeof(obj));
+    if(rec_ref)
+    {
+        rec_ref->file_rec->counters[DFS_STATS] += 1;
+        DARSHAN_TIMER_INC_NO_OVERLAP(
+            rec_ref->file_rec->fcounters[DFS_F_META_TIME],
+            tm1, tm2, rec_ref->last_meta_end);
+    }
+    DFS_POST_RECORD();
+
+    return(ret);
+}
+
+int DARSHAN_DECL(dfs_osetattr)(dfs_t *dfs, dfs_obj_t *obj, struct stat *stbuf, int flags)
+{
+    int ret;
+    double tm1, tm2;
+    struct dfs_file_record_ref *rec_ref = NULL;
+
+    MAP_OR_FAIL(dfs_osetattr);
+
+    tm1 = darshan_core_wtime();
+    ret = __real_dfs_osetattr(dfs, obj, stbuf, flags);
+    tm2 = darshan_core_wtime();
+
+    DFS_PRE_RECORD();
+    rec_ref = darshan_lookup_record_ref(dfs_runtime->file_obj_hash, &obj, sizeof(obj));
+    if(rec_ref)
+    {
+        rec_ref->file_rec->counters[DFS_STATS] += 1;
+        DARSHAN_TIMER_INC_NO_OVERLAP(
+            rec_ref->file_rec->fcounters[DFS_F_META_TIME],
+            tm1, tm2, rec_ref->last_meta_end);
+    }
+    DFS_POST_RECORD();
+
+    return(ret);
+}
+
+/*********************************************************
+ * Internal functions for manipulating DAOS module state *
+ *********************************************************/
+
+static void dfs_runtime_initialize()
+{
+    int dfs_buf_size;
+    darshan_module_funcs mod_funcs = {
+#ifdef HAVE_MPI
+        .mod_redux_func = &dfs_mpi_redux,
+#endif
+        .mod_shutdown_func = &dfs_shutdown
+        };
+
+    /* try to store a default number of records for this module */
+    dfs_buf_size = DARSHAN_DEF_MOD_REC_COUNT * sizeof(struct darshan_dfs_file);
+
+    /* register the DFS module with darshan core */
+    darshan_core_register_module(
+        DARSHAN_DFS_MOD,
+        mod_funcs,
+        &dfs_buf_size,
+        &my_rank,
+        NULL);
+
+    /* return if darshan-core does not provide enough module memory */
+    if(dfs_buf_size < sizeof(struct darshan_dfs_file))
+    {
+        darshan_core_unregister_module(DARSHAN_DFS_MOD);
+        return;
+    }
+
+    dfs_runtime = malloc(sizeof(*dfs_runtime));
+    if(!dfs_runtime)
+    {
+        darshan_core_unregister_module(DARSHAN_DFS_MOD);
+        return;
+    }
+    memset(dfs_runtime, 0, sizeof(*dfs_runtime));
+
+    return;
+}
+
+static struct dfs_file_record_ref *dfs_track_new_file_record(
+    darshan_record_id rec_id, const char *path)
+{
+    struct darshan_dfs_file *file_rec = NULL;
+    struct dfs_file_record_ref *rec_ref = NULL;
+    int ret;
+
+    rec_ref = malloc(sizeof(*rec_ref));
+    if(!rec_ref)
+        return(NULL);
+    memset(rec_ref, 0, sizeof(*rec_ref));
+
+    /* add a reference to this file record based on record id */
+    ret = darshan_add_record_ref(&(dfs_runtime->rec_id_hash), &rec_id,
+        sizeof(darshan_record_id), rec_ref);
+    if(ret == 0)
+    {
+        free(rec_ref);
+        return(NULL);
+    }
+
+    /* register the actual file record with darshan-core so it is persisted
+     * in the log file
+     */
+    file_rec = darshan_core_register_record(
+        rec_id,
+        path,
+        DARSHAN_DFS_MOD,
+        sizeof(struct darshan_dfs_file),
+        NULL);
+
+    if(!file_rec)
+    {
+        darshan_delete_record_ref(&(dfs_runtime->rec_id_hash),
+            &rec_id, sizeof(darshan_record_id));
+        free(rec_ref);
+        return(NULL);
+    }
+
+    /* registering this file record was successful, so initialize some fields */
+    file_rec->base_rec.id = rec_id;
+    file_rec->base_rec.rank = my_rank;
+    /* XXX set initial data */
+    rec_ref->file_rec = file_rec;
+    dfs_runtime->file_rec_count++;
+
+    return(rec_ref);
+}
+
+static void dfs_finalize_file_records(void *rec_ref_p, void *user_ptr)
+{
+    struct dfs_file_record_ref *rec_ref =
+        (struct dfs_file_record_ref *)rec_ref_p;
+
+    tdestroy(rec_ref->access_root, free);
+    return;
+}
+
+static void dfs_cleanup_runtime()
+{
+    struct dfs_mount_info *mnt_info, *tmp;
+
+    darshan_clear_record_refs(&(dfs_runtime->file_obj_hash), 0);
+    darshan_clear_record_refs(&(dfs_runtime->rec_id_hash), 1);
+
+    HASH_ITER(hlink, dfs_runtime->mount_hash, mnt_info, tmp)
+    {
+        HASH_DELETE(hlink, dfs_runtime->mount_hash, mnt_info);
+        free(mnt_info);
+    }
+
+    free(dfs_runtime);
+    dfs_runtime = NULL;
+
+    return;
+}
+
+#ifdef HAVE_MPI
+static void dfs_record_reduction_op(
+    void* infile_v, void* inoutfile_v, int *len, MPI_Datatype *datatype)
+{
+    struct darshan_dfs_file tmp_file;
+    struct darshan_dfs_file *infile = infile_v;
+    struct darshan_dfs_file *inoutfile = inoutfile_v;
+    int i, j, k;
+
+    for(i=0; i<*len; i++)
+    {
+        memset(&tmp_file, 0, sizeof(struct darshan_dfs_file));
+        tmp_file.base_rec.id = infile->base_rec.id;
+        tmp_file.base_rec.rank = -1;
+
+        /* sum */
+        for(j=DFS_OPENS; j<=DFS_RW_SWITCHES; j++)
+        {
+            tmp_file.counters[j] = infile->counters[j] + inoutfile->counters[j];
+            if(tmp_file.counters[j] < 0) /* make sure invalid counters are -1 exactly */
+                tmp_file.counters[j] = -1;
+        }
+
+        tmp_file.counters[DFS_CHUNK_SIZE] = infile->counters[DFS_CHUNK_SIZE];
+        tmp_file.counters[DFS_USE_DTX] = infile->counters[DFS_USE_DTX];
+
+        /* skip DFS_MAX_*_TIME_SIZE; handled in floating point section */
+
+        for(j=DFS_SIZE_READ_0_100; j<=DFS_SIZE_WRITE_1G_PLUS; j++)
+        {
+            tmp_file.counters[j] = infile->counters[j] + inoutfile->counters[j];
+        }
+
+        /* common access counters */
+
+        /* first collapse any duplicates */
+        for(j=DFS_ACCESS1_ACCESS; j<=DFS_ACCESS4_ACCESS; j++)
+        {
+            for(k=DFS_ACCESS1_ACCESS; k<=DFS_ACCESS4_ACCESS; k++)
+            {
+                if(infile->counters[j] == inoutfile->counters[k])
+                {
+                    infile->counters[j+4] += inoutfile->counters[k+4];
+                    inoutfile->counters[k] = 0;
+                    inoutfile->counters[k+4] = 0;
+                }
+            }
+        }
+
+        /* first set */
+        for(j=DFS_ACCESS1_ACCESS; j<=DFS_ACCESS4_ACCESS; j++)
+        {
+            DARSHAN_UPDATE_COMMON_VAL_COUNTERS(
+                &(tmp_file.counters[DFS_ACCESS1_ACCESS]),
+                &(tmp_file.counters[DFS_ACCESS1_COUNT]),
+                &infile->counters[j], 1, infile->counters[j+4], 1);
+        }
+        /* second set */
+        for(j=DFS_ACCESS1_ACCESS; j<=DFS_ACCESS4_ACCESS; j++)
+        {
+            DARSHAN_UPDATE_COMMON_VAL_COUNTERS(
+                &(tmp_file.counters[DFS_ACCESS1_ACCESS]),
+                &(tmp_file.counters[DFS_ACCESS1_COUNT]),
+                &inoutfile->counters[j], 1, inoutfile->counters[j+4], 1);
+        }
+
+        /* min non-zero (if available) value */
+        for(j=DFS_F_OPEN_START_TIMESTAMP; j<=DFS_F_CLOSE_START_TIMESTAMP; j++)
+        {
+            if((infile->fcounters[j] < inoutfile->fcounters[j] &&
+               infile->fcounters[j] > 0) || inoutfile->fcounters[j] == 0)
+                tmp_file.fcounters[j] = infile->fcounters[j];
+            else
+                tmp_file.fcounters[j] = inoutfile->fcounters[j];
+        }
+
+        /* max */
+        for(j=DFS_F_OPEN_END_TIMESTAMP; j<=DFS_F_CLOSE_END_TIMESTAMP; j++)
+        {
+            if(infile->fcounters[j] > inoutfile->fcounters[j])
+                tmp_file.fcounters[j] = infile->fcounters[j];
+            else
+                tmp_file.fcounters[j] = inoutfile->fcounters[j];
+        }
+
+        /* sum */
+        for(j=DFS_F_READ_TIME; j<=DFS_F_META_TIME; j++)
+        {
+            tmp_file.fcounters[j] = infile->fcounters[j] + inoutfile->fcounters[j];
+        }
+
+        /* max (special case) */
+        if(infile->fcounters[DFS_F_MAX_READ_TIME] >
+            inoutfile->fcounters[DFS_F_MAX_READ_TIME])
+        {
+            tmp_file.fcounters[DFS_F_MAX_READ_TIME] =
+                infile->fcounters[DFS_F_MAX_READ_TIME];
+            tmp_file.counters[DFS_MAX_READ_TIME_SIZE] =
+                infile->counters[DFS_MAX_READ_TIME_SIZE];
+        }
+        else
+        {
+            tmp_file.fcounters[DFS_F_MAX_READ_TIME] =
+                inoutfile->fcounters[DFS_F_MAX_READ_TIME];
+            tmp_file.counters[DFS_MAX_READ_TIME_SIZE] =
+                inoutfile->counters[DFS_MAX_READ_TIME_SIZE];
+        }
+
+        if(infile->fcounters[DFS_F_MAX_WRITE_TIME] >
+            inoutfile->fcounters[DFS_F_MAX_WRITE_TIME])
+        {
+            tmp_file.fcounters[DFS_F_MAX_WRITE_TIME] =
+                infile->fcounters[DFS_F_MAX_WRITE_TIME];
+            tmp_file.counters[DFS_MAX_WRITE_TIME_SIZE] =
+                infile->counters[DFS_MAX_WRITE_TIME_SIZE];
+        }
+        else
+        {
+            tmp_file.fcounters[DFS_F_MAX_WRITE_TIME] =
+                inoutfile->fcounters[DFS_F_MAX_WRITE_TIME];
+            tmp_file.counters[DFS_MAX_WRITE_TIME_SIZE] =
+                inoutfile->counters[DFS_MAX_WRITE_TIME_SIZE];
+        }
+
+        /* min (zeroes are ok here; some procs don't do I/O) */
+        if(infile->fcounters[DFS_F_FASTEST_RANK_TIME] <
+           inoutfile->fcounters[DFS_F_FASTEST_RANK_TIME])
+        {
+            tmp_file.counters[DFS_FASTEST_RANK] =
+                infile->counters[DFS_FASTEST_RANK];
+            tmp_file.counters[DFS_FASTEST_RANK_BYTES] =
+                infile->counters[DFS_FASTEST_RANK_BYTES];
+            tmp_file.fcounters[DFS_F_FASTEST_RANK_TIME] =
+                infile->fcounters[DFS_F_FASTEST_RANK_TIME];
+        }
+        else
+        {
+            tmp_file.counters[DFS_FASTEST_RANK] =
+                inoutfile->counters[DFS_FASTEST_RANK];
+            tmp_file.counters[DFS_FASTEST_RANK_BYTES] =
+                inoutfile->counters[DFS_FASTEST_RANK_BYTES];
+            tmp_file.fcounters[DFS_F_FASTEST_RANK_TIME] =
+                inoutfile->fcounters[DFS_F_FASTEST_RANK_TIME];
+        }
+
+        /* max */
+        if(infile->fcounters[DFS_F_SLOWEST_RANK_TIME] >
+           inoutfile->fcounters[DFS_F_SLOWEST_RANK_TIME])
+        {
+            tmp_file.counters[DFS_SLOWEST_RANK] =
+                infile->counters[DFS_SLOWEST_RANK];
+            tmp_file.counters[DFS_SLOWEST_RANK_BYTES] =
+                infile->counters[DFS_SLOWEST_RANK_BYTES];
+            tmp_file.fcounters[DFS_F_SLOWEST_RANK_TIME] =
+                infile->fcounters[DFS_F_SLOWEST_RANK_TIME];
+        }
+        else
+        {
+            tmp_file.counters[DFS_SLOWEST_RANK] =
+                inoutfile->counters[DFS_SLOWEST_RANK];
+            tmp_file.counters[DFS_SLOWEST_RANK_BYTES] =
+                inoutfile->counters[DFS_SLOWEST_RANK_BYTES];
+            tmp_file.fcounters[DFS_F_SLOWEST_RANK_TIME] =
+                inoutfile->fcounters[DFS_F_SLOWEST_RANK_TIME];
+        }
+
+        /* update pointers */
+        *inoutfile = tmp_file;
+        inoutfile++;
+        infile++;
+    }
+
+    return;
+}
+#endif
+
+/*********************************************************************************
+ * shutdown functions exported by this module for coordinating with darshan-core *
+ *********************************************************************************/
+
+#ifdef HAVE_MPI
+static void dfs_mpi_redux(
+    void *dfs_buf, MPI_Comm mod_comm,
+    darshan_record_id *shared_recs, int shared_rec_count)
+{
+    int dfs_rec_count;
+    struct dfs_file_record_ref *rec_ref;
+    struct darshan_dfs_file *dfs_rec_buf = (struct darshan_dfs_file *)dfs_buf;
+    double dfs_time;
+    struct darshan_dfs_file *red_send_buf = NULL;
+    struct darshan_dfs_file *red_recv_buf = NULL;
+    MPI_Datatype red_type;
+    MPI_Op red_op;
+    int i;
+
+    DAOS_LOCK();
+    assert(dfs_runtime);
+
+    fprintf(stderr, "****ENTERING DFS REDUX [%d]\n", my_rank);
+
+    dfs_rec_count = dfs_runtime->file_rec_count;
+
+    /* necessary initialization of shared records */
+    for(i = 0; i < shared_rec_count; i++)
+    {
+        rec_ref = darshan_lookup_record_ref(dfs_runtime->rec_id_hash,
+            &shared_recs[i], sizeof(darshan_record_id));
+        assert(rec_ref);
+
+        dfs_time =
+            rec_ref->file_rec->fcounters[DFS_F_READ_TIME] +
+            rec_ref->file_rec->fcounters[DFS_F_WRITE_TIME] +
+            rec_ref->file_rec->fcounters[DFS_F_META_TIME];
+
+        /* initialize fastest/slowest info prior to the reduction */
+        rec_ref->file_rec->counters[DFS_FASTEST_RANK] =
+            rec_ref->file_rec->base_rec.rank;
+        rec_ref->file_rec->counters[DFS_FASTEST_RANK_BYTES] =
+            rec_ref->file_rec->counters[DFS_BYTES_READ] +
+            rec_ref->file_rec->counters[DFS_BYTES_WRITTEN];
+        rec_ref->file_rec->fcounters[DFS_F_FASTEST_RANK_TIME] =
+            dfs_time;
+
+        /* until reduction occurs, we assume that this rank is both
+         * the fastest and slowest. It is up to the reduction operator
+         * to find the true min and max.
+         */
+        rec_ref->file_rec->counters[DFS_SLOWEST_RANK] =
+            rec_ref->file_rec->counters[DFS_FASTEST_RANK];
+        rec_ref->file_rec->counters[DFS_SLOWEST_RANK_BYTES] =
+            rec_ref->file_rec->counters[DFS_FASTEST_RANK_BYTES];
+        rec_ref->file_rec->fcounters[DFS_F_SLOWEST_RANK_TIME] =
+            rec_ref->file_rec->fcounters[DFS_F_FASTEST_RANK_TIME];
+
+        rec_ref->file_rec->base_rec.rank = -1;
+    }
+
+    /* sort the array of records so we get all of the shared records
+     * (marked by rank -1) in a contiguous portion at end of the array
+     */
+    darshan_record_sort(dfs_rec_buf, dfs_rec_count,
+        sizeof(struct darshan_dfs_file));
+
+    /* make send_buf point to the shared files at the end of sorted array */
+    red_send_buf = &(dfs_rec_buf[dfs_rec_count-shared_rec_count]);
+
+    /* allocate memory for the reduction output on rank 0 */
+    if(my_rank == 0)
+    {
+        red_recv_buf = malloc(shared_rec_count * sizeof(struct darshan_dfs_file));
+        if(!red_recv_buf)
+        {
+            DAOS_UNLOCK();
+            return;
+        }
+    }
+
+    /* construct a datatype for a DFS file record.  This is serving no purpose
+     * except to make sure we can do a reduction on proper boundaries
+     */
+    PMPI_Type_contiguous(sizeof(struct darshan_dfs_file),
+        MPI_BYTE, &red_type);
+    PMPI_Type_commit(&red_type);
+
+    /* register a DFS file record reduction operator */
+    PMPI_Op_create(dfs_record_reduction_op, 1, &red_op);
+
+    /* reduce shared DFS file records */
+    PMPI_Reduce(red_send_buf, red_recv_buf,
+        shared_rec_count, red_type, red_op, 0, mod_comm);
+
+    /* clean up reduction state */
+    if(my_rank == 0)
+    {
+        int tmp_ndx = dfs_rec_count - shared_rec_count;
+        memcpy(&(dfs_rec_buf[tmp_ndx]), red_recv_buf,
+            shared_rec_count * sizeof(struct darshan_dfs_file));
+        free(red_recv_buf);
+    }
+    else
+    {
+        dfs_runtime->file_rec_count -= shared_rec_count;
+    }
+
+    PMPI_Type_free(&red_type);
+    PMPI_Op_free(&red_op);
+
+    DAOS_UNLOCK();
+    return;
+}
+#endif
+
+static void dfs_shutdown(
+    void **dfs_buf, int *dfs_buf_sz)
+{
+    int dfs_rec_count;
+
+    DAOS_LOCK();
+    assert(dfs_runtime);
+
+    fprintf(stderr, "****ENTERING DFS SHUTDOWN [%d]\n", my_rank);
+
+    dfs_rec_count = dfs_runtime->file_rec_count;
+
+    /* perform any final transformations on DFS file records before
+     * writing them out to log file
+     */
+    darshan_iter_record_refs(dfs_runtime->rec_id_hash,
+        &dfs_finalize_file_records, NULL);
+
+    /* shutdown internal structures used for instrumenting */
+    dfs_cleanup_runtime();
+
+    /* set output buffer size according to number of records we have */
+    *dfs_buf_sz = dfs_rec_count * sizeof(struct darshan_dfs_file);
+
+    DAOS_UNLOCK();
+    return;
+}
+
 /*
  * Local variables:
  *  c-indent-level: 4


=====================================
darshan-runtime/share/ld-opts/darshan-daos-ld-opts
=====================================
@@ -0,0 +1,20 @@
+--wrap=dfs_mount
+--wrap=dfs_global2local
+--wrap=dfs_umount
+--wrap=dfs_lookup
+--wrap=dfs_lookup_rel
+--wrap=dfs_open
+--wrap=dfs_dup
+--wrap=dfs_obj_global2local
+--wrap=dfs_release
+--wrap=dfs_read
+--wrap=dfs_readx
+--wrap=dfs_write
+--wrap=dfs_writex
+--wrap=dfs_get_size
+--wrap=dfs_punch
+--wrap=dfs_move
+--wrap=dfs_exchange
+--wrap=dfs_stat
+--wrap=dfs_ostat
+--wrap=dfs_osetattr


=====================================
darshan-util/Makefile.in
=====================================
@@ -19,7 +19,8 @@ DARSHAN_MOD_LOG_FORMATS = $(srcdir)/../darshan-posix-log-format.h \
 			  $(srcdir)/../darshan-lustre-log-format.h \
 			  $(srcdir)/../darshan-stdio-log-format.h \
 			  $(srcdir)/../darshan-dxt-log-format.h \
-			  $(srcdir)/../darshan-mdhim-log-format.h
+			  $(srcdir)/../darshan-mdhim-log-format.h \
+			  $(srcdir)/../darshan-daos-log-format.h
 
 DARSHAN_MOD_LOGUTIL_HEADERS = darshan-posix-logutils.h \
 			      darshan-mpiio-logutils.h \
@@ -29,7 +30,8 @@ DARSHAN_MOD_LOGUTIL_HEADERS = darshan-posix-logutils.h \
 			      darshan-lustre-logutils.h \
 			      darshan-stdio-logutils.h \
 			      darshan-dxt-logutils.h \
-			      darshan-mdhim-logutils.h
+			      darshan-mdhim-logutils.h \
+			      darshan-daos-logutils.h
 
 DARSHAN_STATIC_MOD_OBJS = darshan-posix-logutils.o \
 			  darshan-mpiio-logutils.o \
@@ -39,7 +41,8 @@ DARSHAN_STATIC_MOD_OBJS = darshan-posix-logutils.o \
 			  darshan-lustre-logutils.o \
 			  darshan-stdio-logutils.o \
 			  darshan-dxt-logutils.o \
-			  darshan-mdhim-logutils.o
+			  darshan-mdhim-logutils.o \
+			  darshan-daos-logutils.o
 
 DARSHAN_DYNAMIC_MOD_OBJS = darshan-posix-logutils.po \
 			   darshan-mpiio-logutils.po \
@@ -49,7 +52,8 @@ DARSHAN_DYNAMIC_MOD_OBJS = darshan-posix-logutils.po \
 			   darshan-lustre-logutils.po \
 			   darshan-stdio-logutils.po \
 			   darshan-dxt-logutils.po \
-			   darshan-mdhim-logutils.po
+			   darshan-mdhim-logutils.po \
+			   darshan-daos-logutils.po
 
 DARSHAN_ENABLE_SHARED=@DARSHAN_ENABLE_SHARED@
 DARSHAN_ENABLE_PYDARSHAN=@DARSHAN_ENABLE_PYDARSHAN@
@@ -140,6 +144,11 @@ darshan-mdhim-logutils.o: darshan-mdhim-logutils.c darshan-logutils.h darshan-md
 darshan-mdhim-logutils.po: darshan-mdhim-logutils.c darshan-logutils.h darshan-mdhim-logutils.h $(DARSHAN_LOG_FORMAT) $(srcdir)/../darshan-mdhim-log-format.h | uthash-1.9.2
 	$(CC) $(CFLAGS_SHARED) -c  $< -o $@
 
+darshan-daos-logutils.o: darshan-daos-logutils.c darshan-logutils.h darshan-daos-logutils.h $(DARSHAN_LOG_FORMAT) $(srcdir)/../darshan-daos-log-format.h | uthash-1.9.2
+	$(CC) $(CFLAGS) -c  $< -o $@
+darshan-daos-logutils.po: darshan-daos-logutils.c darshan-logutils.h darshan-daos-logutils.h $(DARSHAN_LOG_FORMAT) $(srcdir)/../darshan-daos-log-format.h | uthash-1.9.2
+	$(CC) $(CFLAGS_SHARED) -c  $< -o $@
+
 
 libdarshan-util.a: darshan-logutils.o $(DARSHAN_STATIC_MOD_OBJS)
 	ar rcs libdarshan-util.a $^


=====================================
darshan-util/darshan-daos-logutils.c
=====================================
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2020 University of Chicago.
+ * See COPYRIGHT notice in top-level directory.
+ *
+ */
+
+#define _GNU_SOURCE
+#include "darshan-util-config.h"
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <errno.h>
+
+#include "darshan-logutils.h"
+
+/* counter name strings for the DFS module */
+#define X(a) #a,
+char *dfs_counter_names[] = {
+    DFS_COUNTERS
+};
+
+char *dfs_f_counter_names[] = {
+    DFS_F_COUNTERS
+};
+#undef X
+
+static int darshan_log_get_dfs_file(darshan_fd fd, void** dfs_buf_p);
+static int darshan_log_put_dfs_file(darshan_fd fd, void* dfs_buf);
+static void darshan_log_print_dfs_file(void *file_rec,
+    char *file_name, char *mnt_pt, char *fs_type);
+static void darshan_log_print_dfs_description(int ver);
+static void darshan_log_print_dfs_file_diff(void *file_rec1, char *file_name1,
+    void *file_rec2, char *file_name2);
+static void darshan_log_agg_dfs_files(void *rec, void *agg_rec, int init_flag);
+
+struct darshan_mod_logutil_funcs dfs_logutils =
+{
+    .log_get_record = &darshan_log_get_dfs_file,
+    .log_put_record = &darshan_log_put_dfs_file,
+    .log_print_record = &darshan_log_print_dfs_file,
+    .log_print_description = &darshan_log_print_dfs_description,
+    .log_print_diff = &darshan_log_print_dfs_file_diff,
+    .log_agg_records = &darshan_log_agg_dfs_files,
+};
+
+static int darshan_log_get_dfs_file(darshan_fd fd, void** dfs_buf_p)
+{
+    struct darshan_dfs_file *file = *((struct darshan_dfs_file **)dfs_buf_p);
+    int rec_len;
+    int i;
+    int ret = -1;
+
+    if(fd->mod_map[DARSHAN_DFS_MOD].len == 0)
+        return(0);
+
+    if(fd->mod_ver[DARSHAN_DFS_MOD] == 0 ||
+        fd->mod_ver[DARSHAN_DFS_MOD] > DARSHAN_DFS_VER)
+    {
+        fprintf(stderr, "Error: Invalid DFS module version number (got %d)\n",
+            fd->mod_ver[DARSHAN_DFS_MOD]);
+        return(-1);
+    }
+
+    if(*dfs_buf_p == NULL)
+    {
+        file = malloc(sizeof(*file));
+        if(!file)
+            return(-1);
+    }
+
+    if(fd->mod_ver[DARSHAN_DFS_MOD] == DARSHAN_DFS_VER) 
+    {
+        /* log format is in current version, so we don't need to do any
+         * translation of counters while reading
+         */
+        rec_len = sizeof(struct darshan_dfs_file);
+        ret = darshan_log_get_mod(fd, DARSHAN_DFS_MOD, file, rec_len);
+    }
+    else
+    {
+        assert(0);
+    }
+
+exit:
+    if(*dfs_buf_p == NULL)
+    {
+        if(ret == rec_len)
+            *dfs_buf_p = file;
+        else
+            free(file);
+    }
+
+    if(ret < 0)
+        return(-1);
+    else if(ret < rec_len)
+        return(0);
+    else
+    {
+        /* if the read was successful, do any necessary byte-swapping */
+        if(fd->swap_flag)
+        {
+            DARSHAN_BSWAP64(&file->base_rec.id);
+            DARSHAN_BSWAP64(&file->base_rec.rank);
+            for(i=0; i<DFS_NUM_INDICES; i++)
+                DARSHAN_BSWAP64(&file->counters[i]);
+            for(i=0; i<DFS_F_NUM_INDICES; i++)
+                DARSHAN_BSWAP64(&file->fcounters[i]);
+        }
+
+        return(1);
+    }
+}
+
+static int darshan_log_put_dfs_file(darshan_fd fd, void* dfs_buf)
+{
+    struct darshan_dfs_file *file = (struct darshan_dfs_file *)dfs_buf;
+    int ret;
+
+    ret = darshan_log_put_mod(fd, DARSHAN_DFS_MOD, file,
+        sizeof(struct darshan_dfs_file), DARSHAN_DFS_VER);
+    if(ret < 0)
+        return(-1);
+
+    return(0);
+}
+
+static void darshan_log_print_dfs_file(void *file_rec, char *file_name,
+    char *mnt_pt, char *fs_type)
+{
+    int i;
+    struct darshan_dfs_file *dfs_file_rec =
+        (struct darshan_dfs_file *)file_rec;
+
+    for(i=0; i<DFS_NUM_INDICES; i++)
+    {
+        DARSHAN_D_COUNTER_PRINT(darshan_module_names[DARSHAN_DFS_MOD],
+            dfs_file_rec->base_rec.rank, dfs_file_rec->base_rec.id,
+            dfs_counter_names[i], dfs_file_rec->counters[i],
+            file_name, mnt_pt, fs_type);
+    }
+
+    for(i=0; i<DFS_F_NUM_INDICES; i++)
+    {
+        DARSHAN_F_COUNTER_PRINT(darshan_module_names[DARSHAN_DFS_MOD],
+            dfs_file_rec->base_rec.rank, dfs_file_rec->base_rec.id,
+            dfs_f_counter_names[i], dfs_file_rec->fcounters[i],
+            file_name, mnt_pt, fs_type);
+    }
+
+    return;
+}
+
+static void darshan_log_print_dfs_description(int ver)
+{
+    printf("\n# description of DFS counters:\n");
+    printf("#   DFS_*: DFS operation counts.\n");
+    printf("#   OPENS,LOOKUPS,DUPS,READS,READXS,NB_READS,WRITES,WRITEXS,NB_WRITES,GET_SIZES,PUNCHES,MOVES,EXCHANGES,STATS are types of operations.\n");
+    printf("#   DFS_F_*_START_TIMESTAMP: timestamp of first open/read/write/close.\n");
+    printf("#   DFS_F_*_END_TIMESTAMP: timestamp of last open/read/write/close.\n");
+    printf("#   DFS_F_READ/WRITE/META_TIME: cumulative time spent in read, write, or metadata operations.\n");
+    printf("#   DFS_BYTES_*: total bytes read and written.\n");
+    printf("#   DFS_RW_SWITCHES: number of times access alternated between read and write.\n");
+    printf("#   DFS_CHUNK_SIZE: DFS file chunk size.\n");
+    printf("#   DFS_USE_DTX: whether DFS distributed transactions are used.\n");
+    printf("#   DFS_MAX_*_TIME_SIZE: size of the slowest read and write operations.\n");
+    printf("#   DFS_SIZE_*_*: histogram of read and write access sizes.\n");
+    printf("#   DFS_ACCESS*_ACCESS: the four most common access sizes.\n");
+    printf("#   DFS_ACCESS*_COUNT: count of the four most common access sizes.\n");
+    printf("#   DFS_*_RANK: rank of the processes that were the fastest and slowest at I/O (for shared files).\n");
+    printf("#   DFS_*_RANK_BYTES: bytes transferred by the fastest and slowest ranks (for shared files).\n");
+    printf("#   DFS_F_*_START_TIMESTAMP: timestamp of first open/read/write/close.\n");
+    printf("#   DFS_F_*_END_TIMESTAMP: timestamp of last open/read/write/close.\n");
+    printf("#   DFS_F_READ/WRITE/META_TIME: cumulative time spent in read, write, or metadata operations.\n");
+    printf("#   DFS_F_MAX_*_TIME: duration of the slowest read and write operations.\n");
+    printf("#   DFS_F_*_RANK_TIME: fastest and slowest I/O time for a single rank (for shared files).\n");
+
+    return;
+}
+
+static void darshan_log_print_dfs_file_diff(void *file_rec1, char *file_name1,
+    void *file_rec2, char *file_name2)
+{
+    /* XXX */
+    return;
+}
+
+static void darshan_log_agg_dfs_files(void *rec, void *agg_rec, int init_flag)
+{
+    /* XXX */
+    return;
+}
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ * End:
+ *
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */


=====================================
darshan-util/darshan-daos-logutils.h
=====================================
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2020 University of Chicago.
+ * See COPYRIGHT notice in top-level directory.
+ *
+ */
+
+#ifndef __DARSHAN_DFS_LOG_UTILS_H
+#define __DARSHAN_DFS_LOG_UTILS_H
+
+extern char *dfs_counter_names[];
+extern char *dfs_f_counter_names[];
+
+extern struct darshan_mod_logutil_funcs dfs_logutils;
+
+#endif


=====================================
darshan-util/darshan-logutils.h
=====================================
@@ -150,10 +150,11 @@ extern struct darshan_mod_logutil_funcs *mod_logutils[];
 #include "darshan-bgq-logutils.h"
 #include "darshan-lustre-logutils.h"
 #include "darshan-stdio-logutils.h"
+#include "darshan-mdhim-logutils.h"
+#include "darshan-daos-logutils.h"
 
 /* DXT */
 #include "darshan-dxt-logutils.h"
-#include "darshan-mdhim-logutils.h"
 
 darshan_fd darshan_log_open(const char *name);
 darshan_fd darshan_log_create(const char *name, enum darshan_comp_type comp_type,



View it on GitLab: https://xgitlab.cels.anl.gov/darshan/darshan/-/commit/520301c3556a2f410e30b26cf54407a29c0b6cab

-- 
View it on GitLab: https://xgitlab.cels.anl.gov/darshan/darshan/-/commit/520301c3556a2f410e30b26cf54407a29c0b6cab
You're receiving this email because of your account on xgitlab.cels.anl.gov.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.mcs.anl.gov/pipermail/darshan-commits/attachments/20210127/80305b42/attachment-0001.html>


More information about the Darshan-commits mailing list