50879
|
1 |
/*
|
57360
|
2 |
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
50879
|
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 |
#include "logging/log.hpp"
|
|
27 |
#include "jfr/jfrEvents.hpp"
|
|
28 |
#include "jfr/metadata/jfrSerializer.hpp"
|
|
29 |
#include "jfr/periodic/jfrNetworkUtilization.hpp"
|
|
30 |
#include "jfr/periodic/jfrOSInterface.hpp"
|
|
31 |
#include "jfr/utilities/jfrTime.hpp"
|
|
32 |
#include "jfr/utilities/jfrTypes.hpp"
|
|
33 |
#include "runtime/os_perf.hpp"
|
|
34 |
#include "utilities/globalDefinitions.hpp"
|
|
35 |
#include "utilities/growableArray.hpp"
|
|
36 |
|
|
37 |
struct InterfaceEntry {
|
|
38 |
char* name;
|
|
39 |
traceid id;
|
|
40 |
uint64_t bytes_in;
|
|
41 |
uint64_t bytes_out;
|
58154
|
42 |
mutable bool written;
|
50879
|
43 |
};
|
|
44 |
|
|
45 |
static GrowableArray<InterfaceEntry>* _interfaces = NULL;
|
|
46 |
|
|
47 |
void JfrNetworkUtilization::destroy() {
|
|
48 |
if (_interfaces != NULL) {
|
|
49 |
for (int i = 0; i < _interfaces->length(); ++i) {
|
|
50 |
FREE_C_HEAP_ARRAY(char, _interfaces->at(i).name);
|
|
51 |
}
|
|
52 |
delete _interfaces;
|
|
53 |
_interfaces = NULL;
|
|
54 |
}
|
|
55 |
}
|
|
56 |
|
|
57 |
static InterfaceEntry& new_entry(const NetworkInterface* iface, GrowableArray<InterfaceEntry>* interfaces) {
|
|
58 |
assert(iface != NULL, "invariant");
|
|
59 |
assert(interfaces != NULL, "invariant");
|
|
60 |
|
|
61 |
// single threaded premise
|
|
62 |
static traceid interface_id = 0;
|
|
63 |
|
|
64 |
const char* name = iface->get_name();
|
|
65 |
assert(name != NULL, "invariant");
|
|
66 |
|
|
67 |
InterfaceEntry entry;
|
|
68 |
const size_t length = strlen(name);
|
|
69 |
entry.name = NEW_C_HEAP_ARRAY(char, length + 1, mtInternal);
|
|
70 |
strncpy(entry.name, name, length + 1);
|
|
71 |
entry.id = ++interface_id;
|
|
72 |
entry.bytes_in = iface->get_bytes_in();
|
|
73 |
entry.bytes_out = iface->get_bytes_out();
|
57360
|
74 |
entry.written = false;
|
50879
|
75 |
return _interfaces->at(_interfaces->append(entry));
|
|
76 |
}
|
|
77 |
|
|
78 |
static GrowableArray<InterfaceEntry>* get_interfaces() {
|
|
79 |
if (_interfaces == NULL) {
|
|
80 |
_interfaces = new(ResourceObj::C_HEAP, mtTracing) GrowableArray<InterfaceEntry>(10, true, mtTracing);
|
|
81 |
}
|
|
82 |
return _interfaces;
|
|
83 |
}
|
|
84 |
|
|
85 |
static InterfaceEntry& get_entry(const NetworkInterface* iface) {
|
|
86 |
// Remember the index we started at last time, since we're most likely looking at them
|
|
87 |
// in the same order every time.
|
|
88 |
static int saved_index = -1;
|
|
89 |
|
|
90 |
GrowableArray<InterfaceEntry>* interfaces = get_interfaces();
|
|
91 |
assert(interfaces != NULL, "invariant");
|
|
92 |
for (int i = 0; i < _interfaces->length(); ++i) {
|
|
93 |
saved_index = (saved_index + 1) % _interfaces->length();
|
|
94 |
if (strcmp(_interfaces->at(saved_index).name, iface->get_name()) == 0) {
|
|
95 |
return _interfaces->at(saved_index);
|
|
96 |
}
|
|
97 |
}
|
|
98 |
return new_entry(iface, interfaces);
|
|
99 |
}
|
|
100 |
|
|
101 |
// If current counters are less than previous we assume the interface has been reset
|
|
102 |
// If no bytes have been either sent or received, we'll also skip the event
|
|
103 |
static uint64_t rate_per_second(uint64_t current, uint64_t old, const JfrTickspan& interval) {
|
|
104 |
assert(interval.value() > 0, "invariant");
|
|
105 |
if (current <= old) {
|
|
106 |
return 0;
|
|
107 |
}
|
|
108 |
return ((current - old) * NANOSECS_PER_SEC) / interval.nanoseconds();
|
|
109 |
}
|
|
110 |
|
58154
|
111 |
class JfrNetworkInterfaceName : public JfrSerializer {
|
|
112 |
public:
|
|
113 |
void serialize(JfrCheckpointWriter& writer) {} // we write each constant lazily
|
|
114 |
|
|
115 |
void on_rotation() {
|
|
116 |
for (int i = 0; i < _interfaces->length(); ++i) {
|
|
117 |
const InterfaceEntry& entry = _interfaces->at(i);
|
|
118 |
if (entry.written) {
|
|
119 |
entry.written = false;
|
|
120 |
}
|
|
121 |
}
|
|
122 |
}
|
|
123 |
};
|
|
124 |
|
|
125 |
static bool register_network_interface_name_serializer() {
|
|
126 |
assert(_interfaces != NULL, "invariant");
|
|
127 |
return JfrSerializer::register_serializer(TYPE_NETWORKINTERFACENAME,
|
|
128 |
false, // disallow caching; we want a callback every rotation
|
|
129 |
new JfrNetworkInterfaceName());
|
|
130 |
}
|
|
131 |
|
|
132 |
static void write_interface_constant(const InterfaceEntry& entry) {
|
|
133 |
if (entry.written) {
|
|
134 |
return;
|
|
135 |
}
|
|
136 |
JfrCheckpointWriter writer;
|
|
137 |
writer.write_type(TYPE_NETWORKINTERFACENAME);
|
|
138 |
writer.write_count(1);
|
|
139 |
writer.write_key(entry.id);
|
|
140 |
writer.write(entry.name);
|
|
141 |
entry.written = true;
|
|
142 |
}
|
|
143 |
|
50879
|
144 |
static bool get_interfaces(NetworkInterface** network_interfaces) {
|
|
145 |
const int ret_val = JfrOSInterface::network_utilization(network_interfaces);
|
|
146 |
if (ret_val == OS_ERR) {
|
|
147 |
log_debug(jfr, system)("Unable to generate network utilization events");
|
|
148 |
return false;
|
|
149 |
}
|
|
150 |
return ret_val != FUNCTIONALITY_NOT_IMPLEMENTED;
|
|
151 |
}
|
|
152 |
|
|
153 |
void JfrNetworkUtilization::send_events() {
|
|
154 |
ResourceMark rm;
|
|
155 |
NetworkInterface* network_interfaces;
|
|
156 |
if (!get_interfaces(&network_interfaces)) {
|
|
157 |
return;
|
|
158 |
}
|
|
159 |
log_trace(jfr, event)("Reporting network utilization");
|
|
160 |
static JfrTicks last_sample_instant;
|
|
161 |
const JfrTicks cur_time = JfrTicks::now();
|
|
162 |
const JfrTickspan interval = last_sample_instant == 0 ? cur_time - cur_time : cur_time - last_sample_instant;
|
|
163 |
last_sample_instant = cur_time;
|
|
164 |
for (NetworkInterface *cur = network_interfaces; cur != NULL; cur = cur->next()) {
|
|
165 |
InterfaceEntry& entry = get_entry(cur);
|
|
166 |
if (interval.value() > 0) {
|
|
167 |
const uint64_t current_bytes_in = cur->get_bytes_in();
|
|
168 |
const uint64_t current_bytes_out = cur->get_bytes_out();
|
|
169 |
const uint64_t read_rate = rate_per_second(current_bytes_in, entry.bytes_in, interval);
|
|
170 |
const uint64_t write_rate = rate_per_second(current_bytes_out, entry.bytes_out, interval);
|
|
171 |
if (read_rate > 0 || write_rate > 0) {
|
58154
|
172 |
write_interface_constant(entry);
|
50879
|
173 |
EventNetworkUtilization event(UNTIMED);
|
|
174 |
event.set_starttime(cur_time);
|
|
175 |
event.set_endtime(cur_time);
|
|
176 |
event.set_networkInterface(entry.id);
|
53013
|
177 |
event.set_readRate(8 * read_rate);
|
|
178 |
event.set_writeRate(8 * write_rate);
|
50879
|
179 |
event.commit();
|
|
180 |
}
|
|
181 |
// update existing entry with new values
|
|
182 |
entry.bytes_in = current_bytes_in;
|
|
183 |
entry.bytes_out = current_bytes_out;
|
|
184 |
}
|
|
185 |
}
|
|
186 |
|
|
187 |
static bool is_serializer_registered = false;
|
|
188 |
if (!is_serializer_registered) {
|
|
189 |
is_serializer_registered = register_network_interface_name_serializer();
|
|
190 |
}
|
|
191 |
}
|