summaryrefslogtreecommitdiffstats
path: root/staging_vespalib
diff options
context:
space:
mode:
authorHenning Baldersheim <balder@yahoo-inc.com>2019-12-03 11:24:26 +0100
committerGitHub <noreply@github.com>2019-12-03 11:24:26 +0100
commit29bf1eeec717dc33ab627bfb1c6f1e8f403cdfd0 (patch)
tree45bc7361e3157b1b8f0b6830a0151069c15748a7 /staging_vespalib
parent42cc516b2ef408ee52c9e8b552ce4fac10041f1a (diff)
parentbf2823fc6629d4b1093724e30ed755968e728453 (diff)
Merge pull request #11400 from vespa-engine/balder/sanitize-the-clock-2
Balder/sanitize the clock 2
Diffstat (limited to 'staging_vespalib')
-rw-r--r--staging_vespalib/src/tests/clock/.gitignore1
-rw-r--r--staging_vespalib/src/tests/clock/CMakeLists.txt6
-rw-r--r--staging_vespalib/src/tests/clock/clock_benchmark.cpp171
-rw-r--r--staging_vespalib/src/tests/clock/clock_test.cpp2
-rw-r--r--staging_vespalib/src/vespa/vespalib/util/clock.cpp1
5 files changed, 179 insertions, 2 deletions
diff --git a/staging_vespalib/src/tests/clock/.gitignore b/staging_vespalib/src/tests/clock/.gitignore
index 1826ba1563b..b0fcd343176 100644
--- a/staging_vespalib/src/tests/clock/.gitignore
+++ b/staging_vespalib/src/tests/clock/.gitignore
@@ -2,3 +2,4 @@
Makefile
clock_test
staging_vespalib_clock_test_app
+staging_vespalib_clock_benchmark_app
diff --git a/staging_vespalib/src/tests/clock/CMakeLists.txt b/staging_vespalib/src/tests/clock/CMakeLists.txt
index e62ef47e18a..825c0ae36cb 100644
--- a/staging_vespalib/src/tests/clock/CMakeLists.txt
+++ b/staging_vespalib/src/tests/clock/CMakeLists.txt
@@ -1,4 +1,10 @@
# Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(staging_vespalib_clock_benchmark_app TEST
+ SOURCES
+ clock_benchmark.cpp
+ DEPENDS
+ staging_vespalib
+)
vespa_add_executable(staging_vespalib_clock_test_app TEST
SOURCES
clock_test.cpp
diff --git a/staging_vespalib/src/tests/clock/clock_benchmark.cpp b/staging_vespalib/src/tests/clock/clock_benchmark.cpp
new file mode 100644
index 00000000000..c5229adea31
--- /dev/null
+++ b/staging_vespalib/src/tests/clock/clock_benchmark.cpp
@@ -0,0 +1,171 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vespalib/util/clock.h>
+#include <cassert>
+#include <vector>
+#include <atomic>
+#include <cstring>
+
+using vespalib::Clock;
+using fastos::TimeStamp;
+
+struct UpdateClock {
+ virtual ~UpdateClock() {}
+ virtual void update() = 0;
+};
+
+struct NSValue : public UpdateClock {
+ void update() override { _value = std::chrono::steady_clock::now().time_since_epoch().count(); }
+ int64_t _value;
+};
+
+struct NSVolatile : public UpdateClock {
+ void update() override { _value = std::chrono::steady_clock::now().time_since_epoch().count(); }
+ volatile int64_t _value;
+};
+struct NSAtomic : public UpdateClock {
+ void update() override { _value.store(std::chrono::steady_clock::now().time_since_epoch().count()); }
+ std::atomic<int64_t> _value;
+};
+
+class TestClock : public FastOS_Runnable
+{
+private:
+ int _timePeriodMS;
+ std::mutex _lock;
+ std::condition_variable _cond;
+ UpdateClock &_clock;
+ bool _stop;
+
+ void Run(FastOS_ThreadInterface *thisThread, void *arguments) override;
+
+public:
+ TestClock(UpdateClock & clock, double timePeriod)
+ : _timePeriodMS(static_cast<uint32_t>(timePeriod*1000)),
+ _lock(),
+ _cond(),
+ _clock(clock),
+ _stop(false)
+ { }
+ ~TestClock() {
+ std::lock_guard<std::mutex> guard(_lock);
+ _stop = true;
+ _cond.notify_all();
+ }
+};
+
+void TestClock::Run(FastOS_ThreadInterface *thread, void *)
+{
+ std::unique_lock<std::mutex> guard(_lock);
+ while ( ! thread->GetBreakFlag() && !_stop) {
+ _clock.update();
+ _cond.wait_for(guard, std::chrono::milliseconds(_timePeriodMS));
+ }
+}
+
+struct SamplerBase : public FastOS_Runnable {
+ SamplerBase(uint32_t threadId)
+ : _thread(nullptr),
+ _threadId(threadId),
+ _samples(0),
+ _count()
+ {
+ memset(_count, 0, sizeof(_count));
+ }
+ FastOS_ThreadInterface * _thread;
+ uint32_t _threadId;
+ uint64_t _samples;
+ uint64_t _count[3];
+};
+
+template<typename Func>
+struct Sampler : public SamplerBase {
+ Sampler(Func func, uint32_t threadId)
+ : SamplerBase(threadId),
+ _func(func)
+ { }
+ void Run(FastOS_ThreadInterface *, void *) override {
+ uint64_t samples;
+ fastos::SteadyTimeStamp prev = _func();
+ for (samples = 0; (samples < _samples); samples++) {
+ fastos::SteadyTimeStamp now = _func();
+ fastos::TimeStamp diff = now - prev;
+ if (diff > 0) prev = now;
+ _count[1 + ((diff == 0) ? 0 : (diff > 0) ? 1 : -1)]++;
+ }
+
+ }
+ Func _func;
+};
+
+template<typename Func>
+void benchmark(const char * desc, FastOS_ThreadPool & pool, uint64_t samples, uint32_t numThreads, Func func) {
+ std::vector<std::unique_ptr<SamplerBase>> threads;
+ threads.reserve(numThreads);
+ fastos::SteadyTimeStamp start = fastos::ClockSteady::now();
+ for (uint32_t i(0); i < numThreads; i++) {
+ SamplerBase * sampler = new Sampler<Func>(func, i);
+ sampler->_samples = samples;
+ sampler->_thread = pool.NewThread(sampler, nullptr);
+ threads.emplace_back(sampler);
+ }
+ uint64_t count[3];
+ memset(count, 0, sizeof(count));
+ for (const auto & sampler : threads) {
+ sampler->_thread->Join();
+ for (uint32_t i(0); i < 3; i++) {
+ count[i] += sampler->_count[i];
+ }
+ }
+ printf("%s: Took %ld clock samples in %2.3f with [%ld, %ld, %ld] counts\n", desc, samples, (fastos::ClockSteady::now() - start).sec(), count[0], count[1], count[2]);
+}
+
+int
+main(int , char *argv[])
+{
+ uint64_t frequency = atoll(argv[1]);
+ uint32_t numThreads = atoi(argv[2]);
+ uint64_t samples = atoll(argv[3]);
+ FastOS_ThreadPool pool(0x10000);
+ NSValue nsValue;
+ NSVolatile nsVolatile;
+ NSAtomic nsAtomic;
+ Clock clock(1.0/frequency);
+ TestClock nsClock(nsValue, 1.0/frequency);
+ TestClock nsVolatileClock(nsVolatile, 1.0/frequency);
+ TestClock nsAtomicClock(nsAtomic, 1.0/frequency);
+ assert(pool.NewThread(&clock, nullptr) != nullptr);
+ assert(pool.NewThread(&nsClock, nullptr) != nullptr);
+ assert(pool.NewThread(&nsVolatileClock, nullptr) != nullptr);
+ assert(pool.NewThread(&nsAtomicClock, nullptr) != nullptr);
+
+ benchmark("vespalib::Clock", pool, samples, numThreads, [&clock]() {
+ return clock.getTimeNSAssumeRunning();
+ });
+ benchmark("uint64_t", pool, samples, numThreads, [&nsValue]() {
+ return fastos::SteadyTimeStamp(nsValue._value) ;
+ });
+ benchmark("volatile uint64_t", pool, samples, numThreads, [&nsVolatile]() {
+ return fastos::SteadyTimeStamp(nsVolatile._value) ;
+ });
+ benchmark("memory_order_relaxed", pool, samples, numThreads, [&nsAtomic]() {
+ return fastos::SteadyTimeStamp(nsAtomic._value.load(std::memory_order_relaxed)) ;
+ });
+ benchmark("memory_order_consume", pool, samples, numThreads, [&nsAtomic]() {
+ return fastos::SteadyTimeStamp(nsAtomic._value.load(std::memory_order_consume)) ;
+ });
+ benchmark("memory_order_acquire", pool, samples, numThreads, [&nsAtomic]() {
+ return fastos::SteadyTimeStamp(nsAtomic._value.load(std::memory_order_acquire)) ;
+ });
+ benchmark("memory_order_seq_cst", pool, samples, numThreads, [&nsAtomic]() {
+ return fastos::SteadyTimeStamp(nsAtomic._value.load(std::memory_order_seq_cst)) ;
+ });
+
+ benchmark("fastos::ClockSteady::now()", pool, samples, numThreads, []() {
+ return fastos::ClockSteady::now();
+ });
+
+ pool.Close();
+ clock.stop();
+ return 0;
+}
diff --git a/staging_vespalib/src/tests/clock/clock_test.cpp b/staging_vespalib/src/tests/clock/clock_test.cpp
index 45f17bbba92..c8c93272e85 100644
--- a/staging_vespalib/src/tests/clock/clock_test.cpp
+++ b/staging_vespalib/src/tests/clock/clock_test.cpp
@@ -20,7 +20,7 @@ Test::Main()
Clock clock(0.050);
FastOS_ThreadPool pool(0x10000);
- ASSERT_TRUE(pool.NewThread(&clock, NULL) != NULL);
+ ASSERT_TRUE(pool.NewThread(&clock, nullptr) != nullptr);
fastos::SteadyTimeStamp start = clock.getTimeNS();
FastOS_Thread::Sleep(5000);
fastos::SteadyTimeStamp stop = clock.getTimeNS();
diff --git a/staging_vespalib/src/vespa/vespalib/util/clock.cpp b/staging_vespalib/src/vespa/vespalib/util/clock.cpp
index 18892a3a7ea..e935a80bd6b 100644
--- a/staging_vespalib/src/vespa/vespalib/util/clock.cpp
+++ b/staging_vespalib/src/vespa/vespalib/util/clock.cpp
@@ -6,7 +6,6 @@
namespace vespalib {
-
Clock::Clock(double timePeriod) :
_timeNS(0u),
_timePeriodMS(static_cast<uint32_t>(timePeriod*1000)),