test/hotspot/gtest/jfr/test_networkUtilization.cpp
changeset 50879 d90c3cbf13df
child 50894 e8d55141afd2
--- /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());
+}