blob: d0e2da7fb0894c567a0030526fc20e0c114a575e [file] [log] [blame]
/*
* 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
}