blob: ad5c81836727518479aa0968f30d025d5dab328d [file] [log] [blame]
/*
* Copyright (c) 2007, 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.share.test;
import java.io.PrintStream;
import nsk.share.TestBug;
/**
* Support class for implementing configurable stress execution.
*
* This class is intended to be used in one thread
*
* <code>
* Stresser stresser = new Stresser(stressOptions);
*
* try {
* stresser.start(100);
* while (stresser.iteration()) {
* ...
* }
* } finally {
* stresser.finish();
* }
* </code>
*
* Standard number of iterations (integer parameter to start() method) is
* defined by particular test itself. It may be different for different tests
* because average execution time of one iteration may be different.
* This is value which is enough to do what test intends to do and it should
* also give average execution time on most configurations less than
* standard value of stressTime parameter (60 seconds).
*
* @see nsk.share.test.StressOptions for explanation of stress options.
*/
public class Stresser implements ExecutionController {
private StressOptions options;
private String name;
private long maxIterations;
private long iterations;
private long startTime;
private long finishTime;
private long currentTime;
private PrintStream defaultOutput = System.out;
/*
* Flag which indicates that execution is finished.
* Volatile, because another thread might read this variable.
*/
private volatile boolean finished;
/*
* Flag which indicates that execution should be forced to finish.
* Volatile, because another thread might set this variable.
*/
private volatile boolean forceFinish;
/**
* Creates stresser with default settings.
*/
public Stresser() {
this(new StressOptions());
}
/**
* Creates stresser with given options.
*
* @param options stress options
*/
public Stresser(StressOptions options) {
setOptions(options);
}
/**
* Create stresser configured from command line arguments.
*
* @param arg arguments
*/
public Stresser(String[] args) {
this(new StressOptions(args));
}
/**
* Creates stresser configured from command line arguments and
* sets its output stream to a given one
*
* @param arg arguments
* @param out default output stream
*/
public Stresser(String[] args, PrintStream out) {
this(new StressOptions(args));
setDefaultOutput(out);
}
/**
* Creates stresser with default options and given name.
*
* @param name stresser name
*/
public Stresser(String name) {
this();
setName(name);
}
/**
* Creates stresser with given name and options.
*
* @param name stresser name
* @param options stress options
*/
public Stresser(String name, StressOptions options) {
this(options);
setName(name);
}
/**
* Creates stresser with given name from command line arguments.
*
* @param name stresser name
* @param args arguments
*/
public Stresser(String name, String[] args) {
this(args);
setName(name);
}
/**
* Sets default output stream for printing debug messages.
* Initially it is set to System.out.
*
* @param out The stream to print to
*/
public void setDefaultOutput(PrintStream out) {
defaultOutput = out;
}
/**
* Displays information about stress options.
*/
public void printStressOptions(PrintStream out) {
options.printInfo(out);
}
/**
* Displays information about this stresser.
*
* @param out output stream
*/
public void printStressInfo(PrintStream out) {
println(out, "Stress time: " + options.getTime() + " seconds");
println(out, "Iterations: " + maxIterations);
}
/**
* Displays information about this particular execution
* of this stresser.
*
* @param out output stream
*/
public void printExecutionInfo(PrintStream out) {
println(out, "Completed iterations: " + iterations);
println(out, "Execution time: " + (currentTime - startTime) + " seconds");
if (!finished) {
println(out, "Execution is not finished yet");
} else if (forceFinish) {
println(out, "Execution was forced to finish");
} else if (maxIterations != 0 && iterations >= maxIterations) {
println(out, "Execution finished because number of iterations was exceeded: " + iterations + " >= " + maxIterations);
} else if (finishTime != 0 && currentTime >= finishTime) {
println(out, "Execution finished because time was exceeded: " + (currentTime - startTime) + " >= " + (finishTime - startTime));
}
}
private void println(PrintStream out, String s) {
if (name != null) {
out.print(name);
out.print(": ");
}
out.println(s);
out.flush();
}
/**
* Starts stress execution.
*
* @param stdIterations standard number of iterations.
*/
public void start(long stdIterations) {
maxIterations = stdIterations * options.getIterationsFactor();
iterations = 0;
long stressTime = options.getTime();
startTime = System.currentTimeMillis();
if (stressTime == 0) {
finishTime = 0;
} else {
finishTime = startTime + stressTime * 1000;
}
finished = false;
forceFinish = false;
if (options.isDebugEnabled()) {
println(defaultOutput, "Starting stress execution: " + stdIterations);
printStressInfo(defaultOutput);
}
}
/**
* Finishes stress execution.
*
* This method should be called from the thread where
* execution is performed after the loop. It is also
* recommended that this method is called from
* finally {} block.
*/
public void finish() {
currentTime = System.currentTimeMillis();
finished = true;
if (options.isDebugEnabled()) {
printExecutionInfo(defaultOutput);
}
}
/**
* Forces execution to finish.
*
* This method may be called from other thread.
*/
public void forceFinish() {
forceFinish = true;
}
/**
* Marks the beginning of new iteration.
*
* @return true if execution needs to continue
*/
public boolean iteration() {
++iterations;
if (options.isDebugDetailed()) {
printExecutionInfo(defaultOutput);
}
return continueExecution();
}
/**
* Checks if execution needs to continue. This does not mark new iteration.
*
* @return true if execution needs to continue
*/
public boolean continueExecution() {
currentTime = System.currentTimeMillis();
if (startTime == 0) {
throw new TestBug("Stresser is not started.");
}
return !forceFinish
&& !finished
&& (maxIterations == 0 || iterations < maxIterations)
&& (finishTime == 0 || currentTime < finishTime);
}
/**
* Obtains current iteration number.
*
* @return current iteration
*/
public long getIteration() {
return iterations;
}
/**
* Obtains maximum number of iterations.
*
* @return max number of iterations
*/
public long getMaxIterations() {
return maxIterations;
}
public long getIterationsLeft() {
if (iterations >= maxIterations) {
return 0;
} else {
return maxIterations - iterations;
}
}
/**
* Obtains time passed from start of stress execution in milliseconds.
*
* @return time
*/
public long getExecutionTime() {
return System.currentTimeMillis() - startTime;
}
/**
* Obtains time left till end of execution in milliseconds.
*
* @return time
*/
public long getTimeLeft() {
long current = System.currentTimeMillis();
if (current >= finishTime) {
return 0;
} else {
return finishTime - current;
}
}
/**
* Sets stress options for this stresser.
*
* @param options stress options
*/
public void setOptions(StressOptions options) {
this.options = options;
}
/**
* Sets name of this stresser.
*
* @param name name of stresser
*/
public void setName(String name) {
this.name = name;
}
/**
* Obtains name of this stresser.
*/
public String getName() {
return name;
}
}