1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
// 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>
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 NSVolatileValue : public UpdateClock {
void update() override { _value = std::chrono::steady_clock::now().time_since_epoch().count(); }
volatile 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 {
FastOS_ThreadInterface * _thread;
uint64_t _samples;
};
template<typename Func>
struct Sampler : public SamplerBase {
Sampler(Func func) :
_func(func)
{ }
void Run(FastOS_ThreadInterface *, void *) override {
fastos::SteadyTimeStamp start = fastos::ClockSteady::now();
printf("Starting at %s \n", fastos::ClockSystem::now().toString().c_str());
uint64_t samples;
uint64_t countFalse(0);
for (samples = 0; (samples < _samples); samples++) {
if ( ! _func(samples)) countFalse++;
}
printf("Took %ld clock samples in %2.3f with %ld keeping up\n", samples, (fastos::ClockSteady::now() - start).sec(), countFalse);
}
Func _func;
};
template<typename Func>
void benchmark(FastOS_ThreadPool & pool, uint64_t samples, int numThreads, Func func) {
std::vector<std::unique_ptr<SamplerBase>> threads;
threads.reserve(numThreads);
for (int i(0); i < numThreads; i++) {
SamplerBase * sampler = new Sampler(func);
sampler->_samples = samples;
sampler->_thread = pool.NewThread(sampler, nullptr);
threads.emplace_back(sampler);
}
for (const auto & sampler : threads) {
sampler->_thread->Join();
}
}
int
main(int , char *argv[])
{
long frequency = atoll(argv[1]);
int numThreads = atoi(argv[2]);
uint64_t samples = atoll(argv[3]);
FastOS_ThreadPool pool(0x10000);
NSValue nsValue;
NSVolatileValue nsVolatileValue;
Clock clock(1.0/frequency);
TestClock nsClock(nsValue, 1.0/frequency);
TestClock nsVolatileClock(nsVolatileValue, 1.0/frequency);
assert(pool.NewThread(&clock, nullptr) != nullptr);
assert(pool.NewThread(&nsClock, nullptr) != nullptr);
assert(pool.NewThread(&nsVolatileClock, nullptr) != nullptr);
fastos::SteadyTimeStamp now = clock.getTimeNSAssumeRunning();
FastOS_Thread::Sleep(100);
benchmark(pool, samples, numThreads, [&clock, &now](int64_t i){ return (now+i < clock.getTimeNSAssumeRunning());});
benchmark(pool, samples, numThreads, [&nsValue, &now](int64_t i){ return (now+i < fastos::SteadyTimeStamp(nsValue._value));});
benchmark(pool, samples, numThreads, [&nsVolatileValue, &now](int64_t i){ return (now+i < fastos::SteadyTimeStamp(nsVolatileValue._value));});
benchmark(pool, samples, numThreads, [&now](uint64_t i){ return (now+i < fastos::ClockSteady::now());});
pool.Close();
clock.stop();
return 0;
}
|