1 | /* |
2 | * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. |
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | * |
5 | * This code is free software; you can redistribute it and/or modify it |
6 | * under the terms of the GNU General Public License version 2 only, as |
7 | * published by the Free Software Foundation. |
8 | * |
9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
12 | * version 2 for more details (a copy is included in the LICENSE file that |
13 | * accompanied this code). |
14 | * |
15 | * You should have received a copy of the GNU General Public License version |
16 | * 2 along with this work; if not, write to the Free Software Foundation, |
17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
18 | * |
19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
20 | * or visit www.oracle.com if you need additional information or have any |
21 | * questions. |
22 | * |
23 | */ |
24 | |
25 | #include "precompiled.hpp" |
26 | |
27 | // This test performs mocking of certain JVM functionality. This works by |
28 | // including the source file under test inside an anonymous namespace (which |
29 | // prevents linking conflicts) with the mocked symbols redefined. |
30 | |
31 | // The include list should mirror the one found in the included source file - |
32 | // with the ones that should pick up the mocks removed. Those should be included |
33 | // later after the mocks have been defined. |
34 | |
35 | #include "logging/log.hpp" |
36 | #include "jfr/jfrEvents.hpp" |
37 | #include "jfr/metadata/jfrSerializer.hpp" |
38 | #include "jfr/periodic/jfrOSInterface.hpp" |
39 | #include "jfr/utilities/jfrTime.hpp" |
40 | #include "jfr/utilities/jfrTypes.hpp" |
41 | #include "runtime/os_perf.hpp" |
42 | #include "utilities/globalDefinitions.hpp" |
43 | #include "utilities/growableArray.hpp" |
44 | |
45 | #include "unittest.hpp" |
46 | |
47 | #include <vector> |
48 | #include <list> |
49 | #include <map> |
50 | |
51 | namespace { |
52 | |
53 | class MockFastUnorderedElapsedCounterSource : public ::FastUnorderedElapsedCounterSource { |
54 | public: |
55 | static jlong current_ticks; |
56 | static Type now() { |
57 | return current_ticks; |
58 | } |
59 | static uint64_t nanoseconds(Type value) { |
60 | return value; |
61 | } |
62 | }; |
63 | |
64 | typedef TimeInstant<CounterRepresentation, MockFastUnorderedElapsedCounterSource> MockJfrTicks; |
65 | typedef TimeInterval<CounterRepresentation, MockFastUnorderedElapsedCounterSource> MockJfrTickspan; |
66 | |
67 | class MockJfrCheckpointWriter { |
68 | public: |
69 | traceid current; |
70 | std::map<traceid, std::string> ids; |
71 | |
72 | const JfrCheckpointContext context() const { |
73 | return JfrCheckpointContext(); |
74 | } |
75 | intptr_t reserve(size_t size) { |
76 | return 0; |
77 | } |
78 | void write_key(traceid id) { |
79 | current = id; |
80 | } |
81 | void write(const char* data) { |
82 | ids[current] = data; |
83 | } |
84 | void set_context(const JfrCheckpointContext ctx) { } |
85 | void write_count(u4 nof_entries, jlong offset) { } |
86 | }; |
87 | |
88 | class MockJfrSerializer { |
89 | public: |
90 | static MockJfrSerializer* current; |
91 | |
92 | static bool register_serializer(JfrTypeId id, bool require_safepoint, bool permit_cache, MockJfrSerializer* serializer) { |
93 | current = serializer; |
94 | return true; |
95 | } |
96 | |
97 | virtual void serialize(MockJfrCheckpointWriter& writer) = 0; |
98 | }; |
99 | |
100 | MockJfrSerializer* MockJfrSerializer::current; |
101 | |
102 | class MockEventNetworkUtilization : public ::EventNetworkUtilization |
103 | { |
104 | public: |
105 | std::string iface; |
106 | s8 readRate; |
107 | s8 writeRate; |
108 | static std::vector<MockEventNetworkUtilization> committed; |
109 | MockJfrCheckpointWriter writer; |
110 | |
111 | public: |
112 | MockEventNetworkUtilization(EventStartTime timing=TIMED) : |
113 | ::EventNetworkUtilization(timing) { |
114 | } |
115 | |
116 | void set_networkInterface(traceid new_value) { |
117 | MockJfrSerializer::current->serialize(writer); |
118 | iface = writer.ids[new_value]; |
119 | } |
120 | void set_readRate(s8 new_value) { |
121 | readRate = new_value; |
122 | } |
123 | void set_writeRate(s8 new_value) { |
124 | writeRate = new_value; |
125 | } |
126 | |
127 | void commit() { |
128 | committed.push_back(*this); |
129 | } |
130 | |
131 | void set_starttime(const MockJfrTicks& time) {} |
132 | |
133 | void set_endtime(const MockJfrTicks& time) {} |
134 | |
135 | static const MockEventNetworkUtilization& get_committed(const std::string& name) { |
136 | static MockEventNetworkUtilization placeholder; |
137 | for (std::vector<MockEventNetworkUtilization>::const_iterator i = committed.begin(); |
138 | i != committed.end(); |
139 | ++i) { |
140 | if (name == i->iface) { |
141 | return *i; |
142 | } |
143 | } |
144 | return placeholder; |
145 | } |
146 | }; |
147 | |
148 | std::vector<MockEventNetworkUtilization> MockEventNetworkUtilization::committed; |
149 | |
150 | jlong MockFastUnorderedElapsedCounterSource::current_ticks; |
151 | |
152 | struct MockNetworkInterface { |
153 | std::string name; |
154 | uint64_t bytes_in; |
155 | uint64_t bytes_out; |
156 | MockNetworkInterface(std::string name, uint64_t bytes_in, uint64_t bytes_out) |
157 | : name(name), |
158 | bytes_in(bytes_in), |
159 | bytes_out(bytes_out) { |
160 | |
161 | } |
162 | bool operator==(const MockNetworkInterface& rhs) const { |
163 | return name == rhs.name; |
164 | } |
165 | }; |
166 | |
167 | class NetworkInterface : public ::NetworkInterface { |
168 | public: |
169 | NetworkInterface(const char* name, uint64_t bytes_in, uint64_t bytes_out, NetworkInterface* next) |
170 | : ::NetworkInterface(name, bytes_in, bytes_out, next) { |
171 | } |
172 | NetworkInterface* next(void) const { |
173 | return reinterpret_cast<NetworkInterface*>(::NetworkInterface::next()); |
174 | } |
175 | }; |
176 | |
177 | class MockJfrOSInterface { |
178 | static std::list<MockNetworkInterface> _interfaces; |
179 | |
180 | public: |
181 | MockJfrOSInterface() { |
182 | } |
183 | static int network_utilization(NetworkInterface** network_interfaces) { |
184 | *network_interfaces = NULL; |
185 | for (std::list<MockNetworkInterface>::const_iterator i = _interfaces.begin(); |
186 | i != _interfaces.end(); |
187 | ++i) { |
188 | NetworkInterface* cur = new NetworkInterface(i->name.c_str(), i->bytes_in, i->bytes_out, *network_interfaces); |
189 | *network_interfaces = cur; |
190 | } |
191 | return OS_OK; |
192 | } |
193 | static MockNetworkInterface& add_interface(const std::string& name) { |
194 | MockNetworkInterface iface(name, 0, 0); |
195 | _interfaces.push_back(iface); |
196 | return _interfaces.back(); |
197 | } |
198 | static void remove_interface(const MockNetworkInterface& iface) { |
199 | _interfaces.remove(iface); |
200 | } |
201 | static void clear_interfaces() { |
202 | _interfaces.clear(); |
203 | } |
204 | }; |
205 | |
206 | std::list<MockNetworkInterface> MockJfrOSInterface::_interfaces; |
207 | |
208 | // Reincluding source files in the anonymous namespace unfortunately seems to |
209 | // behave strangely with precompiled headers (only when using gcc though) |
210 | #ifndef DONT_USE_PRECOMPILED_HEADER |
211 | #define |
212 | #endif |
213 | |
214 | #define EventNetworkUtilization MockEventNetworkUtilization |
215 | #define FastUnorderedElapsedCounterSource MockFastUnorderedElapsedCounterSource |
216 | #define JfrOSInterface MockJfrOSInterface |
217 | #define JfrSerializer MockJfrSerializer |
218 | #define JfrCheckpointWriter MockJfrCheckpointWriter |
219 | #define JfrTicks MockJfrTicks |
220 | #define JfrTickspan MockJfrTickspan |
221 | |
222 | #include "jfr/periodic/jfrNetworkUtilization.hpp" |
223 | #include "jfr/periodic/jfrNetworkUtilization.cpp" |
224 | |
225 | #undef EventNetworkUtilization |
226 | #undef FastUnorderedElapsedCounterSource |
227 | #undef JfrOSInterface |
228 | #undef JfrSerializer |
229 | #undef JfrCheckpointWriter |
230 | #undef JfrTicks |
231 | #undef JfrTickspan |
232 | |
233 | } // anonymous namespace |
234 | |
235 | class JfrTestNetworkUtilization : public ::testing::Test { |
236 | protected: |
237 | void SetUp() { |
238 | MockEventNetworkUtilization::committed.clear(); |
239 | MockJfrOSInterface::clear_interfaces(); |
240 | // Ensure that tests are separated in time |
241 | MockFastUnorderedElapsedCounterSource::current_ticks += 1 * NANOSECS_PER_SEC; |
242 | } |
243 | |
244 | void TearDown() { |
245 | JfrNetworkUtilization::destroy(); |
246 | } |
247 | }; |
248 | |
249 | TEST_VM_F(JfrTestNetworkUtilization, RequestFunctionBasic) { |
250 | |
251 | MockNetworkInterface& eth0 = MockJfrOSInterface::add_interface("eth0" ); |
252 | JfrNetworkUtilization::send_events(); |
253 | ASSERT_EQ(0u, MockEventNetworkUtilization::committed.size()); |
254 | |
255 | eth0.bytes_in += 10; |
256 | MockFastUnorderedElapsedCounterSource::current_ticks += 2 * NANOSECS_PER_SEC; |
257 | |
258 | JfrNetworkUtilization::send_events(); |
259 | ASSERT_EQ(1u, MockEventNetworkUtilization::committed.size()); |
260 | MockEventNetworkUtilization& e = MockEventNetworkUtilization::committed[0]; |
261 | EXPECT_EQ(40, e.readRate); |
262 | EXPECT_EQ(0, e.writeRate); |
263 | EXPECT_STREQ("eth0" , e.iface.c_str()); |
264 | } |
265 | |
266 | TEST_VM_F(JfrTestNetworkUtilization, RequestFunctionMultiple) { |
267 | |
268 | MockNetworkInterface& eth0 = MockJfrOSInterface::add_interface("eth0" ); |
269 | MockNetworkInterface& eth1 = MockJfrOSInterface::add_interface("eth1" ); |
270 | MockNetworkInterface& ppp0 = MockJfrOSInterface::add_interface("ppp0" ); |
271 | JfrNetworkUtilization::send_events(); |
272 | ASSERT_EQ(0u, MockEventNetworkUtilization::committed.size()); |
273 | |
274 | eth0.bytes_in += 10; |
275 | eth1.bytes_in += 100; |
276 | ppp0.bytes_out += 50; |
277 | MockFastUnorderedElapsedCounterSource::current_ticks += 2 * NANOSECS_PER_SEC; |
278 | |
279 | JfrNetworkUtilization::send_events(); |
280 | ASSERT_EQ(3u, MockEventNetworkUtilization::committed.size()); |
281 | const MockEventNetworkUtilization& eth0_event = MockEventNetworkUtilization::get_committed("eth0" ); |
282 | const MockEventNetworkUtilization& eth1_event = MockEventNetworkUtilization::get_committed("eth1" ); |
283 | const MockEventNetworkUtilization& ppp0_event = MockEventNetworkUtilization::get_committed("ppp0" ); |
284 | |
285 | EXPECT_EQ(40, eth0_event.readRate); |
286 | EXPECT_EQ(0, eth0_event.writeRate); |
287 | EXPECT_STREQ("eth0" , eth0_event.iface.c_str()); |
288 | |
289 | EXPECT_EQ(400, eth1_event.readRate); |
290 | EXPECT_EQ(0, eth1_event.writeRate); |
291 | EXPECT_STREQ("eth1" , eth1_event.iface.c_str()); |
292 | |
293 | EXPECT_EQ(0, ppp0_event.readRate); |
294 | EXPECT_EQ(200, ppp0_event.writeRate); |
295 | EXPECT_STREQ("ppp0" , ppp0_event.iface.c_str()); |
296 | } |
297 | |
298 | TEST_VM_F(JfrTestNetworkUtilization, InterfaceRemoved) { |
299 | MockNetworkInterface& eth0 = MockJfrOSInterface::add_interface("eth0" ); |
300 | MockNetworkInterface& eth1 = MockJfrOSInterface::add_interface("eth1" ); |
301 | JfrNetworkUtilization::send_events(); |
302 | ASSERT_EQ(0u, MockEventNetworkUtilization::committed.size()); |
303 | |
304 | eth0.bytes_in += 10; |
305 | eth1.bytes_in += 20; |
306 | MockFastUnorderedElapsedCounterSource::current_ticks += 2 * NANOSECS_PER_SEC; |
307 | |
308 | JfrNetworkUtilization::send_events(); |
309 | ASSERT_EQ(2u, MockEventNetworkUtilization::committed.size()); |
310 | const MockEventNetworkUtilization& eth0_event = MockEventNetworkUtilization::get_committed("eth0" ); |
311 | const MockEventNetworkUtilization& eth1_event = MockEventNetworkUtilization::get_committed("eth1" ); |
312 | |
313 | EXPECT_EQ(40, eth0_event.readRate); |
314 | EXPECT_EQ(0, eth0_event.writeRate); |
315 | EXPECT_STREQ("eth0" , eth0_event.iface.c_str()); |
316 | |
317 | EXPECT_EQ(80, eth1_event.readRate); |
318 | EXPECT_EQ(0, eth1_event.writeRate); |
319 | EXPECT_STREQ("eth1" , eth1_event.iface.c_str()); |
320 | |
321 | MockJfrOSInterface::remove_interface(eth0); |
322 | MockEventNetworkUtilization::committed.clear(); |
323 | |
324 | eth1.bytes_in += 10; |
325 | MockFastUnorderedElapsedCounterSource::current_ticks += 2 * NANOSECS_PER_SEC; |
326 | JfrNetworkUtilization::send_events(); |
327 | ASSERT_EQ(1u, MockEventNetworkUtilization::committed.size()); |
328 | const MockEventNetworkUtilization& eth1_event_v2 = MockEventNetworkUtilization::get_committed("eth1" ); |
329 | |
330 | EXPECT_EQ(40, eth1_event_v2.readRate); |
331 | EXPECT_EQ(0, eth1_event_v2.writeRate); |
332 | EXPECT_STREQ("eth1" , eth1_event_v2.iface.c_str()); |
333 | } |
334 | |
335 | TEST_VM_F(JfrTestNetworkUtilization, InterfaceReset) { |
336 | MockNetworkInterface& eth0 = MockJfrOSInterface::add_interface("eth0" ); |
337 | JfrNetworkUtilization::send_events(); |
338 | ASSERT_EQ(0u, MockEventNetworkUtilization::committed.size()); |
339 | |
340 | eth0.bytes_in += 10; |
341 | MockFastUnorderedElapsedCounterSource::current_ticks += 2 * NANOSECS_PER_SEC; |
342 | |
343 | JfrNetworkUtilization::send_events(); |
344 | ASSERT_EQ(1u, MockEventNetworkUtilization::committed.size()); |
345 | const MockEventNetworkUtilization& event = MockEventNetworkUtilization::committed[0]; |
346 | EXPECT_EQ(40, event.readRate); |
347 | EXPECT_EQ(0, event.writeRate); |
348 | EXPECT_STREQ("eth0" , event.iface.c_str()); |
349 | |
350 | eth0.bytes_in = 0; |
351 | MockFastUnorderedElapsedCounterSource::current_ticks += 2 * NANOSECS_PER_SEC; |
352 | MockEventNetworkUtilization::committed.clear(); |
353 | |
354 | JfrNetworkUtilization::send_events(); |
355 | ASSERT_EQ(0u, MockEventNetworkUtilization::committed.size()); |
356 | |
357 | eth0.bytes_in = 10; |
358 | MockFastUnorderedElapsedCounterSource::current_ticks += 2 * NANOSECS_PER_SEC; |
359 | |
360 | JfrNetworkUtilization::send_events(); |
361 | ASSERT_EQ(1u, MockEventNetworkUtilization::committed.size()); |
362 | const MockEventNetworkUtilization& event_v2 = MockEventNetworkUtilization::committed[0]; |
363 | EXPECT_EQ(40, event_v2.readRate); |
364 | EXPECT_EQ(0, event_v2.writeRate); |
365 | EXPECT_STREQ("eth0" , event_v2.iface.c_str()); |
366 | } |
367 | |