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