diff options
author | Håvard Pettersen <havardpe@oath.com> | 2022-01-06 15:44:33 +0000 |
---|---|---|
committer | Håvard Pettersen <havardpe@oath.com> | 2022-01-07 14:16:28 +0000 |
commit | ad3649d3dcb3bc53d878da8e7447cbdf74de4592 (patch) | |
tree | 9115327fd7f48122777420c1782d5056a44ee80e /vespalib | |
parent | cdb6a8521b56ff30ff8abda7b5342986df977f2e (diff) |
low-level code to sample CPU usage per thread
Diffstat (limited to 'vespalib')
-rw-r--r-- | vespalib/CMakeLists.txt | 1 | ||||
-rw-r--r-- | vespalib/src/tests/cpu_usage/CMakeLists.txt | 8 | ||||
-rw-r--r-- | vespalib/src/tests/cpu_usage/cpu_usage_test.cpp | 94 | ||||
-rw-r--r-- | vespalib/src/vespa/vespalib/util/CMakeLists.txt | 1 | ||||
-rw-r--r-- | vespalib/src/vespa/vespalib/util/cpu_usage.cpp | 26 | ||||
-rw-r--r-- | vespalib/src/vespa/vespalib/util/cpu_usage.h | 27 | ||||
-rw-r--r-- | vespalib/src/vespa/vespalib/util/time.h | 4 |
7 files changed, 161 insertions, 0 deletions
diff --git a/vespalib/CMakeLists.txt b/vespalib/CMakeLists.txt index 9f98d23d6a9..eb7e1f7d4c0 100644 --- a/vespalib/CMakeLists.txt +++ b/vespalib/CMakeLists.txt @@ -31,6 +31,7 @@ vespa_define_module( src/tests/component src/tests/compress src/tests/compression + src/tests/cpu_usage src/tests/crypto src/tests/data/databuffer src/tests/data/input_reader diff --git a/vespalib/src/tests/cpu_usage/CMakeLists.txt b/vespalib/src/tests/cpu_usage/CMakeLists.txt new file mode 100644 index 00000000000..e3e2def6056 --- /dev/null +++ b/vespalib/src/tests/cpu_usage/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(vespalib_cpu_usage_test_app TEST + SOURCES + cpu_usage_test.cpp + DEPENDS + vespalib +) +vespa_add_test(NAME vespalib_cpu_usage_test_app COMMAND vespalib_cpu_usage_test_app) diff --git a/vespalib/src/tests/cpu_usage/cpu_usage_test.cpp b/vespalib/src/tests/cpu_usage/cpu_usage_test.cpp new file mode 100644 index 00000000000..c8835d82cd8 --- /dev/null +++ b/vespalib/src/tests/cpu_usage/cpu_usage_test.cpp @@ -0,0 +1,94 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include <vespa/vespalib/util/cpu_usage.h> +#include <vespa/vespalib/util/benchmark_timer.h> +#include <vespa/vespalib/testkit/test_kit.h> + +#include <thread> + +using namespace vespalib; + +bool verbose = false; +size_t loop_cnt = 10; +double budget = 0.25; + +using Sampler = vespalib::cpu_usage::ThreadSampler; + +//----------------------------------------------------------------------------- + +void be_busy(duration d) { + if (d > 0ms) { + volatile int tmp = 123; + auto t0 = steady_clock::now(); + while ((steady_clock::now() - t0) < d) { + for (int i = 0; i < 1000; ++i) { + tmp = (tmp + i); + tmp = (tmp - i); + } + } + } +} + +std::vector<duration> sample(const std::vector<Sampler*> &list) { + std::vector<duration> result; + result.reserve(list.size()); + for (Sampler *sampler: list) { + result.push_back(sampler->sample()); + } + return result; +} + +//----------------------------------------------------------------------------- + +TEST_MT_F("require that external thread-based CPU usage sampling works", 5, std::vector<Sampler*>(4, nullptr)) { + if (thread_id == 0) { + TEST_BARRIER(); // #1 + auto t0 = steady_clock::now(); + std::vector<duration> pre_usage = sample(f1); + TEST_BARRIER(); // #2 + TEST_BARRIER(); // #3 + auto t1 = steady_clock::now(); + std::vector<duration> post_usage = sample(f1); + TEST_BARRIER(); // #4 + double wall = to_s(t1 - t0); + std::vector<double> load(4, 0.0); + for (size_t i = 0; i < 4; ++i) { + load[i] = to_s(post_usage[i] - pre_usage[i]) / wall; + } + EXPECT_GREATER(load[3], load[0]); + fprintf(stderr, "loads: { %.2f, %.2f, %.2f, %.2f }\n", load[0], load[1], load[2], load[3]); + } else { + int idx = (thread_id - 1); + Sampler sampler; + f1[idx] = &sampler; + TEST_BARRIER(); // #1 + TEST_BARRIER(); // #2 + for (size_t i = 0; i < loop_cnt; ++i) { + be_busy(std::chrono::milliseconds(idx)); + } + TEST_BARRIER(); // #3 + TEST_BARRIER(); // #4 + } +} + +//----------------------------------------------------------------------------- + +TEST("measure thread CPU clock overhead") { + Sampler sampler; + duration d; + 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); +} + +//----------------------------------------------------------------------------- + +int main(int argc, char **argv) { + TEST_MASTER.init(__FILE__); + if ((argc == 2) && (argv[1] == std::string("verbose"))) { + verbose = true; + loop_cnt = 1000; + budget = 5.0; + } + TEST_RUN_ALL(); + return (TEST_MASTER.fini() ? 0 : 1); +} diff --git a/vespalib/src/vespa/vespalib/util/CMakeLists.txt b/vespalib/src/vespa/vespalib/util/CMakeLists.txt index 58f6a93babc..32f679d22d7 100644 --- a/vespalib/src/vespa/vespalib/util/CMakeLists.txt +++ b/vespalib/src/vespa/vespalib/util/CMakeLists.txt @@ -18,6 +18,7 @@ vespa_add_library(vespalib_vespalib_util OBJECT classname.cpp compress.cpp compressor.cpp + cpu_usage.cpp destructor_callbacks.cpp dual_merge_director.cpp error.cpp diff --git a/vespalib/src/vespa/vespalib/util/cpu_usage.cpp b/vespalib/src/vespa/vespalib/util/cpu_usage.cpp new file mode 100644 index 00000000000..b5bd3ed76ac --- /dev/null +++ b/vespalib/src/vespa/vespalib/util/cpu_usage.cpp @@ -0,0 +1,26 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "cpu_usage.h" +#include "require.h" + +namespace vespalib { + +namespace cpu_usage { + +ThreadSampler::ThreadSampler() + : _my_clock() +{ + REQUIRE_EQ(pthread_getcpuclockid(pthread_self(), &_my_clock), 0); +} + +duration +ThreadSampler::sample() const +{ + timespec ts; + REQUIRE_EQ(clock_gettime(_my_clock, &ts), 0); + return from_timespec(ts); +} + +} // cpu_usage + +} // namespace diff --git a/vespalib/src/vespa/vespalib/util/cpu_usage.h b/vespalib/src/vespa/vespalib/util/cpu_usage.h new file mode 100644 index 00000000000..452e96ba0ff --- /dev/null +++ b/vespalib/src/vespa/vespalib/util/cpu_usage.h @@ -0,0 +1,27 @@ +// 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> + +namespace vespalib { + +namespace cpu_usage { + +/** + * 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(); + duration sample() const; +}; + +} // cpu_usage + +} // namespace diff --git a/vespalib/src/vespa/vespalib/util/time.h b/vespalib/src/vespa/vespalib/util/time.h index f1f529b64b6..f19d71afb32 100644 --- a/vespalib/src/vespa/vespalib/util/time.h +++ b/vespalib/src/vespa/vespalib/util/time.h @@ -67,6 +67,10 @@ constexpr duration from_timeval(const timeval & tv) { return duration(tv.tv_sec*1000000000L + tv.tv_usec*1000L); } +constexpr duration from_timespec(const timespec & ts) { + return duration(ts.tv_sec*1000000000L + ts.tv_nsec); +} + vespalib::string to_string(system_time time); /** |