From 99298c4392b1bdf9ff3313d4f87d464e2209b773 Mon Sep 17 00:00:00 2001 From: Christian Glusa Date: Fri, 13 Dec 2019 15:46:28 -0700 Subject: [PATCH 1/3] Teuchos: Add SyncTimeMonitor A TimeMonitor that waits at a MPI barrier before destruction. --- .../teuchos/comm/src/Teuchos_TimeMonitor.cpp | 8 +++++ .../teuchos/comm/src/Teuchos_TimeMonitor.hpp | 33 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/packages/teuchos/comm/src/Teuchos_TimeMonitor.cpp b/packages/teuchos/comm/src/Teuchos_TimeMonitor.cpp index 7e72788041d7..adf69b19e382 100644 --- a/packages/teuchos/comm/src/Teuchos_TimeMonitor.cpp +++ b/packages/teuchos/comm/src/Teuchos_TimeMonitor.cpp @@ -1113,6 +1113,14 @@ namespace Teuchos { computeGlobalTimerStatistics (statData, statNames, comm.ptr(), setOp, filter); } + SyncTimeMonitor::SyncTimeMonitor(Time& timer, Ptr > comm, bool reset) + : TimeMonitor(timer, reset), comm_(comm) + { } + + SyncTimeMonitor::~SyncTimeMonitor() { + comm_->barrier(); + } + namespace { /// \brief Quote the given string for YAML output. diff --git a/packages/teuchos/comm/src/Teuchos_TimeMonitor.hpp b/packages/teuchos/comm/src/Teuchos_TimeMonitor.hpp index 1bd68c1ba90b..b65094fe6ea1 100644 --- a/packages/teuchos/comm/src/Teuchos_TimeMonitor.hpp +++ b/packages/teuchos/comm/src/Teuchos_TimeMonitor.hpp @@ -757,12 +757,45 @@ class TEUCHOSCOMM_LIB_DLL_EXPORT TimeMonitor : /// ParameterList around. static bool setParams_; +protected: /// \brief Stacked timer for optional injection of timing from /// TimeMonitor-enabled objects. static Teuchos::RCP stackedTimer_; }; +/// \class SyncTimeMonitor +/// \brief A TimeMonitor that waits at a MPI barrier before destruction. +class SyncTimeMonitor : + public TimeMonitor { +public: + + /** \name Constructor/Destructor */ + //@{ + + /// \brief Constructor: starts the timer. + /// + /// \param timer [in/out] Reference to the timer to be wrapped. + /// This constructor starts the timer, and the destructor stops + /// the timer. + /// + /// \param reset [in] If true, reset the timer before starting it. + /// Default behavior is not to reset the timer. + SyncTimeMonitor(Time& timer, Ptr > comm, bool reset=false); + + //! Default constructor is deleted, since it would be unsafe. + SyncTimeMonitor () = delete; + + //! Destructor: stops the timer. + ~SyncTimeMonitor() override; + //@} + +private: + // \brief Communicator on which barrier will be called. + Ptr > comm_; +}; + + } // namespace Teuchos From 89e24c3666d5fbe1bfdceba44f9d204030a4b004 Mon Sep 17 00:00:00 2001 From: Christian Glusa Date: Fri, 13 Dec 2019 15:37:27 -0700 Subject: [PATCH 2/3] MueLu RefMaxwell: Refactor timers, use SyncTimeMonitor --- .../adapters/xpetra/MueLu_RefMaxwell_decl.hpp | 4 +- .../adapters/xpetra/MueLu_RefMaxwell_def.hpp | 84 +++++++++++-------- 2 files changed, 52 insertions(+), 36 deletions(-) diff --git a/packages/muelu/adapters/xpetra/MueLu_RefMaxwell_decl.hpp b/packages/muelu/adapters/xpetra/MueLu_RefMaxwell_decl.hpp index ca106f8f9ac7..1168eda6caea 100644 --- a/packages/muelu/adapters/xpetra/MueLu_RefMaxwell_decl.hpp +++ b/packages/muelu/adapters/xpetra/MueLu_RefMaxwell_decl.hpp @@ -389,6 +389,8 @@ namespace MueLu { //! dump out real-valued multivector void dumpCoords(const RealValuedMultiVector& X, std::string name) const; + Teuchos::RCP getTimer(std::string name, RCP > comm=Teuchos::null) const; + //! set parameters void setMatvecParams(Matrix& A, RCP matvecParams) { RCP xpImporter = A.getCrsGraph()->getImporter(); @@ -428,7 +430,7 @@ namespace MueLu { Teuchos::RCP AH_AP_reuse_data_, AH_RAP_reuse_data_; Teuchos::RCP A22_AP_reuse_data_, A22_RAP_reuse_data_; //! Some options - bool disable_addon_, dump_matrices_,useKokkos_,use_as_preconditioner_,implicitTranspose_,fuseProlongationAndUpdate_; + bool disable_addon_, dump_matrices_, useKokkos_, use_as_preconditioner_, implicitTranspose_, fuseProlongationAndUpdate_, syncTimers_; int numItersH_, numIters22_; std::string mode_; //! Temporary memory diff --git a/packages/muelu/adapters/xpetra/MueLu_RefMaxwell_def.hpp b/packages/muelu/adapters/xpetra/MueLu_RefMaxwell_def.hpp index 2f8b3fe19ef3..c96d8492d085 100644 --- a/packages/muelu/adapters/xpetra/MueLu_RefMaxwell_def.hpp +++ b/packages/muelu/adapters/xpetra/MueLu_RefMaxwell_def.hpp @@ -136,6 +136,7 @@ namespace MueLu { dump_matrices_ = list.get("refmaxwell: dump matrices",MasterList::getDefault("refmaxwell: dump matrices")); implicitTranspose_ = list.get("transpose: use implicit",MasterList::getDefault("transpose: use implicit")); fuseProlongationAndUpdate_ = list.get("fuse prolongation and update",MasterList::getDefault("fuse prolongation and update")); + syncTimers_ = list.get("sync timers",false); numItersH_ = list.get("refmaxwell: num iters H",1); numIters22_ = list.get("refmaxwell: num iters 22",1); @@ -191,7 +192,7 @@ namespace MueLu { timerLabel = "MueLu RefMaxwell: compute (reuse)"; else timerLabel = "MueLu RefMaxwell: compute"; - Teuchos::TimeMonitor tmCompute(*Teuchos::TimeMonitor::getNewTimer(timerLabel)); + RCP tmCompute = getTimer(timerLabel); std::map verbMap; verbMap["none"] = None; @@ -588,7 +589,7 @@ namespace MueLu { if (doRebalancing) { // rebalance AH if (!reuse) { - Teuchos::TimeMonitor tm(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: Rebalance AH")); + RCP tm = getTimer("MueLu RefMaxwell: Rebalance AH"); Level fineLevel, coarseLevel; fineLevel.SetFactoryManager(null); @@ -771,7 +772,7 @@ namespace MueLu { GetOStream(Runtime0) << "RefMaxwell::compute(): building MG for (2,2)-block" << std::endl; { // build fine grid operator for (2,2)-block, D0* SM D0 (aka TMT) - Teuchos::TimeMonitor tm(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: Build A22")); + RCP tm = getTimer("MueLu RefMaxwell: Build A22"); Level fineLevel, coarseLevel; fineLevel.SetFactoryManager(null); @@ -1224,6 +1225,19 @@ namespace MueLu { } + template + Teuchos::RCP RefMaxwell::getTimer(std::string name, RCP > comm) const { + if (!syncTimers_) + return Teuchos::rcp(new Teuchos::TimeMonitor(*Teuchos::TimeMonitor::getNewTimer(name))); + else { + if (comm.is_null()) + return Teuchos::rcp(new Teuchos::SyncTimeMonitor(*Teuchos::TimeMonitor::getNewTimer(name), SM_Matrix_->getRowMap()->getComm().ptr())); + else + return Teuchos::rcp(new Teuchos::SyncTimeMonitor(*Teuchos::TimeMonitor::getNewTimer(name), comm.ptr())); + } + } + + template void RefMaxwell::buildProlongator() { // The P11 matrix maps node based aggregrates { A_j } to edges { e_i }. @@ -1758,7 +1772,7 @@ namespace MueLu { template void RefMaxwell::formCoarseMatrix() { - Teuchos::TimeMonitor tm(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: Build coarse (1,1) matrix")); + RCP tm = getTimer("MueLu RefMaxwell: Build coarse (1,1) matrix"); // coarse matrix for P11* (M1 + D1* M2 D1) P11 RCP Matrix1; @@ -1820,7 +1834,7 @@ namespace MueLu { } else { if (Addon_Matrix_.is_null()) { - Teuchos::TimeMonitor tmAddon(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: Build coarse addon matrix")); + RCP tmAddon = getTimer("MueLu RefMaxwell: Build coarse addon matrix"); // catch a failure TEUCHOS_TEST_FOR_EXCEPTION(M0inv_Matrix_==Teuchos::null,std::invalid_argument, "MueLu::RefMaxwell::formCoarseMatrix(): Inverse of " @@ -1910,7 +1924,7 @@ namespace MueLu { { // compute residual - Teuchos::TimeMonitor tmRes(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: residual calculation")); + RCP tmRes = getTimer("MueLu RefMaxwell: residual calculation"); Utilities::Residual(*SM_Matrix_, X, RHS, *residual_); } @@ -1918,44 +1932,44 @@ namespace MueLu { if (implicitTranspose_) { { - Teuchos::TimeMonitor tmP11(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: restriction coarse (1,1) (implicit)")); + RCP tmRes = getTimer("MueLu RefMaxwell: restriction coarse (1,1) (implicit)"); P11_->apply(*residual_,*P11res_,Teuchos::TRANS); } { - Teuchos::TimeMonitor tmD0(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: restriction (2,2) (implicit)")); + RCP tmD0 = getTimer("MueLu RefMaxwell: restriction (2,2) (implicit)"); D0_Matrix_->apply(*residual_,*D0res_,Teuchos::TRANS); } } else { { - Teuchos::TimeMonitor tmP11(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: restriction coarse (1,1) (explicit)")); + RCP tmP11 = getTimer("MueLu RefMaxwell: restriction coarse (1,1) (explicit)"); R11_->apply(*residual_,*P11res_,Teuchos::NO_TRANS); } { - Teuchos::TimeMonitor tmD0(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: restriction (2,2) (explicit)")); + RCP tmD0 = getTimer("MueLu RefMaxwell: restriction (2,2) (explicit)"); D0_T_Matrix_->apply(*residual_,*D0res_,Teuchos::NO_TRANS); } } } { - Teuchos::TimeMonitor tmSubSolves(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: subsolves")); + RCP tmSubSolves = getTimer("MueLu RefMaxwell: subsolves"); // block diagonal preconditioner on 2x2 (V-cycle for diagonal blocks) if (!ImporterH_.is_null()) { - Teuchos::TimeMonitor tmH(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: import coarse (1,1)")); + RCP tmH = getTimer("MueLu RefMaxwell: import coarse (1,1)"); P11resTmp_->doImport(*P11res_, *ImporterH_, Xpetra::INSERT); P11res_.swap(P11resTmp_); } if (!Importer22_.is_null()) { - Teuchos::TimeMonitor tm22(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: import (2,2)")); + RCP tm22 = getTimer("MueLu RefMaxwell: import (2,2)"); D0resTmp_->doImport(*D0res_, *Importer22_, Xpetra::INSERT); D0res_.swap(D0resTmp_); } // iterate on coarse (1, 1) block if (!AH_.is_null()) { - Teuchos::TimeMonitor tmH(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: solve coarse (1,1)")); + RCP tmH = getTimer("MueLu RefMaxwell: solve coarse (1,1)", AH_->getRowMap()->getComm()); RCP origXMap = P11x_->getMap(); RCP origRhsMap = P11res_->getMap(); @@ -1970,7 +1984,7 @@ namespace MueLu { // iterate on (2, 2) block if (!A22_.is_null()) { - Teuchos::TimeMonitor tm22(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: solve (2,2)")); + RCP tm22 = getTimer("MueLu RefMaxwell: solve (2,2)", A22_->getRowMap()->getComm()); RCP origXMap = D0x_->getMap(); RCP origRhsMap = D0res_->getMap(); @@ -1984,13 +1998,13 @@ namespace MueLu { } if (!Importer22_.is_null()) { - Teuchos::TimeMonitor tm22(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: export (2,2)")); + RCP tm22 = getTimer("MueLu RefMaxwell: export (2,2)"); D0xTmp_->doExport(*D0x_, *Importer22_, Xpetra::INSERT); D0x_.swap(D0xTmp_); } if (!ImporterH_.is_null()) { - Teuchos::TimeMonitor tmH(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: export coarse (1,1)")); + RCP tmH = getTimer("MueLu RefMaxwell: export coarse (1,1)"); P11xTmp_->doExport(*P11x_, *ImporterH_, Xpetra::INSERT); P11x_.swap(P11xTmp_); } @@ -1999,27 +2013,27 @@ namespace MueLu { if (fuseProlongationAndUpdate_) { { // prolongate (1,1) block - Teuchos::TimeMonitor tmP11(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: prolongation coarse (1,1) (fused)")); + RCP tmP11 = getTimer("MueLu RefMaxwell: prolongation coarse (1,1) (fused)"); P11_->apply(*P11x_,X,Teuchos::NO_TRANS,one,one); } { // prolongate (2,2) block - Teuchos::TimeMonitor tmD0(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: prolongation (2,2) (fused)")); + RCP tmD0 = getTimer("MueLu RefMaxwell: prolongation (2,2) (fused)"); D0_Matrix_->apply(*D0x_,X,Teuchos::NO_TRANS,one,one); } } else { { // prolongate (1,1) block - Teuchos::TimeMonitor tmP11(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: prolongation coarse (1,1) (unfused)")); + RCP tmP11 = getTimer("MueLu RefMaxwell: prolongation coarse (1,1) (unfused)"); P11_->apply(*P11x_,*residual_,Teuchos::NO_TRANS); } { // prolongate (2,2) block - Teuchos::TimeMonitor tmD0(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: prolongation (2,2) (unfused)")); + RCP tmD0 = getTimer("MueLu RefMaxwell: prolongation (2,2) (unfused)"); D0_Matrix_->apply(*D0x_,*residual_,Teuchos::NO_TRANS,one,one); } { // update current solution - Teuchos::TimeMonitor tmUpdate(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: update")); + RCP tmUpdate = getTimer("MueLu RefMaxwell: update"); X.update(one, *residual_, one); } } @@ -2067,7 +2081,7 @@ namespace MueLu { Scalar one = Teuchos::ScalarTraits::one(); { // compute residual - Teuchos::TimeMonitor tmRes(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: residual calculation")); + RCP tmRes = getTimer("MueLu RefMaxwell: residual calculation"); Utilities::Residual(*SM_Matrix_, X, RHS,*residual_); if (implicitTranspose_) P11_->apply(*residual_,*P11res_,Teuchos::TRANS); @@ -2077,12 +2091,12 @@ namespace MueLu { { // solve coarse (1,1) block if (!ImporterH_.is_null()) { - Teuchos::TimeMonitor tmH(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: import coarse (1,1)")); + RCP tmH = getTimer("MueLu RefMaxwell: import coarse (1,1)"); P11resTmp_->doImport(*P11res_, *ImporterH_, Xpetra::INSERT); P11res_.swap(P11resTmp_); } if (!AH_.is_null()) { - Teuchos::TimeMonitor tmH(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: solve coarse (1,1)")); + RCP tmH = getTimer("MueLu RefMaxwell: solve coarse (1,1)", AH_->getRowMap()->getComm()); RCP origXMap = P11x_->getMap(); RCP origRhsMap = P11res_->getMap(); @@ -2095,14 +2109,14 @@ namespace MueLu { P11res_->replaceMap(origRhsMap); } if (!ImporterH_.is_null()) { - Teuchos::TimeMonitor tmH(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: export coarse (1,1)")); + RCP tmH = getTimer("MueLu RefMaxwell: export coarse (1,1)"); P11xTmp_->doExport(*P11x_, *ImporterH_, Xpetra::INSERT); P11x_.swap(P11xTmp_); } } { // update current solution - Teuchos::TimeMonitor tmUp(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: update")); + RCP tmUp = getTimer("MueLu RefMaxwell: update"); P11_->apply(*P11x_,*residual_,Teuchos::NO_TRANS); X.update(one, *residual_, one); } @@ -2116,7 +2130,7 @@ namespace MueLu { Scalar one = Teuchos::ScalarTraits::one(); { // compute residual - Teuchos::TimeMonitor tmRes(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: residual calculation")); + RCP tmRes = getTimer("MueLu RefMaxwell: residual calculation"); Utilities::Residual(*SM_Matrix_, X, RHS, *residual_); if (implicitTranspose_) D0_Matrix_->apply(*residual_,*D0res_,Teuchos::TRANS); @@ -2126,12 +2140,12 @@ namespace MueLu { { // solve (2,2) block if (!Importer22_.is_null()) { - Teuchos::TimeMonitor tm22(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: import (2,2)")); + RCP tm22 = getTimer("MueLu RefMaxwell: import (2,2)"); D0resTmp_->doImport(*D0res_, *Importer22_, Xpetra::INSERT); D0res_.swap(D0resTmp_); } if (!A22_.is_null()) { - Teuchos::TimeMonitor tm22(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: solve (2,2)")); + RCP tm22 = getTimer("MueLu RefMaxwell: solve (2,2)", A22_->getRowMap()->getComm()); RCP origXMap = D0x_->getMap(); RCP origRhsMap = D0res_->getMap(); @@ -2144,14 +2158,14 @@ namespace MueLu { D0res_->replaceMap(origRhsMap); } if (!Importer22_.is_null()) { - Teuchos::TimeMonitor tm22(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: export (2,2)")); + RCP tm22 = getTimer("MueLu RefMaxwell: export (2,2)"); D0xTmp_->doExport(*D0x_, *Importer22_, Xpetra::INSERT); D0x_.swap(D0xTmp_); } } { //update current solution - Teuchos::TimeMonitor tmUp(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: update")); + RCP tmUp = getTimer("MueLu RefMaxwell: update"); D0_Matrix_->apply(*D0x_,*residual_,Teuchos::NO_TRANS); X.update(one, *residual_, one); } @@ -2165,7 +2179,7 @@ namespace MueLu { Scalar /* alpha */, Scalar /* beta */) const { - Teuchos::TimeMonitor tm(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: solve")); + RCP tm = getTimer("MueLu RefMaxwell: solve"); // make sure that we have enough temporary memory if (X.getNumVectors() != P11res_->getNumVectors()) @@ -2173,7 +2187,7 @@ namespace MueLu { { // apply pre-smoothing - Teuchos::TimeMonitor tmSm(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: smoothing")); + RCP tmSm = getTimer("MueLu RefMaxwell: smoothing"); #if defined(MUELU_REFMAXWELL_CAN_USE_HIPTMAIR) if (useHiptmairSmoothing_) { @@ -2205,7 +2219,7 @@ namespace MueLu { { // apply post-smoothing - Teuchos::TimeMonitor tmSm(*Teuchos::TimeMonitor::getNewTimer("MueLu RefMaxwell: smoothing")); + RCP tmSm = getTimer("MueLu RefMaxwell: smoothing"); #if defined(MUELU_REFMAXWELL_CAN_USE_HIPTMAIR) if (useHiptmairSmoothing_) From a7421a90e6658f5d810ae0f8733d11ffd9133f31 Mon Sep 17 00:00:00 2001 From: Christian Glusa Date: Tue, 7 Jan 2020 10:35:03 -0700 Subject: [PATCH 3/3] Teuchos: Add unit test for SyncTimeMonitor --- .../comm/test/TimeMonitor/CMakeLists.txt | 9 ++ .../comm/test/TimeMonitor/SyncTimeMonitor.cpp | 98 +++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 packages/teuchos/comm/test/TimeMonitor/SyncTimeMonitor.cpp diff --git a/packages/teuchos/comm/test/TimeMonitor/CMakeLists.txt b/packages/teuchos/comm/test/TimeMonitor/CMakeLists.txt index 0c3d1bc9c183..5e12cf76d1a1 100644 --- a/packages/teuchos/comm/test/TimeMonitor/CMakeLists.txt +++ b/packages/teuchos/comm/test/TimeMonitor/CMakeLists.txt @@ -26,3 +26,12 @@ TRIBITS_ADD_EXECUTABLE_AND_TEST( COMM mpi NUM_MPI_PROCS 4 ) + +TRIBITS_ADD_EXECUTABLE_AND_TEST( + SyncTimeMonitor + SOURCES + SyncTimeMonitor.cpp + ${TEUCHOS_STD_UNIT_TEST_MAIN} + COMM mpi + NUM_MPI_PROCS 4 + ) diff --git a/packages/teuchos/comm/test/TimeMonitor/SyncTimeMonitor.cpp b/packages/teuchos/comm/test/TimeMonitor/SyncTimeMonitor.cpp new file mode 100644 index 000000000000..bbf24c5b2ebd --- /dev/null +++ b/packages/teuchos/comm/test/TimeMonitor/SyncTimeMonitor.cpp @@ -0,0 +1,98 @@ +// @HEADER +// @HEADER + +#include "Teuchos_UnitTestHarness.hpp" +#include "Teuchos_TimeMonitor.hpp" +#include "Teuchos_DefaultComm.hpp" +#include "Teuchos_CommHelpers.hpp" +#ifdef HAVE_TEUCHOS_MPI +# include "Teuchos_DefaultMpiComm.hpp" +#endif // HAVE_TEUCHOS_MPI +#include +#include + +// Check that timers are sync'd +TEUCHOS_UNIT_TEST(TimeMonitor, SyncTimeMonitor) { + using Teuchos::SyncTimeMonitor; + using Teuchos::Comm; + using Teuchos::outArg; + using Teuchos::RCP; + using Teuchos::REDUCE_MAX; + using Teuchos::reduceAll; + using Clock = std::chrono::high_resolution_clock; + + RCP > comm = Teuchos::DefaultComm::getComm (); + + const int numProcs = comm->getSize (); + TEST_ASSERT( numProcs > 1 ); + if (numProcs < 4) { + out << "This test requires at least 4 MPI processes." << std::endl; + return; + } + + const int myRank = comm->getRank(); + + double time; + { + Clock::time_point start_time = Clock::now(); + { + SyncTimeMonitor timer(*Teuchos::TimeMonitor::getNewTimer(std::string("myTimer")), comm.ptr()); + // sleep a second on rank 1 only + if (myRank == 1) + std::this_thread::sleep_for (std::chrono::seconds(1)); + } + time = std::chrono::duration_cast>(Clock::now() - start_time).count(); + } + + std::ostringstream out1; + Teuchos::TimeMonitor::summarize(out1,false,true,false,Teuchos::Union,"",true); + std::string outStr = out1.str(); + int test = (outStr.find("myTimer") != std::string::npos); + // Check that we took at least a second. + int test2 = (time >= 1.0); + test = std::min(test, test2); + + int gblTest = false; // output argument + reduceAll (*comm, REDUCE_MAX, test, outArg (gblTest)); + TEST_EQUALITY(gblTest, 1); + +} + +// Check that sync'd timers do not hang execution. +TEUCHOS_UNIT_TEST(TimeMonitor, HangingSyncTimeMonitor) { + using Teuchos::SyncTimeMonitor; + using Teuchos::Comm; + using Teuchos::outArg; + using Teuchos::RCP; + using Teuchos::REDUCE_MAX; + using Teuchos::reduceAll; + + RCP > comm = Teuchos::DefaultComm::getComm (); + + const int numProcs = comm->getSize (); + TEST_ASSERT( numProcs > 1 ); + if (numProcs < 4) { + out << "This test requires at least 4 MPI processes." << std::endl; + return; + } + + const int myRank = comm->getRank(); + int test = false; + + try { + // Setup up a sync'd timer and raise an exception on one rank. + { + SyncTimeMonitor timer(*Teuchos::TimeMonitor::getNewTimer(std::string("myTimer")), comm.ptr()); + if (myRank == 1) + throw std::runtime_error("Test"); + } + test = true; + } catch (const std::runtime_error& e) { + test = (myRank == 1); + } + + int gblTest = false; // output argument + reduceAll (*comm, REDUCE_MAX, test, outArg (gblTest)); + TEST_EQUALITY(gblTest, 1); + +}