/*
* Sun Public License
*
* The contents of this file are subject to the Sun Public License Version
* 1.0 (the "License"). You may not use this file except in compliance with
* the License. A copy of the License is available at http://www.sun.com/
*
* The Original Code is the SLAMD Distributed Load Generation Engine.
* The Initial Developer of the Original Code is Neil A. Wilson.
* Portions created by Neil A. Wilson are Copyright (C) 2004-2010.
* Some preexisting portions Copyright (C) 2002-2006 Sun Microsystems, Inc.
* All Rights Reserved.
*
* Contributor(s): Neil A. Wilson
*/
package com.slamd.loadvariance;
import com.slamd.common.SLAMDException;
/**
* This class defines a load variance algorithm that may be used to increase or
* decrease the number of active threads in spurts rather than gradually over
* time. That is, all the threads to enable or disable will be notified at the
* very beginning of the interval with no change over the duration of that
* interval. That is, the graph will appear to have an initial jump up or down
* but then will remain level for the duration of the interval associated with
* that line. The change in the number of active threads may be specified in
* one of the following ways:
* <UL>
* <LI>"+N", where N is a fixed number of threads to start at the beginning of
* this load variation.</LI>
* <LI>"-N", where N is a fixed number of threads to stop at the beginning of
* this load variation.</LI>
* <LI>"+N%", where N% is a percentage of the overall number of threads per
* client that should be started at the beginning of this load
* variation.</LI>
* <LI>"-N%", where N% is a percentage of the overall number of threads per
* client that should be stopped at the beginning of this load
* variation.</LI>
* <LI>"=N", where N is the fixed number of threads that should be running
* once this load variation completes.</LI>
* <LI>"=N%", where N% is a percentage of the overall number of threads per
* client that should be running once this load variation completes.</LI>
* </UL>
*
*
* @author Neil A. Wilson
*/
public class StairStepLoadVarianceAlgorithm
extends LoadVarianceAlgorithm
{
/**
* The variation method that indicates that the number of active threads
* should be increased by a fixed amount.
*/
public static final int METHOD_INCREASE_BY_NUMBER = 1;
/**
* The variation method that indicates that the number of active threads
* should be decreased by a fixed amount.
*/
public static final int METHOD_DECREASE_BY_NUMBER = 2;
/**
* The variation method that indicates that the number of active threads
* should be increased by a percentage of the total number of threads.
*/
public static final int METHOD_INCREASE_BY_PERCENT = 3;
/**
* The variation method that indicates that the number of active threads
* should be decreased by a percentage of the total number of threads.
*/
public static final int METHOD_DECREASE_BY_PERCENT = 4;
/**
* The variation method that indicates that the number of active threads
* should be set to a fixed number.
*/
public static final int METHOD_SET_TO_NUMBER = 5;
/**
* The variation method that indicates that the number of active threads
* should be set to a percentage of the total number of threads.
*/
public static final int METHOD_SET_TO_PERCENT = 6;
// The variation method that should be used by this algorithm.
private int variationMethod;
// The value associated with the variation.
private int variationValue;
/**
* This constructor is used to create a new instance of this load variation
* algorithm through reflection. A default constructor must be provided in
* all subclasses, but the only thing that it needs to do is call
* <CODE>super()</CODE>.
*/
public StairStepLoadVarianceAlgorithm()
{
super();
}
/**
* Initializes this load variation algorithm based on the provided list of
* arguments.
*
* @param arguments The arguments that may be used to customize the behavior
* of this load variation algorithm.
*
* @throws SLAMDException If a problem occurs while trying to initialize
* this load variation algorithm.
*/
@Override()
public void initializeVariationAlgorithm(String[] arguments)
throws SLAMDException
{
if ((arguments == null) || (arguments.length != 1))
{
throw new SLAMDException("There must be exactly one argument provided " +
"for the linear load variance algorithm.");
}
String value = arguments[0];
if ((value == null) || (value.length() == 0))
{
throw new SLAMDException("The argument to the linear load variance " +
"algorithm may not be blank.");
}
boolean endsWithPercent = value.endsWith("%");
String valueString = null;
switch (value.charAt(0))
{
case '+':
if (endsWithPercent)
{
variationMethod = METHOD_INCREASE_BY_PERCENT;
valueString = value.substring(1, value.length() - 1);
}
else
{
variationMethod = METHOD_INCREASE_BY_NUMBER;
valueString = value.substring(1);
}
break;
case '-':
if (endsWithPercent)
{
variationMethod = METHOD_DECREASE_BY_PERCENT;
valueString = value.substring(1, value.length() - 1);
}
else
{
variationMethod = METHOD_DECREASE_BY_NUMBER;
valueString = value.substring(1);
}
break;
case '=':
if (endsWithPercent)
{
variationMethod = METHOD_SET_TO_PERCENT;
valueString = value.substring(1, value.length() - 1);
}
else
{
variationMethod = METHOD_SET_TO_NUMBER;
valueString = value.substring(1);
}
break;
default:
throw new SLAMDException("The argument to the linear load variance " +
"algorithm must start with '+', '-', or '='.");
}
try
{
variationValue = Integer.parseInt(valueString);
}
catch (Exception e)
{
throw new SLAMDException("Unable to parse '" + valueString +
"' as an integer.");
}
if (variationValue < 0)
{
throw new SLAMDException("The load variance value may not be negative.");
}
if (endsWithPercent && (variationValue > 100))
{
throw new SLAMDException("Percentage values given may not exceed 100.");
}
}
/**
* Retrieves a two-dimensional array that provides information about the
* increase or decrease in active job threads that should be applied over
* time. Each element of the array returned should itself be a two-element
* array with the first element being the number of milliseconds since the
* start of this load variance instruction that the increase or decrease
* should occur, and the second is an integer value that indicates the number
* of threads that should be added at that time (may be negative if threads
* are to be removed).
*
* @param duration The length of time in seconds over which this load
* variance algorithm should operate.
* @param totalThreads The total number of threads that have been scheduled
* for the job with which this algorithm is to be used.
* @param activeThreads The number of threads that are already active at
* the time that this method is called.
*
* @return A two-dimensional array that provides information about the
* increase or decrease in active job threads that should be applied
* over time.
*
* @throws SLAMDException If a problem occurs while calculating the variance
* array.
*/
@Override()
public int[][] calculateVariance(int duration, int totalThreads,
int activeThreads)
throws SLAMDException
{
switch (variationMethod)
{
case METHOD_INCREASE_BY_NUMBER:
return new int[][]
{
new int[]
{
0, Math.min(variationValue, (totalThreads-activeThreads))
}
};
case METHOD_DECREASE_BY_NUMBER:
return new int[][]
{
new int[]
{
0, -(Math.min(variationValue, activeThreads))
}
};
case METHOD_INCREASE_BY_PERCENT:
int numThreads = totalThreads * variationValue / 100;
return new int[][]
{
new int[]
{
0, Math.min(numThreads, (totalThreads-activeThreads))
}
};
case METHOD_DECREASE_BY_PERCENT:
numThreads = totalThreads * variationValue / 100;
return new int[][]
{
new int[]
{
0, -(Math.min(numThreads, activeThreads))
}
};
case METHOD_SET_TO_NUMBER:
numThreads = Math.min(variationValue, totalThreads);
if (numThreads == activeThreads)
{
return new int[0][];
}
else if (numThreads > activeThreads)
{
return new int[][]
{
new int[]
{
0, Math.min(numThreads, (totalThreads-activeThreads))
}
};
}
else
{
return new int[][]
{
new int[]
{
0, -(Math.min(numThreads, activeThreads))
}
};
}
case METHOD_SET_TO_PERCENT:
numThreads = totalThreads * variationValue / 100;
if (numThreads == activeThreads)
{
return new int[0][];
}
else if (numThreads > activeThreads)
{
return new int[][]
{
new int[]
{
0, Math.min(numThreads, (totalThreads-activeThreads))
}
};
}
else
{
return new int[][]
{
new int[]
{
0, -(Math.min(numThreads, activeThreads))
}
};
}
default:
throw new SLAMDException("Invalid variation method: " +
variationMethod);
}
}
}