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