8003209: JFR events for network utilization

Reviewed-by: mgronlun, egahlin
This commit is contained in:
Robin Westberg 2018-06-28 15:06:55 +02:00
parent 724ba7feb2
commit b11c7752e8
19 changed files with 1350 additions and 10 deletions

View file

@ -1041,3 +1041,49 @@ int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
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);
}

View file

@ -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 @@ int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
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);
}

View file

@ -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 @@ int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
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);
}

View file

@ -754,3 +754,88 @@ int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
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);
}

View file

@ -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);
}

View file

@ -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

View file

@ -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 "vm_version_ext_x86.hpp"
#include "utilities/macros.hpp"
#include "vm_version_ext_x86.hpp"
#include <math.h>
#include <psapi.h>
#include <TlHelp32.h>
@ -1380,3 +1381,78 @@ int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
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);
}

View file

@ -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" />

View file

@ -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();
}
}

View file

@ -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

View file

@ -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 @@ JfrOSInterface* JfrOSInterface::create() {
}
void JfrOSInterface::destroy() {
JfrNetworkUtilization::destroy();
if (_instance != NULL) {
delete _instance;
_instance = NULL;
@ -66,6 +68,7 @@ class JfrOSInterface::JfrOSInterfaceImpl : public JfrCHeapObj {
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 @@ class JfrOSInterface::JfrOSInterfaceImpl : public JfrCHeapObj {
// 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 @@ JfrOSInterface::JfrOSInterfaceImpl::JfrOSInterfaceImpl() : _cpu_info_interface(N
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 @@ JfrOSInterface::JfrOSInterfaceImpl::~JfrOSInterfaceImpl(void) {
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 @@ int JfrOSInterface::JfrOSInterfaceImpl::system_processes(SystemProcess** system_
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::generate_initial_environment_variable_events() {
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);
}

View file

@ -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 @@ class JfrOSInterface: public JfrCHeapObj {
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

View file

@ -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 @@ TRACE_REQUEST_FUNC(ThreadCPULoad) {
JfrThreadCPULoadEvent::send_events();
}
TRACE_REQUEST_FUNC(NetworkUtilization) {
JfrNetworkUtilization::send_events();
}
TRACE_REQUEST_FUNC(CPUTimeStampCounter) {
EventCPUTimeStampCounter event;
event.set_fastTimeEnabled(JfrTime::is_ft_enabled());

View file

@ -25,9 +25,8 @@
#ifndef SHARE_VM_RUNTIME_OS_PERF_HPP
#define SHARE_VM_RUNTIME_OS_PERF_HPP
#include "utilities/macros.hpp"
#include "memory/allocation.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp"
#define FUNCTIONALITY_NOT_IMPLEMENTED -8
@ -194,6 +193,47 @@ class SystemProcess : public CHeapObj<mtInternal> {
}
};
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 @@ class SystemProcessInterface : public CHeapObj<mtInternal> {
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

View file

@ -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>

View file

@ -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>

View file

@ -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());
}

View file

@ -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));
}
}
}

View file

@ -155,6 +155,7 @@ public class EventNames {
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";