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