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 <future>
18 
19 #include "benchmark/benchmark.h"
20 #include "os/handler.h"
21 #include "os/queue.h"
22 #include "os/thread.h"
23 
24 using ::benchmark::State;
25 
26 namespace bluetooth {
27 namespace os {
28 
29 class BM_QueuePerformance : public ::benchmark::Fixture {
30 protected:
SetUp(State & st)31   void SetUp(State& st) override {
32     ::benchmark::Fixture::SetUp(st);
33     enqueue_thread_ = new Thread("enqueue_thread", Thread::Priority::NORMAL);
34     enqueue_handler_ = new Handler(enqueue_thread_);
35     dequeue_thread_ = new Thread("dequeue_thread", Thread::Priority::NORMAL);
36     dequeue_handler_ = new Handler(dequeue_thread_);
37   }
38 
TearDown(State & st)39   void TearDown(State& st) override {
40     delete enqueue_handler_;
41     delete enqueue_thread_;
42     delete dequeue_handler_;
43     delete dequeue_thread_;
44     enqueue_handler_ = nullptr;
45     enqueue_thread_ = nullptr;
46     dequeue_handler_ = nullptr;
47     dequeue_thread_ = nullptr;
48     benchmark::Fixture::TearDown(st);
49   }
50 
51   Thread* enqueue_thread_;
52   Handler* enqueue_handler_;
53   Thread* dequeue_thread_;
54   Handler* dequeue_handler_;
55 };
56 
57 class TestEnqueueEnd {
58 public:
TestEnqueueEnd(int64_t count,Queue<std::string> * queue,Handler * handler,std::promise<void> * promise)59   explicit TestEnqueueEnd(int64_t count, Queue<std::string>* queue, Handler* handler,
60                           std::promise<void>* promise)
61       : count_(count), handler_(handler), queue_(queue), promise_(promise) {}
62 
RegisterEnqueue()63   void RegisterEnqueue() {
64     handler_->Post(
65             common::BindOnce(&TestEnqueueEnd::handle_register_enqueue, common::Unretained(this)));
66   }
67 
push(std::string data)68   void push(std::string data) {
69     {
70       std::lock_guard<std::mutex> lock(mutex_);
71       buffer_.push(std::move(data));
72     }
73     if (buffer_.size() == 1) {
74       RegisterEnqueue();
75     }
76   }
77 
EnqueueCallbackForTest()78   std::unique_ptr<std::string> EnqueueCallbackForTest() {
79     std::lock_guard<std::mutex> lock(mutex_);
80     std::unique_ptr<std::string> data = std::make_unique<std::string>(std::move(buffer_.front()));
81     buffer_.pop();
82 
83     if (buffer_.empty()) {
84       queue_->UnregisterEnqueue();
85     }
86 
87     count_--;
88     if (count_ == 0) {
89       promise_->set_value();
90     }
91 
92     return data;
93   }
94 
95   std::queue<std::string> buffer_;
96   int64_t count_;
97 
98 private:
99   Handler* handler_;
100   Queue<std::string>* queue_;
101   std::promise<void>* promise_;
102   std::mutex mutex_;
103 
handle_register_enqueue()104   void handle_register_enqueue() {
105     queue_->RegisterEnqueue(handler_, common::Bind(&TestEnqueueEnd::EnqueueCallbackForTest,
106                                                    common::Unretained(this)));
107   }
108 };
109 
110 class TestDequeueEnd {
111 public:
TestDequeueEnd(int64_t count,Queue<std::string> * queue,Handler * handler,std::promise<void> * promise)112   explicit TestDequeueEnd(int64_t count, Queue<std::string>* queue, Handler* handler,
113                           std::promise<void>* promise)
114       : count_(count), handler_(handler), queue_(queue), promise_(promise) {}
115 
RegisterDequeue()116   void RegisterDequeue() {
117     handler_->Post(
118             common::BindOnce(&TestDequeueEnd::handle_register_dequeue, common::Unretained(this)));
119   }
120 
DequeueCallbackForTest()121   void DequeueCallbackForTest() {
122     std::string data = *(queue_->TryDequeue());
123     buffer_.push(data);
124 
125     count_--;
126     if (count_ == 0) {
127       queue_->UnregisterDequeue();
128       promise_->set_value();
129     }
130   }
131 
132   std::queue<std::string> buffer_;
133   int64_t count_;
134 
135 private:
136   Handler* handler_;
137   Queue<std::string>* queue_;
138   std::promise<void>* promise_;
139 
handle_register_dequeue()140   void handle_register_dequeue() {
141     queue_->RegisterDequeue(handler_, common::Bind(&TestDequeueEnd::DequeueCallbackForTest,
142                                                    common::Unretained(this)));
143   }
144 };
145 
BENCHMARK_DEFINE_F(BM_QueuePerformance,send_packet_vary_by_packet_num)146 BENCHMARK_DEFINE_F(BM_QueuePerformance, send_packet_vary_by_packet_num)(State& state) {
147   for (auto _ : state) {
148     int64_t num_data_to_send_ = state.range(0);
149     Queue<std::string> queue(num_data_to_send_);
150 
151     // register dequeue
152     std::promise<void> dequeue_promise;
153     auto dequeue_future = dequeue_promise.get_future();
154     TestDequeueEnd test_dequeue_end(num_data_to_send_, &queue, enqueue_handler_, &dequeue_promise);
155     test_dequeue_end.RegisterDequeue();
156 
157     // Push data to enqueue end buffer and register enqueue
158     std::promise<void> enqueue_promise;
159     TestEnqueueEnd test_enqueue_end(num_data_to_send_, &queue, enqueue_handler_, &enqueue_promise);
160     for (int i = 0; i < num_data_to_send_; i++) {
161       std::string data = std::to_string(1);
162       test_enqueue_end.push(std::move(data));
163     }
164     dequeue_future.wait();
165   }
166 
167   state.SetBytesProcessed(static_cast<int_fast64_t>(state.iterations()) * state.range(0));
168 }
169 
170 BENCHMARK_REGISTER_F(BM_QueuePerformance, send_packet_vary_by_packet_num)
171         ->Arg(10)
172         ->Arg(100)
173         ->Arg(1000)
174         ->Arg(10000)
175         ->Arg(100000)
176         ->Iterations(100)
177         ->UseRealTime();
178 
BENCHMARK_DEFINE_F(BM_QueuePerformance,send_10000_packet_vary_by_packet_size)179 BENCHMARK_DEFINE_F(BM_QueuePerformance, send_10000_packet_vary_by_packet_size)(State& state) {
180   for (auto _ : state) {
181     int64_t num_data_to_send_ = 10000;
182     int64_t packet_size = state.range(0);
183     Queue<std::string> queue(num_data_to_send_);
184 
185     // register dequeue
186     std::promise<void> dequeue_promise;
187     auto dequeue_future = dequeue_promise.get_future();
188     TestDequeueEnd test_dequeue_end(num_data_to_send_, &queue, enqueue_handler_, &dequeue_promise);
189     test_dequeue_end.RegisterDequeue();
190 
191     // Push data to enqueue end buffer and register enqueue
192     std::promise<void> enqueue_promise;
193     TestEnqueueEnd test_enqueue_end(num_data_to_send_, &queue, enqueue_handler_, &enqueue_promise);
194     for (int i = 0; i < num_data_to_send_; i++) {
195       std::string data = std::string(packet_size, 'x');
196       test_enqueue_end.push(std::move(data));
197     }
198     dequeue_future.wait();
199   }
200 
201   state.SetBytesProcessed(static_cast<int_fast64_t>(state.iterations()) * state.range(0) * 10000);
202 }
203 
204 BENCHMARK_REGISTER_F(BM_QueuePerformance, send_10000_packet_vary_by_packet_size)
205         ->Arg(10)
206         ->Arg(100)
207         ->Arg(1000)
208         ->Iterations(100)
209         ->UseRealTime();
210 
211 }  // namespace os
212 }  // namespace bluetooth
213