1 /*
2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "benchmark/benchmark.h"
18 
19 #include <future>
20 
21 #include "os/handler.h"
22 #include "os/queue.h"
23 #include "os/thread.h"
24 
25 using ::benchmark::State;
26 
27 namespace bluetooth {
28 namespace os {
29 
30 class BM_QueuePerformance : public ::benchmark::Fixture {
31  protected:
32   void SetUp(State& st) override {
33     ::benchmark::Fixture::SetUp(st);
34     enqueue_thread_ = new Thread("enqueue_thread", Thread::Priority::NORMAL);
35     enqueue_handler_ = new Handler(enqueue_thread_);
36     dequeue_thread_ = new Thread("dequeue_thread", Thread::Priority::NORMAL);
37     dequeue_handler_ = new Handler(dequeue_thread_);
38   }
39 
40   void TearDown(State& st) override {
41     delete enqueue_handler_;
42     delete enqueue_thread_;
43     delete dequeue_handler_;
44     delete dequeue_thread_;
45     enqueue_handler_ = nullptr;
46     enqueue_thread_ = nullptr;
47     dequeue_handler_ = nullptr;
48     dequeue_thread_ = nullptr;
49     benchmark::Fixture::TearDown(st);
50   }
51 
52   Thread* enqueue_thread_;
53   Handler* enqueue_handler_;
54   Thread* dequeue_thread_;
55   Handler* dequeue_handler_;
56 };
57 
58 class TestEnqueueEnd {
59  public:
60   explicit TestEnqueueEnd(int64_t count, Queue<std::string>* queue, Handler* handler, std::promise<void>* promise)
61       : count_(count), handler_(handler), queue_(queue), promise_(promise) {}
62 
63   void RegisterEnqueue() {
64     handler_->Post(common::BindOnce(&TestEnqueueEnd::handle_register_enqueue, common::Unretained(this)));
65   }
66 
67   void push(std::string data) {
68     {
69       std::lock_guard<std::mutex> lock(mutex_);
70       buffer_.push(std::move(data));
71     }
72     if (buffer_.size() == 1) {
73       RegisterEnqueue();
74     }
75   }
76 
77   std::unique_ptr<std::string> EnqueueCallbackForTest() {
78     std::lock_guard<std::mutex> lock(mutex_);
79     std::unique_ptr<std::string> data = std::make_unique<std::string>(std::move(buffer_.front()));
80     buffer_.pop();
81 
82     if (buffer_.empty()) {
83       queue_->UnregisterEnqueue();
84     }
85 
86     count_--;
87     if (count_ == 0) {
88       promise_->set_value();
89     }
90 
91     return data;
92   }
93 
94   std::queue<std::string> buffer_;
95   int64_t count_;
96 
97  private:
98   Handler* handler_;
99   Queue<std::string>* queue_;
100   std::promise<void>* promise_;
101   std::mutex mutex_;
102 
103   void handle_register_enqueue() {
104     queue_->RegisterEnqueue(handler_, common::Bind(&TestEnqueueEnd::EnqueueCallbackForTest, common::Unretained(this)));
105   }
106 };
107 
108 class TestDequeueEnd {
109  public:
110   explicit TestDequeueEnd(int64_t count, Queue<std::string>* queue, Handler* handler, std::promise<void>* promise)
111       : count_(count), handler_(handler), queue_(queue), promise_(promise) {}
112 
113   void RegisterDequeue() {
114     handler_->Post(common::BindOnce(&TestDequeueEnd::handle_register_dequeue, common::Unretained(this)));
115   }
116 
117   void DequeueCallbackForTest() {
118     std::string data = *(queue_->TryDequeue());
119     buffer_.push(data);
120 
121     count_--;
122     if (count_ == 0) {
123       queue_->UnregisterDequeue();
124       promise_->set_value();
125     }
126   }
127 
128   std::queue<std::string> buffer_;
129   int64_t count_;
130 
131  private:
132   Handler* handler_;
133   Queue<std::string>* queue_;
134   std::promise<void>* promise_;
135 
136   void handle_register_dequeue() {
137     queue_->RegisterDequeue(handler_, common::Bind(&TestDequeueEnd::DequeueCallbackForTest, common::Unretained(this)));
138   }
139 };
140 
141 BENCHMARK_DEFINE_F(BM_QueuePerformance, send_packet_vary_by_packet_num)(State& state) {
142   for (auto _ : state) {
143     int64_t num_data_to_send_ = state.range(0);
144     Queue<std::string> queue(num_data_to_send_);
145 
146     // register dequeue
147     std::promise<void> dequeue_promise;
148     auto dequeue_future = dequeue_promise.get_future();
149     TestDequeueEnd test_dequeue_end(num_data_to_send_, &queue, enqueue_handler_, &dequeue_promise);
150     test_dequeue_end.RegisterDequeue();
151 
152     // Push data to enqueue end buffer and register enqueue
153     std::promise<void> enqueue_promise;
154     TestEnqueueEnd test_enqueue_end(num_data_to_send_, &queue, enqueue_handler_, &enqueue_promise);
155     for (int i = 0; i < num_data_to_send_; i++) {
156       std::string data = std::to_string(1);
157       test_enqueue_end.push(std::move(data));
158     }
159     dequeue_future.wait();
160   }
161 
162   state.SetBytesProcessed(static_cast<int_fast64_t>(state.iterations()) * state.range(0));
163 };
164 
165 BENCHMARK_REGISTER_F(BM_QueuePerformance, send_packet_vary_by_packet_num)
166     ->Arg(10)
167     ->Arg(100)
168     ->Arg(1000)
169     ->Arg(10000)
170     ->Arg(100000)
171     ->Iterations(100)
172     ->UseRealTime();
173 
174 BENCHMARK_DEFINE_F(BM_QueuePerformance, send_10000_packet_vary_by_packet_size)(State& state) {
175   for (auto _ : state) {
176     int64_t num_data_to_send_ = 10000;
177     int64_t packet_size = state.range(0);
178     Queue<std::string> queue(num_data_to_send_);
179 
180     // register dequeue
181     std::promise<void> dequeue_promise;
182     auto dequeue_future = dequeue_promise.get_future();
183     TestDequeueEnd test_dequeue_end(num_data_to_send_, &queue, enqueue_handler_, &dequeue_promise);
184     test_dequeue_end.RegisterDequeue();
185 
186     // Push data to enqueue end buffer and register enqueue
187     std::promise<void> enqueue_promise;
188     TestEnqueueEnd test_enqueue_end(num_data_to_send_, &queue, enqueue_handler_, &enqueue_promise);
189     for (int i = 0; i < num_data_to_send_; i++) {
190       std::string data = std::string(packet_size, 'x');
191       test_enqueue_end.push(std::move(data));
192     }
193     dequeue_future.wait();
194   }
195 
196   state.SetBytesProcessed(static_cast<int_fast64_t>(state.iterations()) * state.range(0) * 10000);
197 };
198 
199 BENCHMARK_REGISTER_F(BM_QueuePerformance, send_10000_packet_vary_by_packet_size)
200     ->Arg(10)
201     ->Arg(100)
202     ->Arg(1000)
203     ->Iterations(100)
204     ->UseRealTime();
205 
206 }  // namespace os
207 }  // namespace bluetooth
208