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
|
||||
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 <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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
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 "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);
|
||||
}
|
||||
|
|
|
@ -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" />
|
||||
|
|
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 "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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
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 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";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue