diff --git a/src/utils/Timer.hpp b/src/utils/Timer.hpp index c26ea40aa12526b858d6e3a998102c9cd71d7ecd..e1ba542f2cda3969c1af397decc05451e7a3aaa4 100644 --- a/src/utils/Timer.hpp +++ b/src/utils/Timer.hpp @@ -1,8 +1,111 @@ #ifndef TIMER_HPP #define TIMER_HPP -#include <Kokkos_Timer.hpp> +#include <chrono> +#include <iostream> -using Timer = Kokkos::Timer; +class Timer +{ + public: + enum class Status + { + running, + paused, + stopped + }; + + private: + std::chrono::time_point<std::chrono::high_resolution_clock> m_start; + std::chrono::duration<double> m_elapsed_sum; + + Status m_status; + + public: + Status + status() const + { + return m_status; + } + + double + seconds() const + { + switch (m_status) { + case Status::running: { + return (m_elapsed_sum + std::chrono::duration<double>{std::chrono::system_clock::now() - m_start}).count(); + } + case Status::paused: + case Status::stopped: { + return m_elapsed_sum.count(); + } + // LCOV_EXCL_START + default: { + return 0; + } + // LCOV_EXCL_STOP + } + } + + friend std::ostream& + operator<<(std::ostream& os, const Timer& timer) + { + os << timer.seconds() << 's'; + return os; + } + + void + reset() + { + m_start = std::chrono::high_resolution_clock::now(); + m_elapsed_sum = std::chrono::duration<double>::zero(); + } + + void + stop() + { + m_start = std::chrono::high_resolution_clock::now(); + m_elapsed_sum = std::chrono::duration<double>::zero(); + m_status = Status::stopped; + } + + void + pause() + { + if (m_status == Status::running) { + m_elapsed_sum += std::chrono::high_resolution_clock::now() - m_start; + m_start = std::chrono::high_resolution_clock::now(); + m_status = Status::paused; + } + } + + void + start() + { + switch (m_status) { + case Status::running: { + return; + } + case Status::paused: + case Status::stopped: { + m_start = std::chrono::high_resolution_clock::now(); + m_status = Status::running; + } + } + } + + Timer& operator=(const Timer&) = default; + Timer& operator=(Timer&&) = default; + + Timer(const Timer&) = default; + Timer(Timer&&) = default; + + Timer() + : m_start{std::chrono::high_resolution_clock::now()}, + m_elapsed_sum{std::chrono::duration<double>::zero()}, + m_status{Status::running} + {} + + ~Timer() = default; +}; #endif // TIMER_HPP diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0502c414a76e536dc6d2a0d1d49bc260a930b84d..edaa8069ad867aeaa139f68f646519a6219097d0 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -86,6 +86,7 @@ add_executable (unit_tests test_RevisionInfo.cpp test_SparseMatrixDescriptor.cpp test_SymbolTable.cpp + test_Timer.cpp test_TinyMatrix.cpp test_TinyVector.cpp test_TupleToVectorProcessor.cpp diff --git a/tests/test_Timer.cpp b/tests/test_Timer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..adbbd69cbb8aaa4aaad8695b5ce5c0d1ec623f9e --- /dev/null +++ b/tests/test_Timer.cpp @@ -0,0 +1,74 @@ +#include <catch2/catch.hpp> + +#include <utils/Timer.hpp> + +#include <sstream> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("Timer", "[utils]") +{ + SECTION("auto start") + { + Timer t; + + REQUIRE(t.status() == Timer::Status::running); + + double seconds = t.seconds(); + REQUIRE(t.seconds() > seconds); + + t.start(); + seconds = t.seconds(); + REQUIRE(t.status() == Timer::Status::running); + + REQUIRE(t.seconds() > seconds); + } + + SECTION("pause/start") + { + Timer t1; + + REQUIRE(t1.status() == Timer::Status::running); + t1.pause(); + + REQUIRE(t1.status() == Timer::Status::paused); + const double seconds = t1.seconds(); + + REQUIRE(t1.seconds() == seconds); + + std::stringstream os1; + os1 << t1; + + Timer t2 = t1; + std::stringstream os2; + os2 << t2.seconds() << 's'; + + REQUIRE(os1.str() == os2.str()); + + REQUIRE(t1.seconds() == t2.seconds()); + t1.start(); + REQUIRE(t1.status() == Timer::Status::running); + REQUIRE(t1.seconds() > t2.seconds()); + + t2.reset(); + REQUIRE(t2.status() == Timer::Status::paused); + REQUIRE(t2.seconds() == 0); + } + + SECTION("stop/start") + { + Timer t; + REQUIRE(t.status() == Timer::Status::running); + + const double seconds = t.seconds(); + REQUIRE(seconds > 0); + + t.stop(); + REQUIRE(t.status() == Timer::Status::stopped); + REQUIRE(t.seconds() == 0); + + t.start(); + REQUIRE(t.status() == Timer::Status::running); + REQUIRE(t.seconds() > 0); + } +}