/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* ident "%Z%%M% %I% %E% SMI"
*/
/**
* The <code>SystemSolver</code> class implements a dynamic resource
* allocation solver. The Solver takes a configuration and "solves"
* the resource allocation problem.
*
* This class operates upon a configuration which is suppplied during
* initialization. Its responsibilities include:
* <ul>
* <li><p>
* Maintaining decision history
* <li><p>
* Maintaining information about the locality domain
* <li><p>
* Maintaining a map of all elements and their associated set of objectives
* <li><p>
* Identifying objective expressions with a configuration
* </ul>
*/
/**
* The default location of this history file.
*/
/**
* The property overriding the default decision history path.
*/
"system.poold.history-file";
/**
* The LocalityDomain extracted from the configuration.
*/
/**
* The objective map used to link all elements with their set
* of objectives.
*/
/**
* The pattern used to identify objective expressions.
*/
/**
* The configuration for which this solver is "solving".
*/
/**
* Monitor providing statistics for this solver.
*/
/**
* The decision history maintainer.
*/
/**
* The path to the decision history file.
*/
/**
* The number of CPUs on the system.
*/
private int cpuCount;
/**
* The number of locality triggered examinations made.
*/
private int examineCount;
/**
* Constructs a solver which initialises a decision history
* maintainer. The decision history is be used during operation
* to veto historically-poor decisions output from the objective
* function.
*/
{
/*
* Create a HashMap to store all objectives.
*/
}
/**
* Initialize the solver for operation upon the supplied
* configuration. Possible objective expressions set upon
* target elements are identified and stored in an objective
* map which associates elements with the set of their
* objectives.
*
* @param conf The configuration to be manipulated.
* @throws PoolsException If the initialization fails.
*/
{
/*
* Count the CPUs in the system, this is used to
* control locality objective processing in the
* examine() method.
*/
examineCount = 0;
/*
* Remove any old objectives
*/
/*
* Extract any configuration objectives
*/
try {
"system.poold.objectives");
"adding configuration objective " +
oString);
try {
exps[i]);
exp);
} catch (IllegalArgumentException iae) {
}
}
}
} catch (PoolsException pe) {
/*
* Ignore as this means there is no objective
* property
*/
}
/*
* Now extract all pset objectives
*/
try {
"pset.poold.objectives");
"adding " +
"pset.name") +
try {
exp = Expression.
"pset", exp);
} catch
{
false);
}
}
}
} catch (PoolsException pe) {
continue;
}
}
/*
* Capture the LocalityDomain details.
*/
}
try {
} catch (Exception e) {
}
/*
* Load or create the decision history.
*/
try {
} catch (PoolsException pe) {
}
try {
"loaded history file " + newDhPath);
} catch (Exception e) {
if (!(e instanceof FileNotFoundException)) {
": contents unusable; ignoring");
newDhPath + ": contents unusable",
e);
}
/*
* Use current DecisionHistory instead,
* if any.
*/
dh = new DecisionHistory();
}
/*
* Try using the new path.
*/
try {
} catch (Exception e) {
new PooldException(newDhPath +
": couldn't synchronize history file")
.initCause(e), false);
}
}
}
/**
* Determine if the given resource has non-workload-dependent
* objectives.
* @param elem The element to examine.
*/
{
/*
* This code relies upon the fact that an element with
* no objectives will not have an empty set, but rather
* no value in the objMap.
*/
return (false);
return (false);
return (true);
}
/**
* Determine if the given resource has workload-dependent
* objectives.
* @param elem The element to examine.
*/
{
/*
* This code relies upon the fact that an element with
* no objectives will not have an empty set, but rather
* no value in the objMap.
*/
return (false);
return (true);
return (false);
}
/**
* Return true if the monitored configuration should be
* reconfigured. All workload-dependent objectives are
* examined to determine if the configuration is still
* satisfying all specified objectives on all elements. If any
* objectives are failing, then this method will return true.
*
* @param mon The monitoring object used to assess objective
* compliance.
*/
{
/*
* Take advantage of the guaranteed-valid monitor data
* for measuring the improvement of any past decisions.
*/
boolean ret = false;
boolean hasLocalityObjectives = false;
boolean isMonitorValid = true;
/*
* All objectives are examined, even though failure
* could be detected earlier. This is because logging
* of all objectives is required and the information
* about failure can be stored and used during
* solving.
*/
"checking objective " + obj);
if (obj instanceof WorkloadDependentObjective) {
if (isValid()) {
/*
* If any objectives
* are violated, then
* we must
* reconfigure, so
* check them all in
* turn.
*/
ret;
} else
isMonitorValid = false;
}
}
/*
* Check if this is the first element, seen in
* this pass, that has locality objectives.
*/
if (!hasLocalityObjectives &&
hasLocalityObjectives = true;
}
if (isMonitorValid == false) {
"not evaluating workload-dependent objectives " +
"until sufficient statistics are collected");
}
/*
* If we don't have locality objectives, we don't force
* the reexamination. This is controlled by
* hasLocalityObjectives.
*
* So that we don't continually trigger
* reconfiguration examinations for locality
* objectives we stop forcing recalculations when we
* reach cpuCount / 2. This should be enough moves to
* get good locality for those configurations which
* have no WorkloadDependentObjectives.
*/
cpuCount / 2)));
}
/**
* Reallocate resources in a configuration to achieve user
* specified objectives. Return true if the configuration has
* been updated, false otherwise.
*
* This method should only be invoked if a previous
* examination of the configuration which is monitored
* indicates that objectives are failing. The monitored
* configuration is re-opened for editing, locking that
* configuration for the duration of this operation.
*
* @throws Exception If the solve fails.
*/
{
boolean madeMove = false;
/*
* All solving operations must be done in an
* "editable" context, so create a new modifiable
* configuration which is at the same location as the
* monitored configuration
*/
try {
/*
* Build a resource set importance map for use
* when propagating pool importance to each
* possible solution. Use the same logic as
* libpool and let a resource take the highest
* importance value from all pools associated
* with the set.
*/
getLongProperty("pool.importance");
} else
}
}
/*
* Consider all possible alternative
* configurations. This list is generated as a
* series of moves. Administrative constraints
* are applied to the moves to prune the list of
* possible configurations.
*/
donors);
"donor processors: " + processors);
while (itProcessor.hasNext()) {
next();
iterator();
while (itReceiver.hasNext()) {
next();
/*
* Can't move to yourself
*/
continue;
}
}
}
"potential moves: " + moves);
/*
* Now that we have our alternative configurations,
* score each configuration by applying all objectives
* to each configuration. Hold the scores in the
* score set.
*/
double totalContrib = 0;
if (obj instanceof
/*
* If the monitor is
* invalid, do not
* process
* WorkloadDependentObjectives
* since they have an
* implicit dependency
* on the monitor
* data.
*/
if (obj instanceof
if (!isValid())
continue;
throw new
"x: " + contrib +
" is invalid, legal " +
"range is -1 <= x <= " +
"1");
/*
* Modify the basic
* score by the
* importance of the
* objective and (if
* appropriate) the
* importance of an
* associated pool.
*/
longValue();
}
totalContrib += contrib *
obj.getExpression().
}
}
}
/*
* Try to find a move to apply which
* yields a positive contribution.
*/
scoresArray, false)) == false)
scoresArray, true);
} else
"no moves found");
"synchronizing decision history");
throw ex;
}
return (madeMove);
}
/*
* Process the supplied array of scored moves, trying to find
* a move to apply. Return true if a move could be applied,
* false otherwise.
*
* @param conf The configuration to be modified.
* @param scores The areay of scored moves to be tried.
* @param ignoreDH Ignore Decision History details.
*/
{
boolean madeMove = false;
if (ignoreDH)
move + " not applied as " +
"benefit not significant");
break;
}
true)
break;
}
return (madeMove);
}
/*
* Attempt to apply the supplied move to the
* configuration. Return true if the move could be applied,
* false otherwise.
*
* @param conf The configuration to be modified.
* @param move The move to be applied.
* @param ignoreDH Ignore Decision History details.
*/
boolean ignoreDH)
throws PoolsException, StaleMonitorException
{
boolean madeMove = false;
boolean wdpInvolved = false;
double utilization = 0.0;
"Attempting to retrieve utilization for:" + move
wdpInvolved = true;
}
/*
* Unless a move can be vetoed (i.e. decision history
* is effective and there are is a workload-dependent
* involved), the move should alwways be applied.
*/
utilization)) {
getFrom());
try {
"committing configuration");
try {
if (wdpInvolved)
.getMove(),
.getSampleCount());
else
"decision not " +
"recorded due to " +
"lack of workload-"
+ "dependent " +
"objectives");
} catch (Exception e) {
"couldn't update " +
"decision history (" +
e.toString() + ")");
}
madeMove = true;
} catch (PoolsException pe) {
"move failed, possibly due to a " +
"bound process in a 1-processor " +
"set");
}
} else {
/*
* Move was vetoed.
*/
if (!ignoreDH && wdpInvolved)
"poor past results");
}
return (madeMove);
}
/**
* Add an objective based on the supplied expression to the
* supplied set of objectives.
*
* @param oSet Set of objectives to be extended
* @param type Type of element to which the expression is applied
* @param exp Expression to be used in the objective
* @throws IllegalArgumentException If a duplicate objective
* is identified or an invalid expression is supplied for this
* type of element
*/
throws IllegalArgumentException
{
/*
* Check the set of objectives and find contradictions.
*/
if (o.getExpression().contradicts(
other.getExpression()))
throw new IllegalArgumentException(
"contradictory objectives:" + other +
", " + o);
}
throw new IllegalArgumentException(
"duplicate objective:" + o);
}
/**
* Return a list of resource sets prepared to receive
* resources
*
* The list consists of all resource setss (of the supplied
* type) whose size is < their max constraint.
*
* @param resList The list of all resource sets from which
* recipients will be chosen
* @throws PoolsException if there is an error manipulation
* the pool resources
*/
{
}
return (recipientList);
}
/**
* Return a list of resource sets prepared to donate resources
*
* The list consists of all resource sets (of the supplied
* type) whose size (minus the number of pinned resources
* where applicable) is > their min constraint.
*
* @param resList The list of all resource sets from which
* recipients will be chosen
* @throws PoolsException if there is an error manipulation
* the pool resources
*/
{
}
return (donorList);
}
/**
* Return a list of Processors for the supplied resource.
*
* The list consists of all Processors (excluding the pinned
* Processors) in the set.
*
* @param set The resource for which Processors should be found
* @throws PoolsException if there is an error manipulation
* the pool resources
*/
{
try
{
} catch (PoolsException pe)
{
}
}
return (ret);
}
/**
* Return true if the solver is capable of working with
* statistically valid data.
*/
public boolean isValid()
{
}
/**
* Return the monitor used by this solver.
*/
{
return (monitor);
}
/**
* Return the set of objectives associated with the supplied
* element.
*
* @param elem Retrieve objectives for this element.
*/
{
}
/**
* Holds details about the score of a proposed configuration
* move. Each move must be scored so that they can ranked in
* terms of increasing desirability
*/
/**
* The move which is being scored.
*/
private final Move m;
/**
* The score of the move.
*/
private final double score;
/**
* Score formatter.
*/
new DecimalFormat("0.00");
/**
* Constructor.
*
* @param m The move under consideration.
* @param score The score of the move.
*/
{
this.m = m;
}
{
}
{
return ("move (" + m + ") score "
}
/**
* Return the score.
*/
double getScore()
{
return (score);
}
/**
* Return the move.
*/
{
return (m);
}
}
}