--- /dev/null 2019-01-28 17:49:05.000000000 +0800 +++ new/test/jfr/test_threadCpuLoad.cpp 2019-01-28 17:49:05.000000000 +0800 @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2017, 2019, 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 "jvm.h" +#include "classfile/classLoaderStats.hpp" +#include "classfile/javaClasses.hpp" +#include "code/codeCache.hpp" +#include "compiler/compileBroker.hpp" +#include "gc/g1/g1HeapRegionEventSender.hpp" +#include "gc/shared/gcConfiguration.hpp" +#include "gc/shared/gcTrace.hpp" +#include "gc/shared/objectCountEventSender.hpp" +#include "gc/shared/vmGCOperations.hpp" +#include "jfr/periodic/jfrModuleEvent.hpp" +#include "jfr/periodic/jfrOSInterface.hpp" +#include "jfr/periodic/jfrThreadCPULoadEvent.hpp" +#include "jfr/periodic/jfrThreadDumpEvent.hpp" +#include "jfr/recorder/jfrRecorder.hpp" +#include "jfr/utilities/jfrTraceTime.hpp" +#include "logging/log.hpp" +#include "memory/heapInspection.hpp" +#include "memory/resourceArea.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/arguments.hpp" +#include "runtime/globals.hpp" +#include "runtime/os.hpp" +#include "runtime/os_perf.hpp" +#include "runtime/thread.inline.hpp" +#include "runtime/threadSMR.hpp" +#include "runtime/sweeper.hpp" +#include "runtime/vmThread.hpp" +#include "services/classLoadingService.hpp" +#include "services/management.hpp" +#include "services/threadService.hpp" +#include "trace/tracing.hpp" +#include "utilities/exceptions.hpp" +#include "utilities/globalDefinitions.hpp" + +#include "unittest.hpp" + +namespace { + + class MockEventThreadCPULoad : public ::EventThreadCPULoad + { + public: + float user; + float system; + + public: + MockEventThreadCPULoad(EventStartTime timing=TIMED) : ::EventThreadCPULoad(timing) {} + + void set_user(float new_value) { + user = new_value; + } + void set_system(float new_value) { + system = new_value; + } + }; + + class MockOs : public ::os { + public: + static jlong user_cpu_time; + static jlong system_cpu_time; + + static jlong thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { + return user_sys_cpu_time ? user_cpu_time + system_cpu_time : user_cpu_time; + } + }; + + jlong MockOs::user_cpu_time; + jlong MockOs::system_cpu_time; + +// 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 os MockOs +#define EventThreadCPULoad MockEventThreadCPULoad + +#include "tracefiles/tracePeriodic.hpp" +#include "jfr/periodic/jfrPeriodic.cpp" + +#undef os +#undef EventThreadCPULoad + +} // anonymous namespace + +class JfrTestThreadCPULoadSingle : public ::testing::Test { +protected: + JavaThread* thread; + JfrThreadData* thread_data; + MockEventThreadCPULoad event; + + void SetUp() { + thread = new JavaThread(); + thread_data = thread->trace_data(); + thread_data->set_wallclock_time(0); + thread_data->set_user_time(0); + thread_data->set_cpu_time(0); + } + + void TearDown() { + delete thread; + } +}; + +TEST_VM_F(JfrTestThreadCPULoadSingle, SingleCpu) { + MockOs::user_cpu_time = 100 * NANOSECS_PER_MILLISEC; + MockOs::system_cpu_time = 100 * NANOSECS_PER_MILLISEC; + EXPECT_TRUE(JfrThreadCPULoadEvent::update_event(event, thread, 400 * NANOSECS_PER_MILLISEC, 1)); + EXPECT_FLOAT_EQ(0.25, event.user); + EXPECT_FLOAT_EQ(0.25, event.system); +} + +TEST_VM_F(JfrTestThreadCPULoadSingle, MultipleCpus) { + MockOs::user_cpu_time = 100 * NANOSECS_PER_MILLISEC; + MockOs::system_cpu_time = 100 * NANOSECS_PER_MILLISEC; + EXPECT_TRUE(JfrThreadCPULoadEvent::update_event(event, thread, 400 * NANOSECS_PER_MILLISEC, 2)); + EXPECT_FLOAT_EQ(0.125, event.user); + EXPECT_FLOAT_EQ(0.125, event.system); +} + +TEST_VM_F(JfrTestThreadCPULoadSingle, BelowThreshold) { + MockOs::user_cpu_time = 100; + MockOs::system_cpu_time = 100; + EXPECT_FALSE(JfrThreadCPULoadEvent::update_event(event, thread, 400 * NANOSECS_PER_MILLISEC, 2)); +} + +TEST_VM_F(JfrTestThreadCPULoadSingle, UserAboveMaximum) { + + // First call will not report above 100% + MockOs::user_cpu_time = 200 * NANOSECS_PER_MILLISEC; + MockOs::system_cpu_time = 100 * NANOSECS_PER_MILLISEC; + EXPECT_TRUE(JfrThreadCPULoadEvent::update_event(event, thread, 200 * NANOSECS_PER_MILLISEC, 1)); + EXPECT_FLOAT_EQ(0.5, event.user); + EXPECT_FLOAT_EQ(0.5, event.system); + + // Second call will see an extra 100 millisecs user time from the remainder + EXPECT_TRUE(JfrThreadCPULoadEvent::update_event(event, thread, (200 + 400) * NANOSECS_PER_MILLISEC, 1)); + EXPECT_FLOAT_EQ(0.25, event.user); + EXPECT_FLOAT_EQ(0, event.system); +} + +TEST_VM_F(JfrTestThreadCPULoadSingle, SystemAboveMaximum) { + + // First call will not report above 100% + MockOs::user_cpu_time = 100 * NANOSECS_PER_MILLISEC; + MockOs::system_cpu_time = 300 * NANOSECS_PER_MILLISEC; + EXPECT_TRUE(JfrThreadCPULoadEvent::update_event(event, thread, 200 * NANOSECS_PER_MILLISEC, 1)); + EXPECT_FLOAT_EQ(0, event.user); + EXPECT_FLOAT_EQ(1, event.system); + + // Second call will see an extra 100 millisecs user and system time from the remainder + EXPECT_TRUE(JfrThreadCPULoadEvent::update_event(event, thread, (200 + 400) * NANOSECS_PER_MILLISEC, 1)); + EXPECT_FLOAT_EQ(0.25, event.user); + EXPECT_FLOAT_EQ(0.25, event.system); +} + +TEST_VM_F(JfrTestThreadCPULoadSingle, SystemTimeDecreasing) { + + // As seen in an actual run - caused by different resolution for total and user time + // Total time User time (Calculated system time) + // 200 100 100 + // 210 200 10 + // 400 300 100 + + MockOs::user_cpu_time = 100 * NANOSECS_PER_MILLISEC; + MockOs::system_cpu_time = 100 * NANOSECS_PER_MILLISEC; + EXPECT_TRUE(JfrThreadCPULoadEvent::update_event(event, thread, 400 * NANOSECS_PER_MILLISEC, 1)); + EXPECT_FLOAT_EQ(0.25, event.user); + EXPECT_FLOAT_EQ(0.25, event.system); + + MockOs::user_cpu_time += 100 * NANOSECS_PER_MILLISEC; + MockOs::system_cpu_time -= 90 * NANOSECS_PER_MILLISEC; + EXPECT_TRUE(JfrThreadCPULoadEvent::update_event(event, thread, (400 + 400) * NANOSECS_PER_MILLISEC, 1)); + EXPECT_FLOAT_EQ(0.25, event.user); + EXPECT_FLOAT_EQ(0, event.system); + + MockOs::user_cpu_time += 100 * NANOSECS_PER_MILLISEC; + MockOs::system_cpu_time += 90 * NANOSECS_PER_MILLISEC; + EXPECT_TRUE(JfrThreadCPULoadEvent::update_event(event, thread, (400 + 400 + 400) * NANOSECS_PER_MILLISEC, 1)); + EXPECT_FLOAT_EQ(0.25, event.user); + EXPECT_FLOAT_EQ(0, event.system); +}