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