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, std::promise<void>* promise)
60       : count_(count), handler_(handler), queue_(queue), promise_(promise) {}
61 
RegisterEnqueue()62   void RegisterEnqueue() {
63     handler_->Post(common::BindOnce(&TestEnqueueEnd::handle_register_enqueue, common::Unretained(this)));
64   }
65 
push(std::string data)66   void push(std::string data) {
67     {
68       std::lock_guard<std::mutex> lock(mutex_);
69       buffer_.push(std::move(data));
70     }
71     if (buffer_.size() == 1) {
72       RegisterEnqueue();
73     }
74   }
75 
EnqueueCallbackForTest()76   std::unique_ptr<std::string> EnqueueCallbackForTest() {
77     std::lock_guard<std::mutex> lock(mutex_);
78     std::unique_ptr<std::string> data = std::make_unique<std::string>(std::move(buffer_.front()));
79     buffer_.pop();
80 
81     if (buffer_.empty()) {
82       queue_->UnregisterEnqueue();
83     }
84 
85     count_--;
86     if (count_ == 0) {
87       promise_->set_value();
88     }
89 
90     return data;
91   }
92 
93   std::queue<std::string> buffer_;
94   int64_t count_;
95 
96  private:
97   Handler* handler_;
98   Queue<std::string>* queue_;
99   std::promise<void>* promise_;
100   std::mutex mutex_;
101 
handle_register_enqueue()102   void handle_register_enqueue() {
103     queue_->RegisterEnqueue(handler_, common::Bind(&TestEnqueueEnd::EnqueueCallbackForTest, common::Unretained(this)));
104   }
105 };
106 
107 class TestDequeueEnd {
108  public:
TestDequeueEnd(int64_t count,Queue<std::string> * queue,Handler * handler,std::promise<void> * promise)109   explicit TestDequeueEnd(int64_t count, Queue<std::string>* queue, Handler* handler, std::promise<void>* promise)
110       : count_(count), handler_(handler), queue_(queue), promise_(promise) {}
111 
RegisterDequeue()112   void RegisterDequeue() {
113     handler_->Post(common::BindOnce(&TestDequeueEnd::handle_register_dequeue, common::Unretained(this)));
114   }
115 
DequeueCallbackForTest()116   void DequeueCallbackForTest() {
117     std::string data = *(queue_->TryDequeue());
118     buffer_.push(data);
119 
120     count_--;
121     if (count_ == 0) {
122       queue_->UnregisterDequeue();
123       promise_->set_value();
124     }
125   }
126 
127   std::queue<std::string> buffer_;
128   int64_t count_;
129 
130  private:
131   Handler* handler_;
132   Queue<std::string>* queue_;
133   std::promise<void>* promise_;
134 
handle_register_dequeue()135   void handle_register_dequeue() {
136     queue_->RegisterDequeue(handler_, common::Bind(&TestDequeueEnd::DequeueCallbackForTest, common::Unretained(this)));
137   }
138 };
139 
BENCHMARK_DEFINE_F(BM_QueuePerformance,send_packet_vary_by_packet_num)140 BENCHMARK_DEFINE_F(BM_QueuePerformance, send_packet_vary_by_packet_num)(State& state) {
141   for (auto _ : state) {
142     int64_t num_data_to_send_ = state.range(0);
143     Queue<std::string> queue(num_data_to_send_);
144 
145     // register dequeue
146     std::promise<void> dequeue_promise;
147     auto dequeue_future = dequeue_promise.get_future();
148     TestDequeueEnd test_dequeue_end(num_data_to_send_, &queue, enqueue_handler_, &dequeue_promise);
149     test_dequeue_end.RegisterDequeue();
150 
151     // Push data to enqueue end buffer and register enqueue
152     std::promise<void> enqueue_promise;
153     TestEnqueueEnd test_enqueue_end(num_data_to_send_, &queue, enqueue_handler_, &enqueue_promise);
154     for (int i = 0; i < num_data_to_send_; i++) {
155       std::string data = std::to_string(1);
156       test_enqueue_end.push(std::move(data));
157     }
158     dequeue_future.wait();
159   }
160 
161   state.SetBytesProcessed(static_cast<int_fast64_t>(state.iterations()) * state.range(0));
162 };
163 
164 BENCHMARK_REGISTER_F(BM_QueuePerformance, send_packet_vary_by_packet_num)
165     ->Arg(10)
166     ->Arg(100)
167     ->Arg(1000)
168     ->Arg(10000)
169     ->Arg(100000)
170     ->Iterations(100)
171     ->UseRealTime();
172 
BENCHMARK_DEFINE_F(BM_QueuePerformance,send_10000_packet_vary_by_packet_size)173 BENCHMARK_DEFINE_F(BM_QueuePerformance, send_10000_packet_vary_by_packet_size)(State& state) {
174   for (auto _ : state) {
175     int64_t num_data_to_send_ = 10000;
176     int64_t packet_size = state.range(0);
177     Queue<std::string> queue(num_data_to_send_);
178 
179     // register dequeue
180     std::promise<void> dequeue_promise;
181     auto dequeue_future = dequeue_promise.get_future();
182     TestDequeueEnd test_dequeue_end(num_data_to_send_, &queue, enqueue_handler_, &dequeue_promise);
183     test_dequeue_end.RegisterDequeue();
184 
185     // Push data to enqueue end buffer and register enqueue
186     std::promise<void> enqueue_promise;
187     TestEnqueueEnd test_enqueue_end(num_data_to_send_, &queue, enqueue_handler_, &enqueue_promise);
188     for (int i = 0; i < num_data_to_send_; i++) {
189       std::string data = std::string(packet_size, 'x');
190       test_enqueue_end.push(std::move(data));
191     }
192     dequeue_future.wait();
193   }
194 
195   state.SetBytesProcessed(static_cast<int_fast64_t>(state.iterations()) * state.range(0) * 10000);
196 };
197 
198 BENCHMARK_REGISTER_F(BM_QueuePerformance, send_10000_packet_vary_by_packet_size)
199     ->Arg(10)
200     ->Arg(100)
201     ->Arg(1000)
202     ->Iterations(100)
203     ->UseRealTime();
204 
205 }  // namespace os
206 }  // namespace bluetooth
207