OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // This tests the performance of the C API. | 5 // This tests the performance of the C API. |
6 | 6 |
7 #include "mojo/public/system/core.h" | 7 #include "mojo/public/system/core.h" |
8 | 8 |
9 #include <assert.h> | 9 #include <assert.h> |
| 10 #include <stddef.h> |
| 11 #include <stdint.h> |
| 12 #include <stdio.h> |
10 | 13 |
11 #include "mojo/public/system/macros.h" | 14 #include "mojo/public/system/macros.h" |
| 15 #include "mojo/public/tests/test_support.h" |
12 #include "mojo/public/tests/test_utils.h" | 16 #include "mojo/public/tests/test_utils.h" |
13 #include "testing/gtest/include/gtest/gtest.h" | 17 #include "testing/gtest/include/gtest/gtest.h" |
14 | 18 |
| 19 // TODO(vtl): (here and below) crbug.com/342893 |
| 20 #if !defined(WIN32) |
| 21 #include <time.h> |
| 22 #include "mojo/public/utility/thread.h" |
| 23 #endif // !defined(WIN32) |
| 24 |
15 namespace { | 25 namespace { |
16 | 26 |
| 27 #if !defined(WIN32) |
| 28 class MessagePipeWriterThread : public mojo::Thread { |
| 29 public: |
| 30 MessagePipeWriterThread(MojoHandle handle, uint32_t num_bytes) |
| 31 : handle_(handle), |
| 32 num_bytes_(num_bytes), |
| 33 num_writes_(0) {} |
| 34 virtual ~MessagePipeWriterThread() {} |
| 35 |
| 36 virtual void Run() MOJO_OVERRIDE { |
| 37 char buffer[10000]; |
| 38 assert(num_bytes_ <= sizeof(buffer)); |
| 39 |
| 40 // TODO(vtl): Should I throttle somehow? |
| 41 for (;;) { |
| 42 MojoResult result = MojoWriteMessage(handle_, buffer, num_bytes_, NULL, 0, |
| 43 MOJO_WRITE_MESSAGE_FLAG_NONE); |
| 44 if (result == MOJO_RESULT_OK) { |
| 45 num_writes_++; |
| 46 continue; |
| 47 } |
| 48 |
| 49 // We failed to write. |
| 50 // Either |handle_| or its peer was closed. |
| 51 assert(result == MOJO_RESULT_INVALID_ARGUMENT || |
| 52 result == MOJO_RESULT_FAILED_PRECONDITION); |
| 53 break; |
| 54 } |
| 55 } |
| 56 |
| 57 // Use only after joining the thread. |
| 58 int64_t num_writes() const { return num_writes_; } |
| 59 |
| 60 private: |
| 61 const MojoHandle handle_; |
| 62 const uint32_t num_bytes_; |
| 63 int64_t num_writes_; |
| 64 |
| 65 MOJO_DISALLOW_COPY_AND_ASSIGN(MessagePipeWriterThread); |
| 66 }; |
| 67 |
| 68 class MessagePipeReaderThread : public mojo::Thread { |
| 69 public: |
| 70 explicit MessagePipeReaderThread(MojoHandle handle) |
| 71 : handle_(handle), |
| 72 num_reads_(0) { |
| 73 } |
| 74 virtual ~MessagePipeReaderThread() {} |
| 75 |
| 76 virtual void Run() MOJO_OVERRIDE { |
| 77 char buffer[10000]; |
| 78 |
| 79 for (;;) { |
| 80 uint32_t num_bytes = static_cast<uint32_t>(sizeof(buffer)); |
| 81 MojoResult result = MojoReadMessage(handle_, buffer, &num_bytes, NULL, |
| 82 NULL, MOJO_READ_MESSAGE_FLAG_NONE); |
| 83 if (result == MOJO_RESULT_OK) { |
| 84 num_reads_++; |
| 85 continue; |
| 86 } |
| 87 |
| 88 if (result == MOJO_RESULT_SHOULD_WAIT) { |
| 89 result = MojoWait(handle_, MOJO_WAIT_FLAG_READABLE, |
| 90 MOJO_DEADLINE_INDEFINITE); |
| 91 if (result == MOJO_RESULT_OK) { |
| 92 // Go to the top of the loop to read again. |
| 93 continue; |
| 94 } |
| 95 } |
| 96 |
| 97 // We failed to read and possibly failed to wait. |
| 98 // Either |handle_| or its peer was closed. |
| 99 assert(result == MOJO_RESULT_INVALID_ARGUMENT || |
| 100 result == MOJO_RESULT_FAILED_PRECONDITION); |
| 101 break; |
| 102 } |
| 103 } |
| 104 |
| 105 // Use only after joining the thread. |
| 106 int64_t num_reads() const { return num_reads_; } |
| 107 |
| 108 private: |
| 109 const MojoHandle handle_; |
| 110 int64_t num_reads_; |
| 111 |
| 112 MOJO_DISALLOW_COPY_AND_ASSIGN(MessagePipeReaderThread); |
| 113 }; |
| 114 #endif // !defined(WIN32) |
| 115 |
17 class CorePerftest : public testing::Test { | 116 class CorePerftest : public testing::Test { |
18 public: | 117 public: |
19 CorePerftest() : buffer_(NULL), num_bytes_(0) {} | 118 CorePerftest() : buffer_(NULL), num_bytes_(0) {} |
20 virtual ~CorePerftest() {} | 119 virtual ~CorePerftest() {} |
21 | 120 |
22 static void NoOp(void* /*closure*/) { | 121 static void NoOp(void* /*closure*/) { |
23 } | 122 } |
24 | 123 |
25 static void MessagePipe_CreateAndClose(void* closure) { | 124 static void MessagePipe_CreateAndClose(void* closure) { |
26 CorePerftest* self = static_cast<CorePerftest*>(closure); | 125 CorePerftest* self = static_cast<CorePerftest*>(closure); |
(...skipping 26 matching lines...) Expand all Loading... |
53 CorePerftest* self = static_cast<CorePerftest*>(closure); | 152 CorePerftest* self = static_cast<CorePerftest*>(closure); |
54 MojoResult result MOJO_ALLOW_UNUSED; | 153 MojoResult result MOJO_ALLOW_UNUSED; |
55 result = MojoReadMessage(self->h0_, | 154 result = MojoReadMessage(self->h0_, |
56 NULL, NULL, | 155 NULL, NULL, |
57 NULL, NULL, | 156 NULL, NULL, |
58 MOJO_READ_MESSAGE_FLAG_MAY_DISCARD); | 157 MOJO_READ_MESSAGE_FLAG_MAY_DISCARD); |
59 assert(result == MOJO_RESULT_SHOULD_WAIT); | 158 assert(result == MOJO_RESULT_SHOULD_WAIT); |
60 } | 159 } |
61 | 160 |
62 protected: | 161 protected: |
| 162 #if !defined(WIN32) |
| 163 void DoMessagePipeThreadedTest(unsigned num_writers, |
| 164 unsigned num_readers, |
| 165 uint32_t num_bytes) { |
| 166 static const int64_t kPerftestTimeMicroseconds = 3 * 1000000; |
| 167 |
| 168 assert(num_writers > 0); |
| 169 assert(num_readers > 0); |
| 170 |
| 171 MojoResult result MOJO_ALLOW_UNUSED; |
| 172 result = MojoCreateMessagePipe(&h0_, &h1_); |
| 173 assert(result == MOJO_RESULT_OK); |
| 174 |
| 175 std::vector<MessagePipeWriterThread*> writers; |
| 176 for (unsigned i = 0; i < num_writers; i++) |
| 177 writers.push_back(new MessagePipeWriterThread(h0_, num_bytes)); |
| 178 |
| 179 std::vector<MessagePipeReaderThread*> readers; |
| 180 for (unsigned i = 0; i < num_readers; i++) |
| 181 readers.push_back(new MessagePipeReaderThread(h1_)); |
| 182 |
| 183 // Start time here, just before we fire off the threads. |
| 184 const MojoTimeTicks start_time = MojoGetTimeTicksNow(); |
| 185 |
| 186 // Interleave the starts. |
| 187 for (unsigned i = 0; i < num_writers || i < num_readers; i++) { |
| 188 if (i < num_writers) |
| 189 writers[i]->Start(); |
| 190 if (i < num_readers) |
| 191 readers[i]->Start(); |
| 192 } |
| 193 |
| 194 Sleep(kPerftestTimeMicroseconds); |
| 195 |
| 196 // Close both handles to make writers and readers stop immediately. |
| 197 result = MojoClose(h0_); |
| 198 assert(result == MOJO_RESULT_OK); |
| 199 result = MojoClose(h1_); |
| 200 assert(result == MOJO_RESULT_OK); |
| 201 |
| 202 // Join everything. |
| 203 for (unsigned i = 0; i < num_writers; i++) |
| 204 writers[i]->Join(); |
| 205 for (unsigned i = 0; i < num_readers; i++) |
| 206 readers[i]->Join(); |
| 207 |
| 208 // Stop time here. |
| 209 MojoTimeTicks end_time = MojoGetTimeTicksNow(); |
| 210 |
| 211 // Add up write and read counts, and destroy the threads. |
| 212 int64_t num_writes = 0; |
| 213 for (unsigned i = 0; i < num_writers; i++) { |
| 214 num_writes += writers[i]->num_writes(); |
| 215 delete writers[i]; |
| 216 } |
| 217 writers.clear(); |
| 218 int64_t num_reads = 0; |
| 219 for (unsigned i = 0; i < num_readers; i++) { |
| 220 num_reads += readers[i]->num_reads(); |
| 221 delete readers[i]; |
| 222 } |
| 223 readers.clear(); |
| 224 |
| 225 char test_name[200]; |
| 226 sprintf(test_name, "MessagePipe_Threaded_Writes_%uw_%ur_%ubytes", |
| 227 num_writers, num_readers, static_cast<unsigned>(num_bytes)); |
| 228 mojo::test::LogPerfResult(test_name, |
| 229 1000000.0 * static_cast<double>(num_writes) / |
| 230 (end_time - start_time), |
| 231 "writes/second"); |
| 232 sprintf(test_name, "MessagePipe_Threaded_Reads_%uw_%ur_%ubytes", |
| 233 num_writers, num_readers, static_cast<unsigned>(num_bytes)); |
| 234 mojo::test::LogPerfResult(test_name, |
| 235 1000000.0 * static_cast<double>(num_reads) / |
| 236 (end_time - start_time), |
| 237 "reads/second"); |
| 238 } |
| 239 #endif // !defined(WIN32) |
| 240 |
63 MojoHandle h0_; | 241 MojoHandle h0_; |
64 MojoHandle h1_; | 242 MojoHandle h1_; |
65 | 243 |
66 void* buffer_; | 244 void* buffer_; |
67 uint32_t num_bytes_; | 245 uint32_t num_bytes_; |
68 | 246 |
69 private: | 247 private: |
| 248 #if !defined(WIN32) |
| 249 void Sleep(int64_t microseconds) { |
| 250 struct timespec req = { |
| 251 static_cast<time_t>(microseconds / 1000000), // Seconds. |
| 252 static_cast<long>(microseconds % 1000000) * 1000L // Nanoseconds. |
| 253 }; |
| 254 int rv MOJO_ALLOW_UNUSED; |
| 255 rv = nanosleep(&req, NULL); |
| 256 assert(rv == 0); |
| 257 } |
| 258 #endif // !defined(WIN32) |
| 259 |
70 MOJO_DISALLOW_COPY_AND_ASSIGN(CorePerftest); | 260 MOJO_DISALLOW_COPY_AND_ASSIGN(CorePerftest); |
71 }; | 261 }; |
72 | 262 |
73 // A no-op test so we can compare performance. | 263 // A no-op test so we can compare performance. |
74 TEST_F(CorePerftest, NoOp) { | 264 TEST_F(CorePerftest, NoOp) { |
75 mojo::test::IterateAndReportPerf("NoOp", &CorePerftest::NoOp, this); | 265 mojo::test::IterateAndReportPerf("NoOp", &CorePerftest::NoOp, this); |
76 } | 266 } |
77 | 267 |
78 TEST_F(CorePerftest, MessagePipe_CreateAndClose) { | 268 TEST_F(CorePerftest, MessagePipe_CreateAndClose) { |
79 mojo::test::IterateAndReportPerf("MessagePipe_CreateAndClose", | 269 mojo::test::IterateAndReportPerf("MessagePipe_CreateAndClose", |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
115 assert(result == MOJO_RESULT_OK); | 305 assert(result == MOJO_RESULT_OK); |
116 mojo::test::IterateAndReportPerf("MessagePipe_EmptyRead", | 306 mojo::test::IterateAndReportPerf("MessagePipe_EmptyRead", |
117 &CorePerftest::MessagePipe_EmptyRead, | 307 &CorePerftest::MessagePipe_EmptyRead, |
118 this); | 308 this); |
119 result = MojoClose(h0_); | 309 result = MojoClose(h0_); |
120 assert(result == MOJO_RESULT_OK); | 310 assert(result == MOJO_RESULT_OK); |
121 result = MojoClose(h1_); | 311 result = MojoClose(h1_); |
122 assert(result == MOJO_RESULT_OK); | 312 assert(result == MOJO_RESULT_OK); |
123 } | 313 } |
124 | 314 |
| 315 #if !defined(WIN32) |
| 316 TEST_F(CorePerftest, MessagePipe_Threaded) { |
| 317 DoMessagePipeThreadedTest(1u, 1u, 100u); |
| 318 DoMessagePipeThreadedTest(2u, 2u, 100u); |
| 319 DoMessagePipeThreadedTest(3u, 3u, 100u); |
| 320 DoMessagePipeThreadedTest(10u, 10u, 100u); |
| 321 DoMessagePipeThreadedTest(10u, 1u, 100u); |
| 322 DoMessagePipeThreadedTest(1u, 10u, 100u); |
| 323 |
| 324 // For comparison of overhead: |
| 325 DoMessagePipeThreadedTest(1u, 1u, 10u); |
| 326 // 100 was done above. |
| 327 DoMessagePipeThreadedTest(1u, 1u, 1000u); |
| 328 DoMessagePipeThreadedTest(1u, 1u, 10000u); |
| 329 |
| 330 DoMessagePipeThreadedTest(3u, 3u, 10u); |
| 331 // 100 was done above. |
| 332 DoMessagePipeThreadedTest(3u, 3u, 1000u); |
| 333 DoMessagePipeThreadedTest(3u, 3u, 10000u); |
| 334 } |
| 335 #endif // !defined(WIN32) |
| 336 |
125 } // namespace | 337 } // namespace |
OLD | NEW |