From e0df1bc046b7295139f14453c33957cb908afae8 Mon Sep 17 00:00:00 2001 From: Adam Moody Date: Wed, 30 Sep 2020 13:35:39 -0700 Subject: [PATCH 1/2] add spath_assert --- src/spath_mpi.c | 112 ++++++++++++++++++++++++++++++++++++++++-------- src/spath_mpi.h | 10 +++++ 2 files changed, 103 insertions(+), 19 deletions(-) diff --git a/src/spath_mpi.c b/src/spath_mpi.c index b59c5b1..313a746 100644 --- a/src/spath_mpi.c +++ b/src/spath_mpi.c @@ -2,6 +2,7 @@ #include "spath.h" #include "spath_util.h" +#include "spath_mpi.h" #include #include @@ -19,25 +20,106 @@ Functions to send/recv paths with MPI ========================================= */ +spath_assert_mode_t spath_assert_mode = SPATH_ASSERT_ABORT; /* determines how spath_assert behaves on errors */ + +/* Check that given condition is true. + * Returns 0 if assert passes, and 1 if assert fails. + * if in production mode: + * - if condition is false, print msg and call MPI_Abort + * if in testing mode: + * - execute allreduce on comm to verify condition is true on *all* procs, + * if false on *any* proc, print msg and return error on all procs + * if in debugging mode: + * - if condition is false, print msg and call while(1) to hang, + * which allows someone to attach debugger */ +static int spath_assert(int condition, MPI_Comm comm, const char* format, ...) +{ + /* If in production mode and condition is false, + * then print error message and call abort. */ + if (spath_assert_mode == SPATH_ASSERT_ABORT) { + if (! condition) { + /* print error message */ + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + + /* abort */ + MPI_Abort(comm, -1); + } + } + + /* If in debugging mode and condition is false, + * then print error message and hang so one can attach a debugger. */ + if (spath_assert_mode == SPATH_ASSERT_HANG) { + if (! condition) { + /* print error message */ + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + + /* hang, so user can attach a debugger */ + fprintf(stderr, "Hanging in while(1) ..."); + while(1); + } + } + + /* If in testing mode, check that condition is true on all procs in comm. + * If true everywhere, return SUCCESS. Otherwise, print error message + * from one rank and return an error on all ranks. */ + if (spath_assert_mode == SPATH_ASSERT_RETURN) { + /* verify that condition is true on all procs in comm */ + int alltrue; + MPI_Allreduce(&condition, &alltrue, 1, MPI_INT, MPI_LAND, comm); + if (! alltrue) { + /* condition is false on at least one rank in comm, + * print the error message, but just from rank 0 */ + int rank; + MPI_Comm_rank(comm, &rank); + if (rank == 0) { + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + } + + /* everyone return an error from all ranks */ + return 1; + } + } + + /* condition is true */ + return 0; +} + /* broacast path from root to all ranks in comm, * receivers must pass in a newly allocated path from spath_new() */ int spath_bcast(spath* path, int root, MPI_Comm comm) { /* if pointer is NULL, throw an error */ - if (path == NULL) { - fprintf(stderr, "NULL pointer passed for path @ %s:%d", - __FILE__, __LINE__ - ); - MPI_Abort(comm, -1); + int assert_rc = spath_assert(path != NULL, comm, + "NULL pointer passed for path @ %s:%d", + __FILE__, __LINE__); + if (assert_rc) { + return SPATH_FAILURE; } /* lookup our rank in comm */ int rank; MPI_Comm_rank(comm, &rank); + /* as a receiver, verify that we were given an empty path */ + int components = spath_components(path); + assert_rc = spath_assert(rank == root || components == 0, comm, + "Non-null path passed as input in receiver to bcast path @ %s:%d", + __FILE__, __LINE__); + if (assert_rc) { + return SPATH_FAILURE; + } + /* determine number of bytes to send */ int bytes; - int components = spath_components(path); if (rank == root) { if (components > 0) { /* figure out string length of path (including terminating NULL) */ @@ -47,14 +129,6 @@ int spath_bcast(spath* path, int root, MPI_Comm comm) * since even an empty string contains at least one byte */ bytes = 0; } - } else { - /* as a receiver, verify that we were given an empty path */ - if (components > 0) { - fprintf(stderr, "Non-null path passed as input in receiver to bcast path @ %s:%d", - __FILE__, __LINE__ - ); - MPI_Abort(comm, -1); - } } /* broadcast number of bytes in path */ @@ -74,11 +148,11 @@ int spath_bcast(spath* path, int root, MPI_Comm comm) /* non-root processes need to allocate an array */ str = (char*) SPATH_MALLOC((size_t)bytes); } - if (str == NULL) { - fprintf(stderr, "Failed to allocate memory to bcast path @ %s:%d", - __FILE__, __LINE__ - ); - MPI_Abort(comm, -1); + assert_rc = spath_assert(str != NULL, comm, + "Failed to allocate memory to bcast path @ %s:%d", + __FILE__, __LINE__); + if (assert_rc) { + return SPATH_FAILURE; } /* broadcast the string */ diff --git a/src/spath_mpi.h b/src/spath_mpi.h index 0fc9648..d5f0dce 100644 --- a/src/spath_mpi.h +++ b/src/spath_mpi.h @@ -14,6 +14,16 @@ extern "C" { #endif +/* how to behave if an spath_assert condition is found to be false */ +typedef enum { + SPATH_ASSERT_ABORT = 1, /* print error message and call abort */ + SPATH_ASSERT_HANG, /* print error message and hang with while(1) */ + SPATH_ASSERT_RETURN, /* execute allreduce to check on all ranks, + * print error message and return failure on all */ +} spath_assert_mode_t; + +extern spath_assert_mode_t spath_assert_mode; /* determines how spath_assert behaves on errors */ + #if 0 /** send/recv path, recv_path should be from spath_new() */ int spath_sendrecv( From 74b617a89c9344785d6fdd33e23a893fcc6f55e6 Mon Sep 17 00:00:00 2001 From: Adam Moody Date: Wed, 30 Sep 2020 14:21:53 -0700 Subject: [PATCH 2/2] add newlines and fflush --- src/spath_mpi.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/spath_mpi.c b/src/spath_mpi.c index 313a746..0af0d97 100644 --- a/src/spath_mpi.c +++ b/src/spath_mpi.c @@ -43,6 +43,7 @@ static int spath_assert(int condition, MPI_Comm comm, const char* format, ...) va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); + fflush(stderr); /* abort */ MPI_Abort(comm, -1); @@ -60,7 +61,8 @@ static int spath_assert(int condition, MPI_Comm comm, const char* format, ...) va_end(ap); /* hang, so user can attach a debugger */ - fprintf(stderr, "Hanging in while(1) ..."); + fprintf(stderr, "Hanging in while(1) ...\n"); + fflush(stderr); while(1); } } @@ -82,6 +84,7 @@ static int spath_assert(int condition, MPI_Comm comm, const char* format, ...) va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); + fflush(stderr); } /* everyone return an error from all ranks */ @@ -99,7 +102,7 @@ int spath_bcast(spath* path, int root, MPI_Comm comm) { /* if pointer is NULL, throw an error */ int assert_rc = spath_assert(path != NULL, comm, - "NULL pointer passed for path @ %s:%d", + "NULL pointer passed for path @ %s:%d\n", __FILE__, __LINE__); if (assert_rc) { return SPATH_FAILURE; @@ -112,7 +115,7 @@ int spath_bcast(spath* path, int root, MPI_Comm comm) /* as a receiver, verify that we were given an empty path */ int components = spath_components(path); assert_rc = spath_assert(rank == root || components == 0, comm, - "Non-null path passed as input in receiver to bcast path @ %s:%d", + "Non-null path passed as input in receiver to bcast path @ %s:%d\n", __FILE__, __LINE__); if (assert_rc) { return SPATH_FAILURE; @@ -149,7 +152,7 @@ int spath_bcast(spath* path, int root, MPI_Comm comm) str = (char*) SPATH_MALLOC((size_t)bytes); } assert_rc = spath_assert(str != NULL, comm, - "Failed to allocate memory to bcast path @ %s:%d", + "Failed to allocate memory to bcast path @ %s:%d\n", __FILE__, __LINE__); if (assert_rc) { return SPATH_FAILURE;