xref: /aosp_15_r20/external/libchrome/base/threading/thread_perftest.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker // Copyright 2014 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 <stddef.h>
6*635a8641SAndroid Build Coastguard Worker 
7*635a8641SAndroid Build Coastguard Worker #include <memory>
8*635a8641SAndroid Build Coastguard Worker #include <vector>
9*635a8641SAndroid Build Coastguard Worker 
10*635a8641SAndroid Build Coastguard Worker #include "base/base_switches.h"
11*635a8641SAndroid Build Coastguard Worker #include "base/bind.h"
12*635a8641SAndroid Build Coastguard Worker #include "base/command_line.h"
13*635a8641SAndroid Build Coastguard Worker #include "base/location.h"
14*635a8641SAndroid Build Coastguard Worker #include "base/memory/ptr_util.h"
15*635a8641SAndroid Build Coastguard Worker #include "base/message_loop/message_loop.h"
16*635a8641SAndroid Build Coastguard Worker #include "base/single_thread_task_runner.h"
17*635a8641SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
18*635a8641SAndroid Build Coastguard Worker #include "base/synchronization/condition_variable.h"
19*635a8641SAndroid Build Coastguard Worker #include "base/synchronization/lock.h"
20*635a8641SAndroid Build Coastguard Worker #include "base/synchronization/waitable_event.h"
21*635a8641SAndroid Build Coastguard Worker #include "base/threading/thread.h"
22*635a8641SAndroid Build Coastguard Worker #include "base/time/time.h"
23*635a8641SAndroid Build Coastguard Worker #include "build/build_config.h"
24*635a8641SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
25*635a8641SAndroid Build Coastguard Worker #include "testing/perf/perf_test.h"
26*635a8641SAndroid Build Coastguard Worker 
27*635a8641SAndroid Build Coastguard Worker #if defined(OS_POSIX)
28*635a8641SAndroid Build Coastguard Worker #include <pthread.h>
29*635a8641SAndroid Build Coastguard Worker #endif
30*635a8641SAndroid Build Coastguard Worker 
31*635a8641SAndroid Build Coastguard Worker namespace base {
32*635a8641SAndroid Build Coastguard Worker 
33*635a8641SAndroid Build Coastguard Worker namespace {
34*635a8641SAndroid Build Coastguard Worker 
35*635a8641SAndroid Build Coastguard Worker const int kNumRuns = 100000;
36*635a8641SAndroid Build Coastguard Worker 
37*635a8641SAndroid Build Coastguard Worker // Base class for a threading perf-test. This sets up some threads for the
38*635a8641SAndroid Build Coastguard Worker // test and measures the clock-time in addition to time spent on each thread.
39*635a8641SAndroid Build Coastguard Worker class ThreadPerfTest : public testing::Test {
40*635a8641SAndroid Build Coastguard Worker  public:
ThreadPerfTest()41*635a8641SAndroid Build Coastguard Worker   ThreadPerfTest()
42*635a8641SAndroid Build Coastguard Worker       : done_(WaitableEvent::ResetPolicy::AUTOMATIC,
43*635a8641SAndroid Build Coastguard Worker               WaitableEvent::InitialState::NOT_SIGNALED) {}
44*635a8641SAndroid Build Coastguard Worker 
45*635a8641SAndroid Build Coastguard Worker   // To be implemented by each test. Subclass must uses threads_ such that
46*635a8641SAndroid Build Coastguard Worker   // their cpu-time can be measured. Test must return from PingPong() _and_
47*635a8641SAndroid Build Coastguard Worker   // call FinishMeasurement from any thread to complete the test.
Init()48*635a8641SAndroid Build Coastguard Worker   virtual void Init() {
49*635a8641SAndroid Build Coastguard Worker     if (ThreadTicks::IsSupported())
50*635a8641SAndroid Build Coastguard Worker       ThreadTicks::WaitUntilInitialized();
51*635a8641SAndroid Build Coastguard Worker   }
52*635a8641SAndroid Build Coastguard Worker   virtual void PingPong(int hops) = 0;
Reset()53*635a8641SAndroid Build Coastguard Worker   virtual void Reset() {}
54*635a8641SAndroid Build Coastguard Worker 
TimeOnThread(base::ThreadTicks * ticks,base::WaitableEvent * done)55*635a8641SAndroid Build Coastguard Worker   void TimeOnThread(base::ThreadTicks* ticks, base::WaitableEvent* done) {
56*635a8641SAndroid Build Coastguard Worker     *ticks = base::ThreadTicks::Now();
57*635a8641SAndroid Build Coastguard Worker     done->Signal();
58*635a8641SAndroid Build Coastguard Worker   }
59*635a8641SAndroid Build Coastguard Worker 
ThreadNow(const base::Thread & thread)60*635a8641SAndroid Build Coastguard Worker   base::ThreadTicks ThreadNow(const base::Thread& thread) {
61*635a8641SAndroid Build Coastguard Worker     base::WaitableEvent done(WaitableEvent::ResetPolicy::AUTOMATIC,
62*635a8641SAndroid Build Coastguard Worker                              WaitableEvent::InitialState::NOT_SIGNALED);
63*635a8641SAndroid Build Coastguard Worker     base::ThreadTicks ticks;
64*635a8641SAndroid Build Coastguard Worker     thread.task_runner()->PostTask(
65*635a8641SAndroid Build Coastguard Worker         FROM_HERE, base::BindOnce(&ThreadPerfTest::TimeOnThread,
66*635a8641SAndroid Build Coastguard Worker                                   base::Unretained(this), &ticks, &done));
67*635a8641SAndroid Build Coastguard Worker     done.Wait();
68*635a8641SAndroid Build Coastguard Worker     return ticks;
69*635a8641SAndroid Build Coastguard Worker   }
70*635a8641SAndroid Build Coastguard Worker 
RunPingPongTest(const std::string & name,unsigned num_threads)71*635a8641SAndroid Build Coastguard Worker   void RunPingPongTest(const std::string& name, unsigned num_threads) {
72*635a8641SAndroid Build Coastguard Worker     // Create threads and collect starting cpu-time for each thread.
73*635a8641SAndroid Build Coastguard Worker     std::vector<base::ThreadTicks> thread_starts;
74*635a8641SAndroid Build Coastguard Worker     while (threads_.size() < num_threads) {
75*635a8641SAndroid Build Coastguard Worker       threads_.push_back(std::make_unique<base::Thread>("PingPonger"));
76*635a8641SAndroid Build Coastguard Worker       threads_.back()->Start();
77*635a8641SAndroid Build Coastguard Worker       if (base::ThreadTicks::IsSupported())
78*635a8641SAndroid Build Coastguard Worker         thread_starts.push_back(ThreadNow(*threads_.back()));
79*635a8641SAndroid Build Coastguard Worker     }
80*635a8641SAndroid Build Coastguard Worker 
81*635a8641SAndroid Build Coastguard Worker     Init();
82*635a8641SAndroid Build Coastguard Worker 
83*635a8641SAndroid Build Coastguard Worker     base::TimeTicks start = base::TimeTicks::Now();
84*635a8641SAndroid Build Coastguard Worker     PingPong(kNumRuns);
85*635a8641SAndroid Build Coastguard Worker     done_.Wait();
86*635a8641SAndroid Build Coastguard Worker     base::TimeTicks end = base::TimeTicks::Now();
87*635a8641SAndroid Build Coastguard Worker 
88*635a8641SAndroid Build Coastguard Worker     // Gather the cpu-time spent on each thread. This does one extra tasks,
89*635a8641SAndroid Build Coastguard Worker     // but that should be in the noise given enough runs.
90*635a8641SAndroid Build Coastguard Worker     base::TimeDelta thread_time;
91*635a8641SAndroid Build Coastguard Worker     while (threads_.size()) {
92*635a8641SAndroid Build Coastguard Worker       if (base::ThreadTicks::IsSupported()) {
93*635a8641SAndroid Build Coastguard Worker         thread_time += ThreadNow(*threads_.back()) - thread_starts.back();
94*635a8641SAndroid Build Coastguard Worker         thread_starts.pop_back();
95*635a8641SAndroid Build Coastguard Worker       }
96*635a8641SAndroid Build Coastguard Worker       threads_.pop_back();
97*635a8641SAndroid Build Coastguard Worker     }
98*635a8641SAndroid Build Coastguard Worker 
99*635a8641SAndroid Build Coastguard Worker     Reset();
100*635a8641SAndroid Build Coastguard Worker 
101*635a8641SAndroid Build Coastguard Worker     double num_runs = static_cast<double>(kNumRuns);
102*635a8641SAndroid Build Coastguard Worker     double us_per_task_clock = (end - start).InMicroseconds() / num_runs;
103*635a8641SAndroid Build Coastguard Worker     double us_per_task_cpu = thread_time.InMicroseconds() / num_runs;
104*635a8641SAndroid Build Coastguard Worker 
105*635a8641SAndroid Build Coastguard Worker     // Clock time per task.
106*635a8641SAndroid Build Coastguard Worker     perf_test::PrintResult(
107*635a8641SAndroid Build Coastguard Worker         "task", "", name + "_time ", us_per_task_clock, "us/hop", true);
108*635a8641SAndroid Build Coastguard Worker 
109*635a8641SAndroid Build Coastguard Worker     // Total utilization across threads if available (likely higher).
110*635a8641SAndroid Build Coastguard Worker     if (base::ThreadTicks::IsSupported()) {
111*635a8641SAndroid Build Coastguard Worker       perf_test::PrintResult(
112*635a8641SAndroid Build Coastguard Worker           "task", "", name + "_cpu ", us_per_task_cpu, "us/hop", true);
113*635a8641SAndroid Build Coastguard Worker     }
114*635a8641SAndroid Build Coastguard Worker   }
115*635a8641SAndroid Build Coastguard Worker 
116*635a8641SAndroid Build Coastguard Worker  protected:
FinishMeasurement()117*635a8641SAndroid Build Coastguard Worker   void FinishMeasurement() { done_.Signal(); }
118*635a8641SAndroid Build Coastguard Worker   std::vector<std::unique_ptr<base::Thread>> threads_;
119*635a8641SAndroid Build Coastguard Worker 
120*635a8641SAndroid Build Coastguard Worker  private:
121*635a8641SAndroid Build Coastguard Worker   base::WaitableEvent done_;
122*635a8641SAndroid Build Coastguard Worker };
123*635a8641SAndroid Build Coastguard Worker 
124*635a8641SAndroid Build Coastguard Worker // Class to test task performance by posting empty tasks back and forth.
125*635a8641SAndroid Build Coastguard Worker class TaskPerfTest : public ThreadPerfTest {
NextThread(int count)126*635a8641SAndroid Build Coastguard Worker   base::Thread* NextThread(int count) {
127*635a8641SAndroid Build Coastguard Worker     return threads_[count % threads_.size()].get();
128*635a8641SAndroid Build Coastguard Worker   }
129*635a8641SAndroid Build Coastguard Worker 
PingPong(int hops)130*635a8641SAndroid Build Coastguard Worker   void PingPong(int hops) override {
131*635a8641SAndroid Build Coastguard Worker     if (!hops) {
132*635a8641SAndroid Build Coastguard Worker       FinishMeasurement();
133*635a8641SAndroid Build Coastguard Worker       return;
134*635a8641SAndroid Build Coastguard Worker     }
135*635a8641SAndroid Build Coastguard Worker     NextThread(hops)->task_runner()->PostTask(
136*635a8641SAndroid Build Coastguard Worker         FROM_HERE, base::BindOnce(&ThreadPerfTest::PingPong,
137*635a8641SAndroid Build Coastguard Worker                                   base::Unretained(this), hops - 1));
138*635a8641SAndroid Build Coastguard Worker   }
139*635a8641SAndroid Build Coastguard Worker };
140*635a8641SAndroid Build Coastguard Worker 
141*635a8641SAndroid Build Coastguard Worker // This tries to test the 'best-case' as well as the 'worst-case' task posting
142*635a8641SAndroid Build Coastguard Worker // performance. The best-case keeps one thread alive such that it never yeilds,
143*635a8641SAndroid Build Coastguard Worker // while the worse-case forces a context switch for every task. Four threads are
144*635a8641SAndroid Build Coastguard Worker // used to ensure the threads do yeild (with just two it might be possible for
145*635a8641SAndroid Build Coastguard Worker // both threads to stay awake if they can signal each other fast enough).
TEST_F(TaskPerfTest,TaskPingPong)146*635a8641SAndroid Build Coastguard Worker TEST_F(TaskPerfTest, TaskPingPong) {
147*635a8641SAndroid Build Coastguard Worker   RunPingPongTest("1_Task_Threads", 1);
148*635a8641SAndroid Build Coastguard Worker   RunPingPongTest("4_Task_Threads", 4);
149*635a8641SAndroid Build Coastguard Worker }
150*635a8641SAndroid Build Coastguard Worker 
151*635a8641SAndroid Build Coastguard Worker 
152*635a8641SAndroid Build Coastguard Worker // Same as above, but add observers to test their perf impact.
153*635a8641SAndroid Build Coastguard Worker class MessageLoopObserver : public base::MessageLoop::TaskObserver {
154*635a8641SAndroid Build Coastguard Worker  public:
WillProcessTask(const base::PendingTask & pending_task)155*635a8641SAndroid Build Coastguard Worker   void WillProcessTask(const base::PendingTask& pending_task) override {}
DidProcessTask(const base::PendingTask & pending_task)156*635a8641SAndroid Build Coastguard Worker   void DidProcessTask(const base::PendingTask& pending_task) override {}
157*635a8641SAndroid Build Coastguard Worker };
158*635a8641SAndroid Build Coastguard Worker MessageLoopObserver message_loop_observer;
159*635a8641SAndroid Build Coastguard Worker 
160*635a8641SAndroid Build Coastguard Worker class TaskObserverPerfTest : public TaskPerfTest {
161*635a8641SAndroid Build Coastguard Worker  public:
Init()162*635a8641SAndroid Build Coastguard Worker   void Init() override {
163*635a8641SAndroid Build Coastguard Worker     TaskPerfTest::Init();
164*635a8641SAndroid Build Coastguard Worker     for (size_t i = 0; i < threads_.size(); i++) {
165*635a8641SAndroid Build Coastguard Worker       threads_[i]->message_loop()->task_runner()->PostTask(
166*635a8641SAndroid Build Coastguard Worker           FROM_HERE, BindOnce(&MessageLoop::AddTaskObserver,
167*635a8641SAndroid Build Coastguard Worker                               Unretained(threads_[i]->message_loop()),
168*635a8641SAndroid Build Coastguard Worker                               Unretained(&message_loop_observer)));
169*635a8641SAndroid Build Coastguard Worker     }
170*635a8641SAndroid Build Coastguard Worker   }
171*635a8641SAndroid Build Coastguard Worker };
172*635a8641SAndroid Build Coastguard Worker 
TEST_F(TaskObserverPerfTest,TaskPingPong)173*635a8641SAndroid Build Coastguard Worker TEST_F(TaskObserverPerfTest, TaskPingPong) {
174*635a8641SAndroid Build Coastguard Worker   RunPingPongTest("1_Task_Threads_With_Observer", 1);
175*635a8641SAndroid Build Coastguard Worker   RunPingPongTest("4_Task_Threads_With_Observer", 4);
176*635a8641SAndroid Build Coastguard Worker }
177*635a8641SAndroid Build Coastguard Worker 
178*635a8641SAndroid Build Coastguard Worker // Class to test our WaitableEvent performance by signaling back and fort.
179*635a8641SAndroid Build Coastguard Worker // WaitableEvent is templated so we can also compare with other versions.
180*635a8641SAndroid Build Coastguard Worker template <typename WaitableEventType>
181*635a8641SAndroid Build Coastguard Worker class EventPerfTest : public ThreadPerfTest {
182*635a8641SAndroid Build Coastguard Worker  public:
Init()183*635a8641SAndroid Build Coastguard Worker   void Init() override {
184*635a8641SAndroid Build Coastguard Worker     for (size_t i = 0; i < threads_.size(); i++) {
185*635a8641SAndroid Build Coastguard Worker       events_.push_back(std::make_unique<WaitableEventType>(
186*635a8641SAndroid Build Coastguard Worker           WaitableEvent::ResetPolicy::AUTOMATIC,
187*635a8641SAndroid Build Coastguard Worker           WaitableEvent::InitialState::NOT_SIGNALED));
188*635a8641SAndroid Build Coastguard Worker     }
189*635a8641SAndroid Build Coastguard Worker   }
190*635a8641SAndroid Build Coastguard Worker 
Reset()191*635a8641SAndroid Build Coastguard Worker   void Reset() override { events_.clear(); }
192*635a8641SAndroid Build Coastguard Worker 
WaitAndSignalOnThread(size_t event)193*635a8641SAndroid Build Coastguard Worker   void WaitAndSignalOnThread(size_t event) {
194*635a8641SAndroid Build Coastguard Worker     size_t next_event = (event + 1) % events_.size();
195*635a8641SAndroid Build Coastguard Worker     int my_hops = 0;
196*635a8641SAndroid Build Coastguard Worker     do {
197*635a8641SAndroid Build Coastguard Worker       events_[event]->Wait();
198*635a8641SAndroid Build Coastguard Worker       my_hops = --remaining_hops_;  // We own 'hops' between Wait and Signal.
199*635a8641SAndroid Build Coastguard Worker       events_[next_event]->Signal();
200*635a8641SAndroid Build Coastguard Worker     } while (my_hops > 0);
201*635a8641SAndroid Build Coastguard Worker     // Once we are done, all threads will signal as hops passes zero.
202*635a8641SAndroid Build Coastguard Worker     // We only signal completion once, on the thread that reaches zero.
203*635a8641SAndroid Build Coastguard Worker     if (!my_hops)
204*635a8641SAndroid Build Coastguard Worker       FinishMeasurement();
205*635a8641SAndroid Build Coastguard Worker   }
206*635a8641SAndroid Build Coastguard Worker 
PingPong(int hops)207*635a8641SAndroid Build Coastguard Worker   void PingPong(int hops) override {
208*635a8641SAndroid Build Coastguard Worker     remaining_hops_ = hops;
209*635a8641SAndroid Build Coastguard Worker     for (size_t i = 0; i < threads_.size(); i++) {
210*635a8641SAndroid Build Coastguard Worker       threads_[i]->task_runner()->PostTask(
211*635a8641SAndroid Build Coastguard Worker           FROM_HERE, base::BindOnce(&EventPerfTest::WaitAndSignalOnThread,
212*635a8641SAndroid Build Coastguard Worker                                     base::Unretained(this), i));
213*635a8641SAndroid Build Coastguard Worker     }
214*635a8641SAndroid Build Coastguard Worker 
215*635a8641SAndroid Build Coastguard Worker     // Kick off the Signal ping-ponging.
216*635a8641SAndroid Build Coastguard Worker     events_.front()->Signal();
217*635a8641SAndroid Build Coastguard Worker   }
218*635a8641SAndroid Build Coastguard Worker 
219*635a8641SAndroid Build Coastguard Worker   int remaining_hops_;
220*635a8641SAndroid Build Coastguard Worker   std::vector<std::unique_ptr<WaitableEventType>> events_;
221*635a8641SAndroid Build Coastguard Worker };
222*635a8641SAndroid Build Coastguard Worker 
223*635a8641SAndroid Build Coastguard Worker // Similar to the task posting test, this just tests similar functionality
224*635a8641SAndroid Build Coastguard Worker // using WaitableEvents. We only test four threads (worst-case), but we
225*635a8641SAndroid Build Coastguard Worker // might want to craft a way to test the best-case (where the thread doesn't
226*635a8641SAndroid Build Coastguard Worker // end up blocking because the event is already signalled).
227*635a8641SAndroid Build Coastguard Worker typedef EventPerfTest<base::WaitableEvent> WaitableEventThreadPerfTest;
TEST_F(WaitableEventThreadPerfTest,EventPingPong)228*635a8641SAndroid Build Coastguard Worker TEST_F(WaitableEventThreadPerfTest, EventPingPong) {
229*635a8641SAndroid Build Coastguard Worker   RunPingPongTest("4_WaitableEvent_Threads", 4);
230*635a8641SAndroid Build Coastguard Worker }
231*635a8641SAndroid Build Coastguard Worker 
232*635a8641SAndroid Build Coastguard Worker // Build a minimal event using ConditionVariable.
233*635a8641SAndroid Build Coastguard Worker class ConditionVariableEvent {
234*635a8641SAndroid Build Coastguard Worker  public:
ConditionVariableEvent(WaitableEvent::ResetPolicy reset_policy,WaitableEvent::InitialState initial_state)235*635a8641SAndroid Build Coastguard Worker   ConditionVariableEvent(WaitableEvent::ResetPolicy reset_policy,
236*635a8641SAndroid Build Coastguard Worker                          WaitableEvent::InitialState initial_state)
237*635a8641SAndroid Build Coastguard Worker       : cond_(&lock_), signaled_(false) {
238*635a8641SAndroid Build Coastguard Worker     DCHECK_EQ(WaitableEvent::ResetPolicy::AUTOMATIC, reset_policy);
239*635a8641SAndroid Build Coastguard Worker     DCHECK_EQ(WaitableEvent::InitialState::NOT_SIGNALED, initial_state);
240*635a8641SAndroid Build Coastguard Worker   }
241*635a8641SAndroid Build Coastguard Worker 
Signal()242*635a8641SAndroid Build Coastguard Worker   void Signal() {
243*635a8641SAndroid Build Coastguard Worker     {
244*635a8641SAndroid Build Coastguard Worker       base::AutoLock scoped_lock(lock_);
245*635a8641SAndroid Build Coastguard Worker       signaled_ = true;
246*635a8641SAndroid Build Coastguard Worker     }
247*635a8641SAndroid Build Coastguard Worker     cond_.Signal();
248*635a8641SAndroid Build Coastguard Worker   }
249*635a8641SAndroid Build Coastguard Worker 
Wait()250*635a8641SAndroid Build Coastguard Worker   void Wait() {
251*635a8641SAndroid Build Coastguard Worker     base::AutoLock scoped_lock(lock_);
252*635a8641SAndroid Build Coastguard Worker     while (!signaled_)
253*635a8641SAndroid Build Coastguard Worker       cond_.Wait();
254*635a8641SAndroid Build Coastguard Worker     signaled_ = false;
255*635a8641SAndroid Build Coastguard Worker   }
256*635a8641SAndroid Build Coastguard Worker 
257*635a8641SAndroid Build Coastguard Worker  private:
258*635a8641SAndroid Build Coastguard Worker   base::Lock lock_;
259*635a8641SAndroid Build Coastguard Worker   base::ConditionVariable cond_;
260*635a8641SAndroid Build Coastguard Worker   bool signaled_;
261*635a8641SAndroid Build Coastguard Worker };
262*635a8641SAndroid Build Coastguard Worker 
263*635a8641SAndroid Build Coastguard Worker // This is meant to test the absolute minimal context switching time
264*635a8641SAndroid Build Coastguard Worker // using our own base synchronization code.
265*635a8641SAndroid Build Coastguard Worker typedef EventPerfTest<ConditionVariableEvent> ConditionVariablePerfTest;
TEST_F(ConditionVariablePerfTest,EventPingPong)266*635a8641SAndroid Build Coastguard Worker TEST_F(ConditionVariablePerfTest, EventPingPong) {
267*635a8641SAndroid Build Coastguard Worker   RunPingPongTest("4_ConditionVariable_Threads", 4);
268*635a8641SAndroid Build Coastguard Worker }
269*635a8641SAndroid Build Coastguard Worker #if defined(OS_POSIX)
270*635a8641SAndroid Build Coastguard Worker 
271*635a8641SAndroid Build Coastguard Worker // Absolutely 100% minimal posix waitable event. If there is a better/faster
272*635a8641SAndroid Build Coastguard Worker // way to force a context switch, we should use that instead.
273*635a8641SAndroid Build Coastguard Worker class PthreadEvent {
274*635a8641SAndroid Build Coastguard Worker  public:
PthreadEvent(WaitableEvent::ResetPolicy reset_policy,WaitableEvent::InitialState initial_state)275*635a8641SAndroid Build Coastguard Worker   PthreadEvent(WaitableEvent::ResetPolicy reset_policy,
276*635a8641SAndroid Build Coastguard Worker                WaitableEvent::InitialState initial_state) {
277*635a8641SAndroid Build Coastguard Worker     DCHECK_EQ(WaitableEvent::ResetPolicy::AUTOMATIC, reset_policy);
278*635a8641SAndroid Build Coastguard Worker     DCHECK_EQ(WaitableEvent::InitialState::NOT_SIGNALED, initial_state);
279*635a8641SAndroid Build Coastguard Worker     pthread_mutex_init(&mutex_, nullptr);
280*635a8641SAndroid Build Coastguard Worker     pthread_cond_init(&cond_, nullptr);
281*635a8641SAndroid Build Coastguard Worker     signaled_ = false;
282*635a8641SAndroid Build Coastguard Worker   }
283*635a8641SAndroid Build Coastguard Worker 
~PthreadEvent()284*635a8641SAndroid Build Coastguard Worker   ~PthreadEvent() {
285*635a8641SAndroid Build Coastguard Worker     pthread_cond_destroy(&cond_);
286*635a8641SAndroid Build Coastguard Worker     pthread_mutex_destroy(&mutex_);
287*635a8641SAndroid Build Coastguard Worker   }
288*635a8641SAndroid Build Coastguard Worker 
Signal()289*635a8641SAndroid Build Coastguard Worker   void Signal() {
290*635a8641SAndroid Build Coastguard Worker     pthread_mutex_lock(&mutex_);
291*635a8641SAndroid Build Coastguard Worker     signaled_ = true;
292*635a8641SAndroid Build Coastguard Worker     pthread_mutex_unlock(&mutex_);
293*635a8641SAndroid Build Coastguard Worker     pthread_cond_signal(&cond_);
294*635a8641SAndroid Build Coastguard Worker   }
295*635a8641SAndroid Build Coastguard Worker 
Wait()296*635a8641SAndroid Build Coastguard Worker   void Wait() {
297*635a8641SAndroid Build Coastguard Worker     pthread_mutex_lock(&mutex_);
298*635a8641SAndroid Build Coastguard Worker     while (!signaled_)
299*635a8641SAndroid Build Coastguard Worker       pthread_cond_wait(&cond_, &mutex_);
300*635a8641SAndroid Build Coastguard Worker     signaled_ = false;
301*635a8641SAndroid Build Coastguard Worker     pthread_mutex_unlock(&mutex_);
302*635a8641SAndroid Build Coastguard Worker   }
303*635a8641SAndroid Build Coastguard Worker 
304*635a8641SAndroid Build Coastguard Worker  private:
305*635a8641SAndroid Build Coastguard Worker   bool signaled_;
306*635a8641SAndroid Build Coastguard Worker   pthread_mutex_t mutex_;
307*635a8641SAndroid Build Coastguard Worker   pthread_cond_t cond_;
308*635a8641SAndroid Build Coastguard Worker };
309*635a8641SAndroid Build Coastguard Worker 
310*635a8641SAndroid Build Coastguard Worker // This is meant to test the absolute minimal context switching time.
311*635a8641SAndroid Build Coastguard Worker // If there is any faster way to do this we should substitute it in.
312*635a8641SAndroid Build Coastguard Worker typedef EventPerfTest<PthreadEvent> PthreadEventPerfTest;
TEST_F(PthreadEventPerfTest,EventPingPong)313*635a8641SAndroid Build Coastguard Worker TEST_F(PthreadEventPerfTest, EventPingPong) {
314*635a8641SAndroid Build Coastguard Worker   RunPingPongTest("4_PthreadCondVar_Threads", 4);
315*635a8641SAndroid Build Coastguard Worker }
316*635a8641SAndroid Build Coastguard Worker 
317*635a8641SAndroid Build Coastguard Worker #endif
318*635a8641SAndroid Build Coastguard Worker 
319*635a8641SAndroid Build Coastguard Worker }  // namespace
320*635a8641SAndroid Build Coastguard Worker 
321*635a8641SAndroid Build Coastguard Worker }  // namespace base
322