--- a/src/hotspot/os/aix/os_perf_aix.cpp Thu Jun 28 18:04:19 2018 +0530
+++ b/src/hotspot/os/aix/os_perf_aix.cpp Thu Jun 28 15:06:55 2018 +0200
@@ -1041,3 +1041,49 @@
cpu_info = *_cpu_info; // shallow copy assignment
return OS_OK;
}
+
+class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj<mtInternal> {
+ friend class NetworkPerformanceInterface;
+ private:
+ NetworkPerformance();
+ NetworkPerformance(const NetworkPerformance& rhs); // no impl
+ NetworkPerformance& operator=(const NetworkPerformance& rhs); // no impl
+ bool initialize();
+ ~NetworkPerformance();
+ int network_utilization(NetworkInterface** network_interfaces) const;
+};
+
+NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() {
+
+}
+
+bool NetworkPerformanceInterface::NetworkPerformance::initialize() {
+ return true;
+}
+
+NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {
+}
+
+int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const
+{
+ return FUNCTIONALITY_NOT_IMPLEMENTED;
+}
+
+NetworkPerformanceInterface::NetworkPerformanceInterface() {
+ _impl = NULL;
+}
+
+NetworkPerformanceInterface::~NetworkPerformanceInterface() {
+ if (_impl != NULL) {
+ delete _impl;
+ }
+}
+
+bool NetworkPerformanceInterface::initialize() {
+ _impl = new NetworkPerformanceInterface::NetworkPerformance();
+ return _impl != NULL && _impl->initialize();
+}
+
+int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const {
+ return _impl->network_utilization(network_interfaces);
+}
--- a/src/hotspot/os/bsd/os_perf_bsd.cpp Thu Jun 28 18:04:19 2018 +0530
+++ b/src/hotspot/os/bsd/os_perf_bsd.cpp Thu Jun 28 15:06:55 2018 +0200
@@ -34,6 +34,10 @@
#include <sys/sysctl.h>
#include <mach/mach.h>
#include <mach/task_info.h>
+ #include <sys/socket.h>
+ #include <net/if.h>
+ #include <net/if_dl.h>
+ #include <net/route.h>
#endif
static const double NANOS_PER_SEC = 1000000000.0;
@@ -403,3 +407,85 @@
cpu_info = *_cpu_info; // shallow copy assignment
return OS_OK;
}
+
+class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj<mtInternal> {
+ friend class NetworkPerformanceInterface;
+ private:
+ NetworkPerformance();
+ NetworkPerformance(const NetworkPerformance& rhs); // no impl
+ NetworkPerformance& operator=(const NetworkPerformance& rhs); // no impl
+ bool initialize();
+ ~NetworkPerformance();
+ int network_utilization(NetworkInterface** network_interfaces) const;
+};
+
+NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() {
+}
+
+bool NetworkPerformanceInterface::NetworkPerformance::initialize() {
+ return true;
+}
+
+NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {
+}
+
+int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const {
+ size_t len;
+ int mib[] = {CTL_NET, PF_ROUTE, /* protocol number */ 0, /* address family */ 0, NET_RT_IFLIST2, /* NET_RT_FLAGS mask*/ 0};
+ if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &len, NULL, 0) != 0) {
+ return OS_ERR;
+ }
+ uint8_t* buf = NEW_RESOURCE_ARRAY(uint8_t, len);
+ if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &len, NULL, 0) != 0) {
+ return OS_ERR;
+ }
+
+ size_t index = 0;
+ NetworkInterface* ret = NULL;
+ while (index < len) {
+ if_msghdr* msghdr = reinterpret_cast<if_msghdr*>(buf + index);
+ index += msghdr->ifm_msglen;
+
+ if (msghdr->ifm_type != RTM_IFINFO2) {
+ continue;
+ }
+
+ if_msghdr2* msghdr2 = reinterpret_cast<if_msghdr2*>(msghdr);
+ sockaddr_dl* sockaddr = reinterpret_cast<sockaddr_dl*>(msghdr2 + 1);
+
+ // The interface name is not necessarily NUL-terminated
+ char name_buf[128];
+ size_t name_len = MIN2(sizeof(name_buf) - 1, static_cast<size_t>(sockaddr->sdl_nlen));
+ strncpy(name_buf, sockaddr->sdl_data, name_len);
+ name_buf[name_len] = '\0';
+
+ uint64_t bytes_in = msghdr2->ifm_data.ifi_ibytes;
+ uint64_t bytes_out = msghdr2->ifm_data.ifi_obytes;
+
+ NetworkInterface* cur = new NetworkInterface(name_buf, bytes_in, bytes_out, ret);
+ ret = cur;
+ }
+
+ *network_interfaces = ret;
+
+ return OS_OK;
+}
+
+NetworkPerformanceInterface::NetworkPerformanceInterface() {
+ _impl = NULL;
+}
+
+NetworkPerformanceInterface::~NetworkPerformanceInterface() {
+ if (_impl != NULL) {
+ delete _impl;
+ }
+}
+
+bool NetworkPerformanceInterface::initialize() {
+ _impl = new NetworkPerformanceInterface::NetworkPerformance();
+ return _impl != NULL && _impl->initialize();
+}
+
+int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const {
+ return _impl->network_utilization(network_interfaces);
+}
--- a/src/hotspot/os/linux/os_perf_linux.cpp Thu Jun 28 18:04:19 2018 +0530
+++ b/src/hotspot/os/linux/os_perf_linux.cpp Thu Jun 28 15:06:55 2018 +0200
@@ -44,6 +44,8 @@
#include <dlfcn.h>
#include <pthread.h>
#include <limits.h>
+#include <ifaddrs.h>
+#include <fcntl.h>
/**
/proc/[number]/stat
@@ -1048,3 +1050,94 @@
cpu_info = *_cpu_info; // shallow copy assignment
return OS_OK;
}
+
+class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj<mtInternal> {
+ friend class NetworkPerformanceInterface;
+ private:
+ NetworkPerformance();
+ NetworkPerformance(const NetworkPerformance& rhs); // no impl
+ NetworkPerformance& operator=(const NetworkPerformance& rhs); // no impl
+ bool initialize();
+ ~NetworkPerformance();
+ int64_t read_counter(const char* iface, const char* counter) const;
+ int network_utilization(NetworkInterface** network_interfaces) const;
+};
+
+NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() {
+
+}
+
+bool NetworkPerformanceInterface::NetworkPerformance::initialize() {
+ return true;
+}
+
+NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {
+}
+
+int64_t NetworkPerformanceInterface::NetworkPerformance::read_counter(const char* iface, const char* counter) const {
+ char buf[128];
+
+ snprintf(buf, sizeof(buf), "/sys/class/net/%s/statistics/%s", iface, counter);
+
+ int fd = open(buf, O_RDONLY);
+ if (fd == -1) {
+ return -1;
+ }
+
+ ssize_t num_bytes = read(fd, buf, sizeof(buf));
+ close(fd);
+ if ((num_bytes == -1) || (num_bytes >= static_cast<ssize_t>(sizeof(buf))) || (num_bytes < 1)) {
+ return -1;
+ }
+
+ buf[num_bytes] = '\0';
+ int64_t value = strtoll(buf, NULL, 10);
+
+ return value;
+}
+
+int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const
+{
+ ifaddrs* addresses;
+ ifaddrs* cur_address;
+
+ if (getifaddrs(&addresses) != 0) {
+ return OS_ERR;
+ }
+
+ NetworkInterface* ret = NULL;
+ for (cur_address = addresses; cur_address != NULL; cur_address = cur_address->ifa_next) {
+ if (cur_address->ifa_addr->sa_family != AF_PACKET) {
+ continue;
+ }
+
+ int64_t bytes_in = read_counter(cur_address->ifa_name, "rx_bytes");
+ int64_t bytes_out = read_counter(cur_address->ifa_name, "tx_bytes");
+
+ NetworkInterface* cur = new NetworkInterface(cur_address->ifa_name, bytes_in, bytes_out, ret);
+ ret = cur;
+ }
+
+ *network_interfaces = ret;
+
+ return OS_OK;
+}
+
+NetworkPerformanceInterface::NetworkPerformanceInterface() {
+ _impl = NULL;
+}
+
+NetworkPerformanceInterface::~NetworkPerformanceInterface() {
+ if (_impl != NULL) {
+ delete _impl;
+ }
+}
+
+bool NetworkPerformanceInterface::initialize() {
+ _impl = new NetworkPerformanceInterface::NetworkPerformance();
+ return _impl != NULL && _impl->initialize();
+}
+
+int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const {
+ return _impl->network_utilization(network_interfaces);
+}
--- a/src/hotspot/os/solaris/os_perf_solaris.cpp Thu Jun 28 18:04:19 2018 +0530
+++ b/src/hotspot/os/solaris/os_perf_solaris.cpp Thu Jun 28 15:06:55 2018 +0200
@@ -754,3 +754,88 @@
cpu_info = *_cpu_info; // shallow copy assignment
return OS_OK;
}
+
+class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj<mtInternal> {
+ friend class NetworkPerformanceInterface;
+ private:
+ NetworkPerformance();
+ NetworkPerformance(const NetworkPerformance& rhs); // no impl
+ NetworkPerformance& operator=(const NetworkPerformance& rhs); // no impl
+ bool initialize();
+ ~NetworkPerformance();
+ int network_utilization(NetworkInterface** network_interfaces) const;
+};
+
+NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() {
+
+}
+
+bool NetworkPerformanceInterface::NetworkPerformance::initialize() {
+ return true;
+}
+
+NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {
+
+}
+
+int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const
+{
+ kstat_ctl_t* ctl = kstat_open();
+ if (ctl == NULL) {
+ return OS_ERR;
+ }
+
+ NetworkInterface* ret = NULL;
+ for (kstat_t* k = ctl->kc_chain; k != NULL; k = k->ks_next) {
+ if (strcmp(k->ks_class, "net") != 0) {
+ continue;
+ }
+ if (strcmp(k->ks_module, "link") != 0) {
+ continue;
+ }
+
+ if (kstat_read(ctl, k, NULL) == -1) {
+ return OS_ERR;
+ }
+
+ uint64_t bytes_in = UINT64_MAX;
+ uint64_t bytes_out = UINT64_MAX;
+ for (int i = 0; i < k->ks_ndata; ++i) {
+ kstat_named_t* data = &reinterpret_cast<kstat_named_t*>(k->ks_data)[i];
+ if (strcmp(data->name, "rbytes64") == 0) {
+ bytes_in = data->value.ui64;
+ }
+ else if (strcmp(data->name, "obytes64") == 0) {
+ bytes_out = data->value.ui64;
+ }
+ }
+
+ if ((bytes_in != UINT64_MAX) && (bytes_out != UINT64_MAX)) {
+ NetworkInterface* cur = new NetworkInterface(k->ks_name, bytes_in, bytes_out, ret);
+ ret = cur;
+ }
+ }
+
+ *network_interfaces = ret;
+
+ return OS_OK;
+}
+
+NetworkPerformanceInterface::NetworkPerformanceInterface() {
+ _impl = NULL;
+}
+
+NetworkPerformanceInterface::~NetworkPerformanceInterface() {
+ if (_impl != NULL) {
+ delete _impl;
+ }
+}
+
+bool NetworkPerformanceInterface::initialize() {
+ _impl = new NetworkPerformanceInterface::NetworkPerformance();
+ return _impl != NULL && _impl->initialize();
+}
+
+int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const {
+ return _impl->network_utilization(network_interfaces);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/os/windows/iphlp_interface.cpp Thu Jun 28 15:06:55 2018 +0200
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "iphlp_interface.hpp"
+#include "runtime/os.hpp"
+
+// IPHLP API
+typedef DWORD(WINAPI *GetIfTable2_Fn)(PMIB_IF_TABLE2*);
+typedef DWORD(WINAPI *FreeMibTable_Fn)(PVOID);
+
+// IPHLP statics
+GetIfTable2_Fn IphlpDll::_GetIfTable2 = NULL;
+FreeMibTable_Fn IphlpDll::_FreeMibTable = NULL;
+
+LONG IphlpDll::_critical_section = 0;
+LONG IphlpDll::_initialized = 0;
+LONG IphlpDll::_iphlp_reference_count = 0;
+HMODULE IphlpDll::_hModule = NULL;
+
+void IphlpDll::initialize(void) {
+ _hModule = os::win32::load_Windows_dll("iphlpapi.dll", NULL, 0);
+
+ if (NULL == _hModule) {
+ return;
+ }
+
+ // The 'A' at the end means the ANSI (not the UNICODE) vesions of the methods
+ _GetIfTable2 = (GetIfTable2_Fn)::GetProcAddress(_hModule, "GetIfTable2");
+ _FreeMibTable = (FreeMibTable_Fn)::GetProcAddress(_hModule, "FreeMibTable");
+
+ // interlock is used for fencing
+ InterlockedExchange(&_initialized, 1);
+}
+
+bool IphlpDll::IphlpDetach(void) {
+ LONG prev_ref_count = InterlockedExchangeAdd(&_iphlp_reference_count, -1);
+ BOOL ret = false;
+
+ if (1 == prev_ref_count) {
+ if (_initialized && _hModule != NULL) {
+ ret = FreeLibrary(_hModule);
+ if (ret) {
+ _hModule = NULL;
+ _GetIfTable2 = NULL;
+ _FreeMibTable = NULL;
+ InterlockedExchange(&_initialized, 0);
+ }
+ }
+ }
+ return ret != 0;
+}
+
+bool IphlpDll::IphlpAttach(void) {
+ InterlockedExchangeAdd(&_iphlp_reference_count, 1);
+
+ if (1 == _initialized) {
+ return true;
+ }
+
+ while (InterlockedCompareExchange(&_critical_section, 1, 0) == 1);
+
+ if (0 == _initialized) {
+ initialize();
+ }
+
+ while (InterlockedCompareExchange(&_critical_section, 0, 1) == 0);
+
+ return (_GetIfTable2 != NULL && _FreeMibTable != NULL);
+}
+
+DWORD IphlpDll::GetIfTable2(PMIB_IF_TABLE2* Table) {
+ assert(_initialized && _GetIfTable2 != NULL,
+ "IphlpAttach() not yet called");
+
+ return _GetIfTable2(Table);
+}
+
+DWORD IphlpDll::FreeMibTable(PVOID Memory) {
+ assert(_initialized && _FreeMibTable != NULL,
+ "IphlpAttach() not yet called");
+
+ return _FreeMibTable(Memory);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/os/windows/iphlp_interface.hpp Thu Jun 28 15:06:55 2018 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_WINDOWS_VM_IPHLP_INTERFACE_HPP
+#define OS_WINDOWS_VM_IPHLP_INTERFACE_HPP
+
+#include "memory/allocation.hpp"
+#include "utilities/macros.hpp"
+#include <WinSock2.h>
+#include <ws2ipdef.h>
+#include <iphlpapi.h>
+
+class IphlpDll : public AllStatic {
+ private:
+ static LONG _iphlp_reference_count;
+ static LONG _critical_section;
+ static LONG _initialized;
+ static HMODULE _hModule;
+ static void initialize(void);
+ static DWORD(WINAPI *_GetIfTable2)(PMIB_IF_TABLE2*);
+ static DWORD(WINAPI *_FreeMibTable)(PVOID);
+
+ public:
+ static DWORD GetIfTable2(PMIB_IF_TABLE2*);
+ static DWORD FreeMibTable(PVOID);
+ static bool IphlpAttach(void);
+ static bool IphlpDetach(void);
+};
+
+#endif // OS_WINDOWS_VM_IPHLP_INTERFACE_HPP
--- a/src/hotspot/os/windows/os_perf_windows.cpp Thu Jun 28 18:04:19 2018 +0530
+++ b/src/hotspot/os/windows/os_perf_windows.cpp Thu Jun 28 15:06:55 2018 +0200
@@ -23,14 +23,15 @@
*/
#include "precompiled.hpp"
+#include "iphlp_interface.hpp"
#include "logging/log.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "pdh_interface.hpp"
#include "runtime/os_perf.hpp"
#include "runtime/os.hpp"
+#include "utilities/macros.hpp"
#include "vm_version_ext_x86.hpp"
-#include "utilities/macros.hpp"
#include <math.h>
#include <psapi.h>
#include <TlHelp32.h>
@@ -1380,3 +1381,78 @@
cpu_info = *_cpu_info; // shallow copy assignment
return OS_OK;
}
+
+class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj<mtInternal> {
+ friend class NetworkPerformanceInterface;
+ private:
+ bool _iphlp_attached;
+
+ NetworkPerformance();
+ NetworkPerformance(const NetworkPerformance& rhs); // no impl
+ NetworkPerformance& operator=(const NetworkPerformance& rhs); // no impl
+ bool initialize();
+ ~NetworkPerformance();
+ int network_utilization(NetworkInterface** network_interfaces) const;
+};
+
+NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance()
+: _iphlp_attached(false) {
+}
+
+bool NetworkPerformanceInterface::NetworkPerformance::initialize() {
+ _iphlp_attached = IphlpDll::IphlpAttach();
+ return _iphlp_attached;
+}
+
+NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {
+ if (_iphlp_attached) {
+ IphlpDll::IphlpDetach();
+ }
+}
+
+int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const {
+ MIB_IF_TABLE2* table;
+
+ if (IphlpDll::GetIfTable2(&table) != NO_ERROR) {
+ return OS_ERR;
+ }
+
+ NetworkInterface* ret = NULL;
+ for (ULONG i = 0; i < table->NumEntries; ++i) {
+ if (table->Table[i].InterfaceAndOperStatusFlags.FilterInterface) {
+ continue;
+ }
+
+ char buf[256];
+ if (WideCharToMultiByte(CP_UTF8, 0, table->Table[i].Description, -1, buf, sizeof(buf), NULL, NULL) == 0) {
+ continue;
+ }
+
+ NetworkInterface* cur = new NetworkInterface(buf, table->Table[i].InOctets, table->Table[i].OutOctets, ret);
+ ret = cur;
+ }
+
+ IphlpDll::FreeMibTable(table);
+ *network_interfaces = ret;
+
+ return OS_OK;
+}
+
+NetworkPerformanceInterface::NetworkPerformanceInterface() {
+ _impl = NULL;
+}
+
+NetworkPerformanceInterface::~NetworkPerformanceInterface() {
+ if (_impl != NULL) {
+ delete _impl;
+ }
+}
+
+bool NetworkPerformanceInterface::initialize() {
+ _impl = new NetworkPerformanceInterface::NetworkPerformance();
+ return _impl != NULL && _impl->initialize();
+}
+
+int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const {
+ return _impl->network_utilization(network_interfaces);
+}
--- a/src/hotspot/share/jfr/metadata/metadata.xml Thu Jun 28 18:04:19 2018 +0530
+++ b/src/hotspot/share/jfr/metadata/metadata.xml Thu Jun 28 15:06:55 2018 +0200
@@ -656,6 +656,12 @@
<Field type="float" name="switchRate" label="Switch Rate" description="Number of context switches per second" />
</Event>
+ <Event name="NetworkUtilization" category="Operating System, Network" label="Network Utilization" period="everyChunk">
+ <Field type="NetworkInterfaceName" name="networkInterface" label="Network Interface" description="Network Interface Name"/>
+ <Field type="long" contentType="bytes" name="readRate" label="Read Rate" description="Number of incoming bytes per second"/>
+ <Field type="long" contentType="bytes" name="writeRate" label="Write Rate" description="Number of outgoing bytes per second"/>
+ </Event>
+
<Event name="JavaThreadStatistics" category="Java Application, Statistics" label="Java Thread Statistics" period="everyChunk">
<Field type="long" name="activeCount" label="Active Threads" description="Number of live active threads including both daemon and non-daemon threads" />
<Field type="long" name="daemonCount" label="Daemon Threads" description="Number of live daemon threads" />
@@ -918,6 +924,10 @@
<Field type="string" name="sampler" label="Sampler" />
</Type>
+ <Type name="NetworkInterfaceName" label="Network Interface">
+ <Field type="string" name="networkInterface" label="Network Interface" description="Network Interface Name" />
+ </Type>
+
<Type name="Thread" label="Thread">
<Field type="string" name="osName" label="OS Thread Name" />
<Field type="long" name="osThreadId" label="OS Thread Id" />
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp Thu Jun 28 15:06:55 2018 +0200
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "logging/log.hpp"
+#include "jfr/jfrEvents.hpp"
+#include "jfr/metadata/jfrSerializer.hpp"
+#include "jfr/periodic/jfrNetworkUtilization.hpp"
+#include "jfr/periodic/jfrOSInterface.hpp"
+#include "jfr/utilities/jfrTime.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+#include "runtime/os_perf.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/growableArray.hpp"
+
+struct InterfaceEntry {
+ char* name;
+ traceid id;
+ uint64_t bytes_in;
+ uint64_t bytes_out;
+ bool in_use;
+};
+
+static GrowableArray<InterfaceEntry>* _interfaces = NULL;
+
+void JfrNetworkUtilization::destroy() {
+ if (_interfaces != NULL) {
+ for (int i = 0; i < _interfaces->length(); ++i) {
+ FREE_C_HEAP_ARRAY(char, _interfaces->at(i).name);
+ }
+ delete _interfaces;
+ _interfaces = NULL;
+ }
+}
+
+static InterfaceEntry& new_entry(const NetworkInterface* iface, GrowableArray<InterfaceEntry>* interfaces) {
+ assert(iface != NULL, "invariant");
+ assert(interfaces != NULL, "invariant");
+
+ // single threaded premise
+ static traceid interface_id = 0;
+
+ const char* name = iface->get_name();
+ assert(name != NULL, "invariant");
+
+ InterfaceEntry entry;
+ const size_t length = strlen(name);
+ entry.name = NEW_C_HEAP_ARRAY(char, length + 1, mtInternal);
+ strncpy(entry.name, name, length + 1);
+ entry.id = ++interface_id;
+ entry.bytes_in = iface->get_bytes_in();
+ entry.bytes_out = iface->get_bytes_out();
+ entry.in_use = false;
+ return _interfaces->at(_interfaces->append(entry));
+}
+
+static GrowableArray<InterfaceEntry>* get_interfaces() {
+ if (_interfaces == NULL) {
+ _interfaces = new(ResourceObj::C_HEAP, mtTracing) GrowableArray<InterfaceEntry>(10, true, mtTracing);
+ }
+ return _interfaces;
+}
+
+static InterfaceEntry& get_entry(const NetworkInterface* iface) {
+ // Remember the index we started at last time, since we're most likely looking at them
+ // in the same order every time.
+ static int saved_index = -1;
+
+ GrowableArray<InterfaceEntry>* interfaces = get_interfaces();
+ assert(interfaces != NULL, "invariant");
+ for (int i = 0; i < _interfaces->length(); ++i) {
+ saved_index = (saved_index + 1) % _interfaces->length();
+ if (strcmp(_interfaces->at(saved_index).name, iface->get_name()) == 0) {
+ return _interfaces->at(saved_index);
+ }
+ }
+ return new_entry(iface, interfaces);
+}
+
+// If current counters are less than previous we assume the interface has been reset
+// If no bytes have been either sent or received, we'll also skip the event
+static uint64_t rate_per_second(uint64_t current, uint64_t old, const JfrTickspan& interval) {
+ assert(interval.value() > 0, "invariant");
+ if (current <= old) {
+ return 0;
+ }
+ return ((current - old) * NANOSECS_PER_SEC) / interval.nanoseconds();
+}
+
+static bool get_interfaces(NetworkInterface** network_interfaces) {
+ const int ret_val = JfrOSInterface::network_utilization(network_interfaces);
+ if (ret_val == OS_ERR) {
+ log_debug(jfr, system)("Unable to generate network utilization events");
+ return false;
+ }
+ return ret_val != FUNCTIONALITY_NOT_IMPLEMENTED;
+}
+
+class JfrNetworkInterfaceName : public JfrSerializer {
+ public:
+ void serialize(JfrCheckpointWriter& writer) {
+ assert(_interfaces != NULL, "invariant");
+ const JfrCheckpointContext ctx = writer.context();
+ const intptr_t count_offset = writer.reserve(sizeof(u4)); // Don't know how many yet
+ int active_interfaces = 0;
+ for (int i = 0; i < _interfaces->length(); ++i) {
+ InterfaceEntry& entry = _interfaces->at(i);
+ if (entry.in_use) {
+ entry.in_use = false;
+ writer.write_key(entry.id);
+ writer.write(entry.name);
+ ++active_interfaces;
+ }
+ }
+ if (active_interfaces == 0) {
+ // nothing to write, restore context
+ writer.set_context(ctx);
+ return;
+ }
+ writer.write_count(active_interfaces, count_offset);
+ }
+};
+
+static bool register_network_interface_name_serializer() {
+ assert(_interfaces != NULL, "invariant");
+ return JfrSerializer::register_serializer(TYPE_NETWORKINTERFACENAME,
+ false, // require safepoint
+ false, // disallow caching; we want a callback every rotation
+ new JfrNetworkInterfaceName());
+}
+
+void JfrNetworkUtilization::send_events() {
+ ResourceMark rm;
+ NetworkInterface* network_interfaces;
+ if (!get_interfaces(&network_interfaces)) {
+ return;
+ }
+ log_trace(jfr, event)("Reporting network utilization");
+ static JfrTicks last_sample_instant;
+ const JfrTicks cur_time = JfrTicks::now();
+ const JfrTickspan interval = last_sample_instant == 0 ? cur_time - cur_time : cur_time - last_sample_instant;
+ last_sample_instant = cur_time;
+ for (NetworkInterface *cur = network_interfaces; cur != NULL; cur = cur->next()) {
+ InterfaceEntry& entry = get_entry(cur);
+ if (interval.value() > 0) {
+ const uint64_t current_bytes_in = cur->get_bytes_in();
+ const uint64_t current_bytes_out = cur->get_bytes_out();
+ const uint64_t read_rate = rate_per_second(current_bytes_in, entry.bytes_in, interval);
+ const uint64_t write_rate = rate_per_second(current_bytes_out, entry.bytes_out, interval);
+ if (read_rate > 0 || write_rate > 0) {
+ entry.in_use = true;
+ EventNetworkUtilization event(UNTIMED);
+ event.set_starttime(cur_time);
+ event.set_endtime(cur_time);
+ event.set_networkInterface(entry.id);
+ event.set_readRate(read_rate);
+ event.set_writeRate(write_rate);
+ event.commit();
+ }
+ // update existing entry with new values
+ entry.bytes_in = current_bytes_in;
+ entry.bytes_out = current_bytes_out;
+ }
+ }
+
+ static bool is_serializer_registered = false;
+ if (!is_serializer_registered) {
+ is_serializer_registered = register_network_interface_name_serializer();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.hpp Thu Jun 28 15:06:55 2018 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_JFR_PERIODIC_JFRNETWORKUTILIZATION_HPP
+#define SHARE_VM_JFR_PERIODIC_JFRNETWORKUTILIZATION_HPP
+
+#include "memory/allocation.hpp"
+
+class NetworkInterface;
+
+class JfrNetworkUtilization : public AllStatic {
+public:
+ static void destroy();
+ static void send_events();
+};
+
+#endif // SHARE_VM_JFR_PERIODIC_JFRNETWORKUTILIZATION_HPP
--- a/src/hotspot/share/jfr/periodic/jfrOSInterface.cpp Thu Jun 28 18:04:19 2018 +0530
+++ b/src/hotspot/share/jfr/periodic/jfrOSInterface.cpp Thu Jun 28 15:06:55 2018 +0200
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "jfr/jfrEvents.hpp"
+#include "jfr/periodic/jfrNetworkUtilization.hpp"
#include "jfr/periodic/jfrOSInterface.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
@@ -54,6 +55,7 @@
}
void JfrOSInterface::destroy() {
+ JfrNetworkUtilization::destroy();
if (_instance != NULL) {
delete _instance;
_instance = NULL;
@@ -66,6 +68,7 @@
CPUInformationInterface* _cpu_info_interface;
CPUPerformanceInterface* _cpu_perf_interface;
SystemProcessInterface* _system_process_interface;
+ NetworkPerformanceInterface* _network_performance_interface;
// stub helper
void functionality_not_implemented(char** str) const;
@@ -89,6 +92,8 @@
// system processes information
int system_processes(SystemProcess** system_processes, int* no_of_sys_processes);
+
+ int network_utilization(NetworkInterface** network_interfaces) const;
};
JfrOSInterface::JfrOSInterfaceImpl::JfrOSInterfaceImpl() : _cpu_info_interface(NULL),
@@ -97,18 +102,19 @@
bool JfrOSInterface::JfrOSInterfaceImpl::initialize() {
_cpu_info_interface = new CPUInformationInterface();
- bool success = _cpu_info_interface != NULL && _cpu_info_interface->initialize();
- if (!success) {
+ if (!(_cpu_info_interface != NULL && _cpu_info_interface->initialize())) {
return false;
}
_cpu_perf_interface = new CPUPerformanceInterface();
- success = _cpu_perf_interface != NULL && _cpu_perf_interface->initialize();
- if (!success) {
+ if (!(_cpu_perf_interface != NULL && _cpu_perf_interface->initialize())) {
return false;
}
_system_process_interface = new SystemProcessInterface();
- success = _system_process_interface != NULL && _system_process_interface->initialize();
- return success;
+ if (!(_system_process_interface != NULL && _system_process_interface->initialize())) {
+ return false;
+ }
+ _network_performance_interface = new NetworkPerformanceInterface();
+ return _network_performance_interface != NULL && _network_performance_interface->initialize();
}
JfrOSInterface::JfrOSInterfaceImpl::~JfrOSInterfaceImpl(void) {
@@ -124,6 +130,10 @@
delete _system_process_interface;
_system_process_interface = NULL;
}
+ if (_network_performance_interface != NULL) {
+ delete _network_performance_interface;
+ _network_performance_interface = NULL;
+ }
}
int JfrOSInterface::JfrOSInterfaceImpl::cpu_load(int which_logical_cpu, double* cpu_load) {
@@ -154,6 +164,10 @@
return _system_process_interface->system_processes(system_processes, no_of_sys_processes);
}
+int JfrOSInterface::JfrOSInterfaceImpl::network_utilization(NetworkInterface** network_interfaces) const {
+ return _network_performance_interface->network_utilization(network_interfaces);
+}
+
// assigned char* is RESOURCE_HEAP_ALLOCATED
// caller need to ensure proper ResourceMark placement.
int JfrOSInterface::JfrOSInterfaceImpl::os_version(char** os_version) const {
@@ -246,3 +260,7 @@
int JfrOSInterface::system_processes(SystemProcess** sys_processes, int* no_of_sys_processes) {
return instance()._impl->system_processes(sys_processes, no_of_sys_processes);
}
+
+int JfrOSInterface::network_utilization(NetworkInterface** network_interfaces) {
+ return instance()._impl->network_utilization(network_interfaces);
+}
--- a/src/hotspot/share/jfr/periodic/jfrOSInterface.hpp Thu Jun 28 18:04:19 2018 +0530
+++ b/src/hotspot/share/jfr/periodic/jfrOSInterface.hpp Thu Jun 28 15:06:55 2018 +0200
@@ -26,10 +26,10 @@
#define SHARE_VM_JFR_PERIODIC_JFROSINTERFACE_HPP
#include "jfr/utilities/jfrAllocation.hpp"
-#include "utilities/globalDefinitions.hpp"
class CPUInformation;
class EnvironmentVariable;
+class NetworkInterface;
class SystemProcess;
class JfrOSInterface: public JfrCHeapObj {
@@ -54,6 +54,7 @@
static int os_version(char** os_version);
static int generate_initial_environment_variable_events();
static int system_processes(SystemProcess** system_processes, int* no_of_sys_processes);
+ static int network_utilization(NetworkInterface** network_interfaces);
};
#endif // SHARE_VM_JFR_PERIODIC_JFROSINTERFACE_HPP
--- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp Thu Jun 28 18:04:19 2018 +0530
+++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp Thu Jun 28 15:06:55 2018 +0200
@@ -38,6 +38,7 @@
#include "jfr/periodic/jfrOSInterface.hpp"
#include "jfr/periodic/jfrThreadCPULoadEvent.hpp"
#include "jfr/periodic/jfrThreadDumpEvent.hpp"
+#include "jfr/periodic/jfrNetworkUtilization.hpp"
#include "jfr/recorder/jfrRecorder.hpp"
#include "jfr/support/jfrThreadId.hpp"
#include "jfr/utilities/jfrTime.hpp"
@@ -176,6 +177,10 @@
JfrThreadCPULoadEvent::send_events();
}
+TRACE_REQUEST_FUNC(NetworkUtilization) {
+ JfrNetworkUtilization::send_events();
+}
+
TRACE_REQUEST_FUNC(CPUTimeStampCounter) {
EventCPUTimeStampCounter event;
event.set_fastTimeEnabled(JfrTime::is_ft_enabled());
--- a/src/hotspot/share/runtime/os_perf.hpp Thu Jun 28 18:04:19 2018 +0530
+++ b/src/hotspot/share/runtime/os_perf.hpp Thu Jun 28 15:06:55 2018 +0200
@@ -25,9 +25,8 @@
#ifndef SHARE_VM_RUNTIME_OS_PERF_HPP
#define SHARE_VM_RUNTIME_OS_PERF_HPP
+#include "memory/allocation.hpp"
#include "utilities/macros.hpp"
-#include "memory/allocation.hpp"
-#include "utilities/globalDefinitions.hpp"
#define FUNCTIONALITY_NOT_IMPLEMENTED -8
@@ -194,6 +193,47 @@
}
};
+class NetworkInterface : public ResourceObj {
+ private:
+ char* _name;
+ uint64_t _bytes_in;
+ uint64_t _bytes_out;
+ NetworkInterface* _next;
+
+ NetworkInterface(); // no impl
+ NetworkInterface(const NetworkInterface& rhs); // no impl
+ NetworkInterface& operator=(const NetworkInterface& rhs); // no impl
+ public:
+ NetworkInterface(const char* name, uint64_t bytes_in, uint64_t bytes_out, NetworkInterface* next) :
+ _name(NULL),
+ _bytes_in(bytes_in),
+ _bytes_out(bytes_out),
+ _next(next) {
+ assert(name != NULL, "invariant");
+ const size_t length = strlen(name);
+ assert(allocated_on_res_area(), "invariant");
+ _name = NEW_RESOURCE_ARRAY(char, length + 1);
+ strncpy(_name, name, length + 1);
+ assert(strncmp(_name, name, length) == 0, "invariant");
+ }
+
+ NetworkInterface* next() const {
+ return _next;
+ }
+
+ const char* get_name() const {
+ return _name;
+ }
+
+ uint64_t get_bytes_out() const {
+ return _bytes_out;
+ }
+
+ uint64_t get_bytes_in() const {
+ return _bytes_in;
+ }
+};
+
class CPUInformationInterface : public CHeapObj<mtInternal> {
private:
CPUInformation* _cpu_info;
@@ -234,4 +274,17 @@
int system_processes(SystemProcess** system_procs, int* const no_of_sys_processes) const;
};
+class NetworkPerformanceInterface : public CHeapObj<mtInternal> {
+ private:
+ class NetworkPerformance;
+ NetworkPerformance* _impl;
+ NetworkPerformanceInterface(const NetworkPerformanceInterface& rhs); // no impl
+ NetworkPerformanceInterface& operator=(const NetworkPerformanceInterface& rhs); // no impl
+ public:
+ NetworkPerformanceInterface();
+ bool initialize();
+ ~NetworkPerformanceInterface();
+ int network_utilization(NetworkInterface** network_interfaces) const;
+};
+
#endif // SHARE_VM_RUNTIME_OS_PERF_HPP
--- a/src/jdk.jfr/share/conf/jfr/default.jfc Thu Jun 28 18:04:19 2018 +0530
+++ b/src/jdk.jfr/share/conf/jfr/default.jfc Thu Jun 28 15:06:55 2018 +0200
@@ -518,6 +518,11 @@
<setting name="period">endChunk</setting>
</event>
+ <event name="jdk.NetworkUtilization">
+ <setting name="enabled">true</setting>
+ <setting name="period">5 s</setting>
+ </event>
+
<event name="jdk.InitialEnvironmentVariable">
<setting name="enabled">true</setting>
<setting name="period">beginChunk</setting>
--- a/src/jdk.jfr/share/conf/jfr/profile.jfc Thu Jun 28 18:04:19 2018 +0530
+++ b/src/jdk.jfr/share/conf/jfr/profile.jfc Thu Jun 28 15:06:55 2018 +0200
@@ -518,6 +518,11 @@
<setting name="period">endChunk</setting>
</event>
+ <event name="jdk.NetworkUtilization">
+ <setting name="enabled">true</setting>
+ <setting name="period">5 s</setting>
+ </event>
+
<event name="jdk.InitialEnvironmentVariable">
<setting name="enabled">true</setting>
<setting name="period">beginChunk</setting>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/gtest/jfr/test_networkUtilization.cpp Thu Jun 28 15:06:55 2018 +0200
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+
+// This test performs mocking of certain JVM functionality. This works by
+// including the source file under test inside an anonymous namespace (which
+// prevents linking conflicts) with the mocked symbols redefined.
+
+// The include list should mirror the one found in the included source file -
+// with the ones that should pick up the mocks removed. Those should be included
+// later after the mocks have been defined.
+
+#include "logging/log.hpp"
+#include "jfr/jfrEvents.hpp"
+#include "jfr/metadata/jfrSerializer.hpp"
+#include "jfr/periodic/jfrOSInterface.hpp"
+#include "jfr/utilities/jfrTime.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+#include "runtime/os_perf.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/growableArray.hpp"
+
+#include "unittest.hpp"
+
+#include <vector>
+#include <list>
+#include <map>
+
+namespace {
+
+ class MockFastUnorderedElapsedCounterSource : public ::FastUnorderedElapsedCounterSource {
+ public:
+ static jlong current_ticks;
+ static Type now() {
+ return current_ticks;
+ }
+ static uint64_t nanoseconds(Type value) {
+ return value;
+ }
+ };
+
+ typedef TimeInstant<CounterRepresentation, MockFastUnorderedElapsedCounterSource> JfrTicks;
+ typedef TimeInterval<CounterRepresentation, MockFastUnorderedElapsedCounterSource> JfrTickspan;
+
+ class MockJfrCheckpointWriter {
+ public:
+ traceid current;
+ std::map<traceid, std::string> ids;
+
+ const JfrCheckpointContext context() const {
+ return JfrCheckpointContext();
+ }
+ intptr_t reserve(size_t size) {
+ return 0;
+ }
+ void write_key(traceid id) {
+ current = id;
+ }
+ void write(const char* data) {
+ ids[current] = data;
+ }
+ void set_context(const JfrCheckpointContext ctx) { }
+ void write_count(u4 nof_entries, jlong offset) { }
+ };
+
+ class MockJfrSerializer {
+ public:
+ static MockJfrSerializer* current;
+
+ static bool register_serializer(JfrTypeId id, bool require_safepoint, bool permit_cache, MockJfrSerializer* serializer) {
+ current = serializer;
+ return true;
+ }
+
+ virtual void serialize(MockJfrCheckpointWriter& writer) = 0;
+ };
+
+ MockJfrSerializer* MockJfrSerializer::current;
+
+ class MockEventNetworkUtilization : public ::EventNetworkUtilization
+ {
+ public:
+ std::string iface;
+ s8 readRate;
+ s8 writeRate;
+ static std::vector<MockEventNetworkUtilization> committed;
+ MockJfrCheckpointWriter writer;
+
+ public:
+ MockEventNetworkUtilization(EventStartTime timing=TIMED) :
+ ::EventNetworkUtilization(timing) {
+ }
+
+ void set_networkInterface(traceid new_value) {
+ MockJfrSerializer::current->serialize(writer);
+ iface = writer.ids[new_value];
+ }
+ void set_readRate(s8 new_value) {
+ readRate = new_value;
+ }
+ void set_writeRate(s8 new_value) {
+ writeRate = new_value;
+ }
+
+ void commit() {
+ committed.push_back(*this);
+ }
+
+ void set_starttime(const JfrTicks& time) {}
+
+ void set_endtime(const JfrTicks& time) {}
+
+ static const MockEventNetworkUtilization& get_committed(const std::string& name) {
+ static MockEventNetworkUtilization placeholder;
+ for (std::vector<MockEventNetworkUtilization>::const_iterator i = committed.begin();
+ i != committed.end();
+ ++i) {
+ if (name == i->iface) {
+ return *i;
+ }
+ }
+ return placeholder;
+ }
+ };
+
+ std::vector<MockEventNetworkUtilization> MockEventNetworkUtilization::committed;
+
+ jlong MockFastUnorderedElapsedCounterSource::current_ticks;
+
+ struct MockNetworkInterface {
+ std::string name;
+ uint64_t bytes_in;
+ uint64_t bytes_out;
+ MockNetworkInterface(std::string name, uint64_t bytes_in, uint64_t bytes_out)
+ : name(name),
+ bytes_in(bytes_in),
+ bytes_out(bytes_out) {
+
+ }
+ bool operator==(const MockNetworkInterface& rhs) const {
+ return name == rhs.name;
+ }
+ };
+
+ class NetworkInterface : public ::NetworkInterface {
+ public:
+ NetworkInterface(const char* name, uint64_t bytes_in, uint64_t bytes_out, NetworkInterface* next)
+ : ::NetworkInterface(name, bytes_in, bytes_out, next) {
+ }
+ NetworkInterface* next(void) const {
+ return reinterpret_cast<NetworkInterface*>(::NetworkInterface::next());
+ }
+ };
+
+ class MockJfrOSInterface {
+ static std::list<MockNetworkInterface> _interfaces;
+
+ public:
+ MockJfrOSInterface() {
+ }
+ static int network_utilization(NetworkInterface** network_interfaces) {
+ *network_interfaces = NULL;
+ for (std::list<MockNetworkInterface>::const_iterator i = _interfaces.begin();
+ i != _interfaces.end();
+ ++i) {
+ NetworkInterface* cur = new NetworkInterface(i->name.c_str(), i->bytes_in, i->bytes_out, *network_interfaces);
+ *network_interfaces = cur;
+ }
+ return OS_OK;
+ }
+ static MockNetworkInterface& add_interface(const std::string& name) {
+ MockNetworkInterface iface(name, 0, 0);
+ _interfaces.push_back(iface);
+ return _interfaces.back();
+ }
+ static void remove_interface(const MockNetworkInterface& iface) {
+ _interfaces.remove(iface);
+ }
+ static void clear_interfaces() {
+ _interfaces.clear();
+ }
+ };
+
+ std::list<MockNetworkInterface> MockJfrOSInterface::_interfaces;
+
+// Reincluding source files in the anonymous namespace unfortunately seems to
+// behave strangely with precompiled headers (only when using gcc though)
+#ifndef DONT_USE_PRECOMPILED_HEADER
+#define DONT_USE_PRECOMPILED_HEADER
+#endif
+
+#define EventNetworkUtilization MockEventNetworkUtilization
+#define FastUnorderedElapsedCounterSource MockFastUnorderedElapsedCounterSource
+#define JfrOSInterface MockJfrOSInterface
+#define JfrSerializer MockJfrSerializer
+#define JfrCheckpointWriter MockJfrCheckpointWriter
+
+#include "jfr/periodic/jfrNetworkUtilization.hpp"
+#include "jfr/periodic/jfrNetworkUtilization.cpp"
+
+#undef EventNetworkUtilization
+#undef FastUnorderedElapsedCounterSource
+#undef JfrOSInterface
+#undef JfrSerializer
+#undef JfrCheckpointWriter
+
+} // anonymous namespace
+
+class JfrTestNetworkUtilization : public ::testing::Test {
+protected:
+ void SetUp() {
+ MockEventNetworkUtilization::committed.clear();
+ MockJfrOSInterface::clear_interfaces();
+ // Ensure that tests are separated in time
+ MockFastUnorderedElapsedCounterSource::current_ticks += 1 * NANOSECS_PER_SEC;
+ }
+
+ void TearDown() {
+ JfrNetworkUtilization::destroy();
+ }
+};
+
+TEST_VM_F(JfrTestNetworkUtilization, RequestFunctionBasic) {
+
+ MockNetworkInterface& eth0 = MockJfrOSInterface::add_interface("eth0");
+ JfrNetworkUtilization::send_events();
+ ASSERT_EQ(0u, MockEventNetworkUtilization::committed.size());
+
+ eth0.bytes_in += 10;
+ MockFastUnorderedElapsedCounterSource::current_ticks += 2 * NANOSECS_PER_SEC;
+
+ JfrNetworkUtilization::send_events();
+ ASSERT_EQ(1u, MockEventNetworkUtilization::committed.size());
+ MockEventNetworkUtilization& e = MockEventNetworkUtilization::committed[0];
+ EXPECT_EQ(5, e.readRate);
+ EXPECT_EQ(0, e.writeRate);
+ EXPECT_STREQ("eth0", e.iface.c_str());
+}
+
+TEST_VM_F(JfrTestNetworkUtilization, RequestFunctionMultiple) {
+
+ MockNetworkInterface& eth0 = MockJfrOSInterface::add_interface("eth0");
+ MockNetworkInterface& eth1 = MockJfrOSInterface::add_interface("eth1");
+ MockNetworkInterface& ppp0 = MockJfrOSInterface::add_interface("ppp0");
+ JfrNetworkUtilization::send_events();
+ ASSERT_EQ(0u, MockEventNetworkUtilization::committed.size());
+
+ eth0.bytes_in += 10;
+ eth1.bytes_in += 100;
+ ppp0.bytes_out += 50;
+ MockFastUnorderedElapsedCounterSource::current_ticks += 2 * NANOSECS_PER_SEC;
+
+ JfrNetworkUtilization::send_events();
+ ASSERT_EQ(3u, MockEventNetworkUtilization::committed.size());
+ const MockEventNetworkUtilization& eth0_event = MockEventNetworkUtilization::get_committed("eth0");
+ const MockEventNetworkUtilization& eth1_event = MockEventNetworkUtilization::get_committed("eth1");
+ const MockEventNetworkUtilization& ppp0_event = MockEventNetworkUtilization::get_committed("ppp0");
+
+ EXPECT_EQ(5, eth0_event.readRate);
+ EXPECT_EQ(0, eth0_event.writeRate);
+ EXPECT_STREQ("eth0", eth0_event.iface.c_str());
+
+ EXPECT_EQ(50, eth1_event.readRate);
+ EXPECT_EQ(0, eth1_event.writeRate);
+ EXPECT_STREQ("eth1", eth1_event.iface.c_str());
+
+ EXPECT_EQ(0, ppp0_event.readRate);
+ EXPECT_EQ(25, ppp0_event.writeRate);
+ EXPECT_STREQ("ppp0", ppp0_event.iface.c_str());
+}
+
+TEST_VM_F(JfrTestNetworkUtilization, InterfaceRemoved) {
+ MockNetworkInterface& eth0 = MockJfrOSInterface::add_interface("eth0");
+ MockNetworkInterface& eth1 = MockJfrOSInterface::add_interface("eth1");
+ JfrNetworkUtilization::send_events();
+ ASSERT_EQ(0u, MockEventNetworkUtilization::committed.size());
+
+ eth0.bytes_in += 10;
+ eth1.bytes_in += 20;
+ MockFastUnorderedElapsedCounterSource::current_ticks += 2 * NANOSECS_PER_SEC;
+
+ JfrNetworkUtilization::send_events();
+ ASSERT_EQ(2u, MockEventNetworkUtilization::committed.size());
+ const MockEventNetworkUtilization& eth0_event = MockEventNetworkUtilization::get_committed("eth0");
+ const MockEventNetworkUtilization& eth1_event = MockEventNetworkUtilization::get_committed("eth1");
+
+ EXPECT_EQ(5, eth0_event.readRate);
+ EXPECT_EQ(0, eth0_event.writeRate);
+ EXPECT_STREQ("eth0", eth0_event.iface.c_str());
+
+ EXPECT_EQ(10, eth1_event.readRate);
+ EXPECT_EQ(0, eth1_event.writeRate);
+ EXPECT_STREQ("eth1", eth1_event.iface.c_str());
+
+ MockJfrOSInterface::remove_interface(eth0);
+ MockEventNetworkUtilization::committed.clear();
+
+ eth1.bytes_in += 10;
+ MockFastUnorderedElapsedCounterSource::current_ticks += 2 * NANOSECS_PER_SEC;
+ JfrNetworkUtilization::send_events();
+ ASSERT_EQ(1u, MockEventNetworkUtilization::committed.size());
+ const MockEventNetworkUtilization& eth1_event_v2 = MockEventNetworkUtilization::get_committed("eth1");
+
+ EXPECT_EQ(5, eth1_event_v2.readRate);
+ EXPECT_EQ(0, eth1_event_v2.writeRate);
+ EXPECT_STREQ("eth1", eth1_event_v2.iface.c_str());
+}
+
+TEST_VM_F(JfrTestNetworkUtilization, InterfaceReset) {
+ MockNetworkInterface& eth0 = MockJfrOSInterface::add_interface("eth0");
+ JfrNetworkUtilization::send_events();
+ ASSERT_EQ(0u, MockEventNetworkUtilization::committed.size());
+
+ eth0.bytes_in += 10;
+ MockFastUnorderedElapsedCounterSource::current_ticks += 2 * NANOSECS_PER_SEC;
+
+ JfrNetworkUtilization::send_events();
+ ASSERT_EQ(1u, MockEventNetworkUtilization::committed.size());
+ const MockEventNetworkUtilization& event = MockEventNetworkUtilization::committed[0];
+ EXPECT_EQ(5, event.readRate);
+ EXPECT_EQ(0, event.writeRate);
+ EXPECT_STREQ("eth0", event.iface.c_str());
+
+ eth0.bytes_in = 0;
+ MockFastUnorderedElapsedCounterSource::current_ticks += 2 * NANOSECS_PER_SEC;
+ MockEventNetworkUtilization::committed.clear();
+
+ JfrNetworkUtilization::send_events();
+ ASSERT_EQ(0u, MockEventNetworkUtilization::committed.size());
+
+ eth0.bytes_in = 10;
+ MockFastUnorderedElapsedCounterSource::current_ticks += 2 * NANOSECS_PER_SEC;
+
+ JfrNetworkUtilization::send_events();
+ ASSERT_EQ(1u, MockEventNetworkUtilization::committed.size());
+ const MockEventNetworkUtilization& event_v2 = MockEventNetworkUtilization::committed[0];
+ EXPECT_EQ(5, event_v2.readRate);
+ EXPECT_EQ(0, event_v2.writeRate);
+ EXPECT_STREQ("eth0", event_v2.iface.c_str());
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestNetworkUtilizationEvent.java Thu Jun 28 15:06:55 2018 +0200
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jfr.event.runtime;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.Platform;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.List;
+import java.util.Map;
+
+import static java.util.stream.Collectors.averagingLong;
+import static java.util.stream.Collectors.groupingBy;
+
+/*
+ * @test
+ * @key jfr
+ * @library /test/lib
+ *
+ * @run main/othervm jdk.jfr.event.runtime.TestNetworkUtilizationEvent
+ */
+public class TestNetworkUtilizationEvent {
+
+ private static final long packetSendCount = 100;
+
+ public static void main(String[] args) throws Throwable {
+ testSimple();
+ }
+
+ static void testSimple() throws Throwable {
+
+ Instant start = Instant.now();
+ Recording recording = new Recording();
+ recording.enable(EventNames.NetworkUtilization);
+ recording.start();
+
+ DatagramSocket socket = new DatagramSocket();
+ String msg = "hello!";
+ byte[] buf = msg.getBytes();
+
+ // Send a few packets both to the loopback address as well to an external
+ DatagramPacket packet = new DatagramPacket(buf, buf.length, InetAddress.getLoopbackAddress(), 12345);
+ for (int i = 0; i < packetSendCount; ++i) {
+ socket.send(packet);
+ }
+ packet = new DatagramPacket(buf, buf.length, InetAddress.getByName("10.0.0.0"), 12345);
+ for (int i = 0; i < packetSendCount; ++i) {
+ socket.send(packet);
+ }
+
+ // Now there should have been traffic on at least two different interfaces
+ recording.stop();
+ Duration runtime = Duration.between(start, Instant.now());
+ List<RecordedEvent> events = Events.fromRecording(recording);
+
+ // Calculate the average write rate for each interface
+ Map<String, Double> writeRates = events.stream()
+ .collect(groupingBy(e -> Events.assertField(e, "networkInterface").getValue(),
+ averagingLong(e -> Events.assertField(e, "writeRate").getValue())));
+
+ // Our test packets should have generated at least this much traffic per second
+ long expectedTraffic = (buf.length * packetSendCount) / Math.max(1, runtime.toSeconds());
+
+ // Count the number of interfaces that have seen at least our test traffic
+ long interfacesWithTraffic = writeRates.values().stream()
+ .filter(d -> d >= expectedTraffic)
+ .count();
+
+ if (Platform.isWindows() || Platform.isSolaris()) {
+ // Windows and Solaris do not track statistics for the loopback interface
+ Asserts.assertGreaterThanOrEqual(writeRates.size(), 1);
+ Asserts.assertGreaterThanOrEqual(interfacesWithTraffic, Long.valueOf(1));
+ } else {
+ Asserts.assertGreaterThanOrEqual(writeRates.size(), 2);
+ Asserts.assertGreaterThanOrEqual(interfacesWithTraffic, Long.valueOf(2));
+ }
+ }
+}
--- a/test/lib/jdk/test/lib/jfr/EventNames.java Thu Jun 28 18:04:19 2018 +0530
+++ b/test/lib/jdk/test/lib/jfr/EventNames.java Thu Jun 28 15:06:55 2018 +0200
@@ -155,6 +155,7 @@
public final static String InitialEnvironmentVariable = PREFIX + "InitialEnvironmentVariable";
public final static String NativeLibrary = PREFIX + "NativeLibrary";
public final static String PhysicalMemory = PREFIX + "PhysicalMemory";
+ public final static String NetworkUtilization = PREFIX + "NetworkUtilization";
// JDK
public static final String FileForce = PREFIX + "FileForce";