OLD | NEW |
| (Empty) |
1 // Copyright 2016 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 wait sets via the C API. | |
6 | |
7 #include <mojo/system/wait_set.h> | |
8 | |
9 #include <assert.h> | |
10 #include <mojo/macros.h> | |
11 #include <mojo/result.h> | |
12 #include <mojo/system/handle.h> | |
13 #include <mojo/system/message_pipe.h> | |
14 #include <stdint.h> | |
15 #include <stdio.h> | |
16 | |
17 #include <atomic> | |
18 #include <thread> | |
19 #include <vector> | |
20 | |
21 #include "gtest/gtest.h" | |
22 #include "mojo/public/c/tests/system/perftest_utils.h" | |
23 #include "mojo/public/cpp/test_support/test_support.h" | |
24 | |
25 namespace { | |
26 | |
27 // Creates a wait set, creates a bunch of message pipes, and populates the wait | |
28 // set with entries. There will be |num_entries| entries; the |i|-th entry will | |
29 // be given cookie |i| and will be watching for readability on the message pipe | |
30 // endpoint |h0s->at(i)| whose corresponding endpoint is |h1s->at(i)|. | |
31 void CreateAndPopulateWaitSet(unsigned num_entries, | |
32 MojoHandle* wait_set, | |
33 std::vector<MojoHandle>* h0s, | |
34 std::vector<MojoHandle>* h1s) { | |
35 MojoResult result = MojoCreateWaitSet(nullptr, wait_set); | |
36 MOJO_ALLOW_UNUSED_LOCAL(result); | |
37 assert(result == MOJO_RESULT_OK); | |
38 | |
39 assert(h0s->empty()); | |
40 h0s->resize(num_entries); | |
41 assert(h1s->empty()); | |
42 h1s->resize(num_entries); | |
43 | |
44 for (unsigned i = 0; i < num_entries; i++) { | |
45 result = MojoCreateMessagePipe(nullptr, &h0s->at(i), &h1s->at(i)); | |
46 assert(result == MOJO_RESULT_OK); | |
47 | |
48 result = MojoWaitSetAdd(*wait_set, h0s->at(i), MOJO_HANDLE_SIGNAL_READABLE, | |
49 static_cast<uint64_t>(i), nullptr); | |
50 assert(result == MOJO_RESULT_OK); | |
51 } | |
52 } | |
53 | |
54 void Close(MojoHandle h) { | |
55 MojoResult result = MojoClose(h); | |
56 MOJO_ALLOW_UNUSED_LOCAL(result); | |
57 assert(result == MOJO_RESULT_OK); | |
58 } | |
59 | |
60 void DoWaitSetPretriggeredWaitTest(unsigned num_entries) { | |
61 MojoHandle wait_set = MOJO_HANDLE_INVALID; | |
62 std::vector<MojoHandle> h0s; | |
63 std::vector<MojoHandle> h1s; | |
64 CreateAndPopulateWaitSet(num_entries, &wait_set, &h0s, &h1s); | |
65 | |
66 char sub_test_name[100]; | |
67 sprintf(sub_test_name, "%uentries", num_entries); | |
68 // We'll write to |h1s[n % num_entries]|. | |
69 uint64_t n = 0; | |
70 mojo::test::IterateAndReportPerf( | |
71 "WaitSet_PretriggeredWait", sub_test_name, | |
72 [num_entries, wait_set, &h0s, &h1s, &n]() { | |
73 MojoResult result = | |
74 MojoWriteMessage(h1s[n % num_entries], nullptr, 0, nullptr, 0, | |
75 MOJO_WRITE_MESSAGE_FLAG_NONE); | |
76 MOJO_ALLOW_UNUSED_LOCAL(result); | |
77 assert(result == MOJO_RESULT_OK); | |
78 | |
79 uint32_t num_results = 4; | |
80 MojoWaitSetResult results[4]; // Note: Don't initialize |results[]|. | |
81 result = MojoWaitSetWait(wait_set, static_cast<MojoDeadline>(1000), | |
82 &num_results, results, nullptr); | |
83 assert(result == MOJO_RESULT_OK); | |
84 assert(num_results == 1u); | |
85 assert(results[0].cookie == n % num_entries); | |
86 | |
87 result = | |
88 MojoReadMessage(h0s[results[0].cookie], nullptr, nullptr, nullptr, | |
89 nullptr, MOJO_READ_MESSAGE_FLAG_MAY_DISCARD); | |
90 assert(result == MOJO_RESULT_OK); | |
91 | |
92 n++; | |
93 }); | |
94 | |
95 for (auto h : h0s) | |
96 Close(h); | |
97 for (auto h : h1s) | |
98 Close(h); | |
99 Close(wait_set); | |
100 } | |
101 | |
102 TEST(WaitSetPerftest, PretriggeredWait) { | |
103 DoWaitSetPretriggeredWaitTest(10u); | |
104 DoWaitSetPretriggeredWaitTest(100u); | |
105 DoWaitSetPretriggeredWaitTest(1000u); | |
106 DoWaitSetPretriggeredWaitTest(10000u); | |
107 } | |
108 | |
109 void DoWaitSetThreadedWaitTest(unsigned num_entries) { | |
110 MojoHandle wait_set = MOJO_HANDLE_INVALID; | |
111 std::vector<MojoHandle> h0s; | |
112 std::vector<MojoHandle> h1s; | |
113 CreateAndPopulateWaitSet(num_entries, &wait_set, &h0s, &h1s); | |
114 | |
115 std::atomic<bool> done(false); | |
116 // Number of outstanding message writes. We don't want the writer/waker thread | |
117 // to get far ahead of the reader/waiter (main) thread. | |
118 // TODO(vtl): Maybe also parametrize these tests based on the number of | |
119 // outstanding writes? | |
120 std::atomic<unsigned> outstanding(0u); | |
121 | |
122 std::thread writer_thread([num_entries, &h1s, &done, &outstanding]() { | |
123 for (unsigned n = 0u; !done.load(); n = (n + 13u) % num_entries) { | |
124 while (outstanding.load() > 5u) { | |
125 // Assume a zero sleep is a yield. | |
126 mojo::test::Sleep(static_cast<MojoTimeTicks>(0)); | |
127 if (done.load()) | |
128 return; | |
129 } | |
130 | |
131 outstanding.fetch_add(1u); | |
132 MojoResult result = MojoWriteMessage(h1s[n], nullptr, 0, nullptr, 0, | |
133 MOJO_WRITE_MESSAGE_FLAG_NONE); | |
134 MOJO_ALLOW_UNUSED_LOCAL(result); | |
135 assert(result == MOJO_RESULT_OK); | |
136 } | |
137 }); | |
138 | |
139 char sub_test_name[100]; | |
140 sprintf(sub_test_name, "%uentries", num_entries); | |
141 // TODO(vtl): This reports iterations (wake-ups). Possibly, we should also | |
142 // measure the number of results handled (total or per second). | |
143 mojo::test::IterateAndReportPerf( | |
144 "WaitSet_ThreadedWait", sub_test_name, | |
145 [num_entries, wait_set, &h0s, &outstanding]() { | |
146 uint32_t num_results = 10; | |
147 MojoWaitSetResult results[10]; // Note: Don't initialize |results[]|. | |
148 MojoResult result = MojoWaitSetWait(wait_set, MOJO_DEADLINE_INDEFINITE, | |
149 &num_results, results, nullptr); | |
150 MOJO_ALLOW_UNUSED_LOCAL(result); | |
151 assert(result == MOJO_RESULT_OK); | |
152 assert(num_results >= 1u); | |
153 for (uint32_t i = 0u; i < num_results; i++) { | |
154 assert(results[i].cookie < num_entries); | |
155 result = | |
156 MojoReadMessage(h0s[results[i].cookie], nullptr, nullptr, nullptr, | |
157 nullptr, MOJO_READ_MESSAGE_FLAG_MAY_DISCARD); | |
158 assert(result == MOJO_RESULT_OK); | |
159 outstanding.fetch_sub(1u); | |
160 } | |
161 }); | |
162 done.store(true); | |
163 writer_thread.join(); | |
164 | |
165 for (auto h : h0s) | |
166 Close(h); | |
167 for (auto h : h1s) | |
168 Close(h); | |
169 Close(wait_set); | |
170 } | |
171 | |
172 TEST(WaitSetPerftest, ThreadedWait) { | |
173 DoWaitSetThreadedWaitTest(10u); | |
174 DoWaitSetThreadedWaitTest(100u); | |
175 DoWaitSetThreadedWaitTest(1000u); | |
176 DoWaitSetThreadedWaitTest(10000u); | |
177 } | |
178 | |
179 } // namespace | |
OLD | NEW |