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 #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" 35 36 struct InterfaceEntry { 37 char* name; 38 traceid id; 39 uint64_t bytes_in; 40 uint64_t bytes_out; 41 bool in_use; 42 }; 43 44 static GrowableArray<InterfaceEntry>* _interfaces = NULL; 45 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 } 55 56 static InterfaceEntry& new_entry(const NetworkInterface* iface, GrowableArray<InterfaceEntry>* interfaces) { 57 assert(iface != NULL, "invariant"); 58 assert(interfaces != NULL, "invariant"); 59 60 // single threaded premise 61 static traceid interface_id = 0; 62 63 const char* name = iface->get_name(); 64 assert(name != NULL, "invariant"); 65 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 } 76 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 } 83 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; 88 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 } 99 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 } 109 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 } 118 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 }; 143 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 } 151 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(read_rate); 177 event.set_writeRate(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 } 185 186 static bool is_serializer_registered = false; 187 if (!is_serializer_registered) { 188 is_serializer_registered = register_network_interface_name_serializer(); 189 } 190 }