diff --git a/quest/src/api/channels.cpp b/quest/src/api/channels.cpp index d6e3ac4fb..450d04cbd 100644 --- a/quest/src/api/channels.cpp +++ b/quest/src/api/channels.cpp @@ -456,11 +456,15 @@ extern "C" void reportSuperOp(SuperOp op) { size_t elemMem = mem_getLocalSuperOpMemoryRequired(op.numQubits); size_t structMem = sizeof(op); + printer_sync(); + print_header(op, elemMem + structMem); print_elems(op); // exclude mandatory newline above print_oneFewerNewlines(); + + printer_sync(); } @@ -479,6 +483,8 @@ extern "C" void reportKrausMap(KrausMap map) { size_t superMem = mem_getLocalSuperOpMemoryRequired(map.superop.numQubits); size_t strucMem = sizeof(map); + printer_sync(); + // gauranteed not to overflow size_t totalMem = krausMem + superMem + strucMem; print_header(map, totalMem); @@ -486,4 +492,6 @@ extern "C" void reportKrausMap(KrausMap map) { // exclude mandatory newline above print_oneFewerNewlines(); + + printer_sync(); } diff --git a/quest/src/api/environment.cpp b/quest/src/api/environment.cpp index 1cc2f6862..6c72b14c0 100644 --- a/quest/src/api/environment.cpp +++ b/quest/src/api/environment.cpp @@ -482,6 +482,8 @@ void reportQuESTEnv() { /// @todo add function to write this output to file (useful for HPC debugging) + printer_sync(); + print_label("QuEST execution environment"); bool statevec = false; @@ -503,6 +505,8 @@ void reportQuESTEnv() { // exclude mandatory newline above print_oneFewerNewlines(); + + printer_sync(); } diff --git a/quest/src/api/matrices.cpp b/quest/src/api/matrices.cpp index b17987eb4..c7e963359 100644 --- a/quest/src/api/matrices.cpp +++ b/quest/src/api/matrices.cpp @@ -763,11 +763,16 @@ void validateAndPrintMatrix(T matr, const char* caller) { structMem -= elemMem; size_t numBytesPerNode = elemMem + structMem; + + printer_sync(); + print_header(matr, numBytesPerNode); print_elems(matr); // exclude mandatory newline above print_oneFewerNewlines(); + + printer_sync(); } diff --git a/quest/src/api/paulis.cpp b/quest/src/api/paulis.cpp index 855a9cfd8..a996f83c0 100644 --- a/quest/src/api/paulis.cpp +++ b/quest/src/api/paulis.cpp @@ -263,12 +263,16 @@ extern "C" void destroyPauliStrSum(PauliStrSum sum) { extern "C" void reportPauliStr(PauliStr str) { + printer_sync(); + // no header, so no indentation string indent = ""; print_elemsWithoutNewline(str, indent); // print all user-set newlines (including none) print_newlines(); + + printer_sync(); } @@ -285,11 +289,15 @@ extern "C" void reportPauliStrSum(PauliStrSum sum) { // linearly with user input parameters, unlike Qureg and matrices. qindex numTotalBytes = numStrBytes + numCoeffBytes + numStrucBytes; + printer_sync(); + print_header(sum, numTotalBytes); print_elems(sum); // exclude mandatory newline above print_oneFewerNewlines(); + + printer_sync(); } diff --git a/quest/src/api/qureg.cpp b/quest/src/api/qureg.cpp index 034c96e5c..3bad734e4 100644 --- a/quest/src/api/qureg.cpp +++ b/quest/src/api/qureg.cpp @@ -360,7 +360,8 @@ void reportQuregParams(Qureg qureg) { /// @todo add function to write this output to file (useful for HPC debugging) - // printer routines will consult env rank to avoid duplicate printing + printer_sync(); + print_label("Qureg"); printDeploymentInfo(qureg); printDimensionInfo(qureg); @@ -369,6 +370,8 @@ void reportQuregParams(Qureg qureg) { // exclude mandatory newline above print_oneFewerNewlines(); + + printer_sync(); } @@ -385,11 +388,15 @@ void reportQureg(Qureg qureg) { // include struct size (expected negligibly tiny) localMem += sizeof(qureg); + printer_sync(); + print_header(qureg, localMem); print_elems(qureg); // exclude mandatory newline above print_oneFewerNewlines(); + + printer_sync(); } diff --git a/quest/src/api/types.cpp b/quest/src/api/types.cpp index 4fadf1cb5..cead74301 100644 --- a/quest/src/api/types.cpp +++ b/quest/src/api/types.cpp @@ -22,8 +22,12 @@ using std::string; void reportStr(std::string str) { validate_envIsInit(__func__); + printer_sync(); + print(str); print_newlines(); + + printer_sync(); } extern "C" void reportStr(const char* str) { diff --git a/quest/src/core/errors.cpp b/quest/src/core/errors.cpp index 7b624a2f7..8e61a2d1c 100644 --- a/quest/src/core/errors.cpp +++ b/quest/src/core/errors.cpp @@ -41,6 +41,8 @@ using std::string; void raiseInternalError(string errorMsg) { + printer_sync(); + print(string("") + "\n\n" + "A fatal internal QuEST error occurred. " @@ -49,6 +51,8 @@ void raiseInternalError(string errorMsg) { + "\n" ); + printer_sync(); + exit(EXIT_FAILURE); } diff --git a/quest/src/core/printer.cpp b/quest/src/core/printer.cpp index cea89000d..283f51a4d 100644 --- a/quest/src/core/printer.cpp +++ b/quest/src/core/printer.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -167,6 +168,26 @@ void printer_setPauliStrFormat(int flag) { +/* + * MULTI-PROCESS MANAGEMENT + */ + + +void printer_sync() { + + // make all participating processes flush, to improve the chance + // that user-printing from non-root processes reaches the screen + // before QuEST begins to print from the root process + std::cout << std::flush; // C++ buffer + fflush(stdout); // C buffer + + // wait for all process flushes to complete, which defers non-root + // processes from printing until after root has finished printing + comm_sync(); +} + + + /* * TYPE NAME STRINGS */ diff --git a/quest/src/core/printer.hpp b/quest/src/core/printer.hpp index d2ff8274d..b359bb381 100644 --- a/quest/src/core/printer.hpp +++ b/quest/src/core/printer.hpp @@ -48,6 +48,14 @@ void printer_setPauliStrFormat(int flag); +/* + * MULTI-PROCESS MANAGEMENT + */ + +void printer_sync(); + + + /* * TYPE NAME STRINGS */ diff --git a/quest/src/core/validation.cpp b/quest/src/core/validation.cpp index 959acb61e..fc6adc58f 100644 --- a/quest/src/core/validation.cpp +++ b/quest/src/core/validation.cpp @@ -1142,6 +1142,10 @@ namespace report { void default_inputErrorHandler(const char* func, const char* msg) { + // force a std-flush and comm-sync so that the error message is not (well, less likely + // to be interrupted_ by users printing from a non-root process + printer_sync(); + // safe to call even before MPI has been setup, and ignores user-set trailing newlines. // It begins with \n to interrupt half-printed lines (when trailing newlines are set to // 0 via setQuESTNumReportedNewlines(0)), for visual clarity. Note that user's overriding @@ -1153,7 +1157,7 @@ void default_inputErrorHandler(const char* func, const char* msg) { // force a synch because otherwise non-main nodes may exit before print, and MPI // will then attempt to instantly abort all nodes, losing the error message. - comm_sync(); + printer_sync(); // finalise MPI before error-exit to avoid scaring user with giant MPI error message // we always "take ownership" of MPI here since we're about to kill the whole program