xref: /aosp_15_r20/external/cronet/base/synchronization/waitable_event_perftest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2017 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 "base/memory/raw_ptr.h"
6*6777b538SAndroid Build Coastguard Worker #include "base/synchronization/waitable_event.h"
7*6777b538SAndroid Build Coastguard Worker 
8*6777b538SAndroid Build Coastguard Worker #include <string>
9*6777b538SAndroid Build Coastguard Worker 
10*6777b538SAndroid Build Coastguard Worker #include "base/threading/simple_thread.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/time/time.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/timer/elapsed_timer.h"
13*6777b538SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
14*6777b538SAndroid Build Coastguard Worker #include "testing/perf/perf_result_reporter.h"
15*6777b538SAndroid Build Coastguard Worker 
16*6777b538SAndroid Build Coastguard Worker namespace base {
17*6777b538SAndroid Build Coastguard Worker 
18*6777b538SAndroid Build Coastguard Worker namespace {
19*6777b538SAndroid Build Coastguard Worker 
20*6777b538SAndroid Build Coastguard Worker constexpr char kMetricPrefixWaitableEvent[] = "WaitableEvent.";
21*6777b538SAndroid Build Coastguard Worker constexpr char kMetricWaitTime[] = "wait_time_per_sample";
22*6777b538SAndroid Build Coastguard Worker constexpr char kMetricSignalTime[] = "signal_time_per_sample";
23*6777b538SAndroid Build Coastguard Worker constexpr char kMetricElapsedCycles[] = "elapsed_cycles";
24*6777b538SAndroid Build Coastguard Worker constexpr char kStorySingleThread[] = "single_thread_1000_samples";
25*6777b538SAndroid Build Coastguard Worker constexpr char kStoryMultiThreadWaiter[] = "multi_thread_1000_samples_waiter";
26*6777b538SAndroid Build Coastguard Worker constexpr char kStoryMultiThreadSignaler[] =
27*6777b538SAndroid Build Coastguard Worker     "multi_thread_1000_samples_signaler";
28*6777b538SAndroid Build Coastguard Worker constexpr char kStoryTimedThroughput[] = "timed_throughput";
29*6777b538SAndroid Build Coastguard Worker 
SetUpReporter(const std::string & story_name)30*6777b538SAndroid Build Coastguard Worker perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) {
31*6777b538SAndroid Build Coastguard Worker   perf_test::PerfResultReporter reporter(kMetricPrefixWaitableEvent,
32*6777b538SAndroid Build Coastguard Worker                                          story_name);
33*6777b538SAndroid Build Coastguard Worker   reporter.RegisterImportantMetric(kMetricWaitTime, "ns");
34*6777b538SAndroid Build Coastguard Worker   reporter.RegisterImportantMetric(kMetricSignalTime, "ns");
35*6777b538SAndroid Build Coastguard Worker   reporter.RegisterImportantMetric(kMetricElapsedCycles, "count");
36*6777b538SAndroid Build Coastguard Worker   return reporter;
37*6777b538SAndroid Build Coastguard Worker }
38*6777b538SAndroid Build Coastguard Worker 
39*6777b538SAndroid Build Coastguard Worker class TraceWaitableEvent {
40*6777b538SAndroid Build Coastguard Worker  public:
41*6777b538SAndroid Build Coastguard Worker   TraceWaitableEvent() = default;
42*6777b538SAndroid Build Coastguard Worker 
43*6777b538SAndroid Build Coastguard Worker   TraceWaitableEvent(const TraceWaitableEvent&) = delete;
44*6777b538SAndroid Build Coastguard Worker   TraceWaitableEvent& operator=(const TraceWaitableEvent&) = delete;
45*6777b538SAndroid Build Coastguard Worker 
46*6777b538SAndroid Build Coastguard Worker   ~TraceWaitableEvent() = default;
47*6777b538SAndroid Build Coastguard Worker 
Signal()48*6777b538SAndroid Build Coastguard Worker   void Signal() {
49*6777b538SAndroid Build Coastguard Worker     ElapsedTimer timer;
50*6777b538SAndroid Build Coastguard Worker     event_.Signal();
51*6777b538SAndroid Build Coastguard Worker     total_signal_time_ += timer.Elapsed();
52*6777b538SAndroid Build Coastguard Worker     ++signal_samples_;
53*6777b538SAndroid Build Coastguard Worker   }
54*6777b538SAndroid Build Coastguard Worker 
Wait()55*6777b538SAndroid Build Coastguard Worker   void Wait() {
56*6777b538SAndroid Build Coastguard Worker     ElapsedTimer timer;
57*6777b538SAndroid Build Coastguard Worker     event_.Wait();
58*6777b538SAndroid Build Coastguard Worker     total_wait_time_ += timer.Elapsed();
59*6777b538SAndroid Build Coastguard Worker     ++wait_samples_;
60*6777b538SAndroid Build Coastguard Worker   }
61*6777b538SAndroid Build Coastguard Worker 
TimedWaitUntil(const TimeTicks & end_time)62*6777b538SAndroid Build Coastguard Worker   bool TimedWaitUntil(const TimeTicks& end_time) {
63*6777b538SAndroid Build Coastguard Worker     ElapsedTimer timer;
64*6777b538SAndroid Build Coastguard Worker     const bool signaled = event_.TimedWait(end_time - timer.start_time());
65*6777b538SAndroid Build Coastguard Worker     total_wait_time_ += timer.Elapsed();
66*6777b538SAndroid Build Coastguard Worker     ++wait_samples_;
67*6777b538SAndroid Build Coastguard Worker     return signaled;
68*6777b538SAndroid Build Coastguard Worker   }
69*6777b538SAndroid Build Coastguard Worker 
IsSignaled()70*6777b538SAndroid Build Coastguard Worker   bool IsSignaled() { return event_.IsSignaled(); }
71*6777b538SAndroid Build Coastguard Worker 
total_signal_time() const72*6777b538SAndroid Build Coastguard Worker   TimeDelta total_signal_time() const { return total_signal_time_; }
total_wait_time() const73*6777b538SAndroid Build Coastguard Worker   TimeDelta total_wait_time() const { return total_wait_time_; }
signal_samples() const74*6777b538SAndroid Build Coastguard Worker   size_t signal_samples() const { return signal_samples_; }
wait_samples() const75*6777b538SAndroid Build Coastguard Worker   size_t wait_samples() const { return wait_samples_; }
76*6777b538SAndroid Build Coastguard Worker 
77*6777b538SAndroid Build Coastguard Worker  private:
78*6777b538SAndroid Build Coastguard Worker   WaitableEvent event_{WaitableEvent::ResetPolicy::AUTOMATIC};
79*6777b538SAndroid Build Coastguard Worker 
80*6777b538SAndroid Build Coastguard Worker   TimeDelta total_signal_time_;
81*6777b538SAndroid Build Coastguard Worker   TimeDelta total_wait_time_;
82*6777b538SAndroid Build Coastguard Worker 
83*6777b538SAndroid Build Coastguard Worker   size_t signal_samples_ = 0U;
84*6777b538SAndroid Build Coastguard Worker   size_t wait_samples_ = 0U;
85*6777b538SAndroid Build Coastguard Worker };
86*6777b538SAndroid Build Coastguard Worker 
87*6777b538SAndroid Build Coastguard Worker class SignalerThread : public SimpleThread {
88*6777b538SAndroid Build Coastguard Worker  public:
SignalerThread(TraceWaitableEvent * waiter,TraceWaitableEvent * signaler)89*6777b538SAndroid Build Coastguard Worker   SignalerThread(TraceWaitableEvent* waiter, TraceWaitableEvent* signaler)
90*6777b538SAndroid Build Coastguard Worker       : SimpleThread("WaitableEventPerfTest signaler"),
91*6777b538SAndroid Build Coastguard Worker         waiter_(waiter),
92*6777b538SAndroid Build Coastguard Worker         signaler_(signaler) {}
93*6777b538SAndroid Build Coastguard Worker 
94*6777b538SAndroid Build Coastguard Worker   SignalerThread(const SignalerThread&) = delete;
95*6777b538SAndroid Build Coastguard Worker   SignalerThread& operator=(const SignalerThread&) = delete;
96*6777b538SAndroid Build Coastguard Worker 
97*6777b538SAndroid Build Coastguard Worker   ~SignalerThread() override = default;
98*6777b538SAndroid Build Coastguard Worker 
Run()99*6777b538SAndroid Build Coastguard Worker   void Run() override {
100*6777b538SAndroid Build Coastguard Worker     while (!stop_event_.IsSignaled()) {
101*6777b538SAndroid Build Coastguard Worker       if (waiter_)
102*6777b538SAndroid Build Coastguard Worker         waiter_->Wait();
103*6777b538SAndroid Build Coastguard Worker       if (signaler_)
104*6777b538SAndroid Build Coastguard Worker         signaler_->Signal();
105*6777b538SAndroid Build Coastguard Worker     }
106*6777b538SAndroid Build Coastguard Worker   }
107*6777b538SAndroid Build Coastguard Worker 
108*6777b538SAndroid Build Coastguard Worker   // Signals the thread to stop on the next iteration of its loop (which
109*6777b538SAndroid Build Coastguard Worker   // will happen immediately if no |waiter_| is present or is signaled.
RequestStop()110*6777b538SAndroid Build Coastguard Worker   void RequestStop() { stop_event_.Signal(); }
111*6777b538SAndroid Build Coastguard Worker 
112*6777b538SAndroid Build Coastguard Worker  private:
113*6777b538SAndroid Build Coastguard Worker   WaitableEvent stop_event_;
114*6777b538SAndroid Build Coastguard Worker   raw_ptr<TraceWaitableEvent> waiter_;
115*6777b538SAndroid Build Coastguard Worker   raw_ptr<TraceWaitableEvent> signaler_;
116*6777b538SAndroid Build Coastguard Worker };
117*6777b538SAndroid Build Coastguard Worker 
PrintPerfWaitableEvent(const TraceWaitableEvent * event,const std::string & story_name,size_t * elapsed_cycles=nullptr)118*6777b538SAndroid Build Coastguard Worker void PrintPerfWaitableEvent(const TraceWaitableEvent* event,
119*6777b538SAndroid Build Coastguard Worker                             const std::string& story_name,
120*6777b538SAndroid Build Coastguard Worker                             size_t* elapsed_cycles = nullptr) {
121*6777b538SAndroid Build Coastguard Worker   auto reporter = SetUpReporter(story_name);
122*6777b538SAndroid Build Coastguard Worker   reporter.AddResult(
123*6777b538SAndroid Build Coastguard Worker       kMetricSignalTime,
124*6777b538SAndroid Build Coastguard Worker       static_cast<size_t>(event->total_signal_time().InNanoseconds()) /
125*6777b538SAndroid Build Coastguard Worker           event->signal_samples());
126*6777b538SAndroid Build Coastguard Worker   reporter.AddResult(
127*6777b538SAndroid Build Coastguard Worker       kMetricWaitTime,
128*6777b538SAndroid Build Coastguard Worker       static_cast<size_t>(event->total_wait_time().InNanoseconds()) /
129*6777b538SAndroid Build Coastguard Worker           event->wait_samples());
130*6777b538SAndroid Build Coastguard Worker   if (elapsed_cycles) {
131*6777b538SAndroid Build Coastguard Worker     reporter.AddResult(kMetricElapsedCycles, *elapsed_cycles);
132*6777b538SAndroid Build Coastguard Worker   }
133*6777b538SAndroid Build Coastguard Worker }
134*6777b538SAndroid Build Coastguard Worker 
135*6777b538SAndroid Build Coastguard Worker }  // namespace
136*6777b538SAndroid Build Coastguard Worker 
TEST(WaitableEventPerfTest,SingleThread)137*6777b538SAndroid Build Coastguard Worker TEST(WaitableEventPerfTest, SingleThread) {
138*6777b538SAndroid Build Coastguard Worker   const size_t kSamples = 1000;
139*6777b538SAndroid Build Coastguard Worker 
140*6777b538SAndroid Build Coastguard Worker   TraceWaitableEvent event;
141*6777b538SAndroid Build Coastguard Worker 
142*6777b538SAndroid Build Coastguard Worker   for (size_t i = 0; i < kSamples; ++i) {
143*6777b538SAndroid Build Coastguard Worker     event.Signal();
144*6777b538SAndroid Build Coastguard Worker     event.Wait();
145*6777b538SAndroid Build Coastguard Worker   }
146*6777b538SAndroid Build Coastguard Worker 
147*6777b538SAndroid Build Coastguard Worker   PrintPerfWaitableEvent(&event, kStorySingleThread);
148*6777b538SAndroid Build Coastguard Worker }
149*6777b538SAndroid Build Coastguard Worker 
TEST(WaitableEventPerfTest,MultipleThreads)150*6777b538SAndroid Build Coastguard Worker TEST(WaitableEventPerfTest, MultipleThreads) {
151*6777b538SAndroid Build Coastguard Worker   const size_t kSamples = 1000;
152*6777b538SAndroid Build Coastguard Worker 
153*6777b538SAndroid Build Coastguard Worker   TraceWaitableEvent waiter;
154*6777b538SAndroid Build Coastguard Worker   TraceWaitableEvent signaler;
155*6777b538SAndroid Build Coastguard Worker 
156*6777b538SAndroid Build Coastguard Worker   // The other thread will wait and signal on the respective opposite events.
157*6777b538SAndroid Build Coastguard Worker   SignalerThread thread(&signaler, &waiter);
158*6777b538SAndroid Build Coastguard Worker   thread.Start();
159*6777b538SAndroid Build Coastguard Worker 
160*6777b538SAndroid Build Coastguard Worker   for (size_t i = 0; i < kSamples; ++i) {
161*6777b538SAndroid Build Coastguard Worker     signaler.Signal();
162*6777b538SAndroid Build Coastguard Worker     waiter.Wait();
163*6777b538SAndroid Build Coastguard Worker   }
164*6777b538SAndroid Build Coastguard Worker 
165*6777b538SAndroid Build Coastguard Worker   // Signal the stop event and then make sure the signaler event it is
166*6777b538SAndroid Build Coastguard Worker   // waiting on is also signaled.
167*6777b538SAndroid Build Coastguard Worker   thread.RequestStop();
168*6777b538SAndroid Build Coastguard Worker   signaler.Signal();
169*6777b538SAndroid Build Coastguard Worker 
170*6777b538SAndroid Build Coastguard Worker   thread.Join();
171*6777b538SAndroid Build Coastguard Worker 
172*6777b538SAndroid Build Coastguard Worker   PrintPerfWaitableEvent(&waiter, kStoryMultiThreadWaiter);
173*6777b538SAndroid Build Coastguard Worker   PrintPerfWaitableEvent(&signaler, kStoryMultiThreadSignaler);
174*6777b538SAndroid Build Coastguard Worker }
175*6777b538SAndroid Build Coastguard Worker 
TEST(WaitableEventPerfTest,Throughput)176*6777b538SAndroid Build Coastguard Worker TEST(WaitableEventPerfTest, Throughput) {
177*6777b538SAndroid Build Coastguard Worker   TraceWaitableEvent event;
178*6777b538SAndroid Build Coastguard Worker 
179*6777b538SAndroid Build Coastguard Worker   SignalerThread thread(nullptr, &event);
180*6777b538SAndroid Build Coastguard Worker   thread.Start();
181*6777b538SAndroid Build Coastguard Worker 
182*6777b538SAndroid Build Coastguard Worker   const TimeTicks end_time = TimeTicks::Now() + Seconds(1);
183*6777b538SAndroid Build Coastguard Worker   size_t count = 0;
184*6777b538SAndroid Build Coastguard Worker   while (event.TimedWaitUntil(end_time)) {
185*6777b538SAndroid Build Coastguard Worker     ++count;
186*6777b538SAndroid Build Coastguard Worker   }
187*6777b538SAndroid Build Coastguard Worker 
188*6777b538SAndroid Build Coastguard Worker   thread.RequestStop();
189*6777b538SAndroid Build Coastguard Worker   thread.Join();
190*6777b538SAndroid Build Coastguard Worker 
191*6777b538SAndroid Build Coastguard Worker   PrintPerfWaitableEvent(&event, kStoryTimedThroughput, &count);
192*6777b538SAndroid Build Coastguard Worker }
193*6777b538SAndroid Build Coastguard Worker 
194*6777b538SAndroid Build Coastguard Worker }  // namespace base
195