/* * Copyright (c) 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. */ /* * @test * @summary Tests ThreadMXBean statistics methods optimized for * the current thread * * @run main/othervm ThreadStatistics */ import com.sun.management.ThreadMXBean; import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.util.concurrent.CountDownLatch; public class ThreadStatistics { private static final ThreadMXBean mbean = (com.sun.management.ThreadMXBean) ManagementFactory.getThreadMXBean(); private static boolean testFailed = false; public static void main(String[] args) throws Exception { System.loadLibrary("threadStatistics"); if (mbean.isThreadContentionMonitoringSupported()) { mbean.setThreadContentionMonitoringEnabled(true); checkResetContentionCountForCurrentThread(); checkResetContentionCount(); checkResetContentionTimeForCurrentThread(); checkResetContentionTime(); } else { System.out.println("Thread contention monitoring is not supported"); } if (mbean.isThreadCpuTimeSupported()) { mbean.setThreadCpuTimeEnabled(true); checkThreadCpuTimeForCurrentThread(); checkThreadCpuTime(); checkThreadUserTimeForCurrentThread(); checkThreadUserTime(); } else { System.out.println("Thread CPU time monitoring is not supported"); } if (mbean.isThreadAllocatedMemorySupported()) { mbean.setThreadAllocatedMemoryEnabled(true); checkThreadAllocatedBytesForCurrentThread(); checkThreadAllocatedBytes(); } else { System.out.println("Thread allocated memory monitoring is not supported"); } if (testFailed) { throw new RuntimeException("TEST FAILED."); } System.out.println("Test passed"); } public static void checkResetContentionCountForCurrentThread() throws Exception { System.out.println("Checking resetting the block count for the current thread"); long tid = createContentionInCurrentThread(); checkResetContentionCount(tid); } public static void checkResetContentionCount() throws Exception { System.out.println("Checking resetting the block count for another thread"); CountDownLatch finish = new CountDownLatch(1); long tid = createContentionInNewThread(finish); checkResetContentionCount(tid); finish.countDown(); } public static void checkResetContentionTimeForCurrentThread() throws Exception { System.out.println("Checking resetting the block time for the current thread"); long tid = createContentionInCurrentThread(); checkResetContentionTime(tid); } public static void checkResetContentionTime() throws Exception { System.out.println("Checking resetting the block time for another thread"); CountDownLatch finish = new CountDownLatch(1); long tid = createContentionInNewThread(finish); checkResetContentionTime(tid); finish.countDown(); } public static void checkThreadCpuTimeForCurrentThread() { System.out.println("Checking the thread CPU time for the current thread"); doComputeWork(); checkThreadCpuTime(Thread.currentThread().getId()); } public static void checkThreadCpuTime() { System.out.println("Checking the thread CPU time for another thread"); CountDownLatch finish = new CountDownLatch(1); long tid = runInNewThread(finish, ThreadStatistics::doComputeWork); checkThreadCpuTime(tid); finish.countDown(); } public static void checkThreadUserTimeForCurrentThread() { System.out.println("Checking the thread user time for the current thread"); doComputeWork(); checkThreadUserTime(Thread.currentThread().getId()); } public static void checkThreadUserTime() { System.out.println("Checking the thread user time for another thread"); CountDownLatch finish = new CountDownLatch(1); long tid = runInNewThread(finish, ThreadStatistics::doComputeWork); checkThreadUserTime(tid); finish.countDown(); } public static void checkThreadAllocatedBytesForCurrentThread() { System.out.println("Checking the thread allocated bytes for the current thread"); doMemoryAllocationWork(); checkThreadAllocatedBytes(Thread.currentThread().getId()); } public static void checkThreadAllocatedBytes() { System.out.println("Checking the thread allocated bytes for another thread"); CountDownLatch finish = new CountDownLatch(1); long tid = runInNewThread(finish, ThreadStatistics::doMemoryAllocationWork); checkThreadAllocatedBytes(tid); finish.countDown(); } private static void checkResetContentionCount(long tid) { ThreadInfo info = mbean.getThreadInfo(tid); if (info.getBlockedCount() <= 0) { testFailed = true; System.out.println("CHECK FAILED. Invalid blocked count was returned for thread:" + info.getBlockedCount()); return; } resetThreadContentionCount(tid); ThreadInfo newInfo = mbean.getThreadInfo(tid); System.out.println("blockedCount:" + info.getBlockedCount() + " blockedTime:" + info.getBlockedTime()); if (newInfo.getBlockedCount() != 0) { testFailed = true; System.out.println("CHECK FAILED. The blocked count for the tested thread was not reset, " + " threadInfo.getBlockedCount() = " + newInfo.getBlockedCount()); return; } System.out.println("Check passed"); } private static void checkResetContentionTime(long tid) { ThreadInfo info = mbean.getThreadInfo(tid); if (info.getBlockedTime() < 0) { testFailed = true; System.out.println("Invalid blocked time was returned for thread:" + info.getBlockedTime()); return; } resetThreadContentionTime(tid); ThreadInfo newInfo = mbean.getThreadInfo(tid); System.out.println("blockedCount:" + info.getBlockedCount() + " blockedTime:" + info.getBlockedTime()); if (newInfo.getBlockedTime() != 0) { testFailed = true; System.out.println("CHECK FAILED. The blocked time for the tested thread was not reset," + " threadInfo.getBlockedTime() = " + newInfo.getBlockedTime()); return; } System.out.println("Check passed"); } private static void checkThreadCpuTime(long tid) { long time = mbean.getThreadCpuTime(tid); System.out.println("CPU time:" + time); if (time < 0) { testFailed = true; System.out.println("CHECK FAILED. Invalid CPU time returned for thread:" + time); return; } System.out.println("Check passed"); } private static void checkThreadUserTime(long tid) { long time = mbean.getThreadUserTime(tid); System.out.println("User time:" + time); if (time < 0) { testFailed = true; System.out.println("CHECK FAILED. Invalid user time returned for thread:" + time); return; } System.out.println("Check passed"); } private static void checkThreadAllocatedBytes(long tid) { long bytes = mbean.getThreadAllocatedBytes(tid); System.out.println("Allocated bytes:" + bytes); if (bytes < 0) { testFailed = true; System.out.println("CHECK FAILED. Invalid allocated bytes returned for thread:"); return; } System.out.println("Check passed"); } private static long createContentionInCurrentThread() throws Exception { CountDownLatch start = new CountDownLatch(1); Object lock = new Object(); long tid = Thread.currentThread().getId(); new Thread(() -> { synchronized (lock) { start.countDown(); while (true) { ThreadInfo info = mbean.getThreadInfo(tid); if (info.getThreadState() == Thread.State.BLOCKED) { break; } try { Thread.sleep(10); } catch (InterruptedException ex) { System.out.println("Interrupted exception " + ex); } } } }).start(); start.await(); synchronized (lock) { System.out.println("Inside the lock for the current thread"); } return tid; } public static long createContentionInNewThread(CountDownLatch okToTerminate) throws Exception { Object lock = new Object(); Thread t = new Thread(() -> { synchronized (lock) { System.out.println("Inside the lock"); } try { // Wait till the statistics is collected okToTerminate.await(); } catch (InterruptedException ex) { System.out.println("Interrupted exception " + ex); } }); synchronized (lock) { t.start(); while (true) { ThreadInfo info = mbean.getThreadInfo(t.getId()); if (info.getThreadState() == Thread.State.BLOCKED) { break; } Thread.sleep(10); } } return t.getId(); } public static long runInNewThread(CountDownLatch okToTerminate, Runnable extraWork) { CountDownLatch workCompleted = new CountDownLatch(1); Thread t = new Thread(() -> { if (extraWork != null) { extraWork.run(); } workCompleted.countDown(); try { // Wait till the statistics is collected okToTerminate.await(); } catch (InterruptedException ex) { System.out.println("Interrupted exception " + ex); } }); t.start(); try { workCompleted.await(); } catch (InterruptedException ex) { System.out.println("Interrupted exception " + ex); } return t.getId(); } private static void doMemoryAllocationWork() { String tmp = ""; long hashCode = 0; for (int counter = 0; counter < 1000; counter++) { tmp += counter; hashCode = tmp.hashCode(); } System.out.println(Thread.currentThread().getName() + " hashcode: " + hashCode); } private static void doComputeWork() { double sum = 0; for (int i = 0; i < 5000; i++) { double r = Math.random(); double x = Math.pow(3, r); sum += x - r; } System.out.println(Thread.currentThread().getName() + " sum = " + sum); } native static void resetThreadContentionCount(long tid); native static void resetThreadContentionTime(long tid); }