mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-18 10:04:42 +02:00
8003209: JFR events for network utilization
Reviewed-by: mgronlun, egahlin
This commit is contained in:
parent
724ba7feb2
commit
b11c7752e8
19 changed files with 1350 additions and 10 deletions
|
@ -1041,3 +1041,49 @@ int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
|
||||||
cpu_info = *_cpu_info; // shallow copy assignment
|
cpu_info = *_cpu_info; // shallow copy assignment
|
||||||
return OS_OK;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -34,6 +34,10 @@
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#include <mach/mach.h>
|
#include <mach/mach.h>
|
||||||
#include <mach/task_info.h>
|
#include <mach/task_info.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <net/if_dl.h>
|
||||||
|
#include <net/route.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const double NANOS_PER_SEC = 1000000000.0;
|
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
|
cpu_info = *_cpu_info; // shallow copy assignment
|
||||||
return OS_OK;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -44,6 +44,8 @@
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
/proc/[number]/stat
|
/proc/[number]/stat
|
||||||
|
@ -1048,3 +1050,94 @@ int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
|
||||||
cpu_info = *_cpu_info; // shallow copy assignment
|
cpu_info = *_cpu_info; // shallow copy assignment
|
||||||
return OS_OK;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -754,3 +754,88 @@ int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
|
||||||
cpu_info = *_cpu_info; // shallow copy assignment
|
cpu_info = *_cpu_info; // shallow copy assignment
|
||||||
return OS_OK;
|
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);
|
||||||
|
}
|
||||||
|
|
105
src/hotspot/os/windows/iphlp_interface.cpp
Normal file
105
src/hotspot/os/windows/iphlp_interface.cpp
Normal 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);
|
||||||
|
}
|
51
src/hotspot/os/windows/iphlp_interface.hpp
Normal file
51
src/hotspot/os/windows/iphlp_interface.hpp
Normal 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
|
|
@ -23,14 +23,15 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
|
#include "iphlp_interface.hpp"
|
||||||
#include "logging/log.hpp"
|
#include "logging/log.hpp"
|
||||||
#include "memory/allocation.inline.hpp"
|
#include "memory/allocation.inline.hpp"
|
||||||
#include "memory/resourceArea.hpp"
|
#include "memory/resourceArea.hpp"
|
||||||
#include "pdh_interface.hpp"
|
#include "pdh_interface.hpp"
|
||||||
#include "runtime/os_perf.hpp"
|
#include "runtime/os_perf.hpp"
|
||||||
#include "runtime/os.hpp"
|
#include "runtime/os.hpp"
|
||||||
#include "vm_version_ext_x86.hpp"
|
|
||||||
#include "utilities/macros.hpp"
|
#include "utilities/macros.hpp"
|
||||||
|
#include "vm_version_ext_x86.hpp"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <psapi.h>
|
#include <psapi.h>
|
||||||
#include <TlHelp32.h>
|
#include <TlHelp32.h>
|
||||||
|
@ -1380,3 +1381,78 @@ int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
|
||||||
cpu_info = *_cpu_info; // shallow copy assignment
|
cpu_info = *_cpu_info; // shallow copy assignment
|
||||||
return OS_OK;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -656,6 +656,12 @@
|
||||||
<Field type="float" name="switchRate" label="Switch Rate" description="Number of context switches per second" />
|
<Field type="float" name="switchRate" label="Switch Rate" description="Number of context switches per second" />
|
||||||
</Event>
|
</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">
|
<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="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" />
|
<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" />
|
<Field type="string" name="sampler" label="Sampler" />
|
||||||
</Type>
|
</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">
|
<Type name="Thread" label="Thread">
|
||||||
<Field type="string" name="osName" label="OS Thread Name" />
|
<Field type="string" name="osName" label="OS Thread Name" />
|
||||||
<Field type="long" name="osThreadId" label="OS Thread Id" />
|
<Field type="long" name="osThreadId" label="OS Thread Id" />
|
||||||
|
|
191
src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp
Normal file
191
src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
38
src/hotspot/share/jfr/periodic/jfrNetworkUtilization.hpp
Normal file
38
src/hotspot/share/jfr/periodic/jfrNetworkUtilization.hpp
Normal 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
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "jfr/jfrEvents.hpp"
|
#include "jfr/jfrEvents.hpp"
|
||||||
|
#include "jfr/periodic/jfrNetworkUtilization.hpp"
|
||||||
#include "jfr/periodic/jfrOSInterface.hpp"
|
#include "jfr/periodic/jfrOSInterface.hpp"
|
||||||
#include "memory/allocation.inline.hpp"
|
#include "memory/allocation.inline.hpp"
|
||||||
#include "memory/resourceArea.hpp"
|
#include "memory/resourceArea.hpp"
|
||||||
|
@ -54,6 +55,7 @@ JfrOSInterface* JfrOSInterface::create() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void JfrOSInterface::destroy() {
|
void JfrOSInterface::destroy() {
|
||||||
|
JfrNetworkUtilization::destroy();
|
||||||
if (_instance != NULL) {
|
if (_instance != NULL) {
|
||||||
delete _instance;
|
delete _instance;
|
||||||
_instance = NULL;
|
_instance = NULL;
|
||||||
|
@ -66,6 +68,7 @@ class JfrOSInterface::JfrOSInterfaceImpl : public JfrCHeapObj {
|
||||||
CPUInformationInterface* _cpu_info_interface;
|
CPUInformationInterface* _cpu_info_interface;
|
||||||
CPUPerformanceInterface* _cpu_perf_interface;
|
CPUPerformanceInterface* _cpu_perf_interface;
|
||||||
SystemProcessInterface* _system_process_interface;
|
SystemProcessInterface* _system_process_interface;
|
||||||
|
NetworkPerformanceInterface* _network_performance_interface;
|
||||||
|
|
||||||
// stub helper
|
// stub helper
|
||||||
void functionality_not_implemented(char** str) const;
|
void functionality_not_implemented(char** str) const;
|
||||||
|
@ -89,6 +92,8 @@ class JfrOSInterface::JfrOSInterfaceImpl : public JfrCHeapObj {
|
||||||
|
|
||||||
// system processes information
|
// system processes information
|
||||||
int system_processes(SystemProcess** system_processes, int* no_of_sys_processes);
|
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),
|
JfrOSInterface::JfrOSInterfaceImpl::JfrOSInterfaceImpl() : _cpu_info_interface(NULL),
|
||||||
|
@ -97,18 +102,19 @@ JfrOSInterface::JfrOSInterfaceImpl::JfrOSInterfaceImpl() : _cpu_info_interface(N
|
||||||
|
|
||||||
bool JfrOSInterface::JfrOSInterfaceImpl::initialize() {
|
bool JfrOSInterface::JfrOSInterfaceImpl::initialize() {
|
||||||
_cpu_info_interface = new CPUInformationInterface();
|
_cpu_info_interface = new CPUInformationInterface();
|
||||||
bool success = _cpu_info_interface != NULL && _cpu_info_interface->initialize();
|
if (!(_cpu_info_interface != NULL && _cpu_info_interface->initialize())) {
|
||||||
if (!success) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_cpu_perf_interface = new CPUPerformanceInterface();
|
_cpu_perf_interface = new CPUPerformanceInterface();
|
||||||
success = _cpu_perf_interface != NULL && _cpu_perf_interface->initialize();
|
if (!(_cpu_perf_interface != NULL && _cpu_perf_interface->initialize())) {
|
||||||
if (!success) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
_system_process_interface = new SystemProcessInterface();
|
_system_process_interface = new SystemProcessInterface();
|
||||||
success = _system_process_interface != NULL && _system_process_interface->initialize();
|
if (!(_system_process_interface != NULL && _system_process_interface->initialize())) {
|
||||||
return success;
|
return false;
|
||||||
|
}
|
||||||
|
_network_performance_interface = new NetworkPerformanceInterface();
|
||||||
|
return _network_performance_interface != NULL && _network_performance_interface->initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
JfrOSInterface::JfrOSInterfaceImpl::~JfrOSInterfaceImpl(void) {
|
JfrOSInterface::JfrOSInterfaceImpl::~JfrOSInterfaceImpl(void) {
|
||||||
|
@ -124,6 +130,10 @@ JfrOSInterface::JfrOSInterfaceImpl::~JfrOSInterfaceImpl(void) {
|
||||||
delete _system_process_interface;
|
delete _system_process_interface;
|
||||||
_system_process_interface = NULL;
|
_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) {
|
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);
|
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
|
// assigned char* is RESOURCE_HEAP_ALLOCATED
|
||||||
// caller need to ensure proper ResourceMark placement.
|
// caller need to ensure proper ResourceMark placement.
|
||||||
int JfrOSInterface::JfrOSInterfaceImpl::os_version(char** os_version) const {
|
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) {
|
int JfrOSInterface::system_processes(SystemProcess** sys_processes, int* no_of_sys_processes) {
|
||||||
return instance()._impl->system_processes(sys_processes, 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);
|
||||||
|
}
|
||||||
|
|
|
@ -26,10 +26,10 @@
|
||||||
#define SHARE_VM_JFR_PERIODIC_JFROSINTERFACE_HPP
|
#define SHARE_VM_JFR_PERIODIC_JFROSINTERFACE_HPP
|
||||||
|
|
||||||
#include "jfr/utilities/jfrAllocation.hpp"
|
#include "jfr/utilities/jfrAllocation.hpp"
|
||||||
#include "utilities/globalDefinitions.hpp"
|
|
||||||
|
|
||||||
class CPUInformation;
|
class CPUInformation;
|
||||||
class EnvironmentVariable;
|
class EnvironmentVariable;
|
||||||
|
class NetworkInterface;
|
||||||
class SystemProcess;
|
class SystemProcess;
|
||||||
|
|
||||||
class JfrOSInterface: public JfrCHeapObj {
|
class JfrOSInterface: public JfrCHeapObj {
|
||||||
|
@ -54,6 +54,7 @@ class JfrOSInterface: public JfrCHeapObj {
|
||||||
static int os_version(char** os_version);
|
static int os_version(char** os_version);
|
||||||
static int generate_initial_environment_variable_events();
|
static int generate_initial_environment_variable_events();
|
||||||
static int system_processes(SystemProcess** system_processes, int* no_of_sys_processes);
|
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
|
#endif // SHARE_VM_JFR_PERIODIC_JFROSINTERFACE_HPP
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#include "jfr/periodic/jfrOSInterface.hpp"
|
#include "jfr/periodic/jfrOSInterface.hpp"
|
||||||
#include "jfr/periodic/jfrThreadCPULoadEvent.hpp"
|
#include "jfr/periodic/jfrThreadCPULoadEvent.hpp"
|
||||||
#include "jfr/periodic/jfrThreadDumpEvent.hpp"
|
#include "jfr/periodic/jfrThreadDumpEvent.hpp"
|
||||||
|
#include "jfr/periodic/jfrNetworkUtilization.hpp"
|
||||||
#include "jfr/recorder/jfrRecorder.hpp"
|
#include "jfr/recorder/jfrRecorder.hpp"
|
||||||
#include "jfr/support/jfrThreadId.hpp"
|
#include "jfr/support/jfrThreadId.hpp"
|
||||||
#include "jfr/utilities/jfrTime.hpp"
|
#include "jfr/utilities/jfrTime.hpp"
|
||||||
|
@ -176,6 +177,10 @@ TRACE_REQUEST_FUNC(ThreadCPULoad) {
|
||||||
JfrThreadCPULoadEvent::send_events();
|
JfrThreadCPULoadEvent::send_events();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TRACE_REQUEST_FUNC(NetworkUtilization) {
|
||||||
|
JfrNetworkUtilization::send_events();
|
||||||
|
}
|
||||||
|
|
||||||
TRACE_REQUEST_FUNC(CPUTimeStampCounter) {
|
TRACE_REQUEST_FUNC(CPUTimeStampCounter) {
|
||||||
EventCPUTimeStampCounter event;
|
EventCPUTimeStampCounter event;
|
||||||
event.set_fastTimeEnabled(JfrTime::is_ft_enabled());
|
event.set_fastTimeEnabled(JfrTime::is_ft_enabled());
|
||||||
|
|
|
@ -25,9 +25,8 @@
|
||||||
#ifndef SHARE_VM_RUNTIME_OS_PERF_HPP
|
#ifndef SHARE_VM_RUNTIME_OS_PERF_HPP
|
||||||
#define SHARE_VM_RUNTIME_OS_PERF_HPP
|
#define SHARE_VM_RUNTIME_OS_PERF_HPP
|
||||||
|
|
||||||
#include "utilities/macros.hpp"
|
|
||||||
#include "memory/allocation.hpp"
|
#include "memory/allocation.hpp"
|
||||||
#include "utilities/globalDefinitions.hpp"
|
#include "utilities/macros.hpp"
|
||||||
|
|
||||||
#define FUNCTIONALITY_NOT_IMPLEMENTED -8
|
#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> {
|
class CPUInformationInterface : public CHeapObj<mtInternal> {
|
||||||
private:
|
private:
|
||||||
CPUInformation* _cpu_info;
|
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;
|
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
|
#endif // SHARE_VM_RUNTIME_OS_PERF_HPP
|
||||||
|
|
|
@ -518,6 +518,11 @@
|
||||||
<setting name="period">endChunk</setting>
|
<setting name="period">endChunk</setting>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
|
<event name="jdk.NetworkUtilization">
|
||||||
|
<setting name="enabled">true</setting>
|
||||||
|
<setting name="period">5 s</setting>
|
||||||
|
</event>
|
||||||
|
|
||||||
<event name="jdk.InitialEnvironmentVariable">
|
<event name="jdk.InitialEnvironmentVariable">
|
||||||
<setting name="enabled">true</setting>
|
<setting name="enabled">true</setting>
|
||||||
<setting name="period">beginChunk</setting>
|
<setting name="period">beginChunk</setting>
|
||||||
|
|
|
@ -518,6 +518,11 @@
|
||||||
<setting name="period">endChunk</setting>
|
<setting name="period">endChunk</setting>
|
||||||
</event>
|
</event>
|
||||||
|
|
||||||
|
<event name="jdk.NetworkUtilization">
|
||||||
|
<setting name="enabled">true</setting>
|
||||||
|
<setting name="period">5 s</setting>
|
||||||
|
</event>
|
||||||
|
|
||||||
<event name="jdk.InitialEnvironmentVariable">
|
<event name="jdk.InitialEnvironmentVariable">
|
||||||
<setting name="enabled">true</setting>
|
<setting name="enabled">true</setting>
|
||||||
<setting name="period">beginChunk</setting>
|
<setting name="period">beginChunk</setting>
|
||||||
|
|
362
test/hotspot/gtest/jfr/test_networkUtilization.cpp
Normal file
362
test/hotspot/gtest/jfr/test_networkUtilization.cpp
Normal 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());
|
||||||
|
}
|
109
test/jdk/jdk/jfr/event/runtime/TestNetworkUtilizationEvent.java
Normal file
109
test/jdk/jdk/jfr/event/runtime/TestNetworkUtilizationEvent.java
Normal 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -155,6 +155,7 @@ public class EventNames {
|
||||||
public final static String InitialEnvironmentVariable = PREFIX + "InitialEnvironmentVariable";
|
public final static String InitialEnvironmentVariable = PREFIX + "InitialEnvironmentVariable";
|
||||||
public final static String NativeLibrary = PREFIX + "NativeLibrary";
|
public final static String NativeLibrary = PREFIX + "NativeLibrary";
|
||||||
public final static String PhysicalMemory = PREFIX + "PhysicalMemory";
|
public final static String PhysicalMemory = PREFIX + "PhysicalMemory";
|
||||||
|
public final static String NetworkUtilization = PREFIX + "NetworkUtilization";
|
||||||
|
|
||||||
// JDK
|
// JDK
|
||||||
public static final String FileForce = PREFIX + "FileForce";
|
public static final String FileForce = PREFIX + "FileForce";
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue