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