1*635a8641SAndroid Build Coastguard Worker // Copyright 2017 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker
5*635a8641SAndroid Build Coastguard Worker #include "base/synchronization/waitable_event.h"
6*635a8641SAndroid Build Coastguard Worker
7*635a8641SAndroid Build Coastguard Worker #include <numeric>
8*635a8641SAndroid Build Coastguard Worker
9*635a8641SAndroid Build Coastguard Worker #include "base/threading/simple_thread.h"
10*635a8641SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
11*635a8641SAndroid Build Coastguard Worker #include "testing/perf/perf_test.h"
12*635a8641SAndroid Build Coastguard Worker
13*635a8641SAndroid Build Coastguard Worker namespace base {
14*635a8641SAndroid Build Coastguard Worker
15*635a8641SAndroid Build Coastguard Worker namespace {
16*635a8641SAndroid Build Coastguard Worker
17*635a8641SAndroid Build Coastguard Worker class TraceWaitableEvent {
18*635a8641SAndroid Build Coastguard Worker public:
TraceWaitableEvent(size_t samples)19*635a8641SAndroid Build Coastguard Worker TraceWaitableEvent(size_t samples)
20*635a8641SAndroid Build Coastguard Worker : event_(WaitableEvent::ResetPolicy::AUTOMATIC,
21*635a8641SAndroid Build Coastguard Worker WaitableEvent::InitialState::NOT_SIGNALED),
22*635a8641SAndroid Build Coastguard Worker samples_(samples) {
23*635a8641SAndroid Build Coastguard Worker signal_times_.reserve(samples);
24*635a8641SAndroid Build Coastguard Worker wait_times_.reserve(samples);
25*635a8641SAndroid Build Coastguard Worker }
26*635a8641SAndroid Build Coastguard Worker
27*635a8641SAndroid Build Coastguard Worker ~TraceWaitableEvent() = default;
28*635a8641SAndroid Build Coastguard Worker
Signal()29*635a8641SAndroid Build Coastguard Worker void Signal() {
30*635a8641SAndroid Build Coastguard Worker TimeTicks start = TimeTicks::Now();
31*635a8641SAndroid Build Coastguard Worker event_.Signal();
32*635a8641SAndroid Build Coastguard Worker signal_times_.push_back(TimeTicks::Now() - start);
33*635a8641SAndroid Build Coastguard Worker }
34*635a8641SAndroid Build Coastguard Worker
Wait()35*635a8641SAndroid Build Coastguard Worker void Wait() {
36*635a8641SAndroid Build Coastguard Worker TimeTicks start = TimeTicks::Now();
37*635a8641SAndroid Build Coastguard Worker event_.Wait();
38*635a8641SAndroid Build Coastguard Worker wait_times_.push_back(TimeTicks::Now() - start);
39*635a8641SAndroid Build Coastguard Worker }
40*635a8641SAndroid Build Coastguard Worker
TimedWaitUntil(const TimeTicks & end_time)41*635a8641SAndroid Build Coastguard Worker bool TimedWaitUntil(const TimeTicks& end_time) {
42*635a8641SAndroid Build Coastguard Worker TimeTicks start = TimeTicks::Now();
43*635a8641SAndroid Build Coastguard Worker bool signaled = event_.TimedWaitUntil(end_time);
44*635a8641SAndroid Build Coastguard Worker wait_times_.push_back(TimeTicks::Now() - start);
45*635a8641SAndroid Build Coastguard Worker return signaled;
46*635a8641SAndroid Build Coastguard Worker }
47*635a8641SAndroid Build Coastguard Worker
IsSignaled()48*635a8641SAndroid Build Coastguard Worker bool IsSignaled() { return event_.IsSignaled(); }
49*635a8641SAndroid Build Coastguard Worker
signal_times() const50*635a8641SAndroid Build Coastguard Worker const std::vector<TimeDelta>& signal_times() const { return signal_times_; }
wait_times() const51*635a8641SAndroid Build Coastguard Worker const std::vector<TimeDelta>& wait_times() const { return wait_times_; }
samples() const52*635a8641SAndroid Build Coastguard Worker size_t samples() const { return samples_; }
53*635a8641SAndroid Build Coastguard Worker
54*635a8641SAndroid Build Coastguard Worker private:
55*635a8641SAndroid Build Coastguard Worker WaitableEvent event_;
56*635a8641SAndroid Build Coastguard Worker
57*635a8641SAndroid Build Coastguard Worker std::vector<TimeDelta> signal_times_;
58*635a8641SAndroid Build Coastguard Worker std::vector<TimeDelta> wait_times_;
59*635a8641SAndroid Build Coastguard Worker
60*635a8641SAndroid Build Coastguard Worker const size_t samples_;
61*635a8641SAndroid Build Coastguard Worker
62*635a8641SAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(TraceWaitableEvent);
63*635a8641SAndroid Build Coastguard Worker };
64*635a8641SAndroid Build Coastguard Worker
65*635a8641SAndroid Build Coastguard Worker class SignalerThread : public SimpleThread {
66*635a8641SAndroid Build Coastguard Worker public:
SignalerThread(TraceWaitableEvent * waiter,TraceWaitableEvent * signaler)67*635a8641SAndroid Build Coastguard Worker SignalerThread(TraceWaitableEvent* waiter, TraceWaitableEvent* signaler)
68*635a8641SAndroid Build Coastguard Worker : SimpleThread("WaitableEventPerfTest signaler"),
69*635a8641SAndroid Build Coastguard Worker waiter_(waiter),
70*635a8641SAndroid Build Coastguard Worker signaler_(signaler) {}
71*635a8641SAndroid Build Coastguard Worker
72*635a8641SAndroid Build Coastguard Worker ~SignalerThread() override = default;
73*635a8641SAndroid Build Coastguard Worker
Run()74*635a8641SAndroid Build Coastguard Worker void Run() override {
75*635a8641SAndroid Build Coastguard Worker while (!stop_event_.IsSignaled()) {
76*635a8641SAndroid Build Coastguard Worker if (waiter_)
77*635a8641SAndroid Build Coastguard Worker waiter_->Wait();
78*635a8641SAndroid Build Coastguard Worker if (signaler_)
79*635a8641SAndroid Build Coastguard Worker signaler_->Signal();
80*635a8641SAndroid Build Coastguard Worker }
81*635a8641SAndroid Build Coastguard Worker }
82*635a8641SAndroid Build Coastguard Worker
83*635a8641SAndroid Build Coastguard Worker // Signals the thread to stop on the next iteration of its loop (which
84*635a8641SAndroid Build Coastguard Worker // will happen immediately if no |waiter_| is present or is signaled.
RequestStop()85*635a8641SAndroid Build Coastguard Worker void RequestStop() { stop_event_.Signal(); }
86*635a8641SAndroid Build Coastguard Worker
87*635a8641SAndroid Build Coastguard Worker private:
88*635a8641SAndroid Build Coastguard Worker WaitableEvent stop_event_{WaitableEvent::ResetPolicy::MANUAL,
89*635a8641SAndroid Build Coastguard Worker WaitableEvent::InitialState::NOT_SIGNALED};
90*635a8641SAndroid Build Coastguard Worker TraceWaitableEvent* waiter_;
91*635a8641SAndroid Build Coastguard Worker TraceWaitableEvent* signaler_;
92*635a8641SAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(SignalerThread);
93*635a8641SAndroid Build Coastguard Worker };
94*635a8641SAndroid Build Coastguard Worker
PrintPerfWaitableEvent(const TraceWaitableEvent * event,const std::string & modifier,const std::string & trace)95*635a8641SAndroid Build Coastguard Worker void PrintPerfWaitableEvent(const TraceWaitableEvent* event,
96*635a8641SAndroid Build Coastguard Worker const std::string& modifier,
97*635a8641SAndroid Build Coastguard Worker const std::string& trace) {
98*635a8641SAndroid Build Coastguard Worker TimeDelta signal_time = std::accumulate(
99*635a8641SAndroid Build Coastguard Worker event->signal_times().begin(), event->signal_times().end(), TimeDelta());
100*635a8641SAndroid Build Coastguard Worker TimeDelta wait_time = std::accumulate(event->wait_times().begin(),
101*635a8641SAndroid Build Coastguard Worker event->wait_times().end(), TimeDelta());
102*635a8641SAndroid Build Coastguard Worker perf_test::PrintResult(
103*635a8641SAndroid Build Coastguard Worker "signal_time", modifier, trace,
104*635a8641SAndroid Build Coastguard Worker static_cast<size_t>(signal_time.InNanoseconds()) / event->samples(),
105*635a8641SAndroid Build Coastguard Worker "ns/sample", true);
106*635a8641SAndroid Build Coastguard Worker perf_test::PrintResult(
107*635a8641SAndroid Build Coastguard Worker "wait_time", modifier, trace,
108*635a8641SAndroid Build Coastguard Worker static_cast<size_t>(wait_time.InNanoseconds()) / event->samples(),
109*635a8641SAndroid Build Coastguard Worker "ns/sample", true);
110*635a8641SAndroid Build Coastguard Worker }
111*635a8641SAndroid Build Coastguard Worker
112*635a8641SAndroid Build Coastguard Worker } // namespace
113*635a8641SAndroid Build Coastguard Worker
TEST(WaitableEventPerfTest,SingleThread)114*635a8641SAndroid Build Coastguard Worker TEST(WaitableEventPerfTest, SingleThread) {
115*635a8641SAndroid Build Coastguard Worker const size_t kSamples = 1000;
116*635a8641SAndroid Build Coastguard Worker
117*635a8641SAndroid Build Coastguard Worker TraceWaitableEvent event(kSamples);
118*635a8641SAndroid Build Coastguard Worker
119*635a8641SAndroid Build Coastguard Worker for (size_t i = 0; i < kSamples; ++i) {
120*635a8641SAndroid Build Coastguard Worker event.Signal();
121*635a8641SAndroid Build Coastguard Worker event.Wait();
122*635a8641SAndroid Build Coastguard Worker }
123*635a8641SAndroid Build Coastguard Worker
124*635a8641SAndroid Build Coastguard Worker PrintPerfWaitableEvent(&event, "", "singlethread-1000-samples");
125*635a8641SAndroid Build Coastguard Worker }
126*635a8641SAndroid Build Coastguard Worker
TEST(WaitableEventPerfTest,MultipleThreads)127*635a8641SAndroid Build Coastguard Worker TEST(WaitableEventPerfTest, MultipleThreads) {
128*635a8641SAndroid Build Coastguard Worker const size_t kSamples = 1000;
129*635a8641SAndroid Build Coastguard Worker
130*635a8641SAndroid Build Coastguard Worker TraceWaitableEvent waiter(kSamples);
131*635a8641SAndroid Build Coastguard Worker TraceWaitableEvent signaler(kSamples);
132*635a8641SAndroid Build Coastguard Worker
133*635a8641SAndroid Build Coastguard Worker // The other thread will wait and signal on the respective opposite events.
134*635a8641SAndroid Build Coastguard Worker SignalerThread thread(&signaler, &waiter);
135*635a8641SAndroid Build Coastguard Worker thread.Start();
136*635a8641SAndroid Build Coastguard Worker
137*635a8641SAndroid Build Coastguard Worker for (size_t i = 0; i < kSamples; ++i) {
138*635a8641SAndroid Build Coastguard Worker signaler.Signal();
139*635a8641SAndroid Build Coastguard Worker waiter.Wait();
140*635a8641SAndroid Build Coastguard Worker }
141*635a8641SAndroid Build Coastguard Worker
142*635a8641SAndroid Build Coastguard Worker // Signal the stop event and then make sure the signaler event it is
143*635a8641SAndroid Build Coastguard Worker // waiting on is also signaled.
144*635a8641SAndroid Build Coastguard Worker thread.RequestStop();
145*635a8641SAndroid Build Coastguard Worker signaler.Signal();
146*635a8641SAndroid Build Coastguard Worker
147*635a8641SAndroid Build Coastguard Worker thread.Join();
148*635a8641SAndroid Build Coastguard Worker
149*635a8641SAndroid Build Coastguard Worker PrintPerfWaitableEvent(&waiter, "_waiter", "multithread-1000-samples");
150*635a8641SAndroid Build Coastguard Worker PrintPerfWaitableEvent(&signaler, "_signaler", "multithread-1000-samples");
151*635a8641SAndroid Build Coastguard Worker }
152*635a8641SAndroid Build Coastguard Worker
TEST(WaitableEventPerfTest,Throughput)153*635a8641SAndroid Build Coastguard Worker TEST(WaitableEventPerfTest, Throughput) {
154*635a8641SAndroid Build Coastguard Worker // Reserve a lot of sample space.
155*635a8641SAndroid Build Coastguard Worker const size_t kCapacity = 500000;
156*635a8641SAndroid Build Coastguard Worker TraceWaitableEvent event(kCapacity);
157*635a8641SAndroid Build Coastguard Worker
158*635a8641SAndroid Build Coastguard Worker SignalerThread thread(nullptr, &event);
159*635a8641SAndroid Build Coastguard Worker thread.Start();
160*635a8641SAndroid Build Coastguard Worker
161*635a8641SAndroid Build Coastguard Worker TimeTicks end_time = TimeTicks::Now() + TimeDelta::FromSeconds(1);
162*635a8641SAndroid Build Coastguard Worker size_t count = 0;
163*635a8641SAndroid Build Coastguard Worker while (event.TimedWaitUntil(end_time)) {
164*635a8641SAndroid Build Coastguard Worker ++count;
165*635a8641SAndroid Build Coastguard Worker }
166*635a8641SAndroid Build Coastguard Worker
167*635a8641SAndroid Build Coastguard Worker thread.RequestStop();
168*635a8641SAndroid Build Coastguard Worker thread.Join();
169*635a8641SAndroid Build Coastguard Worker
170*635a8641SAndroid Build Coastguard Worker perf_test::PrintResult("counts", "", "throughput", count, "signals", true);
171*635a8641SAndroid Build Coastguard Worker PrintPerfWaitableEvent(&event, "", "throughput");
172*635a8641SAndroid Build Coastguard Worker
173*635a8641SAndroid Build Coastguard Worker // Make sure that allocation didn't happen during the test.
174*635a8641SAndroid Build Coastguard Worker EXPECT_LE(event.signal_times().capacity(), kCapacity);
175*635a8641SAndroid Build Coastguard Worker EXPECT_LE(event.wait_times().capacity(), kCapacity);
176*635a8641SAndroid Build Coastguard Worker }
177*635a8641SAndroid Build Coastguard Worker
178*635a8641SAndroid Build Coastguard Worker } // namespace base
179