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