msgq_benchmark_client.cpp 15 KB

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