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