Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add spath_assert #7

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 96 additions & 19 deletions src/spath_mpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "spath.h"
#include "spath_util.h"
#include "spath_mpi.h"

#include <stdio.h>
#include <stdlib.h>
Expand All @@ -19,25 +20,109 @@ 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);
fflush(stderr);

/* 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) ...\n");
fflush(stderr);
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);
fflush(stderr);
}

/* 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\n",
__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\n",
__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) */
Expand All @@ -47,14 +132,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 */
Expand All @@ -74,11 +151,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\n",
__FILE__, __LINE__);
if (assert_rc) {
return SPATH_FAILURE;
}

/* broadcast the string */
Expand Down
10 changes: 10 additions & 0 deletions src/spath_mpi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down