diff -r 746229cc1ab0 -r cc29d7717e3a test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon001.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon001.java Wed May 02 16:43:56 2018 -0700 @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2003, 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. + */ + +package nsk.monitoring.stress.thread; + +import java.lang.management.*; +import java.io.*; + +import nsk.share.*; +import nsk.monitoring.share.*; + +public class cmon001 { + final static long CONST_BARRIER_TIME = 200; + final static long ITERATIONS = 50; + + // Precision of value returned by ThreadInfo.getWaitedTime(). + // System.nanoTime() and ThreadInfo.getWaitedTime() may use + // different methods to sample time, so PRECISION is essential to + // compare those two times. + final static long PRECISION = 3; // Milliseconds + + // Ratio between nano and milli + final static long NANO_MILLI = 1000000; + + private static volatile boolean testFailed = false; + private static Integer calculated; + private static Object common = new Object(); + private static Object[] finishBarriers; + private static long[] startTime; + private static long[] endTime; + private static long[] waitedTime; + + public static void main(String[] argv) { + System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE); + } + + public static int run(String[] argv, PrintStream out) { + ArgumentHandler argHandler = new ArgumentHandler(argv); + Log log = new Log(out, argHandler); + ThreadMonitor monitor = Monitor.getThreadMonitor(log, argHandler); + + // The test passes, if thread contention monitoring is not supported + if (!monitor.isThreadContentionMonitoringSupported()) { + log.display("Thread contention monitoring is not supported."); + log.display("TEST PASSED."); + return Consts.TEST_PASSED; + } + + // Enable thread contention monitoring, if it is supported + monitor.setThreadContentionMonitoringEnabled(true); + + int threadCount = argHandler.getThreadCount(); + MyThread threads[] = new MyThread[threadCount]; + finishBarriers = new Object[threadCount]; + startTime = new long[threadCount]; + endTime = new long[threadCount]; + waitedTime = new long[threadCount]; + + for (int i = 0; i < threadCount; i++) + finishBarriers[i] = new Object(); + + // Begin a loop which will start a number of threads + for (int time = 0; time < ITERATIONS; time++) { + log.display("Iteration: " + time); + + calculated = new Integer(0); + + // Start all threads. Half of them are user threads, + // others - daemon. + for (int i = 0; i < threadCount; i++) { + threads[i] = new MyThread(i, time, log, monitor); + threads[i].setDaemon(i % 2 == 0); + threads[i].start(); + } + + // Wait for all threads to access "calculated" variable + while (calculated.intValue() < threadCount) + Thread.currentThread().yield(); + log.display("All threads have finished calculation: " + calculated); + + // Notify all threads to finish + for (int i = 0; i < threadCount; i++) + synchronized (finishBarriers[i]) { + finishBarriers[i].notify(); + } + + // Wait for all threads to die + for (int i = 0; i < threadCount; i++) + try { + threads[i].join(); + } catch (InterruptedException e) { + log.complain("Unexpected exception"); + e.printStackTrace(log.getOutStream()); + testFailed = true; + } + log.display("All threads have died."); + + // Perform checks + + // All threads must increase "calculated" value by one, so + // "calculated" must be equal to number of started threads. + if (calculated.intValue() != threadCount) { + log.complain("Number of threads that accessed the variable: " + + calculated.intValue() + ", expected: " + + threadCount); + testFailed = true; + } + + // Waited time of each thread must not be greater than overall + // time of execution of the thread. + // Precision must be taken into account in this case. + for (int i = 0; i < threadCount; i++) { + long liveNano = endTime[i] - startTime[i]; + long liveMilli = liveNano / NANO_MILLI; + long leastWaitedTime = 2 * CONST_BARRIER_TIME + time; + + if (leastWaitedTime - 2 * PRECISION > waitedTime[i]) { + // that is not a bug. see 5070997 for details + log.display("Thread " + i + " was waiting for a monitor " + + "for at least " + leastWaitedTime + + " milliseconds, but " + + "ThreadInfo.getWaitedTime() returned value " + + waitedTime[i]); + } + + if (liveMilli + PRECISION < waitedTime[i]) { + log.complain("Life time of thread " + i + " is " + liveMilli + + " milliseconds, but " + + "ThreadInfo.getWaitedTime() returned value " + + waitedTime[i]); + testFailed = true; + } + } + } // for time + + if (testFailed) + log.complain("TEST FAILED."); + return (testFailed) ? Consts.TEST_FAILED : Consts.TEST_PASSED; + } // run() + + private static class MyThread extends Thread { + int num; + int time; + Log log; + ThreadMonitor monitor; + Object constBarrier = new Object(); + Object varBarrier = new Object(); + + MyThread(int num, int time, Log log, ThreadMonitor monitor) { + this.num = num; + this.time = time; + this.log = log; + this.monitor = monitor; + } + + public void run() { + startTime[num] = System.nanoTime(); + + // constBarrier does not receive notification, so the thread will + // be waiting for CONST_BARRIER_TIME milliseconds + synchronized (constBarrier) { + try { + constBarrier.wait(CONST_BARRIER_TIME); + } catch (InterruptedException e) { + log.complain("Unexpected exception"); + e.printStackTrace(log.getOutStream()); + testFailed = true; + } + } + + // varBarrier does not receive notification, so the thread will + // be waiting for (CONST_BARRIER_TIME + time) milliseconds. This + // time is different for each iteration. + synchronized (varBarrier) { + try { + varBarrier.wait(CONST_BARRIER_TIME + time); + } catch (InterruptedException e) { + log.complain("Unexpected exception"); + e.printStackTrace(log.getOutStream()); + testFailed = true; + } + } + + // Increase "calculated" value by one + synchronized (common) { + synchronized (calculated) { + calculated = new Integer(calculated.intValue() + 1); + } + } + + synchronized (finishBarriers[num]) { + try { + finishBarriers[num].wait(10 * CONST_BARRIER_TIME); + } catch (InterruptedException e) { + log.complain("Unexpected exception"); + e.printStackTrace(log.getOutStream()); + testFailed = true; + } + } + + // Save all time stats for the thread + ThreadInfo info = monitor.getThreadInfo(this.getId(), 0); + waitedTime[num] = info.getWaitedTime(); + endTime[num] = System.nanoTime(); + } + } // class MyThread +}