[Darshan-commits] [Darshan] branch, dev-modular, updated. darshan-2.3.1-100-g5ecf401
Service Account
git at mcs.anl.gov
Wed Apr 8 16:00:52 CDT 2015
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "".
The branch, dev-modular has been updated
via 5ecf4013b55c356441590ce97e4ef29cf03d3a1f (commit)
from 233f1607498e8197f127a5b2712f1593e752ae28 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 5ecf4013b55c356441590ce97e4ef29cf03d3a1f
Author: Shane Snyder <ssnyder at mcs.anl.gov>
Date: Wed Apr 8 15:59:58 2015 -0500
more docs + "NULL" example module implementation
-----------------------------------------------------------------------
Summary of changes:
darshan-log-format.h | 9 +-
darshan-mpiio-log-format.h | 5 +-
darshan-null-log-format.h | 47 ++++
darshan-runtime/Makefile.in | 18 +-
darshan-runtime/darshan.h | 46 ++--
darshan-runtime/lib/darshan-core.c | 9 +-
darshan-runtime/lib/darshan-mpiio.c | 12 +-
darshan-runtime/lib/darshan-null.c | 382 +++++++++++++++++++++++++++
darshan-runtime/lib/darshan-posix.c | 20 +-
darshan-runtime/utlist.h | 490 +++++++++++++++++++++++++++++++++++
doc/darshan-modularization.txt | 7 +-
11 files changed, 994 insertions(+), 51 deletions(-)
create mode 100644 darshan-null-log-format.h
create mode 100644 darshan-runtime/lib/darshan-null.c
create mode 100644 darshan-runtime/utlist.h
Diff of changes:
diff --git a/darshan-log-format.h b/darshan-log-format.h
index 7c49cbb..8886700 100644
--- a/darshan-log-format.h
+++ b/darshan-log-format.h
@@ -1,6 +1,7 @@
/*
- * (C) 2009 by Argonne National Laboratory.
- * See COPYRIGHT in top-level directory.
+ * Copyright (C) 2015 University of Chicago.
+ * See COPYRIGHT notice in top-level directory.
+ *
*/
#ifndef __DARSHAN_LOG_FORMAT_H
@@ -39,7 +40,8 @@ typedef uint64_t darshan_record_id;
#define DARSHAN_MAX_MODS 16
typedef enum
{
- DARSHAN_POSIX_MOD = 0,
+ DARSHAN_NULL_MOD = 0,
+ DARSHAN_POSIX_MOD,
DARSHAN_MPIIO_MOD,
DARSHAN_HDF5_MOD,
DARSHAN_PNETCDF_MOD,
@@ -47,6 +49,7 @@ typedef enum
static char * const darshan_module_names[] =
{
+ "NULL",
"POSIX",
"MPI-IO",
"HDF5",
diff --git a/darshan-mpiio-log-format.h b/darshan-mpiio-log-format.h
index 48a10f0..857133d 100644
--- a/darshan-mpiio-log-format.h
+++ b/darshan-mpiio-log-format.h
@@ -1,6 +1,7 @@
/*
- * (C) 2015 by Argonne National Laboratory.
- * See COPYRIGHT in top-level directory.
+ * Copyright (C) 2015 University of Chicago.
+ * See COPYRIGHT notice in top-level directory.
+ *
*/
#ifndef __DARSHAN_MPIIO_LOG_FORMAT_H
diff --git a/darshan-null-log-format.h b/darshan-null-log-format.h
new file mode 100644
index 0000000..152dd1a
--- /dev/null
+++ b/darshan-null-log-format.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 University of Chicago.
+ * See COPYRIGHT notice in top-level directory.
+ *
+ */
+
+#ifndef __DARSHAN_NULL_LOG_FORMAT_H
+#define __DARSHAN_NULL_LOG_FORMAT_H
+
+#include "darshan-log-format.h"
+
+/* integer counters for the "NULL" example module */
+enum darshan_null_indices
+{
+ NULL_BARS, /* count of number of 'bar' function calls */
+ NULL_BAR_DAT, /* arbitrary data value set by last call to 'bar' */
+
+ NULL_NUM_INDICES,
+};
+
+/* floating point counters for the "NULL" example module */
+enum darshan_null_f_indices
+{
+ NULL_F_BAR_TIMESTAMP, /* timestamp of the first call to function 'bar' */
+ NULL_F_BAR_DURATION, /* timer indicating duration of last call to 'bar' */
+
+ NULL_F_NUM_INDICES,
+};
+
+/* the darshan_null_record structure encompasses the high-level data/counters
+ * which would actually be logged to file by Darshan for the "NULL" example
+ * module. This example implementation logs the following data for each
+ * record:
+ * - a corresponding Darshan record identifier
+ * - the rank of the process responsible for the record
+ * - integer I/O counters (operation counts, I/O sizes, etc.)
+ * - floating point I/O counters (timestamps, cumulative timers, etc.)
+ */
+struct darshan_null_record
+{
+ darshan_record_id f_id;
+ int64_t rank;
+ int64_t counters[NULL_NUM_INDICES];
+ double fcounters[NULL_F_NUM_INDICES];
+};
+
+#endif /* __DARSHAN_NULL_LOG_FORMAT_H */
diff --git a/darshan-runtime/Makefile.in b/darshan-runtime/Makefile.in
index 791cac6..be3485b 100644
--- a/darshan-runtime/Makefile.in
+++ b/darshan-runtime/Makefile.in
@@ -1,4 +1,4 @@
-all: lib/libdarshan.a
+all: lib/libdarshan.a lib/darshan-null.o
DESTDIR =
srcdir = @srcdir@
@@ -19,7 +19,7 @@ DARSHAN_LOG_FORMAT = $(srcdir)/../darshan-log-format.h
DARSHAN_VERSION = @DARSHAN_VERSION@
ifndef DISABLE_LDPRELOAD
-all: lib/libdarshan.so
+all: lib/libdarshan.so lib/darshan-null.po
endif
VPATH = $(srcdir)
@@ -51,16 +51,22 @@ lib/darshan-common.o: lib/darshan-common.c darshan.h $(DARSHAN_LOG_FORMAT) | lib
lib/darshan-common.po: lib/darshan-common.c darshan.h $(DARSHAN_LOG_FORMAT) | lib
$(CC) $(CFLAGS_SHARED) -c $< -o $@
-lib/darshan-posix.o: lib/darshan-posix.c darshan.h $(DARSHAN_LOG_FORMAT) | lib
+lib/darshan-null.o: lib/darshan-null.c darshan.h $(DARSHAN_LOG_FORMAT) $(srcdir)/../darshan-null-log-format.h | lib
$(CC) $(CFLAGS) -c $< -o $@
-lib/darshan-posix.po: lib/darshan-posix.c darshan.h $(DARSHAN_LOG_FORMAT) | lib
+lib/darshan-null.po: lib/darshan-null.c darshan.h $(DARSHAN_LOG_FORMAT) $(srcdir)/../darshan-null-log-format.h | lib
$(CC) $(CFLAGS_SHARED) -c $< -o $@
-lib/darshan-mpiio.o: lib/darshan-mpiio.c darshan.h $(DARSHAN_LOG_FORMAT) | lib
+lib/darshan-posix.o: lib/darshan-posix.c darshan.h $(DARSHAN_LOG_FORMAT) $(srcdir)/../darshan-posix-log-format.h | lib
$(CC) $(CFLAGS) -c $< -o $@
-lib/darshan-mpiio.po: lib/darshan-mpiio.c darshan.h $(DARSHAN_LOG_FORMAT) | lib
+lib/darshan-posix.po: lib/darshan-posix.c darshan.h $(DARSHAN_LOG_FORMAT) $(srcdir)/../darshan-posix-log-format.h | lib
+ $(CC) $(CFLAGS_SHARED) -c $< -o $@
+
+lib/darshan-mpiio.o: lib/darshan-mpiio.c darshan.h $(DARSHAN_LOG_FORMAT) $(srcdir)/../darshan-mpiio-log-format.h | lib
+ $(CC) $(CFLAGS) -c $< -o $@
+
+lib/darshan-mpiio.po: lib/darshan-mpiio.c darshan.h $(DARSHAN_LOG_FORMAT) $(srcdir)/../darshan-mpiio-log-format.h | lib
$(CC) $(CFLAGS_SHARED) -c $< -o $@
lib/lookup3.o: lib/lookup3.c
diff --git a/darshan-runtime/darshan.h b/darshan-runtime/darshan.h
index b9c7066..6016d24 100644
--- a/darshan-runtime/darshan.h
+++ b/darshan-runtime/darshan.h
@@ -34,38 +34,43 @@
#include <dlfcn.h>
#include <stdlib.h>
-#define DARSHAN_FORWARD_DECL(name,ret,args) \
- ret (*__real_ ## name)args = NULL
+#define DARSHAN_FORWARD_DECL(__func,__ret,__args) \
+ __ret (*__real_ ## __func)__args = NULL
-#define DARSHAN_DECL(__name) __name
+#define DARSHAN_DECL(__func) __func
-#define DARSHAN_MPI_CALL(func) __real_ ## func
+#define DARSHAN_MPI_CALL(__func) __real_ ## __func
-#define MAP_OR_FAIL(func) \
- if (!(__real_ ## func)) \
+#define MAP_OR_FAIL(__func) \
+ if (!(__real_ ## __func)) \
{ \
- __real_ ## func = dlsym(RTLD_NEXT, #func); \
- if(!(__real_ ## func)) { \
- fprintf(stderr, "Darshan failed to map symbol: %s\n", #func); \
+ __real_ ## __func = dlsym(RTLD_NEXT, #__func); \
+ if(!(__real_ ## __func)) { \
+ fprintf(stderr, "Darshan failed to map symbol: %s\n", #__func); \
exit(1); \
} \
}
#else
-#define DARSHAN_FORWARD_DECL(name,ret,args) \
- extern ret __real_ ## name args;
+#define DARSHAN_FORWARD_DECL(__name,__ret,__args) \
+ extern __ret __real_ ## __name __args;
#define DARSHAN_DECL(__name) __wrap_ ## __name
-#define DARSHAN_MPI_CALL(func) func
+#define DARSHAN_MPI_CALL(__func) __func
-#define MAP_OR_FAIL(func)
+#define MAP_OR_FAIL(__func)
#endif
-/* macros for manipulating module's counter variables */
-/* NOTE: */
+/* macros for manipulating a module's counter variables */
+/* NOTE: These macros assume a module's record stores integer
+ * and floating point counters in arrays, named counters and
+ * fcounters, respectively. __rec_p is the a pointer to the
+ * data record, __counter is the counter in question, and
+ * __value is the corresponding data value.
+ */
#define DARSHAN_COUNTER_SET(__rec_p, __counter, __value) do{ \
(__rec_p)->counters[__counter] = __value; \
} while(0)
@@ -102,6 +107,11 @@
(__rec_p)->counters[__counter] = __value; \
} while(0)
+/* NOTE: This macro is for storing histogram counters with 10
+ * distinct buckets. For an example of how it is used, consult
+ * the POSIX module implementation, which stores histograms of
+ * access sizes for POSIX I/O functions.
+ */
#define DARSHAN_BUCKET_INC(__rec_p, __counter_base, __value) do {\
if(__value < 101) \
(__rec_p)->counters[__counter_base] += 1; \
@@ -128,10 +138,10 @@
/* module developers provide the following functions to darshan-core */
struct darshan_module_funcs
{
- /* disable futher instrumentation within a module */
- void (*disable_instrumentation)(void);
+ /* perform any necessary pre-shutdown steps */
+ void (*begin_shutdown)(void);
/* perform any necessary steps prior to reducing */
- void (*prepare_for_reduction)(
+ void (*setup_reduction)(
darshan_record_id *shared_recs, /* input list of shared records */
int *shared_rec_count, /* in/out shared record count */
void **send_buf, /* send buffer for shared file reduction */
diff --git a/darshan-runtime/lib/darshan-core.c b/darshan-runtime/lib/darshan-core.c
index 55006bc..aee8c6f 100644
--- a/darshan-runtime/lib/darshan-core.c
+++ b/darshan-runtime/lib/darshan-core.c
@@ -258,14 +258,15 @@ void darshan_core_shutdown()
darshan_core = NULL;
/* we also need to set which modules were registered on this process and
- * disable tracing within those modules while we shutdown
+ * call into those modules and give them a chance to perform any necessary
+ * pre-shutdown steps.
*/
for(i = 0; i < DARSHAN_MAX_MODS; i++)
{
if(final_core->mod_array[i])
{
local_mod_use[i] = 1;
- final_core->mod_array[i]->mod_funcs.disable_instrumentation();
+ final_core->mod_array[i]->mod_funcs.begin_shutdown();
}
}
DARSHAN_CORE_UNLOCK();
@@ -492,10 +493,10 @@ void darshan_core_shutdown()
}
/* if there are globally shared files, do a shared file reduction */
- if(shared_rec_count && this_mod->mod_funcs.prepare_for_reduction &&
+ if(shared_rec_count && this_mod->mod_funcs.setup_reduction &&
this_mod->mod_funcs.record_reduction_op)
{
- this_mod->mod_funcs.prepare_for_reduction(mod_shared_recs, &shared_rec_count,
+ this_mod->mod_funcs.setup_reduction(mod_shared_recs, &shared_rec_count,
&red_send_buf, &red_recv_buf, &rec_sz);
if(shared_rec_count)
diff --git a/darshan-runtime/lib/darshan-mpiio.c b/darshan-runtime/lib/darshan-mpiio.c
index 67f30a5..2d3a82d 100644
--- a/darshan-runtime/lib/darshan-mpiio.c
+++ b/darshan-runtime/lib/darshan-mpiio.c
@@ -114,7 +114,7 @@ static int my_rank = -1;
#define MPIIO_UNLOCK() pthread_mutex_unlock(&mpiio_runtime_mutex)
static void mpiio_runtime_initialize(void);
-static void mpiio_disable_instrumentation(void);
+static void mpiio_begin_shutdown(void);
static void mpiio_shutdown(void);
static void mpiio_get_output_data(
void **buffer,
@@ -123,7 +123,7 @@ static struct mpiio_file_runtime* mpiio_file_by_name_setfh(const char* name, MPI
static struct mpiio_file_runtime* mpiio_file_by_name(const char *name);
static void mpiio_record_reduction_op(void* infile_v, void* inoutfile_v,
int *len, MPI_Datatype *datatype);
-static void mpiio_prepare_for_reduction(darshan_record_id *shared_recs,
+static void mpiio_setup_reduction(darshan_record_id *shared_recs,
int *shared_rec_count, void **send_buf, void **recv_buf, int *rec_size);
static int mpiio_file_compare(const void* a, const void* b);
@@ -192,8 +192,8 @@ static void mpiio_runtime_initialize()
int mem_limit;
struct darshan_module_funcs mpiio_mod_fns =
{
- .disable_instrumentation = &mpiio_disable_instrumentation,
- .prepare_for_reduction = &mpiio_prepare_for_reduction,
+ .begin_shutdown = &mpiio_begin_shutdown,
+ .setup_reduction = &mpiio_setup_reduction,
.record_reduction_op = &mpiio_record_reduction_op,
.get_output_data = &mpiio_get_output_data,
.shutdown = &mpiio_shutdown
@@ -245,7 +245,7 @@ static void mpiio_runtime_initialize()
return;
}
-static void mpiio_disable_instrumentation()
+static void mpiio_begin_shutdown()
{
assert(mpiio_runtime);
@@ -444,7 +444,7 @@ static void mpiio_record_reduction_op(
return;
}
-static void mpiio_prepare_for_reduction(
+static void mpiio_setup_reduction(
darshan_record_id *shared_recs,
int *shared_rec_count,
void **send_buf,
diff --git a/darshan-runtime/lib/darshan-null.c b/darshan-runtime/lib/darshan-null.c
new file mode 100644
index 0000000..0a864e2
--- /dev/null
+++ b/darshan-runtime/lib/darshan-null.c
@@ -0,0 +1,382 @@
+/*
+ * Copyright (C) 2015 University of Chicago.
+ * See COPYRIGHT notice in top-level directory.
+ *
+ */
+
+#define _XOPEN_SOURCE 500
+#define _GNU_SOURCE
+
+#include "darshan-runtime-config.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <assert.h>
+
+#include "uthash.h"
+#include "darshan.h"
+#include "darshan-null-log-format.h"
+
+/* The "NULL" module is an example instrumentation module implementation provided
+ * with Darshan, primarily to indicate how arbitrary modules may be integrated
+ * into Darshan. In particular, this module demonstrates how to develop wrapper
+ * functions for intercepting functions of interest, how to best manage necessary
+ * runtime data structures, and how to coordinate with the darshan-core component,
+ * among other things. This module is not linked with the darshan-runtime library;
+ * it is intended mainly to serve as a basic stubbed out module implementation
+ * that may be reused and expanded on by developers adding new instrumentation modules.
+ */
+
+/* TODO: this probably shouldn't be here -- LD_PRELOADing POSIX wrappers will cause MPI linker dependency */
+#ifdef DARSHAN_PRELOAD
+extern double (*__real_PMPI_Comm_rank)(MPI_Comm comm, int *rank);
+#endif
+
+/* The DARSHAN_FORWARD_DECL macro (defined in darshan.h) is used to provide forward
+ * declarations for wrapped funcions, regardless if Darshan is used with statically
+ * or dynamically linked executables.
+ */
+DARSHAN_FORWARD_DECL(foo, int, (const char *name, int arg1, int arg2));
+
+
+/* The null_record_runtime structure maintains necessary runtime metadata
+ * for a "NULL" module data record (darshan_null_record structure, defined
+ * in darshan-null-log-format.h). This metadata assists with the instrumenting
+ * of specific statistics in the file record.
+ *
+ * RATIONALE: In general, a module may need to track some stateful, volatile
+ * information regarding specific I/O statistics to aid in the instrumentation
+ * process. However, this information should not be stored in the darshan_null_record
+ * struct because we don't want it to appear in the final darshan log file.
+ * We therefore associate a null_record_runtime structure with each darshan_null_record
+ * structure in order to track this information.
+ *
+ * NOTE: The null_record_runtime struct contains a pointer to a darshan_null_record
+ * struct (see the *record_p member) rather than simply embedding an entire
+ * darshan_null_record struct. This is done so that all of the darshan_null_record
+ * structs can be kept contiguous in memory as a single array to simplify
+ * reduction, compression, and storage.
+ */
+struct null_record_runtime
+{
+ /* Darshan record for the "NULL" example module */
+ struct darshan_null_record* record_p;
+
+ /* ... other runtime data ... */
+
+ /* hash table link for this record */
+ /* NOTE: it is entirely up to the module developer how to persist module
+ * records in memory as the instrumented application runs. These records
+ * could just as easily be stored in an array or linked list. That said,
+ * the data structure selection should be mindful of the resulting memory
+ * footprint and search time complexity to attempt minimize Darshan overheads.
+ * hash table and linked list implementations are available in uthash.h and
+ * utlist.h, respectively.
+ */
+ UT_hash_handle hlink;
+};
+
+/* The null_runtime structure simply encapsulates global data structures needed
+ * by the module for instrumenting functions of interest and providing the output
+ * I/O data for this module to the darshan-core component at shutdown time.
+ */
+struct null_runtime
+{
+ /* runtime_record_array is the array of runtime records for the "NULL" module. */
+ struct null_record_runtime* runtime_record_array;
+ /* record_array is the array of high-level Darshan records for the "NULL" module,
+ * each corresponding to the the runtime record structure stored at the same array
+ * index in runtime_record_array.
+ */
+ struct darshan_null_record* record_array;
+ /* file_array_size is the maximum amount of records that can be stored in
+ * record_array (and consequentially, runtime_record_array).
+ */
+ int rec_array_size;
+ /* file_array_ndx is the current index into both runtime_record_array and
+ * record_array.
+ */
+ int rec_array_ndx;
+ /* record_hash is a pointer to a hash table of null_record_runtime structures
+ * currently maintained by the "NULL" module.
+ */
+ struct null_record_runtime* record_hash;
+};
+
+/* null_runtime is the global data structure encapsulating "NULL" module state */
+static struct null_runtime *null_runtime = NULL;
+/* The null_runtime_mutex is a lock used when updating the null_runtime global
+ * structure (or any other global data structures). This is necessary to avoid race
+ * conditions as multiple threads execute function wrappers and update module state.
+ * NOTE: Recursive mutexes are used in case functions wrapped by this module call
+ * other wrapped functions that would result in deadlock, otherwise. This mechanism
+ * may not be necessary for all instrumentation modules.
+ */
+static pthread_mutex_t null_runtime_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+/* the instrumentation_disabled flag is used to toggle wrapper functions on/off */
+static int instrumentation_disabled = 0;
+/* my_rank indicates the MPI rank of this process */
+static int my_rank = -1;
+
+/* internal helper functions for the "NULL" module */
+static void null_runtime_initialize(void);
+static struct null_record_runtime* null_record_by_name(const char *name);
+
+/* forward declaration for module functions needed to interface with darshan-core */
+static void null_begin_shutdown(void);
+static void null_get_output_data(void **buffer, int *size);
+static void null_shutdown(void);
+
+/* macros for obtaining/releasing the "NULL" module lock */
+#define NULL_LOCK() pthread_mutex_lock(&null_runtime_mutex)
+#define NULL_UNLOCK() pthread_mutex_unlock(&null_runtime_mutex)
+
+/* macro for instrumenting the "NULL" module's foo function */
+/* NOTE: this macro makes use of the DARSHAN_COUNTER_* macros defined
+ * and documented in darshan.h.
+ */
+#define NULL_RECORD_FOO(__ret, __name, __dat, __tm1, __tm2) do{ \
+ struct null_record_runtime* rec; \
+ double elapsed = __tm2 - __tm1; \
+ /* if foo returns error (return code < 0), don't instrument anything */ \
+ if(__ret < 0) break; \
+ /* use '__name' to lookup a corresponding "NULL" record */ \
+ rec = null_record_by_name(__name); \
+ if(!rec) break; \
+ /* increment counter indicating number of calls to 'bar' */ \
+ DARSHAN_COUNTER_INC(rec->record_p, NULL_BARS, 1); \
+ /* store data value for most recent call to 'bar' */ \
+ DARSHAN_COUNTER_SET(rec->record_p, NULL_BAR_DAT, __dat); \
+ /* store timestamp of most recent call to 'bar' */ \
+ DARSHAN_COUNTER_F_SET(rec->record_p, NULL_F_BAR_TIMESTAMP, __tm1); \
+ /* store duration of most recent call to 'bar' */ \
+ DARSHAN_COUNTER_F_SET(rec->record_p, NULL_F_BAR_DURATION, elapsed); \
+} while(0)
+
+/**********************************************************
+ * Wrappers for "NULL" module functions of interest *
+ **********************************************************/
+
+/* The DARSHAN_DECL macro provides the appropriate wrapper function names,
+ * depending on whether the Darshan library is statically or dynamically linked.
+ */
+int DARSHAN_DECL(foo)(const char* name, int arg1, int arg2)
+{
+ ssize_t ret;
+ double tm1, tm2;
+
+ /* The MAP_OR_FAIL macro attempts to obtain the address of the actual
+ * underlying foo function call (__real_foo), in the case of LD_PRELOADing
+ * the Darshan library. For statically linked executables, this macro is
+ * just a NOP.
+ */
+ MAP_OR_FAIL(foo);
+
+ /* In general, Darshan wrappers begin by calling the real version of the
+ * given wrapper function. Timers are used to record the duration of this
+ * operation. */
+ tm1 = darshan_core_wtime();
+ ret = __real_foo(name, arg1, arg2);
+ tm2 = darshan_core_wtime();
+
+ NULL_LOCK();
+
+ /* Before attempting to instrument I/O statistics for function foo, make
+ * sure the "NULL" module runtime environment has been initialized.
+ * NOTE: this runtime environment is initialized only once -- if the
+ * appropriate structures have already been initialized, this function simply
+ * returns.
+ */
+ null_runtime_initialize();
+
+ /* Call macro for instrumenting data for foo function calls. */
+ NULL_RECORD_FOO(ret, name, arg1+arg2, tm1, tm2);
+
+ NULL_UNLOCK();
+
+ return(ret);
+}
+
+/**********************************************************
+ * Internal functions for manipulating POSIX module state *
+ **********************************************************/
+
+/* Initialize internal POSIX module data structures and register with darshan-core. */
+static void null_runtime_initialize()
+{
+ /* struct of function pointers for interfacing with darshan-core */
+ struct darshan_module_funcs null_mod_fns =
+ {
+ .begin_shutdown = &null_begin_shutdown,
+ .setup_reduction = NULL, /* "NULL" module does not do reductions */
+ .record_reduction_op = NULL, /* "NULL" module does not do reductions */
+ .get_output_data = &null_get_output_data,
+ .shutdown = &null_shutdown
+ };
+ int mem_limit; /* max. memory this module can consume, dictated by darshan-core */
+
+ /* don't do anything if already initialized or instrumenation is disabled */
+ if(null_runtime || instrumentation_disabled)
+ return;
+
+ /* register the "NULL" module with the darshan-core component */
+ darshan_core_register_module(
+ DARSHAN_NULL_MOD, /* Darshan module identifier, defined in darshan-log-format.h */
+ &null_mod_fns,
+ &mem_limit,
+ NULL);
+
+ /* return if no memory assigned by darshan-core */
+ if(mem_limit == 0)
+ return;
+
+ /* initialize module's global state */
+ null_runtime = malloc(sizeof(*null_runtime));
+ if(!null_runtime)
+ return;
+ memset(null_runtime, 0, sizeof(*null_runtime));
+
+ /* Set the maximum number of data records this module may track, as indicated
+ * by mem_limit (set by darshan-core).
+ * NOTE: We interpret the maximum memory limit to be related to the maximum
+ * amount of data which may be written to log by a single process for a given
+ * module. We therefore use this maximum memory limit to determine how many
+ * darshan_null_record structures we can track per process.
+ */
+ null_runtime->rec_array_size = mem_limit / sizeof(struct darshan_null_record);
+ null_runtime->rec_array_ndx = 0;
+
+ /* allocate both record arrays (runtime and high-level records) */
+ null_runtime->runtime_record_array = malloc(null_runtime->rec_array_size *
+ sizeof(struct null_record_runtime));
+ null_runtime->record_array = malloc(null_runtime->rec_array_size *
+ sizeof(struct darshan_null_record));
+ if(!null_runtime->runtime_record_array || !null_runtime->record_array)
+ {
+ null_runtime->rec_array_size = 0;
+ return;
+ }
+ memset(null_runtime->runtime_record_array, 0, null_runtime->rec_array_size *
+ sizeof(struct null_record_runtime));
+ memset(null_runtime->record_array, 0, null_runtime->rec_array_size *
+ sizeof(struct darshan_null_record));
+
+ /* TODO: we should move this out of here.. perhaps register_module returns rank? */
+ DARSHAN_MPI_CALL(PMPI_Comm_rank)(MPI_COMM_WORLD, &my_rank);
+
+ return;
+}
+
+/* Search for and return a "NULL" module record corresponding to name parameter. */
+static struct null_record_runtime* null_record_by_name(const char *name)
+{
+ struct null_record_runtime *rec = NULL;
+ darshan_record_id rec_id;
+
+ /* Don't search for a record if the "NULL" module is not initialized or
+ * if instrumentation has been toggled off.
+ */
+ if(!null_runtime || instrumentation_disabled)
+ return(NULL);
+
+ /* get a unique record identifier for this record from darshan-core */
+ darshan_core_register_record(
+ (void*)name,
+ strlen(name),
+ 1,
+ DARSHAN_NULL_MOD,
+ &rec_id,
+ NULL);
+
+ /* search the hash table for this file record, and return if found */
+ HASH_FIND(hlink, null_runtime->record_hash, &rec_id, sizeof(darshan_record_id), rec);
+ if(rec)
+ {
+ return(rec);
+ }
+
+ if(null_runtime->rec_array_ndx < null_runtime->rec_array_size);
+ {
+ /* no existing record, assign a new one from the global array */
+ rec = &(null_runtime->runtime_record_array[null_runtime->rec_array_ndx]);
+ rec->record_p = &(null_runtime->record_array[null_runtime->rec_array_ndx]);
+
+ /* set the darshan record id and corresponding process rank for this record */
+ rec->record_p->f_id = rec_id;
+ rec->record_p->rank = my_rank;
+
+ /* add new record to file hash table */
+ HASH_ADD(hlink, null_runtime->record_hash, record_p->f_id, sizeof(darshan_record_id), rec);
+
+ null_runtime->rec_array_ndx++;
+ }
+
+ return(rec);
+}
+
+/******************************************************************************
+ * Functions exported by the "NULL" module for coordinating with darshan-core *
+ ******************************************************************************/
+
+/* Perform any necessary steps prior to shutting down for the "NULL" module. */
+static void null_begin_shutdown()
+{
+ assert(null_runtime);
+
+ NULL_LOCK();
+
+ /* In general, we want to disable all wrappers while Darshan shuts down.
+ * This is to avoid race conditions and ensure data consistency, as
+ * executing wrappers could potentially modify module state while Darshan
+ * is in the process of shutting down.
+ */
+ instrumentation_disabled = 1;
+
+ /* ... any other code which needs to be executed before beginning shutdown process ... */
+
+ NULL_UNLOCK();
+
+ return;
+}
+
+/* Pass output data for the "NULL" module back to darshan-core to log to file. */
+static void null_get_output_data(
+ void **buffer,
+ int *size)
+{
+ assert(null_runtime);
+
+ /* Just set the output buffer to point at the array of the "NULL" module's
+ * I/O records, and set the output size according to the number of records
+ * currently being tracked.
+ */
+ *buffer = (void *)(null_runtime->record_array);
+ *size = null_runtime->rec_array_ndx * sizeof(struct darshan_null_record);
+
+ return;
+}
+
+/* Shutdown the "NULL" module by freeing up all data structures. */
+static void null_shutdown()
+{
+ assert(null_runtime);
+
+ HASH_CLEAR(hlink, null_runtime->record_hash); /* these hash entries are freed all at once below */
+
+ free(null_runtime->runtime_record_array);
+ free(null_runtime->record_array);
+ free(null_runtime);
+ null_runtime = NULL;
+
+ return;
+}
+
+/*
+ * Local variables:
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * End:
+ *
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
diff --git a/darshan-runtime/lib/darshan-posix.c b/darshan-runtime/lib/darshan-posix.c
index a647f0e..c66a118 100644
--- a/darshan-runtime/lib/darshan-posix.c
+++ b/darshan-runtime/lib/darshan-posix.c
@@ -215,9 +215,9 @@ static void posix_walk_file_accesses(void);
static int posix_access_compare(const void* a_p, const void* b_p);
static int posix_file_compare(const void* a, const void* b);
-static void posix_disable_instrumentation(void);
-static void posix_prepare_for_reduction(darshan_record_id *shared_recs,
- int *shared_rec_count, void **send_buf, void **recv_buf, int *rec_size);
+static void posix_begin_shutdown(void);
+static void posix_setup_reduction(darshan_record_id *shared_recs, int *shared_rec_count,
+ void **send_buf, void **recv_buf, int *rec_size);
static void posix_record_reduction_op(void* infile_v, void* inoutfile_v,
int *len, MPI_Datatype *datatype);
static void posix_get_output_data(void **buffer, int *size);
@@ -1295,8 +1295,8 @@ static void posix_runtime_initialize()
int mem_limit;
struct darshan_module_funcs posix_mod_fns =
{
- .disable_instrumentation = &posix_disable_instrumentation,
- .prepare_for_reduction = &posix_prepare_for_reduction,
+ .begin_shutdown = &posix_begin_shutdown,
+ .setup_reduction = &posix_setup_reduction,
.record_reduction_op = &posix_record_reduction_op,
.get_output_data = &posix_get_output_data,
.shutdown = &posix_shutdown
@@ -1627,21 +1627,25 @@ static int posix_file_compare(const void* a_p, const void* b_p)
* Functions exported by this module for coordinating with darshan-core *
************************************************************************/
-static void posix_disable_instrumentation()
+static void posix_begin_shutdown()
{
assert(posix_runtime);
POSIX_LOCK();
+ /* go through file access data for each record and set the 4 most common
+ * stride/access size counters.
+ */
posix_walk_file_accesses();
+ /* disable further instrumentation while Darshan shuts down */
instrumentation_disabled = 1;
POSIX_UNLOCK();
return;
}
-static void posix_prepare_for_reduction(
+static void posix_setup_reduction(
darshan_record_id *shared_recs,
int *shared_rec_count,
void **send_buf,
@@ -1980,6 +1984,8 @@ static void posix_shutdown()
{
struct posix_file_runtime_ref *ref, *tmp;
+ assert(posix_runtime);
+
HASH_ITER(hlink, posix_runtime->fd_hash, ref, tmp)
{
HASH_DELETE(hlink, posix_runtime->fd_hash, ref);
diff --git a/darshan-runtime/utlist.h b/darshan-runtime/utlist.h
new file mode 100644
index 0000000..35fc9db
--- /dev/null
+++ b/darshan-runtime/utlist.h
@@ -0,0 +1,490 @@
+/*
+Copyright (c) 2007-2010, Troy D. Hanson http://uthash.sourceforge.net
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef UTLIST_H
+#define UTLIST_H
+
+#define UTLIST_VERSION 1.9.1
+
+/*
+ * This file contains macros to manipulate singly and doubly-linked lists.
+ *
+ * 1. LL_ macros: singly-linked lists.
+ * 2. DL_ macros: doubly-linked lists.
+ * 3. CDL_ macros: circular doubly-linked lists.
+ *
+ * To use singly-linked lists, your structure must have a "next" pointer.
+ * To use doubly-linked lists, your structure must "prev" and "next" pointers.
+ * Either way, the pointer to the head of the list must be initialized to NULL.
+ *
+ * ----------------.EXAMPLE -------------------------
+ * struct item {
+ * int id;
+ * struct item *prev, *next;
+ * }
+ *
+ * struct item *list = NULL:
+ *
+ * int main() {
+ * struct item *item;
+ * ... allocate and populate item ...
+ * DL_APPEND(list, item);
+ * }
+ * --------------------------------------------------
+ *
+ * For doubly-linked lists, the append and delete macros are O(1)
+ * For singly-linked lists, append and delete are O(n) but prepend is O(1)
+ * The sort macro is O(n log(n)) for all types of single/double/circular lists.
+ */
+
+/* These macros use decltype or the earlier __typeof GNU extension.
+ As decltype is only available in newer compilers (VS2010 or gcc 4.3+
+ when compiling c++ code), this code uses whatever method is needed
+ or, for VS2008 where neither is available, uses casting workarounds. */
+#ifdef _MSC_VER /* MS compiler */
+#if _MSC_VER >= 1600 && __cplusplus /* VS2010 and newer in C++ mode */
+#define LDECLTYPE(x) decltype(x)
+#else /* VS2008 or older (or VS2010 in C mode) */
+#define NO_DECLTYPE
+#define LDECLTYPE(x) char*
+#endif
+#else /* GNU, Sun and other compilers */
+#define LDECLTYPE(x) __typeof(x)
+#endif
+
+/* for VS2008 we use some workarounds to get around the lack of decltype,
+ * namely, we always reassign our tmp variable to the list head if we need
+ * to dereference its prev/next pointers, and save/restore the real head.*/
+#ifdef NO_DECLTYPE
+#define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); }
+#define _NEXT(elt,list) ((char*)((list)->next))
+#define _NEXTASGN(elt,list,to) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); }
+#define _PREV(elt,list) ((char*)((list)->prev))
+#define _PREVASGN(elt,list,to) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); }
+#define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; }
+#define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); }
+#else
+#define _SV(elt,list)
+#define _NEXT(elt,list) ((elt)->next)
+#define _NEXTASGN(elt,list,to) ((elt)->next)=(to)
+#define _PREV(elt,list) ((elt)->prev)
+#define _PREVASGN(elt,list,to) ((elt)->prev)=(to)
+#define _RS(list)
+#define _CASTASGN(a,b) (a)=(b)
+#endif
+
+/******************************************************************************
+ * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort *
+ * Unwieldy variable names used here to avoid shadowing passed-in variables. *
+ *****************************************************************************/
+#define LL_SORT(list, cmp) \
+do { \
+ LDECLTYPE(list) _ls_p; \
+ LDECLTYPE(list) _ls_q; \
+ LDECLTYPE(list) _ls_e; \
+ LDECLTYPE(list) _ls_tail; \
+ LDECLTYPE(list) _ls_oldhead; \
+ LDECLTYPE(list) _tmp; \
+ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
+ if (list) { \
+ _ls_insize = 1; \
+ _ls_looping = 1; \
+ while (_ls_looping) { \
+ _CASTASGN(_ls_p,list); \
+ _CASTASGN(_ls_oldhead,list); \
+ list = NULL; \
+ _ls_tail = NULL; \
+ _ls_nmerges = 0; \
+ while (_ls_p) { \
+ _ls_nmerges++; \
+ _ls_q = _ls_p; \
+ _ls_psize = 0; \
+ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
+ _ls_psize++; \
+ _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); \
+ if (!_ls_q) break; \
+ } \
+ _ls_qsize = _ls_insize; \
+ while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \
+ if (_ls_psize == 0) { \
+ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \
+ } else if (_ls_qsize == 0 || !_ls_q) { \
+ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \
+ } else if (cmp(_ls_p,_ls_q) <= 0) { \
+ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \
+ } else { \
+ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \
+ } \
+ if (_ls_tail) { \
+ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list); \
+ } else { \
+ _CASTASGN(list,_ls_e); \
+ } \
+ _ls_tail = _ls_e; \
+ } \
+ _ls_p = _ls_q; \
+ } \
+ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL); _RS(list); \
+ if (_ls_nmerges <= 1) { \
+ _ls_looping=0; \
+ } \
+ _ls_insize *= 2; \
+ } \
+ } else _tmp=NULL; /* quiet gcc unused variable warning */ \
+} while (0)
+
+#define DL_SORT(list, cmp) \
+do { \
+ LDECLTYPE(list) _ls_p; \
+ LDECLTYPE(list) _ls_q; \
+ LDECLTYPE(list) _ls_e; \
+ LDECLTYPE(list) _ls_tail; \
+ LDECLTYPE(list) _ls_oldhead; \
+ LDECLTYPE(list) _tmp; \
+ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
+ if (list) { \
+ _ls_insize = 1; \
+ _ls_looping = 1; \
+ while (_ls_looping) { \
+ _CASTASGN(_ls_p,list); \
+ _CASTASGN(_ls_oldhead,list); \
+ list = NULL; \
+ _ls_tail = NULL; \
+ _ls_nmerges = 0; \
+ while (_ls_p) { \
+ _ls_nmerges++; \
+ _ls_q = _ls_p; \
+ _ls_psize = 0; \
+ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
+ _ls_psize++; \
+ _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); \
+ if (!_ls_q) break; \
+ } \
+ _ls_qsize = _ls_insize; \
+ while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \
+ if (_ls_psize == 0) { \
+ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \
+ } else if (_ls_qsize == 0 || !_ls_q) { \
+ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \
+ } else if (cmp(_ls_p,_ls_q) <= 0) { \
+ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \
+ } else { \
+ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \
+ } \
+ if (_ls_tail) { \
+ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list); \
+ } else { \
+ _CASTASGN(list,_ls_e); \
+ } \
+ _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail); _RS(list); \
+ _ls_tail = _ls_e; \
+ } \
+ _ls_p = _ls_q; \
+ } \
+ _CASTASGN(list->prev, _ls_tail); \
+ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL); _RS(list); \
+ if (_ls_nmerges <= 1) { \
+ _ls_looping=0; \
+ } \
+ _ls_insize *= 2; \
+ } \
+ } else _tmp=NULL; /* quiet gcc unused variable warning */ \
+} while (0)
+
+#define CDL_SORT(list, cmp) \
+do { \
+ LDECLTYPE(list) _ls_p; \
+ LDECLTYPE(list) _ls_q; \
+ LDECLTYPE(list) _ls_e; \
+ LDECLTYPE(list) _ls_tail; \
+ LDECLTYPE(list) _ls_oldhead; \
+ LDECLTYPE(list) _tmp; \
+ LDECLTYPE(list) _tmp2; \
+ int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping; \
+ if (list) { \
+ _ls_insize = 1; \
+ _ls_looping = 1; \
+ while (_ls_looping) { \
+ _CASTASGN(_ls_p,list); \
+ _CASTASGN(_ls_oldhead,list); \
+ list = NULL; \
+ _ls_tail = NULL; \
+ _ls_nmerges = 0; \
+ while (_ls_p) { \
+ _ls_nmerges++; \
+ _ls_q = _ls_p; \
+ _ls_psize = 0; \
+ for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) { \
+ _ls_psize++; \
+ _SV(_ls_q,list); \
+ if (_NEXT(_ls_q,list) == _ls_oldhead) { \
+ _ls_q = NULL; \
+ } else { \
+ _ls_q = _NEXT(_ls_q,list); \
+ } \
+ _RS(list); \
+ if (!_ls_q) break; \
+ } \
+ _ls_qsize = _ls_insize; \
+ while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) { \
+ if (_ls_psize == 0) { \
+ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \
+ if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \
+ } else if (_ls_qsize == 0 || !_ls_q) { \
+ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \
+ if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \
+ } else if (cmp(_ls_p,_ls_q) <= 0) { \
+ _ls_e = _ls_p; _SV(_ls_p,list); _ls_p = _NEXT(_ls_p,list); _RS(list); _ls_psize--; \
+ if (_ls_p == _ls_oldhead) { _ls_p = NULL; } \
+ } else { \
+ _ls_e = _ls_q; _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list); _RS(list); _ls_qsize--; \
+ if (_ls_q == _ls_oldhead) { _ls_q = NULL; } \
+ } \
+ if (_ls_tail) { \
+ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e); _RS(list); \
+ } else { \
+ _CASTASGN(list,_ls_e); \
+ } \
+ _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail); _RS(list); \
+ _ls_tail = _ls_e; \
+ } \
+ _ls_p = _ls_q; \
+ } \
+ _CASTASGN(list->prev,_ls_tail); \
+ _CASTASGN(_tmp2,list); \
+ _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp2); _RS(list); \
+ if (_ls_nmerges <= 1) { \
+ _ls_looping=0; \
+ } \
+ _ls_insize *= 2; \
+ } \
+ } else _tmp=NULL; /* quiet gcc unused variable warning */ \
+} while (0)
+
+/******************************************************************************
+ * singly linked list macros (non-circular) *
+ *****************************************************************************/
+#define LL_PREPEND(head,add) \
+do { \
+ (add)->next = head; \
+ head = add; \
+} while (0)
+
+#define LL_APPEND(head,add) \
+do { \
+ LDECLTYPE(head) _tmp; \
+ (add)->next=NULL; \
+ if (head) { \
+ _tmp = head; \
+ while (_tmp->next) { _tmp = _tmp->next; } \
+ _tmp->next=(add); \
+ } else { \
+ (head)=(add); \
+ } \
+} while (0)
+
+#define LL_DELETE(head,del) \
+do { \
+ LDECLTYPE(head) _tmp; \
+ if ((head) == (del)) { \
+ (head)=(head)->next; \
+ } else { \
+ _tmp = head; \
+ while (_tmp->next && (_tmp->next != (del))) { \
+ _tmp = _tmp->next; \
+ } \
+ if (_tmp->next) { \
+ _tmp->next = ((del)->next); \
+ } \
+ } \
+} while (0)
+
+/* Here are VS2008 replacements for LL_APPEND and LL_DELETE */
+#define LL_APPEND_VS2008(head,add) \
+do { \
+ if (head) { \
+ (add)->next = head; /* use add->next as a temp variable */ \
+ while ((add)->next->next) { (add)->next = (add)->next->next; } \
+ (add)->next->next=(add); \
+ } else { \
+ (head)=(add); \
+ } \
+ (add)->next=NULL; \
+} while (0)
+
+#define LL_DELETE_VS2008(head,del) \
+do { \
+ if ((head) == (del)) { \
+ (head)=(head)->next; \
+ } else { \
+ char *_tmp = (char*)(head); \
+ while (head->next && (head->next != (del))) { \
+ head = head->next; \
+ } \
+ if (head->next) { \
+ head->next = ((del)->next); \
+ } \
+ { \
+ char **_head_alias = (char**)&(head); \
+ *_head_alias = _tmp; \
+ } \
+ } \
+} while (0)
+#ifdef NO_DECLTYPE
+#undef LL_APPEND
+#define LL_APPEND LL_APPEND_VS2008
+#undef LL_DELETE
+#define LL_DELETE LL_DELETE_VS2008
+#endif
+/* end VS2008 replacements */
+
+#define LL_FOREACH(head,el) \
+ for(el=head;el;el=el->next)
+
+#define LL_FOREACH_SAFE(head,el,tmp) \
+ for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp)
+
+#define LL_SEARCH_SCALAR(head,out,field,val) \
+do { \
+ LL_FOREACH(head,out) { \
+ if ((out)->field == (val)) break; \
+ } \
+} while(0)
+
+#define LL_SEARCH(head,out,elt,cmp) \
+do { \
+ LL_FOREACH(head,out) { \
+ if ((cmp(out,elt))==0) break; \
+ } \
+} while(0)
+
+/******************************************************************************
+ * doubly linked list macros (non-circular) *
+ *****************************************************************************/
+#define DL_PREPEND(head,add) \
+do { \
+ (add)->next = head; \
+ if (head) { \
+ (add)->prev = (head)->prev; \
+ (head)->prev = (add); \
+ } else { \
+ (add)->prev = (add); \
+ } \
+ (head) = (add); \
+} while (0)
+
+#define DL_APPEND(head,add) \
+do { \
+ if (head) { \
+ (add)->prev = (head)->prev; \
+ (head)->prev->next = (add); \
+ (head)->prev = (add); \
+ (add)->next = NULL; \
+ } else { \
+ (head)=(add); \
+ (head)->prev = (head); \
+ (head)->next = NULL; \
+ } \
+} while (0);
+
+#define DL_DELETE(head,del) \
+do { \
+ if ((del)->prev == (del)) { \
+ (head)=NULL; \
+ } else if ((del)==(head)) { \
+ (del)->next->prev = (del)->prev; \
+ (head) = (del)->next; \
+ } else { \
+ (del)->prev->next = (del)->next; \
+ if ((del)->next) { \
+ (del)->next->prev = (del)->prev; \
+ } else { \
+ (head)->prev = (del)->prev; \
+ } \
+ } \
+} while (0);
+
+
+#define DL_FOREACH(head,el) \
+ for(el=head;el;el=el->next)
+
+/* this version is safe for deleting the elements during iteration */
+#define DL_FOREACH_SAFE(head,el,tmp) \
+ for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp)
+
+/* these are identical to their singly-linked list counterparts */
+#define DL_SEARCH_SCALAR LL_SEARCH_SCALAR
+#define DL_SEARCH LL_SEARCH
+
+/******************************************************************************
+ * circular doubly linked list macros *
+ *****************************************************************************/
+#define CDL_PREPEND(head,add) \
+do { \
+ if (head) { \
+ (add)->prev = (head)->prev; \
+ (add)->next = (head); \
+ (head)->prev = (add); \
+ (add)->prev->next = (add); \
+ } else { \
+ (add)->prev = (add); \
+ (add)->next = (add); \
+ } \
+(head)=(add); \
+} while (0)
+
+#define CDL_DELETE(head,del) \
+do { \
+ if ( ((head)==(del)) && ((head)->next == (head))) { \
+ (head) = 0L; \
+ } else { \
+ (del)->next->prev = (del)->prev; \
+ (del)->prev->next = (del)->next; \
+ if ((del) == (head)) (head)=(del)->next; \
+ } \
+} while (0);
+
+#define CDL_FOREACH(head,el) \
+ for(el=head;el;el=(el->next==head ? 0L : el->next))
+
+#define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \
+ for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL); \
+ (el) && ((tmp2)=(el)->next, 1); \
+ ((el) = (((el)==(tmp1)) ? 0L : (tmp2))))
+
+#define CDL_SEARCH_SCALAR(head,out,field,val) \
+do { \
+ CDL_FOREACH(head,out) { \
+ if ((out)->field == (val)) break; \
+ } \
+} while(0)
+
+#define CDL_SEARCH(head,out,elt,cmp) \
+do { \
+ CDL_FOREACH(head,out) { \
+ if ((cmp(out,elt))==0) break; \
+ } \
+} while(0)
+
+#endif /* UTLIST_H */
+
diff --git a/doc/darshan-modularization.txt b/doc/darshan-modularization.txt
index 40a70f6..693e55a 100644
--- a/doc/darshan-modularization.txt
+++ b/doc/darshan-modularization.txt
@@ -6,11 +6,6 @@ Darshan modularization branch development notes
Darshan is a lightweight toolkit for characterizing the I/O performance of instrumented
HPC applications.
-Darshan was originally designed to gather I/O data from a static set of sources.
-Adding instrumentation for additional sources of I/O data was only possible through
-manual modification of the Darshan log file format, which consequentially breaks
-any other utilities reliant on that format.
-
Starting with version 3.0.0, the Darshan runtime environment and log file format have
been redesigned such that new "instrumentation modules" can be added without breaking
existing tools. Developers are given a framework to implement arbitrary instrumentation
@@ -52,6 +47,8 @@ applications and generating I/O characterization logs.
* *darshan-util*: Darshan utilities for analyzing the contents of a given Darshan
I/O characterization log.
+
+
The following subsections provide an overview of each of these components with specific
attention to how new instrumentation modules may be integrated into Darshan.
hooks/post-receive
--
More information about the Darshan-commits
mailing list