From 5d1b07f12676ad2196da62899a518a7b23e0cf37 Mon Sep 17 00:00:00 2001 From: "Alexander A. Klimov" Date: Thu, 9 Jul 2020 10:47:54 +0200 Subject: [PATCH] Introduce Benchmark --- lib/base/CMakeLists.txt | 1 + lib/base/benchmark.cpp | 34 +++++++++++++++++++++++++++ lib/base/benchmark.hpp | 37 ++++++++++++++++++++++++++++++ test/CMakeLists.txt | 4 ++++ test/base-benchmark.cpp | 51 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 127 insertions(+) create mode 100644 lib/base/benchmark.cpp create mode 100644 lib/base/benchmark.hpp create mode 100644 test/base-benchmark.cpp diff --git a/lib/base/CMakeLists.txt b/lib/base/CMakeLists.txt index e50e330e44e..db02a3caf87 100644 --- a/lib/base/CMakeLists.txt +++ b/lib/base/CMakeLists.txt @@ -19,6 +19,7 @@ set(base_SOURCES atomic.hpp atomic-file.cpp atomic-file.hpp base64.cpp base64.hpp + benchmark.cpp benchmark.hpp boolean.cpp boolean.hpp boolean-script.cpp bulker.hpp configobject.cpp configobject.hpp configobject-ti.hpp configobject-script.cpp diff --git a/lib/base/benchmark.cpp b/lib/base/benchmark.cpp new file mode 100644 index 00000000000..8317561c910 --- /dev/null +++ b/lib/base/benchmark.cpp @@ -0,0 +1,34 @@ +/* Icinga 2 | (c) 2024 Icinga GmbH | GPLv2+ */ + +#include "base/benchmark.hpp" + +using namespace icinga; + +/** + * Adds the elapsedTime to this instance. + * + * May be called multiple times to accumulate time. + * + * @param elapsedTime The distance between two time points + * + * @return This instance for method chaining + */ +Benchmark& Benchmark::operator+=(const Clock::duration& elapsedTime) noexcept +{ + m_Sum.fetch_add(elapsedTime.count(), std::memory_order_relaxed); + return *this; +} + +/** + * Adds the time elapsed since startTime to this instance. + * + * May be called multiple times to accumulate time. + * + * @param startTime The start time to subtract from the current time + * + * @return This instance for method chaining + */ +Benchmark& Benchmark::operator+=(const Clock::time_point& startTime) noexcept +{ + return *this += Clock::now() - startTime; +} diff --git a/lib/base/benchmark.hpp b/lib/base/benchmark.hpp new file mode 100644 index 00000000000..4c2c5f71595 --- /dev/null +++ b/lib/base/benchmark.hpp @@ -0,0 +1,37 @@ +/* Icinga 2 | (c) 2024 Icinga GmbH | GPLv2+ */ + +#pragma once + +#include "base/atomic.hpp" +#include + +namespace icinga +{ + +/** + * Benchmark result. + * + * @ingroup base + */ +class Benchmark +{ +public: + using Clock = std::chrono::steady_clock; + + Benchmark& operator+=(const Clock::duration&) noexcept; + Benchmark& operator+=(const Clock::time_point&) noexcept; + + /** + * @return The total accumulated time in seconds + */ + template + explicit operator T() const noexcept + { + return std::chrono::duration(Clock::duration(m_Sum.load(std::memory_order_relaxed))).count(); + } + +private: + Atomic m_Sum {0}; +}; + +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index dd9724f0bf0..ae02f3f9ca8 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -59,6 +59,7 @@ set(base_test_SOURCES icingaapplication-fixture.cpp base-array.cpp base-base64.cpp + base-benchmark.cpp base-convert.cpp base-dictionary.cpp base-fifo.cpp @@ -112,6 +113,9 @@ add_boost_test(base base_array/clone base_array/json base_base64/base64 + base_benchmark/zero_seconds + base_benchmark/one_second + base_benchmark/two_seconds base_convert/tolong base_convert/todouble base_convert/tostring diff --git a/test/base-benchmark.cpp b/test/base-benchmark.cpp new file mode 100644 index 00000000000..6bf1d0cd916 --- /dev/null +++ b/test/base-benchmark.cpp @@ -0,0 +1,51 @@ +/* Icinga 2 | (c) 2024 Icinga GmbH | GPLv2+ */ + +#include "base/benchmark.hpp" +#include "base/utility.hpp" +#include +#include +#include + +using namespace icinga; + +static bool AssertSumSeconds(Benchmark& sum, long double seconds) +{ + return std::abs(((long double)sum - seconds) / seconds) < 0.05; +} + +BOOST_AUTO_TEST_SUITE(base_benchmark) + +BOOST_AUTO_TEST_CASE(zero_seconds) +{ + BOOST_CHECK_EQUAL((long double)Benchmark(), 0); +} + +BOOST_AUTO_TEST_CASE(one_second) +{ + Benchmark sum; + + auto start (Benchmark::Clock::now()); + Utility::Sleep(1); + sum += start; + + BOOST_CHECK(AssertSumSeconds(sum, 1)); +} + +BOOST_AUTO_TEST_CASE(two_seconds) +{ + Benchmark sum; + + { + auto start (Benchmark::Clock::now()); + Utility::Sleep(1); + sum += start; + } + + auto start (Benchmark::Clock::now()); + Utility::Sleep(1); + sum += start; + + BOOST_CHECK(AssertSumSeconds(sum, 2)); +} + +BOOST_AUTO_TEST_SUITE_END()