xref: /aosp_15_r20/external/libchrome/base/synchronization/waitable_event_perftest.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
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