summaryrefslogtreecommitdiffstats
path: root/vespalib/src/tests/cpu_usage/cpu_usage_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'vespalib/src/tests/cpu_usage/cpu_usage_test.cpp')
-rw-r--r--vespalib/src/tests/cpu_usage/cpu_usage_test.cpp94
1 files changed, 94 insertions, 0 deletions
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);
+}