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
51namespace {
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 DONT_USE_PRECOMPILED_HEADER
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
235class JfrTestNetworkUtilization : public ::testing::Test {
236protected:
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
249TEST_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
266TEST_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
298TEST_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
335TEST_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