blob: e67f1cf02e59350fd006c45ef302ccf0a6ffd15a [file] [log] [blame]
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -08001/*
2* Copyright (C) 2016 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 <android-base/logging.h>
18
19#include <gtest/gtest.h>
20#include <utils/StrongPointer.h>
21#include <chrono>
22#include <iostream>
23
Hridya Valsarajuef924bb2017-03-03 14:08:56 -080024#include <android/hardware/tests/msgq/1.0/IBenchmarkMsgQ.h>
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080025#include <fmq/MessageQueue.h>
26
27// libutils:
28using android::OK;
29using android::sp;
30using android::status_t;
31
32// generated
Hridya Valsarajuef924bb2017-03-03 14:08:56 -080033using android::hardware::tests::msgq::V1_0::IBenchmarkMsgQ;
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080034using std::cerr;
35using std::cout;
36using std::endl;
37
38// libhidl
39using android::hardware::kSynchronizedReadWrite;
40using android::hardware::MQDescriptorSync;
41using android::hardware::MessageQueue;
42
43/*
44 * All the benchmark cases will be performed on an FMQ of size kQueueSize.
45 */
46static const int32_t kQueueSize = 1024 * 16;
47
48/*
49 * The number of iterations for each experiment.
50 */
51static const uint32_t kNumIterations = 1000;
52
53/*
54 * The various packet sizes used are as follows.
55 */
56enum PacketSizes {
57 kPacketSize64 = 64,
58 kPacketSize128 = 128,
59 kPacketSize256 = 256,
60 kPacketSize512 = 512,
61 kPacketSize1024 = 1024
62};
63
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080064class MQTestClient : public ::testing::Test {
65protected:
66 virtual void TearDown() {
67 delete mFmqInbox;
68 delete mFmqOutbox;
69 }
70
71 virtual void SetUp() {
Hridya Valsaraju27493572017-03-07 20:17:54 -080072 service = IBenchmarkMsgQ::getService();
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080073 ASSERT_NE(service, nullptr);
Hridya Valsaraju27493572017-03-07 20:17:54 -080074 ASSERT_TRUE(service->isRemote());
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080075 /*
76 * Request service to configure the client inbox queue.
77 */
Hridya Valsaraju7eff3422016-12-27 11:54:13 -080078 service->configureClientInboxSyncReadWrite([this](bool ret,
79 const MQDescriptorSync<uint8_t>& in) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080080 ASSERT_TRUE(ret);
81 mFmqInbox = new (std::nothrow) MessageQueue<uint8_t, kSynchronizedReadWrite>(in);
82 });
83
84 ASSERT_TRUE(mFmqInbox != nullptr);
85 ASSERT_TRUE(mFmqInbox->isValid());
86 /*
87 * Reqeust service to configure the client outbox queue.
88 */
Hridya Valsaraju7eff3422016-12-27 11:54:13 -080089 service->configureClientOutboxSyncReadWrite([this](bool ret,
90 const MQDescriptorSync<uint8_t>& out) {
Hridya Valsaraju8b0d5a52016-12-16 10:29:03 -080091 ASSERT_TRUE(ret);
92 mFmqOutbox = new (std::nothrow) MessageQueue<uint8_t,
93 kSynchronizedReadWrite>(out);
94 });
95
96 ASSERT_TRUE(mFmqOutbox != nullptr);
97 ASSERT_TRUE(mFmqOutbox->isValid());
98 }
99
100 sp<IBenchmarkMsgQ> service;
101 android::hardware::MessageQueue<uint8_t, kSynchronizedReadWrite>* mFmqInbox = nullptr;
102 android::hardware::MessageQueue<uint8_t, kSynchronizedReadWrite>* mFmqOutbox = nullptr;
103};
104
105/*
106 * Client writes a 64 byte packet into the outbox queue, service reads the
107 * same and
108 * writes the packet into the client's inbox queue. Client reads the packet. The
109 * average time taken for the cycle is measured.
110 */
111TEST_F(MQTestClient, BenchMarkMeasurePingPongTransfer) {
112 uint8_t* data = new (std::nothrow) uint8_t[kPacketSize64];
113 ASSERT_TRUE(data != nullptr);
114 int64_t accumulatedTime = 0;
115 size_t numRoundTrips = 0;
116
117 /*
118 * This method requests the service to create a thread which reads
119 * from mFmqOutbox and writes into mFmqInbox.
120 */
121 service->benchmarkPingPong(kNumIterations);
122 std::chrono::time_point<std::chrono::high_resolution_clock> timeStart =
123 std::chrono::high_resolution_clock::now();
124 while (numRoundTrips < kNumIterations) {
125 while (mFmqOutbox->write(data, kPacketSize64) == 0) {
126 }
127
128 while (mFmqInbox->read(data, kPacketSize64) == 0) {
129 }
130
131 numRoundTrips++;
132 }
133 std::chrono::time_point<std::chrono::high_resolution_clock> timeEnd =
134 std::chrono::high_resolution_clock::now();
135 accumulatedTime += static_cast<int64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(
136 timeEnd - timeStart).count());
137 accumulatedTime /= kNumIterations;
138
139 cout << "Round trip time for " << kPacketSize64 << "bytes: " <<
140 accumulatedTime << "ns" << endl;
141 delete[] data;
142}
143
144/*
145 * Measure the average time taken to read 64 bytes from the queue.
146 */
147TEST_F(MQTestClient, BenchMarkMeasureRead64Bytes) {
148 uint8_t* data = new (std::nothrow) uint8_t[kPacketSize64];
149 ASSERT_TRUE(data != nullptr);
150
151 uint32_t numLoops = kQueueSize / kPacketSize64;
152 uint64_t accumulatedTime = 0;
153 for (uint32_t i = 0; i < kNumIterations; i++) {
154 bool ret = service->requestWrite(kQueueSize);
155 ASSERT_TRUE(ret);
156 std::chrono::time_point<std::chrono::high_resolution_clock> timeStart =
157 std::chrono::high_resolution_clock::now();
158 /*
159 * The read() method returns true only if the the correct number of bytes
160 * were succesfully read from the queue.
161 */
162 for (uint32_t j = 0; j < numLoops; j++) {
163 ASSERT_TRUE(mFmqInbox->read(data, kPacketSize64));
164 }
165
166 std::chrono::time_point<std::chrono::high_resolution_clock> timeEnd =
167 std::chrono::high_resolution_clock::now();
168 accumulatedTime += (timeEnd - timeStart).count();
169 }
170
171 accumulatedTime /= (numLoops * kNumIterations);
172 cout << "Average time to read" << kPacketSize64
173 << "bytes: " << accumulatedTime << "ns" << endl;
174 delete[] data;
175}
176
177/*
178 * Measure the average time taken to read 128 bytes.
179 */
180TEST_F(MQTestClient, BenchMarkMeasureRead128Bytes) {
181 uint8_t* data = new (std::nothrow) uint8_t[kPacketSize128];
182 ASSERT_TRUE(data != nullptr);
183
184 uint32_t numLoops = kQueueSize / kPacketSize128;
185 uint64_t accumulatedTime = 0;
186
187 for (uint32_t i = 0; i < kNumIterations; i++) {
188 bool ret = service->requestWrite(kQueueSize);
189 ASSERT_TRUE(ret);
190 std::chrono::time_point<std::chrono::high_resolution_clock> timeStart =
191 std::chrono::high_resolution_clock::now();
192
193 /*
194 * The read() method returns true only if the the correct number of bytes
195 * were succesfully read from the queue.
196 */
197 for (uint32_t j = 0; j < numLoops; j++) {
198 ASSERT_TRUE(mFmqInbox->read(data, kPacketSize128));
199 }
200 std::chrono::time_point<std::chrono::high_resolution_clock> timeEnd =
201 std::chrono::high_resolution_clock::now();
202 accumulatedTime += (timeEnd - timeStart).count();
203 }
204
205 accumulatedTime /= (numLoops * kNumIterations);
206 cout << "Average time to read" << kPacketSize128
207 << "bytes: " << accumulatedTime << "ns" << endl;
208 delete[] data;
209}
210
211/*
212 * Measure the average time taken to read 256 bytes from the queue.
213 */
214TEST_F(MQTestClient, BenchMarkMeasureRead256Bytes) {
215 uint8_t* data = new (std::nothrow) uint8_t[kPacketSize256];
216 ASSERT_TRUE(data != nullptr);
217 uint32_t numLoops = kQueueSize / kPacketSize256;
218 uint64_t accumulatedTime = 0;
219
220 for (uint32_t i = 0; i < kNumIterations; i++) {
221 bool ret = service->requestWrite(kQueueSize);
222 ASSERT_TRUE(ret);
223 std::chrono::time_point<std::chrono::high_resolution_clock> timeStart =
224 std::chrono::high_resolution_clock::now();
225 /*
226 * The read() method returns true only if the the correct number of bytes
227 * were succesfully read from the queue.
228 */
229 for (uint32_t j = 0; j < numLoops; j++) {
230 ASSERT_TRUE(mFmqInbox->read(data, kPacketSize256));
231 }
232
233 std::chrono::time_point<std::chrono::high_resolution_clock> timeEnd =
234 std::chrono::high_resolution_clock::now();
235 accumulatedTime += (timeEnd - timeStart).count();
236 }
237
238 accumulatedTime /= (numLoops * kNumIterations);
239 cout << "Average time to read" << kPacketSize256
240 << "bytes: " << accumulatedTime << "ns" << endl;
241 delete[] data;
242}
243
244/*
245 * Measure the average time taken to read 512 bytes from the queue.
246 */
247TEST_F(MQTestClient, BenchMarkMeasureRead512Bytes) {
248 uint8_t* data = new (std::nothrow) uint8_t[kPacketSize512];
249 ASSERT_TRUE(data != nullptr);
250 uint32_t numLoops = kQueueSize / kPacketSize512;
251 uint64_t accumulatedTime = 0;
252 for (uint32_t i = 0; i < kNumIterations; i++) {
253 bool ret = service->requestWrite(kQueueSize);
254 ASSERT_TRUE(ret);
255 std::chrono::time_point<std::chrono::high_resolution_clock> timeStart =
256 std::chrono::high_resolution_clock::now();
257 /*
258 * The read() method returns true only if the the correct number of bytes
259 * were succesfully read from the queue.
260 */
261 for (uint32_t j = 0; j < numLoops; j++) {
262 ASSERT_TRUE(mFmqInbox->read(data, kPacketSize512));
263 }
264 std::chrono::time_point<std::chrono::high_resolution_clock> timeEnd =
265 std::chrono::high_resolution_clock::now();
266 accumulatedTime += (timeEnd - timeStart).count();
267 }
268
269 accumulatedTime /= (numLoops * kNumIterations);
270 cout << "Average time to read" << kPacketSize512
271 << "bytes: " << accumulatedTime << "ns" << endl;
272 delete[] data;
273}
274
275/*
276 * Measure the average time taken to write 64 bytes into the queue.
277 */
278TEST_F(MQTestClient, BenchMarkMeasureWrite64Bytes) {
279 uint8_t* data = new (std::nothrow) uint8_t[kPacketSize64];
280 ASSERT_TRUE(data != nullptr);
281 uint32_t numLoops = kQueueSize / kPacketSize64;
282 uint64_t accumulatedTime = 0;
283
284 for (uint32_t i = 0; i < kNumIterations; i++) {
285 std::chrono::time_point<std::chrono::high_resolution_clock> timeStart =
286 std::chrono::high_resolution_clock::now();
287 /*
288 * Write until the queue is full and request service to empty the queue.
289 */
290 for (uint32_t j = 0; j < numLoops; j++) {
291 bool result = mFmqOutbox->write(data, kPacketSize64);
292 ASSERT_TRUE(result);
293 }
294
295 std::chrono::time_point<std::chrono::high_resolution_clock> timeEnd =
296 std::chrono::high_resolution_clock::now();
297 accumulatedTime += (timeEnd - timeStart).count();
298
299 bool ret = service->requestRead(kQueueSize);
300 ASSERT_TRUE(ret);
301 }
302
303 accumulatedTime /= (numLoops * kNumIterations);
304 cout << "Average time to write " << kPacketSize64
305 << "bytes: " << accumulatedTime << "ns" << endl;
306 delete[] data;
307}
308
309/*
310 * Measure the average time taken to write 128 bytes into the queue.
311 */
312TEST_F(MQTestClient, BenchMarkMeasureWrite128Bytes) {
313 uint8_t* data = new (std::nothrow) uint8_t[kPacketSize128];
314 ASSERT_TRUE(data != nullptr);
315 uint32_t numLoops = kQueueSize / kPacketSize128;
316 uint64_t accumulatedTime = 0;
317
318 for (uint32_t i = 0; i < kNumIterations; i++) {
319 std::chrono::time_point<std::chrono::high_resolution_clock> timeStart =
320 std::chrono::high_resolution_clock::now();
321 /*
322 * Write until the queue is full and request service to empty the queue.
323 */
324 for (uint32_t j = 0; j < numLoops; j++) {
325 ASSERT_TRUE(mFmqOutbox->write(data, kPacketSize128));
326 }
327
328 std::chrono::time_point<std::chrono::high_resolution_clock> timeEnd =
329 std::chrono::high_resolution_clock::now();
330 accumulatedTime += (timeEnd - timeStart).count();
331
332 bool ret = service->requestRead(kQueueSize);
333 ASSERT_TRUE(ret);
334 }
335
336 accumulatedTime /= (numLoops * kNumIterations);
337 cout << "Average time to write " << kPacketSize128
338 << "bytes: " << accumulatedTime << "ns" << endl;
339 delete[] data;
340}
341
342/*
343 * Measure the average time taken to write 256 bytes into the queue.
344 */
345TEST_F(MQTestClient, BenchMarkMeasureWrite256Bytes) {
346 uint8_t* data = new (std::nothrow) uint8_t[kPacketSize256];
347 ASSERT_TRUE(data != nullptr);
348 uint32_t numLoops = kQueueSize / kPacketSize256;
349 uint64_t accumulatedTime = 0;
350
351 for (uint32_t i = 0; i < kNumIterations; i++) {
352 std::chrono::time_point<std::chrono::high_resolution_clock> timeStart =
353 std::chrono::high_resolution_clock::now();
354 /*
355 * Write until the queue is full and request service to empty the queue.
356 */
357 for (uint32_t j = 0; j < numLoops; j++) {
358 ASSERT_TRUE(mFmqOutbox->write(data, kPacketSize256));
359 }
360 std::chrono::time_point<std::chrono::high_resolution_clock> timeEnd =
361 std::chrono::high_resolution_clock::now();
362 accumulatedTime += (timeEnd - timeStart).count();
363
364 bool ret = service->requestRead(kQueueSize);
365 ASSERT_TRUE(ret);
366 }
367
368 accumulatedTime /= (numLoops * kNumIterations);
369 cout << "Average time to write " << kPacketSize256
370 << "bytes: " << accumulatedTime << "ns" << endl;
371 delete[] data;
372}
373
374/*
375 * Measure the average time taken to write 512 bytes into the queue.
376 */
377TEST_F(MQTestClient, BenchMarkMeasureWrite512Bytes) {
378 uint8_t* data = new (std::nothrow) uint8_t[kPacketSize512];
379 ASSERT_TRUE(data != nullptr);
380 uint32_t numLoops = kQueueSize / kPacketSize512;
381 uint64_t accumulatedTime = 0;
382
383 for (uint32_t i = 0; i < kNumIterations; i++) {
384 std::chrono::time_point<std::chrono::high_resolution_clock> timeStart =
385 std::chrono::high_resolution_clock::now();
386
387 /*
388 * Write until the queue is full and request service to empty the queue.
389 * The write() method returns true only if the specified number of bytes
390 * were succesfully written.
391 */
392 for (uint32_t j = 0; j < numLoops; j++) {
393 ASSERT_TRUE(mFmqOutbox->write(data, kPacketSize512));
394 }
395
396 std::chrono::time_point<std::chrono::high_resolution_clock> timeEnd =
397 std::chrono::high_resolution_clock::now();
398 accumulatedTime += (timeEnd - timeStart).count();
399
400 bool ret = service->requestRead(kQueueSize);
401 ASSERT_TRUE(ret);
402 }
403
404 accumulatedTime /= (numLoops * kNumIterations);
405 cout << "Average time to write " << kPacketSize512
406 << "bytes: " << accumulatedTime << "ns" << endl;
407 delete[] data;
408}
409
410/*
411 * Service continuously writes a packet of 64 bytes into the client's inbox
412 * queue
413 * of size 16K. Client keeps reading from the inbox queue. The average write to
414 * read delay is calculated.
415 */
416TEST_F(MQTestClient, BenchMarkMeasureServiceWriteClientRead) {
417 uint8_t* data = new (std::nothrow) uint8_t[kPacketSize64];
418 ASSERT_TRUE(data != nullptr);
419 /*
420 * This method causes the service to create a thread which writes
421 * into the mFmqInbox queue kNumIterations packets.
422 */
423 service->benchmarkServiceWriteClientRead(kNumIterations);
424 android::hardware::hidl_vec<int64_t> clientRcvTimeArray;
425 clientRcvTimeArray.resize(kNumIterations);
426 for (uint32_t i = 0; i < kNumIterations; i++) {
427 do {
428 clientRcvTimeArray[i] =
429 std::chrono::high_resolution_clock::now().time_since_epoch().count();
430 } while (mFmqInbox->read(data, kPacketSize64) == 0);
431 }
432 service->sendTimeData(clientRcvTimeArray);
433 delete[] data;
434}