diff --git a/src/utils/ExecutionStatManager.cpp b/src/utils/ExecutionStatManager.cpp index 06f7942cf37955c7d715fded89b464da74586eb5..6422d08c026ddf2df2169f503a585df936108ad9 100644 --- a/src/utils/ExecutionStatManager.cpp +++ b/src/utils/ExecutionStatManager.cpp @@ -44,7 +44,7 @@ ExecutionStatManager::_prettyPrintTime(double time_in_seconds) const } void -ExecutionStatManager::_printMaxResidentMemory() const +ExecutionStatManager::_printMaxResidentMemory(std::ostream& os) const { class Memory { @@ -85,42 +85,39 @@ ExecutionStatManager::_printMaxResidentMemory() const }; Memory memory; - std::cout << "Memory: " << rang::style::bold << Memory{parallel::allReduceSum(memory.value())}.prettyPrint() - << rang::style::reset; - if (parallel::size() > 1) { - std::cout << " (over " << parallel::size() << " processes)"; - std::cout << " Avg: " << rang::style::bold - << Memory{parallel::allReduceSum(memory.value()) / parallel::size()}.prettyPrint() << rang::style::reset; - std::cout << " Min: " << rang::style::bold << Memory{parallel::allReduceMin(memory.value())}.prettyPrint() - << rang::style::reset; - std::cout << " Max: " << rang::style::bold << Memory{parallel::allReduceMax(memory.value())}.prettyPrint() - << rang::style::reset; - } - std::cout << '\n'; + os << "Memory: " << rang::style::bold << Memory{parallel::allReduceSum(memory.value())}.prettyPrint() + << rang::style::reset; + os << " (over " << parallel::size() << " processes)"; + os << " Avg: " << rang::style::bold << Memory{parallel::allReduceSum(memory.value()) / parallel::size()}.prettyPrint() + << rang::style::reset; + os << " Min: " << rang::style::bold << Memory{parallel::allReduceMin(memory.value())}.prettyPrint() + << rang::style::reset; + os << " Max: " << rang::style::bold << Memory{parallel::allReduceMax(memory.value())}.prettyPrint() + << rang::style::reset; + os << '\n'; } void -ExecutionStatManager::_printElapseTime() const +ExecutionStatManager::_printElapseTime(std::ostream& os) const { const double elapse_time = m_instance->m_elapse_time.seconds(); - std::cout << "Execution: " << rang::style::bold << elapse_time << 's' << rang::style::reset; + os << "Execution: " << rang::style::bold << elapse_time << 's' << rang::style::reset; if (elapse_time > 60) { - std::cout << " [" << rang::style::bold << this->_prettyPrintTime(elapse_time) << rang::style::reset << ']'; + os << " [" << rang::style::bold << this->_prettyPrintTime(elapse_time) << rang::style::reset << ']'; } if (m_run_number > 1) { const double cumulative_elapse_time = elapse_time + m_previous_cumulative_elapse_time; - std::cout << " (Run number " << m_run_number << ").\n - Cumulative execution time: " << rang::style::bold - << cumulative_elapse_time << 's' << rang::style::reset; + os << " (Run number " << m_run_number << ").\n - Cumulative execution time: " << rang::style::bold + << cumulative_elapse_time << 's' << rang::style::reset; if (cumulative_elapse_time > 60) { - std::cout << " [" << rang::style::bold << this->_prettyPrintTime(cumulative_elapse_time) << rang::style::reset - << ']'; + os << " [" << rang::style::bold << this->_prettyPrintTime(cumulative_elapse_time) << rang::style::reset << ']'; } } - std::cout << '\n'; + os << '\n'; } void -ExecutionStatManager::_printTotalCPUTime() const +ExecutionStatManager::_printTotalCPUTime(std::ostream& os) const { rusage u; getrusage(RUSAGE_SELF, &u); @@ -128,36 +125,33 @@ ExecutionStatManager::_printTotalCPUTime() const const double total_cpu_time = parallel::allReduceSum(u.ru_utime.tv_sec + u.ru_stime.tv_sec + (u.ru_utime.tv_usec + u.ru_stime.tv_usec) * 1E-6); - std::cout << "Total CPU: " << rang::style::bold << total_cpu_time << 's' << rang::style::reset; - std::cout << " (" << parallel::allReduceSum(Kokkos::DefaultHostExecutionSpace::concurrency()) << " threads over " - << parallel::size() << " processes)"; + os << "Total CPU: " << rang::style::bold << total_cpu_time << 's' << rang::style::reset; + os << " (" << parallel::allReduceSum(Kokkos::DefaultHostExecutionSpace::concurrency()) << " threads over " + << parallel::size() << " processes)"; if (total_cpu_time > 60) { - std::cout << " [" << _prettyPrintTime(total_cpu_time) << ']'; + os << " [" << _prettyPrintTime(total_cpu_time) << ']'; } if (m_run_number > 1) { const double cumulative_total_cpu_time = total_cpu_time + m_previous_cumulative_total_cpu_time; - std::cout << "\n - Cumulative total CPU: " << rang::style::bold << cumulative_total_cpu_time << 's' - << rang::style::reset; + os << "\n - Cumulative total CPU: " << rang::style::bold << cumulative_total_cpu_time << 's' << rang::style::reset; if (cumulative_total_cpu_time > 60) { - std::cout << " [" << rang::style::bold << this->_prettyPrintTime(cumulative_total_cpu_time) << rang::style::reset - << ']'; + os << " [" << rang::style::bold << this->_prettyPrintTime(cumulative_total_cpu_time) << rang::style::reset << ']'; } } - std::cout << '\n'; + os << '\n'; } void -ExecutionStatManager::printInfo() +ExecutionStatManager::printInfo(std::ostream& os) { if (ExecutionStatManager::getInstance().doPrint()) { - std::cout << "----------------- " << rang::fg::green << "pugs exec stats" << rang::fg::reset - << " ---------------------\n"; + os << "----------------- " << rang::fg::green << "pugs exec stats" << rang::fg::reset << " ---------------------\n"; - ExecutionStatManager::getInstance()._printElapseTime(); - ExecutionStatManager::getInstance()._printTotalCPUTime(); - ExecutionStatManager::getInstance()._printMaxResidentMemory(); + ExecutionStatManager::getInstance()._printElapseTime(os); + ExecutionStatManager::getInstance()._printTotalCPUTime(os); + ExecutionStatManager::getInstance()._printMaxResidentMemory(os); } } diff --git a/src/utils/ExecutionStatManager.hpp b/src/utils/ExecutionStatManager.hpp index f07099eecf4be81a7cea41b1456f826be5c06cbf..a99f6e08c239d0b832feb32748d17c0bb61f023c 100644 --- a/src/utils/ExecutionStatManager.hpp +++ b/src/utils/ExecutionStatManager.hpp @@ -4,9 +4,14 @@ #include <utils/PugsAssert.hpp> #include <utils/Timer.hpp> +#include <iostream> + class ExecutionStatManager { private: + // For unit tests only + friend class ExecutionStatManagerTester; + static ExecutionStatManager* m_instance; Timer m_elapse_time; @@ -19,9 +24,9 @@ class ExecutionStatManager std::string _prettyPrintTime(double seconds) const; - void _printMaxResidentMemory() const; - void _printElapseTime() const; - void _printTotalCPUTime() const; + void _printMaxResidentMemory(std::ostream& os) const; + void _printElapseTime(std::ostream& os) const; + void _printTotalCPUTime(std::ostream& os) const; explicit ExecutionStatManager() = default; ExecutionStatManager(ExecutionStatManager&&) = delete; @@ -99,7 +104,7 @@ class ExecutionStatManager return *m_instance; } - static void printInfo(); + static void printInfo(std::ostream& os = std::cout); static void create(); static void destroy(); }; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index af385092149149d41fbf41f70172759e29320573..bfde508503511a8e6ef6f0c0a82f9e4cf650a05d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -224,6 +224,7 @@ add_executable (mpi_unit_tests test_EmbeddedDiscreteFunctionOperators1D.cpp test_EmbeddedDiscreteFunctionOperators2D.cpp test_EmbeddedDiscreteFunctionOperators3D.cpp + test_ExecutionStatManager.cpp test_InterpolateItemArray.cpp test_InterpolateItemValue.cpp test_ItemArray.cpp diff --git a/tests/test_ExecutionStatManager.cpp b/tests/test_ExecutionStatManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..434b1eaf1cf9460049cc923de3263b52d5a88509 --- /dev/null +++ b/tests/test_ExecutionStatManager.cpp @@ -0,0 +1,89 @@ +#include <catch2/catch_test_macros.hpp> +#include <catch2/matchers/catch_matchers_all.hpp> + +#include <utils/ExecutionStatManager.hpp> +#include <utils/Stringify.hpp> +#include <utils/pugs_config.hpp> + +#include <sstream> + +class ExecutionStatManagerTester +{ + public: + double + getPreviousCumulativeElapseTime() const + { + return ExecutionStatManager::getInstance().m_previous_cumulative_elapse_time; + } + + double + getPreviousCumulativeTotalCpuTime() const + { + return ExecutionStatManager::getInstance().m_previous_cumulative_total_cpu_time; + } + + void + setElapseTime(const Timer& timer) const + { + ExecutionStatManager::getInstance().m_elapse_time = timer; + } + + Timer& + getElapseTime() const + { + return ExecutionStatManager::getInstance().m_elapse_time; + } + + ExecutionStatManagerTester() = default; + ~ExecutionStatManagerTester() = default; +}; + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ExecutionStatManager", "[utils]") +{ + REQUIRE_NOTHROW(ExecutionStatManager::create()); + REQUIRE_THROWS_WITH(ExecutionStatManager::create(), "unexpected error: ExecutionStatManager already created"); + + ExecutionStatManagerTester esm_tester; + + REQUIRE(ExecutionStatManager::getInstance().runNumber() == 1); + REQUIRE(ExecutionStatManager::getInstance().doPrint() == true); + REQUIRE(ExecutionStatManager::getInstance().exitCode() == 0); + + REQUIRE(esm_tester.getPreviousCumulativeElapseTime() == 0); + REQUIRE(esm_tester.getPreviousCumulativeTotalCpuTime() == 0); + + REQUIRE_NOTHROW(ExecutionStatManager::getInstance().setRunNumber(2)); + REQUIRE(ExecutionStatManager::getInstance().runNumber() == 2); + + REQUIRE_NOTHROW(ExecutionStatManager::getInstance().setPreviousCumulativeElapseTime(100)); + REQUIRE_NOTHROW(ExecutionStatManager::getInstance().setPreviousCumulativeTotalCPUTime(200)); + + REQUIRE(esm_tester.getPreviousCumulativeElapseTime() == 100); + REQUIRE(esm_tester.getPreviousCumulativeTotalCpuTime() == 200); + + using namespace std::chrono_literals; + Timer t{std::chrono::high_resolution_clock::now() - (2 * 21h + 267s)}; + t.pause(); + esm_tester.setElapseTime(t); + + REQUIRE(ExecutionStatManager::getInstance().getElapseTime() == t.seconds()); + REQUIRE(ExecutionStatManager::getInstance().getCumulativeElapseTime() == 100 + t.seconds()); + REQUIRE(ExecutionStatManager::getInstance().getCumulativeTotalCPUTime() >= 200); + + std::ostringstream os; + // One just call the function not test is performed. It is quite + // boring to check the result and not that useful. + ExecutionStatManager::getInstance().printInfo(os); + + ExecutionStatManager::getInstance().setPrint(false); + REQUIRE(ExecutionStatManager::getInstance().doPrint() == false); + + ExecutionStatManager::getInstance().setExitCode(1); + REQUIRE(ExecutionStatManager::getInstance().exitCode() == 1); + + REQUIRE_NOTHROW(ExecutionStatManager::destroy()); + // One allows multiple destruction to handle unexpected code exit + REQUIRE_NOTHROW(ExecutionStatManager::destroy()); +}