Path: blob/master/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp
41149 views
/*1* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "logging/log.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"3536struct InterfaceEntry {37char* name;38traceid id;39uint64_t bytes_in;40uint64_t bytes_out;41mutable bool written;42};4344static GrowableArray<InterfaceEntry>* _interfaces = NULL;4546void JfrNetworkUtilization::destroy() {47if (_interfaces != NULL) {48for (int i = 0; i < _interfaces->length(); ++i) {49FREE_C_HEAP_ARRAY(char, _interfaces->at(i).name);50}51delete _interfaces;52_interfaces = NULL;53}54}5556static InterfaceEntry& new_entry(const NetworkInterface* iface, GrowableArray<InterfaceEntry>* interfaces) {57assert(iface != NULL, "invariant");58assert(interfaces != NULL, "invariant");5960// single threaded premise61static traceid interface_id = 0;6263const char* name = iface->get_name();64assert(name != NULL, "invariant");6566InterfaceEntry entry;67const size_t length = strlen(name);68entry.name = NEW_C_HEAP_ARRAY(char, length + 1, mtInternal);69strncpy(entry.name, name, length + 1);70entry.id = ++interface_id;71entry.bytes_in = iface->get_bytes_in();72entry.bytes_out = iface->get_bytes_out();73entry.written = false;74return _interfaces->at(_interfaces->append(entry));75}7677static GrowableArray<InterfaceEntry>* get_interfaces() {78if (_interfaces == NULL) {79_interfaces = new(ResourceObj::C_HEAP, mtTracing) GrowableArray<InterfaceEntry>(10, mtTracing);80}81return _interfaces;82}8384static InterfaceEntry& get_entry(const NetworkInterface* iface) {85// Remember the index we started at last time, since we're most likely looking at them86// in the same order every time.87static int saved_index = -1;8889GrowableArray<InterfaceEntry>* interfaces = get_interfaces();90assert(interfaces != NULL, "invariant");91for (int i = 0; i < _interfaces->length(); ++i) {92saved_index = (saved_index + 1) % _interfaces->length();93if (strcmp(_interfaces->at(saved_index).name, iface->get_name()) == 0) {94return _interfaces->at(saved_index);95}96}97return new_entry(iface, interfaces);98}99100// If current counters are less than previous we assume the interface has been reset101// If no bytes have been either sent or received, we'll also skip the event102static uint64_t rate_per_second(uint64_t current, uint64_t old, const JfrTickspan& interval) {103assert(interval.value() > 0, "invariant");104if (current <= old) {105return 0;106}107return ((current - old) * NANOSECS_PER_SEC) / interval.nanoseconds();108}109110class JfrNetworkInterfaceName : public JfrSerializer {111public:112void serialize(JfrCheckpointWriter& writer) {} // we write each constant lazily113114void on_rotation() {115for (int i = 0; i < _interfaces->length(); ++i) {116const InterfaceEntry& entry = _interfaces->at(i);117if (entry.written) {118entry.written = false;119}120}121}122};123124static bool register_network_interface_name_serializer() {125assert(_interfaces != NULL, "invariant");126return JfrSerializer::register_serializer(TYPE_NETWORKINTERFACENAME,127false, // disallow caching; we want a callback every rotation128new JfrNetworkInterfaceName());129}130131static void write_interface_constant(const InterfaceEntry& entry) {132if (entry.written) {133return;134}135JfrCheckpointWriter writer;136writer.write_type(TYPE_NETWORKINTERFACENAME);137writer.write_count(1);138writer.write_key(entry.id);139writer.write(entry.name);140entry.written = true;141}142143static bool get_interfaces(NetworkInterface** network_interfaces) {144const int ret_val = JfrOSInterface::network_utilization(network_interfaces);145if (ret_val == OS_ERR) {146log_debug(jfr, system)("Unable to generate network utilization events");147return false;148}149return ret_val != FUNCTIONALITY_NOT_IMPLEMENTED;150}151152void JfrNetworkUtilization::send_events() {153ResourceMark rm;154NetworkInterface* network_interfaces;155if (!get_interfaces(&network_interfaces)) {156return;157}158static JfrTicks last_sample_instant;159const JfrTicks cur_time = JfrTicks::now();160if (cur_time > last_sample_instant) {161const JfrTickspan interval = cur_time - last_sample_instant;162for (NetworkInterface *cur = network_interfaces; cur != NULL; cur = cur->next()) {163InterfaceEntry& entry = get_entry(cur);164const uint64_t current_bytes_in = cur->get_bytes_in();165const uint64_t current_bytes_out = cur->get_bytes_out();166const uint64_t read_rate = rate_per_second(current_bytes_in, entry.bytes_in, interval);167const uint64_t write_rate = rate_per_second(current_bytes_out, entry.bytes_out, interval);168if (read_rate > 0 || write_rate > 0) {169write_interface_constant(entry);170EventNetworkUtilization event(UNTIMED);171event.set_starttime(cur_time);172event.set_endtime(cur_time);173event.set_networkInterface(entry.id);174event.set_readRate(8 * read_rate);175event.set_writeRate(8 * write_rate);176event.commit();177}178// update existing entry with new values179entry.bytes_in = current_bytes_in;180entry.bytes_out = current_bytes_out;181}182}183last_sample_instant = cur_time;184185static bool is_serializer_registered = false;186if (!is_serializer_registered) {187is_serializer_registered = register_network_interface_name_serializer();188}189}190191192