aboutsummaryrefslogtreecommitdiffstats
path: root/vespalib
diff options
context:
space:
mode:
authorHåvard Pettersen <havardpe@oath.com>2022-01-12 09:16:01 +0000
committerHåvard Pettersen <havardpe@oath.com>2022-01-12 09:41:23 +0000
commitd2ab95dce0a5aa7a2bb8ad44fb33ce66310021d9 (patch)
tree1674ede0276841d66476bb59e85e8373e38970b5 /vespalib
parent8c4b988a9eaebf9a7af83f1de0d15a4e6f17374f (diff)
hide implementation
Diffstat (limited to 'vespalib')
-rw-r--r--vespalib/src/tests/cpu_usage/cpu_usage_test.cpp22
-rw-r--r--vespalib/src/vespa/vespalib/util/cpu_usage.cpp63
-rw-r--r--vespalib/src/vespa/vespalib/util/cpu_usage.h34
3 files changed, 51 insertions, 68 deletions
diff --git a/vespalib/src/tests/cpu_usage/cpu_usage_test.cpp b/vespalib/src/tests/cpu_usage/cpu_usage_test.cpp
index d003689b864..98a7bd780a7 100644
--- a/vespalib/src/tests/cpu_usage/cpu_usage_test.cpp
+++ b/vespalib/src/tests/cpu_usage/cpu_usage_test.cpp
@@ -12,7 +12,6 @@ bool verbose = false;
size_t loop_cnt = 10;
double budget = 0.25;
-using DummySampler = vespalib::cpu_usage::DummyThreadSampler;
using Sampler = vespalib::cpu_usage::ThreadSampler;
//-----------------------------------------------------------------------------
@@ -30,8 +29,7 @@ void be_busy(duration d) {
}
}
-template <typename LIST>
-std::vector<duration> sample(const LIST &list) {
+std::vector<duration> sample(const std::vector<Sampler*> &list) {
std::vector<duration> result;
result.reserve(list.size());
for (auto *sampler: list) {
@@ -42,8 +40,7 @@ std::vector<duration> sample(const LIST &list) {
//-----------------------------------------------------------------------------
-template <typename SAMPLER>
-void verify_sampling(size_t thread_id, size_t num_threads, std::vector<SAMPLER*> &samplers) {
+void verify_sampling(size_t thread_id, size_t num_threads, std::vector<Sampler*> &samplers, bool force_mock) {
if (thread_id == 0) {
TEST_BARRIER(); // #1
auto t0 = steady_clock::now();
@@ -61,11 +58,10 @@ void verify_sampling(size_t thread_id, size_t num_threads, std::vector<SAMPLER*>
EXPECT_GREATER(load[3], load[0]);
fprintf(stderr, "loads: { %.2f, %.2f, %.2f, %.2f }\n", load[0], load[1], load[2], load[3]);
} else {
- SAMPLER sampler;
int idx = (thread_id - 1);
double target_load = double(thread_id - 1) / (num_threads - 2);
- sampler.expected_load(target_load);
- samplers[idx] = &sampler;
+ auto sampler = cpu_usage::create_thread_sampler(force_mock, target_load);
+ samplers[idx] = sampler.get();
TEST_BARRIER(); // #1
TEST_BARRIER(); // #2
for (size_t i = 0; i < loop_cnt; ++i) {
@@ -78,18 +74,18 @@ void verify_sampling(size_t thread_id, size_t num_threads, std::vector<SAMPLER*>
//-----------------------------------------------------------------------------
-TEST_MT_F("require that dummy thread-based CPU usage sampling with known expected load works", 5, std::vector<DummySampler*>(4, nullptr)) {
- TEST_DO(verify_sampling(thread_id, num_threads, f1));
+TEST_MT_F("require that dummy thread-based CPU usage sampling with known expected load works", 5, std::vector<Sampler*>(4, nullptr)) {
+ TEST_DO(verify_sampling(thread_id, num_threads, f1, true));
}
TEST_MT_F("require that external thread-based CPU usage sampling works", 5, std::vector<Sampler*>(4, nullptr)) {
- TEST_DO(verify_sampling(thread_id, num_threads, f1));
+ TEST_DO(verify_sampling(thread_id, num_threads, f1, false));
}
TEST("measure thread CPU clock overhead") {
- Sampler sampler;
+ auto sampler = cpu_usage::create_thread_sampler();
duration d;
- double min_time_us = BenchmarkTimer::benchmark([&d, &sampler]() noexcept { d = sampler.sample(); }, budget) * 1000000.0;
+ double min_time_us = BenchmarkTimer::benchmark([&d, &sampler]() noexcept { d = sampler->sample(); }, budget) * 1000000.0;
fprintf(stderr, "approx overhead per sample (thread CPU clock): %f us\n", min_time_us);
}
diff --git a/vespalib/src/vespa/vespalib/util/cpu_usage.cpp b/vespalib/src/vespa/vespalib/util/cpu_usage.cpp
index 1c126cb7884..4eee0a63870 100644
--- a/vespalib/src/vespa/vespalib/util/cpu_usage.cpp
+++ b/vespalib/src/vespa/vespalib/util/cpu_usage.cpp
@@ -2,45 +2,54 @@
#include "cpu_usage.h"
#include "require.h"
+#include <pthread.h>
namespace vespalib {
namespace cpu_usage {
-DummyThreadSampler::DummyThreadSampler()
- : _start(steady_clock::now()),
- _load(0.16)
-{
-}
+namespace {
-void
-DummyThreadSampler::expected_load(double load) {
- _load = load;
-}
-
-duration
-DummyThreadSampler::sample() const
-{
- return from_s(to_s(steady_clock::now() - _start) * _load);
-}
+class DummyThreadSampler : public ThreadSampler {
+private:
+ steady_time _start;
+ double _load;
+public:
+ DummyThreadSampler(double load) : _start(steady_clock::now()), _load(load) {}
+ duration sample() const override {
+ return from_s(to_s(steady_clock::now() - _start) * _load);
+ }
+};
#ifdef __linux__
-ThreadSampler::ThreadSampler()
- : _my_clock()
-{
- REQUIRE_EQ(pthread_getcpuclockid(pthread_self(), &_my_clock), 0);
-}
+class LinuxThreadSampler : public ThreadSampler {
+private:
+ clockid_t _my_clock;
+public:
+ LinuxThreadSampler() : _my_clock() {
+ REQUIRE_EQ(pthread_getcpuclockid(pthread_self(), &_my_clock), 0);
+ }
+ duration sample() const override {
+ timespec ts;
+ REQUIRE_EQ(clock_gettime(_my_clock, &ts), 0);
+ return from_timespec(ts);
+ }
+};
-duration
-ThreadSampler::sample() const
-{
- timespec ts;
- REQUIRE_EQ(clock_gettime(_my_clock, &ts), 0);
- return from_timespec(ts);
-}
+#endif
+
+} // <unnamed>
+ThreadSampler::UP create_thread_sampler(bool force_mock_impl, double expected_load) {
+ if (force_mock_impl) {
+ return std::make_unique<DummyThreadSampler>(expected_load);
+ }
+#ifdef __linux__
+ return std::make_unique<LinuxThreadSampler>();
#endif
+ return std::make_unique<DummyThreadSampler>(expected_load);
+}
} // cpu_usage
diff --git a/vespalib/src/vespa/vespalib/util/cpu_usage.h b/vespalib/src/vespa/vespalib/util/cpu_usage.h
index 03a438ef6aa..09509a984b5 100644
--- a/vespalib/src/vespa/vespalib/util/cpu_usage.h
+++ b/vespalib/src/vespa/vespalib/util/cpu_usage.h
@@ -1,46 +1,24 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-#include <pthread.h>
#include <vespa/vespalib/util/time.h>
+#include <memory>
namespace vespalib {
namespace cpu_usage {
-// do not use this directly (use ThreadSampler)
-class DummyThreadSampler {
-private:
- steady_time _start;
- double _load;
-public:
- DummyThreadSampler();
- void expected_load(double load);
- duration sample() const;
-};
-
-#ifdef __linux__
-
/**
* Samples the total CPU usage of the thread that created it. Note
* that this must not be used after thread termination. Enables
* sampling the CPU usage of a thread from outside the thread.
- *
- * uses: pthread_self, pthread_getcpuclockid, clock_gettime
**/
-class ThreadSampler {
-private:
- clockid_t _my_clock;
-public:
- ThreadSampler();
- constexpr void expected_load(double) noexcept {}
- duration sample() const;
+struct ThreadSampler {
+ using UP = std::unique_ptr<ThreadSampler>;
+ virtual duration sample() const = 0;
+ virtual ~ThreadSampler() {}
};
-#else
-
-using ThreadSampler = DummyThreadSampler;
-
-#endif
+ThreadSampler::UP create_thread_sampler(bool force_mock_impl = false, double expected_load = 0.16);
} // cpu_usage