-
Notifications
You must be signed in to change notification settings - Fork 311
/
Copy pathfuture_benchmark.cpp
139 lines (115 loc) · 3.45 KB
/
future_benchmark.cpp
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include <userver/engine/future.hpp>
#include <condition_variable>
#include <future>
#include <mutex>
#include <benchmark/benchmark.h>
#include <userver/engine/async.hpp>
#include <userver/engine/run_standalone.hpp>
#include <userver/engine/single_consumer_event.hpp>
#include <userver/utils/assert.hpp>
USERVER_NAMESPACE_BEGIN
namespace {
class BlockingEvent final {
public:
BlockingEvent() = default;
void Wait() {
std::unique_lock lock(mutex_);
cv_.wait(lock, [&] { return done_; });
}
void Send() {
{
std::lock_guard lock(mutex_);
done_ = true;
}
cv_.notify_one();
}
private:
std::mutex mutex_;
std::condition_variable cv_;
bool done_{false};
};
constexpr std::size_t kBatchSize = 1000;
template <typename Benchmark>
void RunPrepared(benchmark::State& state) {
while (state.KeepRunningBatch(kBatchSize)) {
state.PauseTiming();
for (std::size_t i = 0; i < kBatchSize; ++i) {
Benchmark benchmark;
state.ResumeTiming();
benchmark.Run();
state.PauseTiming();
}
state.ResumeTiming();
}
}
struct FutureStdSetGet {
FutureStdSetGet() : future(promise.get_future()) {
producer = std::thread([&] {
producer_ready.Send();
consumer_ready.Wait();
promise.set_value(42);
});
producer_ready.Wait();
}
~FutureStdSetGet() { producer.join(); }
void Run() {
consumer_ready.Send();
benchmark::DoNotOptimize(future.get());
}
BlockingEvent producer_ready;
BlockingEvent consumer_ready;
std::promise<int> promise;
std::future<int> future;
std::thread producer;
};
struct FutureCoroSetGet {
FutureCoroSetGet() : future(promise.get_future()) {
producer = engine::AsyncNoSpan([&] {
producer_ready.Send();
const bool status = consumer_ready.WaitForEvent();
UASSERT(status);
promise.set_value(42);
});
const bool status = producer_ready.WaitForEvent();
UASSERT(status);
}
void Run() {
consumer_ready.Send();
benchmark::DoNotOptimize(future.get());
}
engine::SingleConsumerEvent producer_ready;
engine::SingleConsumerEvent consumer_ready;
engine::Promise<int> promise;
engine::Future<int> future;
engine::TaskWithResult<void> producer;
};
} // namespace
void future_std_single_threaded(benchmark::State& state) {
for ([[maybe_unused]] auto _ : state) {
std::promise<int> promise;
auto future = promise.get_future();
promise.set_value(42);
benchmark::DoNotOptimize(future.get());
}
}
BENCHMARK(future_std_single_threaded);
void future_coro_single_threaded(benchmark::State& state) {
engine::RunStandalone([&] {
for ([[maybe_unused]] auto _ : state) {
engine::Promise<int> promise;
auto future = promise.get_future();
promise.set_value(42);
benchmark::DoNotOptimize(future.get());
}
});
}
BENCHMARK(future_coro_single_threaded);
void future_std_set_and_get(benchmark::State& state) {
engine::RunStandalone(2, [&] { RunPrepared<FutureStdSetGet>(state); });
}
BENCHMARK(future_std_set_and_get);
void future_coro_set_and_get(benchmark::State& state) {
engine::RunStandalone(2, [&] { RunPrepared<FutureCoroSetGet>(state); });
}
BENCHMARK(future_coro_set_and_get);
USERVER_NAMESPACE_END