OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 // This tests the performance of the C API. | |
6 | |
7 #include "mojo/public/c/system/core.h" | |
8 | |
9 #include <assert.h> | |
10 #include <stddef.h> | |
11 #include <stdint.h> | |
12 #include <stdio.h> | |
13 | |
14 #include "mojo/public/cpp/system/macros.h" | |
15 #include "mojo/public/tests/test_support.h" | |
16 #include "mojo/public/tests/test_utils.h" | |
17 #include "testing/gtest/include/gtest/gtest.h" | |
18 | |
19 // TODO(vtl): (here and below) crbug.com/342893 | |
20 #if !defined(WIN32) | |
21 #include <time.h> | |
22 #include "mojo/public/cpp/utility/thread.h" | |
23 #endif // !defined(WIN32) | |
24 | |
25 namespace { | |
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 | |
116 class CorePerftest : public testing::Test { | |
117 public: | |
118 CorePerftest() : buffer_(NULL), num_bytes_(0) {} | |
119 virtual ~CorePerftest() {} | |
120 | |
121 static void NoOp(void* /*closure*/) { | |
122 } | |
123 | |
124 static void MessagePipe_CreateAndClose(void* closure) { | |
125 CorePerftest* self = static_cast<CorePerftest*>(closure); | |
126 MojoResult result MOJO_ALLOW_UNUSED; | |
127 result = MojoCreateMessagePipe(&self->h0_, &self->h1_); | |
128 assert(result == MOJO_RESULT_OK); | |
129 result = MojoClose(self->h0_); | |
130 assert(result == MOJO_RESULT_OK); | |
131 result = MojoClose(self->h1_); | |
132 assert(result == MOJO_RESULT_OK); | |
133 } | |
134 | |
135 static void MessagePipe_WriteAndRead(void* closure) { | |
136 CorePerftest* self = static_cast<CorePerftest*>(closure); | |
137 MojoResult result MOJO_ALLOW_UNUSED; | |
138 result = MojoWriteMessage(self->h0_, | |
139 self->buffer_, self->num_bytes_, | |
140 NULL, 0, | |
141 MOJO_WRITE_MESSAGE_FLAG_NONE); | |
142 assert(result == MOJO_RESULT_OK); | |
143 uint32_t read_bytes = self->num_bytes_; | |
144 result = MojoReadMessage(self->h1_, | |
145 self->buffer_, &read_bytes, | |
146 NULL, NULL, | |
147 MOJO_READ_MESSAGE_FLAG_NONE); | |
148 assert(result == MOJO_RESULT_OK); | |
149 } | |
150 | |
151 static void MessagePipe_EmptyRead(void* closure) { | |
152 CorePerftest* self = static_cast<CorePerftest*>(closure); | |
153 MojoResult result MOJO_ALLOW_UNUSED; | |
154 result = MojoReadMessage(self->h0_, | |
155 NULL, NULL, | |
156 NULL, NULL, | |
157 MOJO_READ_MESSAGE_FLAG_MAY_DISCARD); | |
158 assert(result == MOJO_RESULT_SHOULD_WAIT); | |
159 } | |
160 | |
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 | |
241 MojoHandle h0_; | |
242 MojoHandle h1_; | |
243 | |
244 void* buffer_; | |
245 uint32_t num_bytes_; | |
246 | |
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 | |
260 MOJO_DISALLOW_COPY_AND_ASSIGN(CorePerftest); | |
261 }; | |
262 | |
263 // A no-op test so we can compare performance. | |
264 TEST_F(CorePerftest, NoOp) { | |
265 mojo::test::IterateAndReportPerf("NoOp", &CorePerftest::NoOp, this); | |
266 } | |
267 | |
268 TEST_F(CorePerftest, MessagePipe_CreateAndClose) { | |
269 mojo::test::IterateAndReportPerf("MessagePipe_CreateAndClose", | |
270 &CorePerftest::MessagePipe_CreateAndClose, | |
271 this); | |
272 } | |
273 | |
274 TEST_F(CorePerftest, MessagePipe_WriteAndRead) { | |
275 MojoResult result MOJO_ALLOW_UNUSED; | |
276 result = MojoCreateMessagePipe(&h0_, &h1_); | |
277 assert(result == MOJO_RESULT_OK); | |
278 char buffer[10000] = { 0 }; | |
279 buffer_ = buffer; | |
280 num_bytes_ = 10u; | |
281 mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead_10bytes", | |
282 &CorePerftest::MessagePipe_WriteAndRead, | |
283 this); | |
284 num_bytes_ = 100u; | |
285 mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead_100bytes", | |
286 &CorePerftest::MessagePipe_WriteAndRead, | |
287 this); | |
288 num_bytes_ = 1000u; | |
289 mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead_1000bytes", | |
290 &CorePerftest::MessagePipe_WriteAndRead, | |
291 this); | |
292 num_bytes_ = 10000u; | |
293 mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead_10000bytes", | |
294 &CorePerftest::MessagePipe_WriteAndRead, | |
295 this); | |
296 result = MojoClose(h0_); | |
297 assert(result == MOJO_RESULT_OK); | |
298 result = MojoClose(h1_); | |
299 assert(result == MOJO_RESULT_OK); | |
300 } | |
301 | |
302 TEST_F(CorePerftest, MessagePipe_EmptyRead) { | |
303 MojoResult result MOJO_ALLOW_UNUSED; | |
304 result = MojoCreateMessagePipe(&h0_, &h1_); | |
305 assert(result == MOJO_RESULT_OK); | |
306 mojo::test::IterateAndReportPerf("MessagePipe_EmptyRead", | |
307 &CorePerftest::MessagePipe_EmptyRead, | |
308 this); | |
309 result = MojoClose(h0_); | |
310 assert(result == MOJO_RESULT_OK); | |
311 result = MojoClose(h1_); | |
312 assert(result == MOJO_RESULT_OK); | |
313 } | |
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 | |
337 } // namespace | |
OLD | NEW |