1 /*
2 * Copyright (C) 2017 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 "BenchmarkMsgQ.h"
18 #include <iostream>
19 #include <thread>
20 #include <fmq/MessageQueue.h>
21
22 namespace android {
23 namespace hardware {
24 namespace tests {
25 namespace msgq {
26 namespace V1_0 {
27 namespace implementation {
28
29 // Methods from ::android::hardware::tests::msgq::V1_0::IBenchmarkMsgQ follow.
configureClientInboxSyncReadWrite(configureClientInboxSyncReadWrite_cb _hidl_cb)30 Return<void> BenchmarkMsgQ::configureClientInboxSyncReadWrite(
31 configureClientInboxSyncReadWrite_cb _hidl_cb) {
32 static constexpr size_t kNumElementsInQueue = 16 * 1024;
33 mFmqOutbox = new (std::nothrow) android::hardware::MessageQueue<uint8_t,
34 kSynchronizedReadWrite>(kNumElementsInQueue);
35 if (mFmqOutbox == nullptr) {
36 _hidl_cb(false /* ret */, android::hardware::MQDescriptorSync<uint8_t>(
37 std::vector<android::hardware::GrantorDescriptor>(),
38 nullptr /* nhandle */, 0 /* size */));
39 } else {
40 _hidl_cb(true /* ret */, *mFmqOutbox->getDesc());
41 }
42
43 return Void();
44 }
45
configureClientOutboxSyncReadWrite(configureClientOutboxSyncReadWrite_cb _hidl_cb)46 Return<void> BenchmarkMsgQ::configureClientOutboxSyncReadWrite(
47 configureClientOutboxSyncReadWrite_cb _hidl_cb) {
48 static constexpr size_t kNumElementsInQueue = 16 * 1024;
49 mFmqInbox = new (std::nothrow) android::hardware::MessageQueue<uint8_t,
50 kSynchronizedReadWrite>(kNumElementsInQueue);
51 if ((mFmqInbox == nullptr) || (mFmqInbox->isValid() == false)) {
52 _hidl_cb(false /* ret */, android::hardware::MQDescriptorSync<uint8_t>(
53 std::vector<android::hardware::GrantorDescriptor>(),
54 nullptr /* nhandle */, 0 /* size */));
55 } else {
56 _hidl_cb(true /* ret */, *mFmqInbox->getDesc());
57 }
58
59 return Void();
60 }
61
requestWrite(int32_t count)62 Return<bool> BenchmarkMsgQ::requestWrite(int32_t count) {
63 uint8_t* data = new (std::nothrow) uint8_t[count];
64 for (int i = 0; i < count; i++) {
65 data[i] = i;
66 }
67 bool result = mFmqOutbox->write(data, count);
68 delete[] data;
69 return result;
70 }
71
requestRead(int32_t count)72 Return<bool> BenchmarkMsgQ::requestRead(int32_t count) {
73 uint8_t* data = new (std::nothrow) uint8_t[count];
74 bool result = mFmqInbox->read(data, count);
75 delete[] data;
76 return result;
77 }
78
benchmarkPingPong(uint32_t numIter)79 Return<void> BenchmarkMsgQ::benchmarkPingPong(uint32_t numIter) {
80 std::thread(QueuePairReadWrite<kSynchronizedReadWrite>, mFmqInbox,
81 mFmqOutbox, numIter)
82 .detach();
83 return Void();
84 }
85
benchmarkServiceWriteClientRead(uint32_t numIter)86 Return<void> BenchmarkMsgQ::benchmarkServiceWriteClientRead(uint32_t numIter) {
87 if (mTimeData) delete[] mTimeData;
88 mTimeData = new (std::nothrow) int64_t[numIter];
89 std::thread(QueueWriter<kSynchronizedReadWrite>, mFmqOutbox,
90 mTimeData, numIter).detach();
91 return Void();
92 }
93
sendTimeData(const hidl_vec<int64_t> & clientRcvTimeArray)94 Return<void> BenchmarkMsgQ::sendTimeData(const hidl_vec<int64_t>& clientRcvTimeArray) {
95 int64_t accumulatedTime = 0;
96
97 for (uint32_t i = 0; i < clientRcvTimeArray.size(); i++) {
98 std::chrono::time_point<std::chrono::high_resolution_clock>
99 clientRcvTime((std::chrono::high_resolution_clock::duration(
100 clientRcvTimeArray[i])));
101 std::chrono::time_point<std::chrono::high_resolution_clock>serverSendTime(
102 (std::chrono::high_resolution_clock::duration(mTimeData[i])));
103 accumulatedTime += static_cast<int64_t>(
104 std::chrono::duration_cast<std::chrono::nanoseconds>(clientRcvTime -
105 serverSendTime).count());
106 }
107
108 accumulatedTime /= clientRcvTimeArray.size();
109 std::cout << "Average service to client write to read delay::"
110 << accumulatedTime << "ns" << std::endl;
111 return Void();
112 }
113
114 template <MQFlavor flavor>
QueueWriter(android::hardware::MessageQueue<uint8_t,flavor> * mFmqOutbox,int64_t * mTimeData,uint32_t numIter)115 void BenchmarkMsgQ::QueueWriter(android::hardware::MessageQueue<uint8_t, flavor>* mFmqOutbox,
116 int64_t* mTimeData,
117 uint32_t numIter) {
118 uint8_t data[kPacketSize64];
119 uint32_t numWrites = 0;
120
121 while (numWrites < numIter) {
122 do {
123 mTimeData[numWrites] =
124 std::chrono::high_resolution_clock::now().time_since_epoch().count();
125 } while (mFmqOutbox->write(data, kPacketSize64) == false);
126 numWrites++;
127 }
128 }
129
130 template <MQFlavor flavor>
QueuePairReadWrite(android::hardware::MessageQueue<uint8_t,flavor> * mFmqInbox,android::hardware::MessageQueue<uint8_t,flavor> * mFmqOutbox,uint32_t numIter)131 void BenchmarkMsgQ::QueuePairReadWrite(
132 android::hardware::MessageQueue<uint8_t, flavor>* mFmqInbox,
133 android::hardware::MessageQueue<uint8_t, flavor>* mFmqOutbox,
134 uint32_t numIter) {
135 uint8_t data[kPacketSize64];
136 uint32_t numRoundTrips = 0;
137
138 while (numRoundTrips < numIter) {
139 while (mFmqInbox->read(data, kPacketSize64) == false)
140 ;
141 while (mFmqOutbox->write(data, kPacketSize64) == false)
142 ;
143 numRoundTrips++;
144 }
145 }
146
HIDL_FETCH_IBenchmarkMsgQ(const char *)147 IBenchmarkMsgQ* HIDL_FETCH_IBenchmarkMsgQ(const char* /* name */) {
148 return new BenchmarkMsgQ();
149 }
150
151 } // namespace implementation
152 } // namespace V1_0
153 } // namespace msgq
154 } // namespace tests
155 } // namespace hardware
156 } // namespace android
157