Skip to content
Closed
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
15 changes: 14 additions & 1 deletion quest/src/api/channels.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,19 @@ using std::vector;



/*
* EXTERNAL FUNCTIONS
*
* which are regrettably extern'd, rather than included
* in a header, because they are defined within /api/,
* within which the headers are user-visible. Gross!
*/


extern bool env_isDistributed();



/*
* PRIVATE UTILITIES
*/
Expand Down Expand Up @@ -107,7 +120,7 @@ void freeAllMemoryIfAnyAllocsFailed(T& obj) {

// determine whether any node experienced a failure
bool anyFail = didAnyLocalAllocsFail(obj);
if (comm_isInit())
if (env_isDistributed())
anyFail = comm_isTrueOnAllNodes(anyFail);

// if so, free all memory before subsequent validation
Expand Down
21 changes: 21 additions & 0 deletions quest/src/api/environment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,27 @@ static bool global_hasEnvBeenFinalized = false;



/*
* PUBLIC ENV PROPERTIES
*
* which are not exposed in the header, since the header is user-facing!
* For now, we grossly require callers to 'extern' these, blegh!
*/


bool env_isDistributed() {

if (global_envPtr == nullptr)
error_envIsNullPtr();

if (global_envPtr->isDistributed && ! comm_isInit())
error_envDistributedButCommIsNotInit();

return global_envPtr->isDistributed;
}



/*
* PRIVATE QUESTENV INITIALISATION INNER FUNCTIONS
*/
Expand Down
15 changes: 14 additions & 1 deletion quest/src/api/matrices.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,19 @@ using std::vector;



/*
* EXTERNAL FUNCTIONS
*
* which are regrettably extern'd, rather than included
* in a header, because they are defined within /api/,
* within which the headers are user-visible. Gross!
*/


extern bool env_isDistributed();



/*
* FIZED-SIZE MATRIX VECTOR GETTERS
*
Expand Down Expand Up @@ -165,7 +178,7 @@ void freeAllMemoryIfAnyAllocsFailed(T matr) {

// ascertain whether any allocs failed on any node
bool anyFail = didAnyLocalAllocsFail(matr);
if (comm_isInit())
if (env_isDistributed())
anyFail = comm_isTrueOnAllNodes(anyFail);

// if so, free all heap fields
Expand Down
15 changes: 14 additions & 1 deletion quest/src/api/paulis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,19 @@ using std::vector;



/*
* EXTERNAL FUNCTIONS
*
* which are regrettably extern'd, rather than included
* in a header, because they are defined within /api/,
* within which the headers are user-visible. Gross!
*/


extern bool env_isDistributed();



/*
* PRIVATE UTILITIES
*/
Expand All @@ -38,7 +51,7 @@ bool didAnyAllocsFailOnAnyNode(PauliStrSum sum) {
! mem_isAllocated(sum.coeffs) ||
! mem_isAllocated(sum.isApproxHermitian) );

if (comm_isInit())
if (env_isDistributed())
anyFail = comm_isTrueOnAllNodes(anyFail);

return anyFail;
Expand Down
15 changes: 14 additions & 1 deletion quest/src/api/qureg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,19 @@ using std::vector;



/*
* EXTERNAL FUNCTIONS
*
* which are regrettably extern'd, rather than included
* in a header, because they are defined within /api/,
* within which the headers are user-visible. Gross!
*/


extern bool env_isDistributed();



/*
* INTERNALLY EXPOSED FUNCTION
*/
Expand Down Expand Up @@ -116,7 +129,7 @@ bool didAnyLocalAllocsFail(Qureg qureg) {
bool didAnyAllocsFailOnAnyNode(Qureg qureg) {

bool anyFail = didAnyLocalAllocsFail(qureg);
if (comm_isInit())
if (env_isDistributed())
anyFail = comm_isTrueOnAllNodes(anyFail);

return anyFail;
Expand Down
72 changes: 59 additions & 13 deletions quest/src/comm/comm_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
*
* Note that even when QUEST_COMPILE_MPI=1, the user may have
* disabled distribution when creating the QuEST environment
* at runtime. Ergo we use comm_isInit() to determine whether
* functions should invoke the MPI API.
* at runtime. Ergo we use env_isDistributed() to determine
* whether functions should invoke the MPI API.
*
* @author Tyson Jones
*/
Expand Down Expand Up @@ -53,6 +53,28 @@



/*
* EXTERNAL FUNCTIONS
*
* which are regrettably extern'd, rather than included
* in a header, because they are defined within /api/,
* within which the headers are user-visible. Gross!
*/


// NOTE I suspect this function is redundant; that we
// can actually just consult whether global_mpiComm
// is NULL to determine whether QuEST distribution is
// active, which may avoid the pitfalls of this function;
// chiefly, that it must not be called before QuESTEnv
// creation, and so must not be invoked during failed
// initQuESTEnv validation (which happens because the
// error-msg printing attempts to print on root only)

extern bool env_isDistributed();



/*
* MPI ENVIRONMENT MANAGEMENT
*
Expand Down Expand Up @@ -154,22 +176,31 @@ void comm_end(bool userOwnsMpi) {
int comm_getRank() {
#if QUEST_COMPILE_MPI

// if distribution was not runtime enabled (or a validation error was
// triggered), every node (if many MPI processes were launched)
// believes it is the root rank
// We must return ROOT_RANK whenever !env_isDistributed(), but alas we
// cannot immediately call that, because this function can be triggered
// BEFORE QuESTEnv is successfully created; this happens when validation
// during initQuESTEnv failed, triggering print(), which calls this
// function to avoid non-root printing! We first check whether MPI itself
// was ever initialised (by us, or by an MPI-owning user); if no, we exit.
if (!comm_isInit())
return ROOT_RANK;

// Consult the (potentially sub-) communicator for rank; if it is still
// NULL, as can only validly happen during failed QuESTEnv init validation
// (which triggers root-only error printing and ergo this function), we
// fall back to every process believing it is root and so attempting to
// print. This safely avoids consulting a potentially bugged MPI communicator
// and losing the message. We once tried to fallback to MPI_COMM_WORLD here,
// NULL, as can only validly happen during failed QuESTEnv init validation,
// we fall back to every process believing it is root; all attempts to print.
// This safely avoids consulting a potentially bugged MPI communicator
// and losing the message. We COULD try to fallback to MPI_COMM_WORLD here,
// to avoid duplicate output, but it is not worth the risk of msg loss!
if (global_mpiComm == MPI_COMM_NULL)
return ROOT_RANK;

// Finally, we must not query MPI if it is user-owned, and QuEST has been
// deployed non-distributed. This scenario actually triggers mpiComm==NULL
// above, but we make it very explicit here to highlight that this can
// occur when input validation has NOT been failed.
if (!env_isDistributed())
return ROOT_RANK;

int rank;
MPI_Comm_rank(global_mpiComm, &rank);
return rank;
Expand All @@ -193,12 +224,19 @@ bool comm_isRootNode() {
int comm_getNumNodes() {
#if QUEST_COMPILE_MPI

// if distribution was not runtime enabled (or a validation error was
// triggered), every node (if many MPI processes were launched)
// believes it is the one and only node
// if MPI is not initialised, either deliberately or because a validation
// error triggered during initialisation, then every node believes it is
// the one and only root node
if (!comm_isInit())
return 1;

// if MPI is initialised, but QuEST is non-distributed, then the MPI is
// user-owned and must not influence our QuEST numNodes. We call this
// AFTER !comm_isInit() because it requires the QuESTEnv has been prior
// validly created, so failed validation must encounter above pathway first.
if (!env_isDistributed())
return 1;

int numNodes;
MPI_Comm_size(global_mpiComm, &numNodes);
return numNodes;
Expand All @@ -224,6 +262,14 @@ void comm_sync() {
if (global_mpiComm == MPI_COMM_NULL)
return;

// when MPI is user-owned (QuEST is not distributed), we never consult it! This
// is checked last because it requires QuESTEnv is validly created, though this
// function can be triggered during failed initQuESTEnv validation. Note too that
// this scenario is already covered by mpiComm == NULL, but we handle it here to
// highlight that this is a valid non-error-triggered scenario!
if (!env_isDistributed())
return;

MPI_Barrier(global_mpiComm);
#endif
}
Expand Down
10 changes: 10 additions & 0 deletions quest/src/core/errors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,16 @@ void error_allocOfQuESTEnvFailed() {
raiseInternalError("Attempted memory allocation for the newly created QuESTEnv unexpectedly failed.");
}

void error_envIsNullPtr() {

raiseInternalError("The private QuESTEnv instance of environment.cpp was unexpectedly nullptr, implying an internal function queried it before QuESTEnv initialisation.");
}

void error_envDistributedButCommIsNotInit() {

raiseInternalError("The QuESTEnv was believed distributed but the communicator was not initialised.");
}



/*
Expand Down
5 changes: 5 additions & 0 deletions quest/src/core/errors.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ void error_validationListUniquenessCheckExceededMaskSize();

void error_allocOfQuESTEnvFailed();

void error_envIsNullPtr();

void error_envDistributedButCommIsNotInit();




/*
Expand Down
17 changes: 15 additions & 2 deletions quest/src/core/randomiser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@ using std::vector;



/*
* EXTERNAL FUNCTIONS
*
* which are regrettably extern'd, rather than included
* in a header, because they are defined within /api/,
* within which the headers are user-visible. Gross!
*/


extern bool env_isDistributed();



/*
* RNG HYPERPARAMTERS
*/
Expand Down Expand Up @@ -66,14 +79,14 @@ void rand_setSeeds(vector<unsigned> seeds) {

// all nodes learn root node's #seeds
unsigned numRootSeeds = seeds.size();
if (comm_isInit())
if (env_isDistributed())
comm_broadcastUnsignedsFromRoot(&numRootSeeds, 1);

// all nodes ensure they have space to receive root node's seeds
seeds.resize(numRootSeeds);

// all nodes receive root seeds
if (comm_isInit())
if (env_isDistributed())
comm_broadcastUnsignedsFromRoot(seeds.data(), seeds.size());

// all nodes remember seeds (in case user wishes to later recall them)
Expand Down
Loading