17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
582a28c42Sgarypen  * Common Development and Distribution License (the "License").
682a28c42Sgarypen  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2182a28c42Sgarypen 
227c478bd9Sstevel@tonic-gate /*
23*967a0a51SMita Solanky  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  *
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate package com.sun.solaris.domain.pools;
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate import java.io.FileInputStream;
317c478bd9Sstevel@tonic-gate import java.io.IOException;
327c478bd9Sstevel@tonic-gate import java.lang.reflect.Field;
337c478bd9Sstevel@tonic-gate import java.text.DecimalFormat;
347c478bd9Sstevel@tonic-gate import java.util.*;
357c478bd9Sstevel@tonic-gate import java.util.logging.*;
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate import com.sun.solaris.service.logging.Severity;
387c478bd9Sstevel@tonic-gate import com.sun.solaris.service.locality.*;
397c478bd9Sstevel@tonic-gate import com.sun.solaris.service.pools.*;
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate /**
437c478bd9Sstevel@tonic-gate  * An objective interface. All classes which wish to contribute to the
447c478bd9Sstevel@tonic-gate  * Objective Function (OF hence) calculation must implement this
457c478bd9Sstevel@tonic-gate  * interface. This interface defines a strategy which can be used to
467c478bd9Sstevel@tonic-gate  * make a contribution to the Objective Function calculation.
477c478bd9Sstevel@tonic-gate  *
487c478bd9Sstevel@tonic-gate  * The OF calculation (which is implemented by <code>Poold</code>)
497c478bd9Sstevel@tonic-gate  * consists of determining all possible resource moves across all
507c478bd9Sstevel@tonic-gate  * resources. Once all moves are known, all registered objectives
517c478bd9Sstevel@tonic-gate  * (i.e. instances of this interface) are called and asked to value
527c478bd9Sstevel@tonic-gate  * the move.
537c478bd9Sstevel@tonic-gate  *
547c478bd9Sstevel@tonic-gate  * Note, the output of this method is constrained to be between -1 and
557c478bd9Sstevel@tonic-gate  * 1, representing minimum and maximum desirability of this move in
567c478bd9Sstevel@tonic-gate  * terms of this objective. This is enforced by <code>Poold</code> and
577c478bd9Sstevel@tonic-gate  * an <code>IllegalOFValueException</code> will be thrown if this
587c478bd9Sstevel@tonic-gate  * constraint is broken.
597c478bd9Sstevel@tonic-gate  */
607c478bd9Sstevel@tonic-gate interface Objective
617c478bd9Sstevel@tonic-gate {
627c478bd9Sstevel@tonic-gate 	/**
637c478bd9Sstevel@tonic-gate 	 * Return the contribution of this objective. The contribution
647c478bd9Sstevel@tonic-gate 	 * is constrainted to be a value between -1 and +1 to ensure
657c478bd9Sstevel@tonic-gate 	 * that no objective can make a disproportionate contribution
667c478bd9Sstevel@tonic-gate 	 * to the total result.
677c478bd9Sstevel@tonic-gate 	 *
687c478bd9Sstevel@tonic-gate 	 * The more desirable this move appears in terms of this
697c478bd9Sstevel@tonic-gate 	 * objective, the closer to +1 will be the value. A value of 0
707c478bd9Sstevel@tonic-gate 	 * indicates that the move is neutral in terms of the
717c478bd9Sstevel@tonic-gate 	 * objective. A negative value indicates that the move is
727c478bd9Sstevel@tonic-gate 	 * undesirable.
737c478bd9Sstevel@tonic-gate 	 *
747c478bd9Sstevel@tonic-gate 	 * @param conf The configuration which is being examined
757c478bd9Sstevel@tonic-gate 	 * @param move The move under consideration
767c478bd9Sstevel@tonic-gate 	 * @param elem The element to which the objective applies
777c478bd9Sstevel@tonic-gate 	 *
787c478bd9Sstevel@tonic-gate 	 * @throws PoolsException if there is an error manipulating
797c478bd9Sstevel@tonic-gate 	 * the configuration
807c478bd9Sstevel@tonic-gate 	 */
calculate(Configuration conf, Move move, Element elem)817c478bd9Sstevel@tonic-gate 	public double calculate(Configuration conf, Move move, Element elem)
827c478bd9Sstevel@tonic-gate 	    throws PoolsException;
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 	/**
857c478bd9Sstevel@tonic-gate 	 * Set the objective's expression to the supplied parameter.
867c478bd9Sstevel@tonic-gate 	 *
877c478bd9Sstevel@tonic-gate 	 * @param exp An expression for this objective.
887c478bd9Sstevel@tonic-gate 	 */
setExpression(Expression exp)897c478bd9Sstevel@tonic-gate 	public void setExpression(Expression exp);
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 	/**
927c478bd9Sstevel@tonic-gate 	 * Get the objective's expression.
937c478bd9Sstevel@tonic-gate 	 */
getExpression()947c478bd9Sstevel@tonic-gate 	public Expression getExpression();
957c478bd9Sstevel@tonic-gate }
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate /**
987c478bd9Sstevel@tonic-gate  * This interface must be implemented by all Objectives which are
997c478bd9Sstevel@tonic-gate  * workload dependent. The examine method is used by a Solver to
1007c478bd9Sstevel@tonic-gate  * determine if the objective is still being satisfied.
1017c478bd9Sstevel@tonic-gate  */
1027c478bd9Sstevel@tonic-gate interface WorkloadDependentObjective extends Objective
1037c478bd9Sstevel@tonic-gate {
1047c478bd9Sstevel@tonic-gate 	/**
1057c478bd9Sstevel@tonic-gate 	 * This method returns true if the Objective is no longer
1067c478bd9Sstevel@tonic-gate 	 * satisfied. If the objective is still satisfied, then return
1077c478bd9Sstevel@tonic-gate 	 * false.
1087c478bd9Sstevel@tonic-gate 	 *
1097c478bd9Sstevel@tonic-gate 	 * @param conf The configuration to be examined
1107c478bd9Sstevel@tonic-gate 	 * @param solver The solving interface used to get utilization
1117c478bd9Sstevel@tonic-gate 	 * information
1127c478bd9Sstevel@tonic-gate 	 * @param elem The element to which the objective belongs
1137c478bd9Sstevel@tonic-gate 	 *
1147c478bd9Sstevel@tonic-gate 	 * @throws PoolsException if there is an error examining the
1157c478bd9Sstevel@tonic-gate 	 * pool configuration
1167c478bd9Sstevel@tonic-gate 	 * @throws StaleMonitorException if there is an error accessing
1177c478bd9Sstevel@tonic-gate 	 * the element's ResourceMonitor
1187c478bd9Sstevel@tonic-gate 	 */
examine(Configuration conf, Solver solver, Element elem)1197c478bd9Sstevel@tonic-gate 	public boolean examine(Configuration conf, Solver solver,
1207c478bd9Sstevel@tonic-gate 	    Element elem) throws PoolsException, StaleMonitorException;
1217c478bd9Sstevel@tonic-gate }
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate /**
1247c478bd9Sstevel@tonic-gate  * This class provides a skeletal implementation of the
1257c478bd9Sstevel@tonic-gate  * <code>Objective</code> interface to minimize the effort required
1267c478bd9Sstevel@tonic-gate  * to implement this interface.
1277c478bd9Sstevel@tonic-gate  *
1287c478bd9Sstevel@tonic-gate  * To implement an objective, the programmer need only to extend this
1297c478bd9Sstevel@tonic-gate  * class and add the name of the class into the appropriate element
1307c478bd9Sstevel@tonic-gate  * objectives property in the <code>poold.properties</code> file.
1317c478bd9Sstevel@tonic-gate  */
1327c478bd9Sstevel@tonic-gate abstract class AbstractObjective implements Objective
1337c478bd9Sstevel@tonic-gate {
calculate(Configuration conf, Move move, Element elem)1347c478bd9Sstevel@tonic-gate 	abstract public double calculate(Configuration conf, Move move,
1357c478bd9Sstevel@tonic-gate 	    Element elem) throws PoolsException;
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate 	/**
1387c478bd9Sstevel@tonic-gate 	 * The objectives which are recognized by this class
1397c478bd9Sstevel@tonic-gate 	 */
1407c478bd9Sstevel@tonic-gate 	private static Map objectives;
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	/**
1437c478bd9Sstevel@tonic-gate 	 * The expression associated with this objective
1447c478bd9Sstevel@tonic-gate 	 */
1457c478bd9Sstevel@tonic-gate 	private Expression exp;
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 	/**
1487c478bd9Sstevel@tonic-gate 	 * Set the objective's expression to the supplied parameter.
1497c478bd9Sstevel@tonic-gate 	 *
1507c478bd9Sstevel@tonic-gate 	 * @param exp An expression for this objective.
1517c478bd9Sstevel@tonic-gate 	 */
setExpression(Expression exp)1527c478bd9Sstevel@tonic-gate 	public void setExpression(Expression exp)
1537c478bd9Sstevel@tonic-gate 	{
1547c478bd9Sstevel@tonic-gate 		this.exp = exp;
15582a28c42Sgarypen 	}
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 	/**
1587c478bd9Sstevel@tonic-gate 	 * Get the objective's expression.
1597c478bd9Sstevel@tonic-gate 	 */
getExpression()1607c478bd9Sstevel@tonic-gate 	public Expression getExpression()
1617c478bd9Sstevel@tonic-gate 	{
1627c478bd9Sstevel@tonic-gate 		return (exp);
1637c478bd9Sstevel@tonic-gate 	}
16482a28c42Sgarypen 
1657c478bd9Sstevel@tonic-gate 	/**
1667c478bd9Sstevel@tonic-gate 	 * A factory method which returns a created objective which is
1677c478bd9Sstevel@tonic-gate 	 * associated with the supplied expression. The type and the
1687c478bd9Sstevel@tonic-gate 	 * expression are used to identify valid types of objectives
1697c478bd9Sstevel@tonic-gate 	 * to which this expression may be applied. If an acceptable
1707c478bd9Sstevel@tonic-gate 	 * objective cannot be found for the supplied type, then an
1717c478bd9Sstevel@tonic-gate 	 * <code>IllegalArgumentException</code> will be thrown.
1727c478bd9Sstevel@tonic-gate 	 *
1737c478bd9Sstevel@tonic-gate 	 * @param type The element type for which an objective must be
1747c478bd9Sstevel@tonic-gate 	 * found
1757c478bd9Sstevel@tonic-gate 	 * @param exp The expression which will be associated with the
1767c478bd9Sstevel@tonic-gate 	 * objective
1777c478bd9Sstevel@tonic-gate 	 *
1787c478bd9Sstevel@tonic-gate 	 * @throws IllegalArgumentExcetion if the supplied expression
1797c478bd9Sstevel@tonic-gate 	 * cannot be associated with an objective of the supplied type
1807c478bd9Sstevel@tonic-gate 	 */
getInstance(String type, Expression exp)1817c478bd9Sstevel@tonic-gate 	public static Objective getInstance(String type, Expression exp)
1827c478bd9Sstevel@tonic-gate 	    throws IllegalArgumentException
1837c478bd9Sstevel@tonic-gate 	{
1847c478bd9Sstevel@tonic-gate 		Objective ret = null;
1857c478bd9Sstevel@tonic-gate 		Map typeObjs = null;
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 		initMapIfNecessary();
1887c478bd9Sstevel@tonic-gate 		typeObjs = (Map)objectives.get(type);
1897c478bd9Sstevel@tonic-gate 		if (typeObjs != null) {
1907c478bd9Sstevel@tonic-gate 			Class objClass = (Class)typeObjs.get(exp.getName());
1917c478bd9Sstevel@tonic-gate 			if (objClass != null) {
1927c478bd9Sstevel@tonic-gate 				try {
1937c478bd9Sstevel@tonic-gate 					ret = (Objective) objClass.
1947c478bd9Sstevel@tonic-gate 					    newInstance();
1957c478bd9Sstevel@tonic-gate 				} catch (Exception e) {
1967c478bd9Sstevel@tonic-gate 					Poold.utility.die(Poold.OPT_LOG, e,
1977c478bd9Sstevel@tonic-gate 					    true);
1987c478bd9Sstevel@tonic-gate 				}
1997c478bd9Sstevel@tonic-gate 				ret.setExpression(exp);
2007c478bd9Sstevel@tonic-gate 			}
2017c478bd9Sstevel@tonic-gate 		}
2027c478bd9Sstevel@tonic-gate 		if (ret == null)
2037c478bd9Sstevel@tonic-gate 			throw new IllegalArgumentException(
2047c478bd9Sstevel@tonic-gate 			    "unrecognized objective name for " + type + ": " +
2057c478bd9Sstevel@tonic-gate 			    exp.toString());
2067c478bd9Sstevel@tonic-gate 		return (ret);
2077c478bd9Sstevel@tonic-gate 	}
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	/**
2107c478bd9Sstevel@tonic-gate 	 * Return a string representation of this objective.
2117c478bd9Sstevel@tonic-gate 	 */
toString()2127c478bd9Sstevel@tonic-gate 	public String toString()
2137c478bd9Sstevel@tonic-gate 	{
2147c478bd9Sstevel@tonic-gate 		return (exp.toString());
2157c478bd9Sstevel@tonic-gate 	}
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	/**
2187c478bd9Sstevel@tonic-gate 	 * Initialize the implementation map the first time it's
2197c478bd9Sstevel@tonic-gate 	 * called.
2207c478bd9Sstevel@tonic-gate 	 */
initMapIfNecessary()2217c478bd9Sstevel@tonic-gate 	private static void initMapIfNecessary()
2227c478bd9Sstevel@tonic-gate 	{
2237c478bd9Sstevel@tonic-gate 		/*
2247c478bd9Sstevel@tonic-gate 		 * Setup the objectives map for the known classes
2257c478bd9Sstevel@tonic-gate 		 */
2267c478bd9Sstevel@tonic-gate 		if (objectives == null) {
2277c478bd9Sstevel@tonic-gate 			objectives = new HashMap();
2287c478bd9Sstevel@tonic-gate 			Properties props = new Properties();
2297c478bd9Sstevel@tonic-gate 			try {
2307c478bd9Sstevel@tonic-gate 				props.load(
2317c478bd9Sstevel@tonic-gate 				    new FileInputStream(
2327c478bd9Sstevel@tonic-gate 				    Poold.POOLD_PROPERTIES_PATH));
2337c478bd9Sstevel@tonic-gate 			} catch (IOException ioe) {
2347c478bd9Sstevel@tonic-gate 				Poold.utility.die(Poold.CONF_LOG, ioe);
2357c478bd9Sstevel@tonic-gate 			}
2367c478bd9Sstevel@tonic-gate 			registerObjectives(props, objectives, "system");
2377c478bd9Sstevel@tonic-gate 			registerObjectives(props, objectives, "pset");
2387c478bd9Sstevel@tonic-gate 		}
2397c478bd9Sstevel@tonic-gate 	}
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	/**
2427c478bd9Sstevel@tonic-gate 	 * Add the objectives contained in the supplied properties to
2437c478bd9Sstevel@tonic-gate 	 * the set of valid objectives. The objectives are updated
2447c478bd9Sstevel@tonic-gate 	 * with objectives of the supplied type contained in the
2457c478bd9Sstevel@tonic-gate 	 * properties.
2467c478bd9Sstevel@tonic-gate 	 *
2477c478bd9Sstevel@tonic-gate 	 * @param props The properties containing the objectives
2487c478bd9Sstevel@tonic-gate 	 * @param objectives The objectives to be updated
2497c478bd9Sstevel@tonic-gate 	 * @param type The type of objectives to be added
2507c478bd9Sstevel@tonic-gate 	 */
registerObjectives(Properties props, Map objectives, String type)2517c478bd9Sstevel@tonic-gate 	private static void registerObjectives(Properties props,
2527c478bd9Sstevel@tonic-gate 	    Map objectives, String type)
2537c478bd9Sstevel@tonic-gate 	{
2547c478bd9Sstevel@tonic-gate 		Map typeObjs = new HashMap();
2557c478bd9Sstevel@tonic-gate 		String objs = props.getProperty(type + ".objectives");
2567c478bd9Sstevel@tonic-gate 		String objNames[] = objs.split(",");
2577c478bd9Sstevel@tonic-gate 		for (int i = 0; i < objNames.length; i++) {
2587c478bd9Sstevel@tonic-gate 			String objName = objNames[i].trim();
2597c478bd9Sstevel@tonic-gate 			try {
2607c478bd9Sstevel@tonic-gate 				Class clazz = Class.forName(objName);
2617c478bd9Sstevel@tonic-gate 				Field field = clazz.getDeclaredField("name");
2627c478bd9Sstevel@tonic-gate 				String key = (String) field.get(null);
2637c478bd9Sstevel@tonic-gate 				typeObjs.put(key, clazz);
2647c478bd9Sstevel@tonic-gate 			} catch (ClassNotFoundException cnfe) {
2657c478bd9Sstevel@tonic-gate 				Poold.utility.die(Poold.CONF_LOG, cnfe);
2667c478bd9Sstevel@tonic-gate 			} catch (NoSuchFieldException nsfe) {
2677c478bd9Sstevel@tonic-gate 				Poold.utility.die(Poold.CONF_LOG, nsfe);
2687c478bd9Sstevel@tonic-gate 			} catch (IllegalAccessException iae) {
2697c478bd9Sstevel@tonic-gate 				Poold.utility.die(Poold.CONF_LOG, iae);
2707c478bd9Sstevel@tonic-gate 			}
2717c478bd9Sstevel@tonic-gate 		}
2727c478bd9Sstevel@tonic-gate 		objectives.put(type, typeObjs);
2737c478bd9Sstevel@tonic-gate 	}
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	/**
2767c478bd9Sstevel@tonic-gate 	 * Indicates whether some other Objective is "equal to this
2777c478bd9Sstevel@tonic-gate 	 * one.
2787c478bd9Sstevel@tonic-gate 	 * @param o the reference object with which to compare.
2797c478bd9Sstevel@tonic-gate 	 * @return <code>true</code> if this object is the same as the
2807c478bd9Sstevel@tonic-gate 	 * o argument; <code>false</code> otherwise.
2817c478bd9Sstevel@tonic-gate 	 * @see	#hashCode()
2827c478bd9Sstevel@tonic-gate 	 */
equals(Object o)2837c478bd9Sstevel@tonic-gate 	public boolean equals(Object o)
2847c478bd9Sstevel@tonic-gate 	{
2857c478bd9Sstevel@tonic-gate 		if (o == this)
2867c478bd9Sstevel@tonic-gate 			return (true);
2877c478bd9Sstevel@tonic-gate 		if (!(o instanceof Objective))
2887c478bd9Sstevel@tonic-gate 			return (false);
2897c478bd9Sstevel@tonic-gate 		Objective other = (Objective) o;
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 		return (getExpression().equals(other.getExpression()));
2927c478bd9Sstevel@tonic-gate 	}
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	/**
2957c478bd9Sstevel@tonic-gate 	 * Returns a hash code value for the object. This method is
2967c478bd9Sstevel@tonic-gate 	 * supported for the benefit of hashtables such as those provided by
2977c478bd9Sstevel@tonic-gate 	 * <code>java.util.Hashtable</code>.
2987c478bd9Sstevel@tonic-gate 	 *
2997c478bd9Sstevel@tonic-gate 	 * @return a hash code value for this object.
3007c478bd9Sstevel@tonic-gate 	 * @see	#equals(java.lang.Object)
3017c478bd9Sstevel@tonic-gate 	 * @see	java.util.Hashtable
3027c478bd9Sstevel@tonic-gate 	 */
hashCode()3037c478bd9Sstevel@tonic-gate 	public int hashCode()
3047c478bd9Sstevel@tonic-gate 	{
3057c478bd9Sstevel@tonic-gate 		return (getExpression().hashCode());
3067c478bd9Sstevel@tonic-gate 	}
3077c478bd9Sstevel@tonic-gate }
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate /**
3117c478bd9Sstevel@tonic-gate  * The <code>WeightedLoadObjective</code> class implements a Weighted
3127c478bd9Sstevel@tonic-gate  * Load Objective for <code>Poold</code>.
3137c478bd9Sstevel@tonic-gate  *
3147c478bd9Sstevel@tonic-gate  * The goal is to allocate more resources to those resource partitions
3157c478bd9Sstevel@tonic-gate  * which are heavily loaded. The weighting is determined from the
3167c478bd9Sstevel@tonic-gate  * objective importance and the pool.importance.
3177c478bd9Sstevel@tonic-gate  */
3187c478bd9Sstevel@tonic-gate final class WeightedLoadObjective extends AbstractObjective
3197c478bd9Sstevel@tonic-gate     implements WorkloadDependentObjective
3207c478bd9Sstevel@tonic-gate {
3217c478bd9Sstevel@tonic-gate 	/**
3227c478bd9Sstevel@tonic-gate 	 * The name of the class.
3237c478bd9Sstevel@tonic-gate 	 */
3247c478bd9Sstevel@tonic-gate 	static final String name = "wt-load";
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	/**
32782a28c42Sgarypen 	 * The map of calculations made during examination.
3287c478bd9Sstevel@tonic-gate 	 */
32982a28c42Sgarypen 	Map calcMap;
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	/**
3327c478bd9Sstevel@tonic-gate 	 * Determine whether an objective is satisfied. If the
3337c478bd9Sstevel@tonic-gate 	 * objective is still satisfied, return false; otherwise
3347c478bd9Sstevel@tonic-gate 	 * return true.
3357c478bd9Sstevel@tonic-gate 	 *
3367c478bd9Sstevel@tonic-gate 	 * This objective examination determines if all resource sets
3377c478bd9Sstevel@tonic-gate 	 * are allocated the share of resources that their utilization
3387c478bd9Sstevel@tonic-gate 	 * would indicate they should be. This attempts to ensure that
3397c478bd9Sstevel@tonic-gate 	 * highly utilized resource sets recieve the greater
3407c478bd9Sstevel@tonic-gate 	 * proportion of available resources.
3417c478bd9Sstevel@tonic-gate 	 *
3427c478bd9Sstevel@tonic-gate 	 * @param conf The configuration to be examined
3437c478bd9Sstevel@tonic-gate 	 * @param solver The solving interface used to get utilization
3447c478bd9Sstevel@tonic-gate 	 * information
3457c478bd9Sstevel@tonic-gate 	 * @param elem The element to which the objective belongs
3467c478bd9Sstevel@tonic-gate 	 *
3477c478bd9Sstevel@tonic-gate 	 * @throws PoolsException if there is an error examining the
3487c478bd9Sstevel@tonic-gate 	 * pool configuration
3497c478bd9Sstevel@tonic-gate 	 * @throws StaleMonitorException if there is an error accessing
3507c478bd9Sstevel@tonic-gate 	 * the element's ResourceMonitor
3517c478bd9Sstevel@tonic-gate 	 */
examine(Configuration conf, Solver solver, Element elem)3527c478bd9Sstevel@tonic-gate 	public boolean examine(Configuration conf, Solver solver,
3537c478bd9Sstevel@tonic-gate 	    Element elem) throws PoolsException, StaleMonitorException
3547c478bd9Sstevel@tonic-gate 	{
3557c478bd9Sstevel@tonic-gate 		Monitor mon = solver.getMonitor();
3567c478bd9Sstevel@tonic-gate 		Value val = new Value("type", "pset");
3577c478bd9Sstevel@tonic-gate 		List valueList = new LinkedList();
35882a28c42Sgarypen 		calcMap = new HashMap();
3597c478bd9Sstevel@tonic-gate 		valueList.add(val);
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 		List resList = conf.getResources(valueList);
3627c478bd9Sstevel@tonic-gate 		val.close();
3637c478bd9Sstevel@tonic-gate 		Iterator itRes = resList.iterator();
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 		Calculation.totalUtil = 0;
3667c478bd9Sstevel@tonic-gate 		Calculation.resQ = 0;
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 		while (itRes.hasNext()) {
3697c478bd9Sstevel@tonic-gate 			Resource res = (Resource) itRes.next();
3707c478bd9Sstevel@tonic-gate 			List CPUs = res.getComponents(null);
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 			try {
3737c478bd9Sstevel@tonic-gate 				Calculation calc = new Calculation(res, CPUs,
37482a28c42Sgarypen 				    mon.getUtilization(res),
37582a28c42Sgarypen 				    res.getLongProperty("pset.min"),
37682a28c42Sgarypen 				    res.getLongProperty("pset.max"));
37782a28c42Sgarypen 				calcMap.put(res, calc);
3787c478bd9Sstevel@tonic-gate 			} catch (StaleMonitorException sme) {
3797c478bd9Sstevel@tonic-gate 				Poold.MON_LOG.log(Severity.INFO,
3807c478bd9Sstevel@tonic-gate 				    res.toString() +
3817c478bd9Sstevel@tonic-gate 				    " not participating in " + toString() +
3827c478bd9Sstevel@tonic-gate 				    " calculatation as it has no " +
3837c478bd9Sstevel@tonic-gate 				    "available statistics.");
3847c478bd9Sstevel@tonic-gate 			}
3857c478bd9Sstevel@tonic-gate 		}
38682a28c42Sgarypen 		Iterator itCalc = calcMap.values().iterator();
3877c478bd9Sstevel@tonic-gate 		while (itCalc.hasNext()) {
3887c478bd9Sstevel@tonic-gate 			Calculation calc = (Calculation) itCalc.next();
38982a28c42Sgarypen 			if (calc.getShare() != calc.comp.size() &&
39082a28c42Sgarypen 			    calc.getShare() >= calc.min) {
3917c478bd9Sstevel@tonic-gate 				Poold.MON_LOG.log(Severity.INFO,
3927c478bd9Sstevel@tonic-gate 				    elem.toString() +
3937c478bd9Sstevel@tonic-gate 				    " utilization objective not satisfied " +
3947c478bd9Sstevel@tonic-gate 				    toString() + " with desired share " +
3957c478bd9Sstevel@tonic-gate 				    calc.getShare() + " and actual share " +
3967c478bd9Sstevel@tonic-gate 				    calc.comp.size());
3977c478bd9Sstevel@tonic-gate 				return (true);
3987c478bd9Sstevel@tonic-gate 			}
3997c478bd9Sstevel@tonic-gate 		}
4007c478bd9Sstevel@tonic-gate 		return (false);
4017c478bd9Sstevel@tonic-gate 	}
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	/**
4047c478bd9Sstevel@tonic-gate 	 * Holds data about weighted load calculations. This class is
4057c478bd9Sstevel@tonic-gate 	 * basically a structure which holds information specific to a
4067c478bd9Sstevel@tonic-gate 	 * weighted-load calculation
4077c478bd9Sstevel@tonic-gate 	 */
4087c478bd9Sstevel@tonic-gate 	static class Calculation {
4097c478bd9Sstevel@tonic-gate 		/**
4107c478bd9Sstevel@tonic-gate 		 * The resource on which this calculation is based.
4117c478bd9Sstevel@tonic-gate 		 */
4127c478bd9Sstevel@tonic-gate 		Resource res;
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 		/**
4157c478bd9Sstevel@tonic-gate 		 * The list of component resources held by this resource.
4167c478bd9Sstevel@tonic-gate 		 */
4177c478bd9Sstevel@tonic-gate 		List comp;
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 		/**
4207c478bd9Sstevel@tonic-gate 		 * The utilization of this resource.
4217c478bd9Sstevel@tonic-gate 		 */
4227c478bd9Sstevel@tonic-gate 		double util;
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 		/**
4257c478bd9Sstevel@tonic-gate 		 * The minimum value of this resource's size.
4267c478bd9Sstevel@tonic-gate 		 */
4277c478bd9Sstevel@tonic-gate 		long min;
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 		/**
4307c478bd9Sstevel@tonic-gate 		 * The maximum value of this resource's size.
4317c478bd9Sstevel@tonic-gate 		 */
4327c478bd9Sstevel@tonic-gate 		long max;
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 		/**
4357c478bd9Sstevel@tonic-gate 		 * The total utilization of all instances of this class.
4367c478bd9Sstevel@tonic-gate 		 */
4377c478bd9Sstevel@tonic-gate 		static double totalUtil;
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 		/**
4407c478bd9Sstevel@tonic-gate 		 * The total quantity of resource for all instances of
4417c478bd9Sstevel@tonic-gate 		 * this class.
4427c478bd9Sstevel@tonic-gate 		 */
4437c478bd9Sstevel@tonic-gate 		static int resQ;
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 		/**
4467c478bd9Sstevel@tonic-gate 		 * Constructor. The class is immutable and holds
4477c478bd9Sstevel@tonic-gate 		 * information specific to a set of calculations about
4487c478bd9Sstevel@tonic-gate 		 * load.
4497c478bd9Sstevel@tonic-gate 		 *
4507c478bd9Sstevel@tonic-gate 		 * @param res The resource set
4517c478bd9Sstevel@tonic-gate 		 * @param comp The resource components
4527c478bd9Sstevel@tonic-gate 		 * @param util The resource utilization
4537c478bd9Sstevel@tonic-gate 		 * @param min The minimum qty of resource for this set
4547c478bd9Sstevel@tonic-gate 		 * @param max The maximum qty of resource for this set
4557c478bd9Sstevel@tonic-gate 		 */
Calculation(Resource res, List comp, double util, long min, long max)4567c478bd9Sstevel@tonic-gate 		public Calculation(Resource res, List comp, double util,
45782a28c42Sgarypen 		    long min, long max)
4587c478bd9Sstevel@tonic-gate 		{
4597c478bd9Sstevel@tonic-gate 			this.res = res;
4607c478bd9Sstevel@tonic-gate 			this.comp = comp;
4617c478bd9Sstevel@tonic-gate 			this.min = min;
4627c478bd9Sstevel@tonic-gate 			this.max = max;
4637c478bd9Sstevel@tonic-gate 			this.util = (util / 100) * comp.size();
4647c478bd9Sstevel@tonic-gate 			Calculation.totalUtil += this.util;
4657c478bd9Sstevel@tonic-gate 			Calculation.resQ += comp.size();
4667c478bd9Sstevel@tonic-gate 		}
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 		/**
4697c478bd9Sstevel@tonic-gate 		 * Return the share of the total resource for this
4707c478bd9Sstevel@tonic-gate 		 * resource.
4717c478bd9Sstevel@tonic-gate 		 */
getShare()4727c478bd9Sstevel@tonic-gate 		long getShare()
4737c478bd9Sstevel@tonic-gate 		{
47482a28c42Sgarypen 			if (util == 0)
47582a28c42Sgarypen 				return (0);
4767c478bd9Sstevel@tonic-gate 			return (Math.round((util / totalUtil) * resQ));
4777c478bd9Sstevel@tonic-gate 		}
4787c478bd9Sstevel@tonic-gate 
toString()4797c478bd9Sstevel@tonic-gate 		public String toString()
4807c478bd9Sstevel@tonic-gate 		{
4817c478bd9Sstevel@tonic-gate 			StringBuffer buf = new StringBuffer();
4827c478bd9Sstevel@tonic-gate 			buf.append("res: " + res.toString());
4837c478bd9Sstevel@tonic-gate 			buf.append(" components: " + comp.toString());
4847c478bd9Sstevel@tonic-gate 			buf.append(" min: " + min);
4857c478bd9Sstevel@tonic-gate 			buf.append(" max: " + max);
4867c478bd9Sstevel@tonic-gate 			buf.append(" util: " + util);
4877c478bd9Sstevel@tonic-gate 			buf.append(" total resource: " + resQ);
4887c478bd9Sstevel@tonic-gate 			buf.append(" total utilization: " + totalUtil);
4897c478bd9Sstevel@tonic-gate 			buf.append(" share: " + getShare());
4907c478bd9Sstevel@tonic-gate 			return (buf.toString());
4917c478bd9Sstevel@tonic-gate 		}
4927c478bd9Sstevel@tonic-gate 	}
49382a28c42Sgarypen 
4947c478bd9Sstevel@tonic-gate 	/**
4957c478bd9Sstevel@tonic-gate 	 * Calculates the value of a configuration in terms of this
4967c478bd9Sstevel@tonic-gate 	 * objective.
4977c478bd9Sstevel@tonic-gate 	 *
4987c478bd9Sstevel@tonic-gate 	 * In the examination step, calculations of each resource's
4997c478bd9Sstevel@tonic-gate 	 * current and desired share were made. The moves can thus be
50082a28c42Sgarypen 	 * assessed in terms of their impact upon the desired
5017c478bd9Sstevel@tonic-gate 	 * share. The current difference from desired is already
5027c478bd9Sstevel@tonic-gate 	 * known, so each move will serve to reduce or increase that
5037c478bd9Sstevel@tonic-gate 	 * difference. Moves that increase the difference have a
5047c478bd9Sstevel@tonic-gate 	 * negative score, those that reduce it have a positive
5057c478bd9Sstevel@tonic-gate 	 * score. All scores are normalized to return a value between
5067c478bd9Sstevel@tonic-gate 	 * -1 and 1.
5077c478bd9Sstevel@tonic-gate 	 *
5087c478bd9Sstevel@tonic-gate 	 * @param conf Configuration to be scored.
5097c478bd9Sstevel@tonic-gate 	 * @param move Move to be scored.
5107c478bd9Sstevel@tonic-gate 	 * @param elem The element to which the objective applies
5117c478bd9Sstevel@tonic-gate 	 * @throws PoolsException If an there is an error in execution.
5127c478bd9Sstevel@tonic-gate 	 */
calculate(Configuration conf, Move move, Element elem)5137c478bd9Sstevel@tonic-gate 	public double calculate(Configuration conf, Move move, Element elem)
5147c478bd9Sstevel@tonic-gate 	    throws PoolsException
5157c478bd9Sstevel@tonic-gate 	{
5167c478bd9Sstevel@tonic-gate 		double ret = 0;
51782a28c42Sgarypen 
5187c478bd9Sstevel@tonic-gate 		Poold.OPT_LOG.log(Severity.DEBUG,
5197c478bd9Sstevel@tonic-gate 		    "Calculating objective type: " + name);
5207c478bd9Sstevel@tonic-gate 		/*
5217c478bd9Sstevel@tonic-gate 		 * There shouldn't be any empty moves, but if there
5227c478bd9Sstevel@tonic-gate 		 * are they are rated at 0.
5237c478bd9Sstevel@tonic-gate 		 */
5247c478bd9Sstevel@tonic-gate 		if (move.getQty() == 0)
5257c478bd9Sstevel@tonic-gate 			return (0);
52682a28c42Sgarypen 
5277c478bd9Sstevel@tonic-gate 		/*
52882a28c42Sgarypen 		 * Find the calculations that represent the source and
52982a28c42Sgarypen 		 * target of the move.
5307c478bd9Sstevel@tonic-gate 		 */
53182a28c42Sgarypen 		Calculation src = (Calculation) calcMap.get(move.getFrom());
53282a28c42Sgarypen 		Calculation tgt = (Calculation) calcMap.get(move.getTo());
53382a28c42Sgarypen 
53482a28c42Sgarypen 		/*
53582a28c42Sgarypen 		 * Use the calculation details to determine the "gap"
53682a28c42Sgarypen 		 * i.e. number of discrete resources (for a processor
53782a28c42Sgarypen 		 * set these are CPUs), between the desired quantity in
53882a28c42Sgarypen 		 * the set which the calculations represent. Do this
53982a28c42Sgarypen 		 * both before and after the proposed move.
54082a28c42Sgarypen 		 *
54182a28c42Sgarypen 		 * The maximum possible improvement is equal to the
54282a28c42Sgarypen 		 * total number of resources for each set participating
54382a28c42Sgarypen 		 * in the calculation. Since there are two sets we
54482a28c42Sgarypen 		 * know the maximum possible improvement is resQ * 2.
54582a28c42Sgarypen 		 *
54682a28c42Sgarypen 		 * Divide the aggregated change in gap across participating
54782a28c42Sgarypen 		 * sets by the maximum possible improvement to obtain
54882a28c42Sgarypen 		 * a value which scores the move and which is normalised
54982a28c42Sgarypen 		 * between -1 <= ret <= 1.
55082a28c42Sgarypen 		 */
55182a28c42Sgarypen 		long oldGap = Math.abs(src.getShare() -
55282a28c42Sgarypen 		    src.comp.size());
55382a28c42Sgarypen 		long newGap = Math.abs(src.getShare() -
55482a28c42Sgarypen 		    (src.comp.size() - move.getQty()));
55582a28c42Sgarypen 		ret = oldGap - newGap;
55682a28c42Sgarypen 		oldGap = Math.abs(tgt.getShare() -
55782a28c42Sgarypen 		    tgt.comp.size());
55882a28c42Sgarypen 		newGap = Math.abs(tgt.getShare() -
55982a28c42Sgarypen 		    (tgt.comp.size() + move.getQty()));
56082a28c42Sgarypen 		ret += oldGap - newGap;
56182a28c42Sgarypen 		ret /= ((double) Calculation.resQ * 2);
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 		Poold.MON_LOG.log(Severity.DEBUG, "ret: " + ret);
5647c478bd9Sstevel@tonic-gate 		return (ret);
5657c478bd9Sstevel@tonic-gate 	}
5667c478bd9Sstevel@tonic-gate }
5677c478bd9Sstevel@tonic-gate 
568*967a0a51SMita Solanky     /*
569*967a0a51SMita Solanky      * The following LGroupData and Resulttuple and PSETData classes
570*967a0a51SMita Solanky      * are used for the purposes of calculating and storing
571*967a0a51SMita Solanky      * results sets for the LocalityObjective calculate method.
572*967a0a51SMita Solanky      */
573*967a0a51SMita Solanky 
574*967a0a51SMita Solanky     /*
575*967a0a51SMita Solanky      * To store data for a Localitygroup.
576*967a0a51SMita Solanky      *
577*967a0a51SMita Solanky      * The lgroup is the LocalityGroup.
578*967a0a51SMita Solanky      * The numcpu is the number of cpu in the LocalityGroup.
579*967a0a51SMita Solanky      * The factor is a value required in calculating the LocalityGroup quotient.
580*967a0a51SMita Solanky      *
581*967a0a51SMita Solanky      * The value of factor will always be a finite number
582*967a0a51SMita Solanky      * because the LocalityGroup will never be empty.
583*967a0a51SMita Solanky      */
584*967a0a51SMita Solanky     final class LGroupData
585*967a0a51SMita Solanky     {
586*967a0a51SMita Solanky             private LocalityGroup lgroup;
587*967a0a51SMita Solanky             private int numcpu = 0;
588*967a0a51SMita Solanky             private double factor;
589*967a0a51SMita Solanky 
LGroupData(LocalityGroup l)590*967a0a51SMita Solanky             LGroupData(LocalityGroup l) {
591*967a0a51SMita Solanky                 lgroup = l;
592*967a0a51SMita Solanky                 int numcpuinlgroup = lgroup.getCPUIDs().length;
593*967a0a51SMita Solanky                 factor = 2.0 / ((numcpuinlgroup * numcpuinlgroup)
594*967a0a51SMita Solanky                         + numcpuinlgroup);
595*967a0a51SMita Solanky             }
596*967a0a51SMita Solanky 
getNumcpu()597*967a0a51SMita Solanky             int getNumcpu() {
598*967a0a51SMita Solanky                 return numcpu;
599*967a0a51SMita Solanky             }
600*967a0a51SMita Solanky 
getFactor()601*967a0a51SMita Solanky             double getFactor() {
602*967a0a51SMita Solanky                 return factor;
603*967a0a51SMita Solanky             }
604*967a0a51SMita Solanky 
incNumcpu()605*967a0a51SMita Solanky             void incNumcpu() {
606*967a0a51SMita Solanky                 numcpu++;
607*967a0a51SMita Solanky             }
608*967a0a51SMita Solanky     }
609*967a0a51SMita Solanky 
610*967a0a51SMita Solanky     /*
611*967a0a51SMita Solanky      * Stores the results of caclulated locality quotients for a PSET.
612*967a0a51SMita Solanky      *
613*967a0a51SMita Solanky      * The AsIsResult is the quotient without any move.
614*967a0a51SMita Solanky      * The FromResult is the quotient when a cpu is taken from it.
615*967a0a51SMita Solanky      * The To result is the quotient when a cpu is added to it.
616*967a0a51SMita Solanky      */
617*967a0a51SMita Solanky     final class ResultTuple
618*967a0a51SMita Solanky     {
619*967a0a51SMita Solanky             private double AsIsResult = 0;
620*967a0a51SMita Solanky             private double FromResult = 0;
621*967a0a51SMita Solanky             private double ToResult = 0;
622*967a0a51SMita Solanky 
ResultTuple(double a, double f, double t)623*967a0a51SMita Solanky             ResultTuple(double a, double f, double t) {
624*967a0a51SMita Solanky                 setAsIsResult(a);
625*967a0a51SMita Solanky                 setFromResult(f);
626*967a0a51SMita Solanky                 setToResult(t);
627*967a0a51SMita Solanky             }
628*967a0a51SMita Solanky 
getAsIsResult()629*967a0a51SMita Solanky             double getAsIsResult() {
630*967a0a51SMita Solanky                 return AsIsResult;
631*967a0a51SMita Solanky             }
632*967a0a51SMita Solanky 
getFromResult()633*967a0a51SMita Solanky             double getFromResult() {
634*967a0a51SMita Solanky                 return FromResult;
635*967a0a51SMita Solanky             }
636*967a0a51SMita Solanky 
getToResult()637*967a0a51SMita Solanky             double getToResult() {
638*967a0a51SMita Solanky                 return ToResult;
639*967a0a51SMita Solanky             }
640*967a0a51SMita Solanky 
setAsIsResult(double asis)641*967a0a51SMita Solanky             void setAsIsResult(double asis) {
642*967a0a51SMita Solanky                 AsIsResult = asis;
643*967a0a51SMita Solanky             }
644*967a0a51SMita Solanky 
setFromResult(double from)645*967a0a51SMita Solanky             void setFromResult(double from) {
646*967a0a51SMita Solanky                 FromResult = from;
647*967a0a51SMita Solanky             }
648*967a0a51SMita Solanky 
setToResult(double to)649*967a0a51SMita Solanky             void setToResult(double to) {
650*967a0a51SMita Solanky                 ToResult = to;
651*967a0a51SMita Solanky             }
652*967a0a51SMita Solanky     }
653*967a0a51SMita Solanky 
654*967a0a51SMita Solanky     /*
655*967a0a51SMita Solanky      * The PSETData class enables storage and population of the data
656*967a0a51SMita Solanky      * required for the LocalityObjective calculate() method.
657*967a0a51SMita Solanky      *
658*967a0a51SMita Solanky      * The lgroupdata HashMap stores LGroupData objects
659*967a0a51SMita Solanky      * for each LGroup in the pset.
660*967a0a51SMita Solanky      * The results HashMap stores resultsTuple objects for each LGroup.
661*967a0a51SMita Solanky      * The countLgroups() method populates the lgroupdata HashMap.
662*967a0a51SMita Solanky      * The calcQ() method calculates the quotient for any given
663*967a0a51SMita Solanky      * value of intersection and lgroup size.
664*967a0a51SMita Solanky      * The calcResults() method populates the results HashMap.
665*967a0a51SMita Solanky      */
666*967a0a51SMita Solanky     final class PSETData
667*967a0a51SMita Solanky     {
668*967a0a51SMita Solanky             private Resource pset;
669*967a0a51SMita Solanky             private Map<LocalityGroup, LGroupData> lgroupdata
670*967a0a51SMita Solanky                  = new HashMap<LocalityGroup, LGroupData>();
671*967a0a51SMita Solanky             private Map<LocalityGroup, ResultTuple> results
672*967a0a51SMita Solanky                  = new HashMap<LocalityGroup, ResultTuple>();
673*967a0a51SMita Solanky             double AsIsTotal = 0;
674*967a0a51SMita Solanky             int numlg = 0;
675*967a0a51SMita Solanky 
getAsIsTotal()676*967a0a51SMita Solanky             double getAsIsTotal() {
677*967a0a51SMita Solanky                 return AsIsTotal;
678*967a0a51SMita Solanky             }
679*967a0a51SMita Solanky 
getResults()680*967a0a51SMita Solanky             Map<LocalityGroup, ResultTuple> getResults() {
681*967a0a51SMita Solanky                 return results;
682*967a0a51SMita Solanky             }
683*967a0a51SMita Solanky 
684*967a0a51SMita Solanky             /*
685*967a0a51SMita Solanky              * Count the number of cpu in each locality group in this pset
686*967a0a51SMita Solanky              * and count the number of locality groups in this pset.
687*967a0a51SMita Solanky              *
688*967a0a51SMita Solanky              * @param allCPUData Map of all cpu and their LocalityGroup.
689*967a0a51SMita Solanky              *
690*967a0a51SMita Solanky              * @throws new PoolsException if no lgroups found, i.e numlg = 0;
691*967a0a51SMita Solanky              */
countLgroups(Map allCPUData)692*967a0a51SMita Solanky             private void countLgroups(Map allCPUData)
693*967a0a51SMita Solanky                     throws PoolsException
694*967a0a51SMita Solanky             {
695*967a0a51SMita Solanky                 List cpuList = pset.getComponents(null);
696*967a0a51SMita Solanky                 Iterator cpuIt = cpuList.iterator();
697*967a0a51SMita Solanky                 while (cpuIt.hasNext()) {
698*967a0a51SMita Solanky                     Component currentCPU = (Component) cpuIt.next();
699*967a0a51SMita Solanky                     int cpuid = (int) currentCPU.getLongProperty("cpu.sys_id");
700*967a0a51SMita Solanky                     if (allCPUData.containsKey(new Integer(cpuid))) {
701*967a0a51SMita Solanky                         LocalityGroup lg =
702*967a0a51SMita Solanky                             (LocalityGroup) allCPUData.get(new Integer(cpuid));
703*967a0a51SMita Solanky                         if (lgroupdata.containsKey(lg)) {
704*967a0a51SMita Solanky                             LGroupData cpulgp = (LGroupData) lgroupdata.get(lg);
705*967a0a51SMita Solanky                             cpulgp.incNumcpu();
706*967a0a51SMita Solanky                         }
707*967a0a51SMita Solanky                     }
708*967a0a51SMita Solanky                 }
709*967a0a51SMita Solanky                 Set groups = lgroupdata.keySet();
710*967a0a51SMita Solanky                 Iterator groupsIt = groups.iterator();
711*967a0a51SMita Solanky                 while (groupsIt.hasNext()) {
712*967a0a51SMita Solanky                     LocalityGroup lg = (LocalityGroup) groupsIt.next();
713*967a0a51SMita Solanky                     LGroupData cpulgp = (LGroupData) lgroupdata.get(lg);
714*967a0a51SMita Solanky                     if (cpulgp.getNumcpu() > 0) {
715*967a0a51SMita Solanky                         numlg++;
716*967a0a51SMita Solanky                     }
717*967a0a51SMita Solanky                 }
718*967a0a51SMita Solanky                 if (numlg == 0) {
719*967a0a51SMita Solanky                     throw new PoolsException();
720*967a0a51SMita Solanky                 }
721*967a0a51SMita Solanky             }
722*967a0a51SMita Solanky 
723*967a0a51SMita Solanky             /**
724*967a0a51SMita Solanky              * Calculate the final quotient with the given
725*967a0a51SMita Solanky              * factor and intersection values.
726*967a0a51SMita Solanky              *
727*967a0a51SMita Solanky              * @param factor double value of factor for this move.
728*967a0a51SMita Solanky              * @param intersection int value of intersection for this move.
729*967a0a51SMita Solanky              */
calcQ(double factor, int intersection)730*967a0a51SMita Solanky 	    private double calcQ(double factor, int intersection)
731*967a0a51SMita Solanky             {
732*967a0a51SMita Solanky                 double q = factor * ((intersection * intersection)
733*967a0a51SMita Solanky                         + intersection) / 2.0;
734*967a0a51SMita Solanky                 return (q);
735*967a0a51SMita Solanky             }
736*967a0a51SMita Solanky 
737*967a0a51SMita Solanky             /*
738*967a0a51SMita Solanky              * Calulate results for all locality groups for this pset.
739*967a0a51SMita Solanky              *
740*967a0a51SMita Solanky              * The logic considers all cases of pset populations;
741*967a0a51SMita Solanky              * i) pset is empty; ii) pset has only one cpu;
742*967a0a51SMita Solanky              * iii) pset more than one  cpu.
743*967a0a51SMita Solanky              * numlg is never zero so we need not try and catch that here.
744*967a0a51SMita Solanky              */
calcqA()745*967a0a51SMita Solanky             private void calcqA()
746*967a0a51SMita Solanky                     throws PoolsException
747*967a0a51SMita Solanky             {
748*967a0a51SMita Solanky                 Set allgroups = (Set) results.keySet();
749*967a0a51SMita Solanky                 Iterator groupIt = (Iterator) allgroups.iterator();
750*967a0a51SMita Solanky                 while (groupIt.hasNext()) {
751*967a0a51SMita Solanky                     LocalityGroup lgroup = (LocalityGroup) groupIt.next();
752*967a0a51SMita Solanky                     if (lgroupdata.containsKey(lgroup)) {
753*967a0a51SMita Solanky                         LGroupData cpulgp =
754*967a0a51SMita Solanky                                 (LGroupData) lgroupdata.get(lgroup);
755*967a0a51SMita Solanky                         ResultTuple rst = (ResultTuple) results.get(lgroup);
756*967a0a51SMita Solanky                         if (cpulgp.getNumcpu() == 0) {
757*967a0a51SMita Solanky                             double toresult =
758*967a0a51SMita Solanky                                     (AsIsTotal + rst.getToResult())/(numlg + 1);
759*967a0a51SMita Solanky                             rst.setToResult(toresult);
760*967a0a51SMita Solanky                         }
761*967a0a51SMita Solanky                         if (cpulgp.getNumcpu() == 1) {
762*967a0a51SMita Solanky                             double fromresult =
763*967a0a51SMita Solanky                                     (AsIsTotal + rst.getFromResult())
764*967a0a51SMita Solanky                                     /(numlg - 1);
765*967a0a51SMita Solanky                             rst.setFromResult(fromresult);
766*967a0a51SMita Solanky                         }
767*967a0a51SMita Solanky                         if (cpulgp.getNumcpu() > 1) {
768*967a0a51SMita Solanky                             double toresult = (AsIsTotal
769*967a0a51SMita Solanky                                     - rst.getAsIsResult()
770*967a0a51SMita Solanky                                     + rst.getToResult())/(numlg);
771*967a0a51SMita Solanky                             rst.setToResult(toresult);
772*967a0a51SMita Solanky                             double fromresult = (AsIsTotal
773*967a0a51SMita Solanky                                     - rst.getAsIsResult()
774*967a0a51SMita Solanky                                     + rst.getFromResult())/(numlg);
775*967a0a51SMita Solanky                             rst.setFromResult(fromresult);
776*967a0a51SMita Solanky                         }
777*967a0a51SMita Solanky                         results.put(lgroup, rst);
778*967a0a51SMita Solanky                     }
779*967a0a51SMita Solanky                 }
780*967a0a51SMita Solanky             }
781*967a0a51SMita Solanky 
782*967a0a51SMita Solanky             /*
783*967a0a51SMita Solanky              * Populates the results map for each locality group.
784*967a0a51SMita Solanky              *
785*967a0a51SMita Solanky              * numlg is never zero so do not need to try and catch it.
786*967a0a51SMita Solanky              *
787*967a0a51SMita Solanky              * @param allLGroups Set of all Locality groups in this config.
788*967a0a51SMita Solanky              */
calcResults(Set allLGroups)789*967a0a51SMita Solanky             private void calcResults(Set allLGroups)
790*967a0a51SMita Solanky                     throws PoolsException
791*967a0a51SMita Solanky             {
792*967a0a51SMita Solanky                 Iterator groupIt = (Iterator) allLGroups.iterator();
793*967a0a51SMita Solanky                 while (groupIt.hasNext()) {
794*967a0a51SMita Solanky                     int intersection = 0;
795*967a0a51SMita Solanky                     double factor = 0;
796*967a0a51SMita Solanky                     LocalityGroup lgroup = (LocalityGroup) groupIt.next();
797*967a0a51SMita Solanky                     if (lgroup.getCPUIDs().length != 0) {
798*967a0a51SMita Solanky                         if (lgroupdata.containsKey(lgroup)) {
799*967a0a51SMita Solanky                             LGroupData cpulgp =
800*967a0a51SMita Solanky                                     (LGroupData)lgroupdata.get(lgroup);
801*967a0a51SMita Solanky                             intersection = cpulgp.getNumcpu();
802*967a0a51SMita Solanky                             factor = cpulgp.getFactor();
803*967a0a51SMita Solanky                         }
804*967a0a51SMita Solanky                         ResultTuple thisresult = new ResultTuple(
805*967a0a51SMita Solanky                             calcQ(factor, intersection),
806*967a0a51SMita Solanky                             calcQ(factor, intersection-1),
807*967a0a51SMita Solanky                             calcQ(factor, intersection+1));
808*967a0a51SMita Solanky                         AsIsTotal += thisresult.getAsIsResult();
809*967a0a51SMita Solanky                         results.put(lgroup, thisresult);
810*967a0a51SMita Solanky                     }
811*967a0a51SMita Solanky                 }
812*967a0a51SMita Solanky                 calcqA();
813*967a0a51SMita Solanky                 AsIsTotal /= numlg;
814*967a0a51SMita Solanky             }
815*967a0a51SMita Solanky 
816*967a0a51SMita Solanky             /*
817*967a0a51SMita Solanky              * Constructor for PSETData.
818*967a0a51SMita Solanky              *
819*967a0a51SMita Solanky              * @param allLGroups Set of all Locality groups in this config.
820*967a0a51SMita Solanky              * @param allCPUData Map of all cpu and their locality group.
821*967a0a51SMita Solanky              * @param p Resource (pset) for which the calculations are made.
822*967a0a51SMita Solanky              *
823*967a0a51SMita Solanky              * @throws PoolsException if accessing the supplied resource
824*967a0a51SMita Solanky              * fails.
825*967a0a51SMita Solanky              */
PSETData(Set allLGroups, Map allCPUData, Resource p)826*967a0a51SMita Solanky             PSETData(Set allLGroups, Map allCPUData, Resource p)
827*967a0a51SMita Solanky                     throws PoolsException
828*967a0a51SMita Solanky             {
829*967a0a51SMita Solanky                 pset = p;
830*967a0a51SMita Solanky                 Iterator groupIt = (Iterator) allLGroups.iterator();
831*967a0a51SMita Solanky                 while (groupIt.hasNext()) {
832*967a0a51SMita Solanky                     LocalityGroup lgroup = (LocalityGroup) groupIt.next();
833*967a0a51SMita Solanky                     if (lgroup.getCPUIDs().length != 0) {
834*967a0a51SMita Solanky                         LGroupData cpulgp = new LGroupData(lgroup);
835*967a0a51SMita Solanky                         lgroupdata.put(lgroup, cpulgp);
836*967a0a51SMita Solanky                     }
837*967a0a51SMita Solanky                 }
838*967a0a51SMita Solanky                 countLgroups(allCPUData);
839*967a0a51SMita Solanky                 calcResults(allLGroups);
840*967a0a51SMita Solanky             }
841*967a0a51SMita Solanky         }
842*967a0a51SMita Solanky 
8437c478bd9Sstevel@tonic-gate /**
8447c478bd9Sstevel@tonic-gate  * A locality based objective which will assess moves in terms of
8457c478bd9Sstevel@tonic-gate  * their impact on the locality of the sets of resources which are
8467c478bd9Sstevel@tonic-gate  * impacted.
8477c478bd9Sstevel@tonic-gate  *
8487c478bd9Sstevel@tonic-gate  * The objective will assess moves with respect to the type of
8497c478bd9Sstevel@tonic-gate  * locality specified in the objective:
8507c478bd9Sstevel@tonic-gate  *
8517c478bd9Sstevel@tonic-gate  * <ul>
8527c478bd9Sstevel@tonic-gate  * <li><p>
8537c478bd9Sstevel@tonic-gate  * tight - resource locality is sought
8547c478bd9Sstevel@tonic-gate  * <li><p>
8557c478bd9Sstevel@tonic-gate  * loose - resource locality is avoided
8567c478bd9Sstevel@tonic-gate  * <li><p>
8577c478bd9Sstevel@tonic-gate  * none - resource locality has no impact
8587c478bd9Sstevel@tonic-gate  * </ul>
8597c478bd9Sstevel@tonic-gate  */
8607c478bd9Sstevel@tonic-gate final class LocalityObjective extends AbstractObjective
8617c478bd9Sstevel@tonic-gate {
862*967a0a51SMita Solanky 	/*
8637c478bd9Sstevel@tonic-gate 	 * The name of the class.
8647c478bd9Sstevel@tonic-gate 	 */
8657c478bd9Sstevel@tonic-gate 	static final String name = "locality";
8667c478bd9Sstevel@tonic-gate 
867*967a0a51SMita Solanky 	/*
8687c478bd9Sstevel@tonic-gate 	 * The locality domain used to describe locality for this
8697c478bd9Sstevel@tonic-gate 	 * objective.
8707c478bd9Sstevel@tonic-gate 	 */
8717c478bd9Sstevel@tonic-gate 	private LocalityDomain ldom;
8727c478bd9Sstevel@tonic-gate 
873*967a0a51SMita Solanky         /*
874*967a0a51SMita Solanky          * The set of LocalityGroups in this ldom.
875*967a0a51SMita Solanky          */
876*967a0a51SMita Solanky         private Set allLGroups;
877*967a0a51SMita Solanky 
878*967a0a51SMita Solanky         /*
879*967a0a51SMita Solanky          * Map of all cpu id and their locality groups
880*967a0a51SMita Solanky          */
881*967a0a51SMita Solanky         private Map<Integer, LocalityGroup> allCPUData
882*967a0a51SMita Solanky                 = new HashMap<Integer, LocalityGroup>();
883*967a0a51SMita Solanky 
884*967a0a51SMita Solanky         /*
885*967a0a51SMita Solanky          * Method to populate the allCPUData cpu locality map.
886*967a0a51SMita Solanky          */
getCPUData()887*967a0a51SMita Solanky         private void getCPUData()
888*967a0a51SMita Solanky 	{
889*967a0a51SMita Solanky             allLGroups = ldom.getGroups();
890*967a0a51SMita Solanky             Iterator LGroupIt = allLGroups.iterator();
891*967a0a51SMita Solanky             while (LGroupIt.hasNext()) {
892*967a0a51SMita Solanky                 LocalityGroup lg = (LocalityGroup) LGroupIt.next();
893*967a0a51SMita Solanky                 int cpu_ids[] = lg.getCPUIDs();
894*967a0a51SMita Solanky                 for (int i = 0; i < cpu_ids.length; i++) {
895*967a0a51SMita Solanky                     allCPUData.put(new Integer(cpu_ids[i]), lg);
896*967a0a51SMita Solanky                 }
897*967a0a51SMita Solanky             }
898*967a0a51SMita Solanky 
899*967a0a51SMita Solanky 	}
900*967a0a51SMita Solanky 
901*967a0a51SMita Solanky         /*
902*967a0a51SMita Solanky          * Map to store all PSET LocalityGroup quotient results.
903*967a0a51SMita Solanky          */
904*967a0a51SMita Solanky         private Map<Resource, PSETData> allPSETData
905*967a0a51SMita Solanky                 = new HashMap<Resource, PSETData>();
906*967a0a51SMita Solanky 
9077c478bd9Sstevel@tonic-gate 	/**
908*967a0a51SMita Solanky 	 * Prepare the calculation for this objective for the resource to
909*967a0a51SMita Solanky 	 * which it applies.
9107c478bd9Sstevel@tonic-gate 	 *
9117c478bd9Sstevel@tonic-gate 	 * @param ldom LocalityDomain containing these resources.
9127c478bd9Sstevel@tonic-gate 	 * @param res Resource to which this objective is applied.
9137c478bd9Sstevel@tonic-gate 	 *
9147c478bd9Sstevel@tonic-gate 	 * @throws PoolsException if accessing the supplied resource
9157c478bd9Sstevel@tonic-gate 	 * fails.
9167c478bd9Sstevel@tonic-gate 	 */
prepare(LocalityDomain ldom, Resource res)9177c478bd9Sstevel@tonic-gate 	public void prepare(LocalityDomain ldom, Resource res)
9187c478bd9Sstevel@tonic-gate 	    throws PoolsException
9197c478bd9Sstevel@tonic-gate 	{
9207c478bd9Sstevel@tonic-gate 		this.ldom = ldom;
9217c478bd9Sstevel@tonic-gate 	}
92282a28c42Sgarypen 
923*967a0a51SMita Solanky 	/*
9247c478bd9Sstevel@tonic-gate 	 * Calculates the value of a configuration in terms of this
9257c478bd9Sstevel@tonic-gate 	 * objective.
9267c478bd9Sstevel@tonic-gate 	 *
9277c478bd9Sstevel@tonic-gate 	 * Firstly check to see if it is possible to short-cut the
9287c478bd9Sstevel@tonic-gate 	 * calculation. If not, then start to examine the disposition
9297c478bd9Sstevel@tonic-gate 	 * of CPUs and locality groups in relation to the processor
9307c478bd9Sstevel@tonic-gate 	 * set being evaluated. The objective scores moves in terms of
9317c478bd9Sstevel@tonic-gate 	 * their impact upon the quotient of cpus contained in each
9327c478bd9Sstevel@tonic-gate 	 * locality group.
9337c478bd9Sstevel@tonic-gate 	 *
934*967a0a51SMita Solanky 	 * Moves which involve a cpu in the same locality group are equivalent.
935*967a0a51SMita Solanky 	 * i.e for a given pset, the quotient calculation is the same
936*967a0a51SMita Solanky 	 * for a move involving cpu x in localitygroup Z,
937*967a0a51SMita Solanky 	 * as the calculation for cpu y in localitygroup Z,
938*967a0a51SMita Solanky 	 * So we store the quotient calculation of the PSET
939*967a0a51SMita Solanky 	 * i) as it is; ii) a cpu is added; iii) a cpu is removed;
940*967a0a51SMita Solanky 	 *
941*967a0a51SMita Solanky 	 * For each move we encounter, we store the quotient caclulations
942*967a0a51SMita Solanky 	 * on a pset basis, holding a map of results for each pset we evaluate.
943*967a0a51SMita Solanky 	 * The map contains results for each locality group in the system.
944*967a0a51SMita Solanky 	 * The results contains the quotient value for a move of a cpu
945*967a0a51SMita Solanky 	 * to, from and without any move.
946*967a0a51SMita Solanky 	 *
947*967a0a51SMita Solanky 	 * For a given configuration, for each cpu we make one JNI call
948*967a0a51SMita Solanky 	 * to getLongProperty() (which is the most expensive call in this code)
949*967a0a51SMita Solanky 	 * so the time spent in calculate() scales linearly with number of cpu.
950*967a0a51SMita Solanky 	 *
9517c478bd9Sstevel@tonic-gate 	 * @param conf Configuration to be scored.
9527c478bd9Sstevel@tonic-gate 	 * @param move Move to be scored.
9537c478bd9Sstevel@tonic-gate 	 * @param elem The element to which the objective applies
9547c478bd9Sstevel@tonic-gate 	 * @throws Exception If an there is an error in execution.
9557c478bd9Sstevel@tonic-gate 	 */
calculate(Configuration conf, Move move, Element elem)9567c478bd9Sstevel@tonic-gate 	public double calculate(Configuration conf, Move move, Element elem)
9577c478bd9Sstevel@tonic-gate 	    throws PoolsException
9587c478bd9Sstevel@tonic-gate 	{
9597c478bd9Sstevel@tonic-gate 		KVExpression kve = (KVExpression) getExpression();
9607c478bd9Sstevel@tonic-gate 		double ret = 0;
9617c478bd9Sstevel@tonic-gate 		double qA = 0;
9627c478bd9Sstevel@tonic-gate 		double qB = 0;
963*967a0a51SMita Solanky 		Resource pset = (Resource) elem;
9647c478bd9Sstevel@tonic-gate 		ComponentMove cm = (ComponentMove) move;
9657c478bd9Sstevel@tonic-gate 		Poold.MON_LOG.log(Severity.DEBUG,
9667c478bd9Sstevel@tonic-gate 		    "Calculating objective type: " + name + " for: " + elem);
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 		/*
9697c478bd9Sstevel@tonic-gate 		 * If we are set to "none" then we don't care which
970*967a0a51SMita Solanky 		 * configuration so just return 0.
9717c478bd9Sstevel@tonic-gate 		 */
9727c478bd9Sstevel@tonic-gate 		if (kve.getValue().compareTo("none") == 0)
9737c478bd9Sstevel@tonic-gate 			return (ret);
9747c478bd9Sstevel@tonic-gate 		/*
9757c478bd9Sstevel@tonic-gate 		 * If the maximum latency is 0, we don't care about
976*967a0a51SMita Solanky 		 * latency.
9777c478bd9Sstevel@tonic-gate 		 */
9787c478bd9Sstevel@tonic-gate 		if (ldom.getMaxLatency() == 0)
9797c478bd9Sstevel@tonic-gate 			return (ret);
9807c478bd9Sstevel@tonic-gate 		/*
9817c478bd9Sstevel@tonic-gate 		 * If this element doesn't participate in the move, we
9827c478bd9Sstevel@tonic-gate 		 * should return 0.
9837c478bd9Sstevel@tonic-gate 		 */
9847c478bd9Sstevel@tonic-gate 		if (elem.equals(move.getFrom()) == false &&
9857c478bd9Sstevel@tonic-gate 		    elem.equals(move.getTo()) == false)
9867c478bd9Sstevel@tonic-gate 			return (ret);
9877c478bd9Sstevel@tonic-gate 
988*967a0a51SMita Solanky                 /*
989*967a0a51SMita Solanky                  * Populate the map of cpu - locality data if it is empty.
990*967a0a51SMita Solanky                  */
991*967a0a51SMita Solanky                 if (allCPUData.isEmpty()) {
992*967a0a51SMita Solanky                     getCPUData();
993*967a0a51SMita Solanky                 }
9947c478bd9Sstevel@tonic-gate 
995*967a0a51SMita Solanky                 /*
996*967a0a51SMita Solanky                  * Lookup in the pset results map if the pset entry exists.
997*967a0a51SMita Solanky                  * If this pset entry exists then use it otherwise add it.
998*967a0a51SMita Solanky                  */
999*967a0a51SMita Solanky                 PSETData psetlg;
10007c478bd9Sstevel@tonic-gate 
1001*967a0a51SMita Solanky                 if (allPSETData.containsKey(pset))
1002*967a0a51SMita Solanky                     psetlg = (PSETData) allPSETData.get(pset);
1003*967a0a51SMita Solanky                 else {
1004*967a0a51SMita Solanky                     psetlg = new PSETData(allLGroups, allCPUData, pset);
1005*967a0a51SMita Solanky                     allPSETData.put(pset, psetlg);
1006*967a0a51SMita Solanky                 }
1007*967a0a51SMita Solanky 
1008*967a0a51SMita Solanky                 /*
1009*967a0a51SMita Solanky                  * Check the locality group of the cpu involved in this move.
1010*967a0a51SMita Solanky                  * If it is a cpu from a locality group we have already seen,
1011*967a0a51SMita Solanky                  * then we can retrieve the results from the pset results map.
1012*967a0a51SMita Solanky                  */
1013*967a0a51SMita Solanky                 List cpulist = (List) cm.getComponents();
1014*967a0a51SMita Solanky                 Component cpu = (Component) cpulist.get(0);
1015*967a0a51SMita Solanky 		int cpuid = (int) cpu.getLongProperty("cpu.sys_id");
1016*967a0a51SMita Solanky                 LocalityGroup lgroup =
1017*967a0a51SMita Solanky                         (LocalityGroup) allCPUData.get(new Integer(cpuid));
1018*967a0a51SMita Solanky                 HashMap allresults = (HashMap) psetlg.getResults();
1019*967a0a51SMita Solanky                 ResultTuple result = (ResultTuple) allresults.get(lgroup);
1020*967a0a51SMita Solanky 
1021*967a0a51SMita Solanky                 qB = psetlg.getAsIsTotal();
1022*967a0a51SMita Solanky                 if (elem.equals(move.getFrom()))
1023*967a0a51SMita Solanky                     qA = result.getFromResult();
1024*967a0a51SMita Solanky                 else
1025*967a0a51SMita Solanky                     qA = result.getToResult();
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 		ret = qA - qB;
10287c478bd9Sstevel@tonic-gate 
1029*967a0a51SMita Solanky                 /*
1030*967a0a51SMita Solanky                  * We return the value based on what locality objective
1031*967a0a51SMita Solanky                  * we want to achieve - tight or loose. The calculations
1032*967a0a51SMita Solanky                  * are based on tightness, so the value is reversed if the
1033*967a0a51SMita Solanky                  * objective specified "loose" locality.
1034*967a0a51SMita Solanky                  */
10357c478bd9Sstevel@tonic-gate 		if (kve.getValue().compareTo("loose") == 0)
1036*967a0a51SMita Solanky                     ret = 0 - ret;
1037*967a0a51SMita Solanky                 Poold.MON_LOG.log(Severity.DEBUG, "ret: " + ret);
10387c478bd9Sstevel@tonic-gate 		return (ret);
10397c478bd9Sstevel@tonic-gate 	}
10407c478bd9Sstevel@tonic-gate }
10417c478bd9Sstevel@tonic-gate /**
10427c478bd9Sstevel@tonic-gate  * A resource set utilization based objective which will assess moves
10437c478bd9Sstevel@tonic-gate  * in terms of their (likely) impact on the future performance of a
10447c478bd9Sstevel@tonic-gate  * resource set with respect to it's specified utilization objective.
10457c478bd9Sstevel@tonic-gate  *
10467c478bd9Sstevel@tonic-gate  * The utilization objective must be specified in terms of a
10477c478bd9Sstevel@tonic-gate  * KVOpExpression, see the class definition for information about the
10487c478bd9Sstevel@tonic-gate  * form of these expressions. The objective can be examined in terms
10497c478bd9Sstevel@tonic-gate  * of it's compliance with the aid of a monitoring object. The actual
10507c478bd9Sstevel@tonic-gate  * assessment of compliance is indicated by the associated monitoring
10517c478bd9Sstevel@tonic-gate  * object, with this class simply acting as a co-ordinator of the
105263360950Smp  * relevant information.
10537c478bd9Sstevel@tonic-gate  */
10547c478bd9Sstevel@tonic-gate final class UtilizationObjective extends AbstractObjective
10557c478bd9Sstevel@tonic-gate     implements WorkloadDependentObjective
10567c478bd9Sstevel@tonic-gate {
10577c478bd9Sstevel@tonic-gate 	/**
10587c478bd9Sstevel@tonic-gate 	 * The name of the class.
10597c478bd9Sstevel@tonic-gate 	 */
10607c478bd9Sstevel@tonic-gate 	static final String name = "utilization";
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	/**
10637c478bd9Sstevel@tonic-gate 	 * Short run detection.
10647c478bd9Sstevel@tonic-gate 	 */
10657c478bd9Sstevel@tonic-gate 	private List zoneList = new LinkedList();
10667c478bd9Sstevel@tonic-gate 
10677c478bd9Sstevel@tonic-gate 	/**
10687c478bd9Sstevel@tonic-gate 	 * Format for printing utilization.
10697c478bd9Sstevel@tonic-gate 	 */
10707c478bd9Sstevel@tonic-gate 	private static final DecimalFormat uf = new DecimalFormat("0.00");
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 	/**
10737c478bd9Sstevel@tonic-gate 	 * Solver used to calculate delta, i.e. gap, between target and
10747c478bd9Sstevel@tonic-gate 	 * actual utilization values.
10757c478bd9Sstevel@tonic-gate 	 */
10767c478bd9Sstevel@tonic-gate 	private Solver gapSolver;
10777c478bd9Sstevel@tonic-gate 
10787c478bd9Sstevel@tonic-gate 	/**
10797c478bd9Sstevel@tonic-gate 	 * Determine whether an objective is satisfied. If the
10807c478bd9Sstevel@tonic-gate 	 * objective is still satisfied, return false; otherwise
10817c478bd9Sstevel@tonic-gate 	 * return true.
10827c478bd9Sstevel@tonic-gate 	 *
10837c478bd9Sstevel@tonic-gate 	 * The assessment of control is made by the monitoring class
10847c478bd9Sstevel@tonic-gate 	 * using the supplied Expression and resource.
10857c478bd9Sstevel@tonic-gate 	 *
10867c478bd9Sstevel@tonic-gate 	 * @param conf The configuration to be examined
10877c478bd9Sstevel@tonic-gate 	 * @param solver The solving interface used to get utilization
10887c478bd9Sstevel@tonic-gate 	 * information
10897c478bd9Sstevel@tonic-gate 	 * @param elem The element to which the objective belongs
10907c478bd9Sstevel@tonic-gate 	 *
10917c478bd9Sstevel@tonic-gate 	 * @throws PoolsException if there is an error examining the
10927c478bd9Sstevel@tonic-gate 	 * pool configuration
10937c478bd9Sstevel@tonic-gate 	 * @throws StaleMonitorException if there is an error accessing
10947c478bd9Sstevel@tonic-gate 	 * the element's ResourceMonitor
10957c478bd9Sstevel@tonic-gate 	 */
examine(Configuration conf, Solver solver, Element elem)10967c478bd9Sstevel@tonic-gate 	public boolean examine(Configuration conf, Solver solver,
10977c478bd9Sstevel@tonic-gate 	    Element elem) throws PoolsException, StaleMonitorException
10987c478bd9Sstevel@tonic-gate 	{
10997c478bd9Sstevel@tonic-gate 		KVOpExpression kve = (KVOpExpression) getExpression();
11007c478bd9Sstevel@tonic-gate 		ResourceMonitor mon;
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate 		/*
11037c478bd9Sstevel@tonic-gate 		 * If there is no resource monitor, then we cannot
11047c478bd9Sstevel@tonic-gate 		 * make an assessment of the objective's achievability.
11057c478bd9Sstevel@tonic-gate 		 * Log a message to make clear that this objective is
11067c478bd9Sstevel@tonic-gate 		 * not being assessed and then indicate that
11077c478bd9Sstevel@tonic-gate 		 * the objective has been achieved.
11087c478bd9Sstevel@tonic-gate 		 */
11097c478bd9Sstevel@tonic-gate 		try {
11107c478bd9Sstevel@tonic-gate 			mon = solver.getMonitor().get((Resource)elem);
11117c478bd9Sstevel@tonic-gate 		} catch (StaleMonitorException sme) {
11127c478bd9Sstevel@tonic-gate 			Poold.MON_LOG.log(Severity.INFO,
11137c478bd9Sstevel@tonic-gate 			    elem.toString() +
11147c478bd9Sstevel@tonic-gate 			    " utilization objective not measured " +
11157c478bd9Sstevel@tonic-gate 			    toString() + " as there are no available " +
11167c478bd9Sstevel@tonic-gate 			    "statistics.");
11177c478bd9Sstevel@tonic-gate 			return (false);
11187c478bd9Sstevel@tonic-gate 		}
11197c478bd9Sstevel@tonic-gate 		gapSolver = solver;
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate 		double val = solver.getMonitor().getUtilization((Resource)elem);
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate 		StatisticList sl = (StatisticList) mon.get("utilization");
11247c478bd9Sstevel@tonic-gate 		int zone = sl.getZone(kve, val);
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 		if (zoneList.size() == 9) {
11277c478bd9Sstevel@tonic-gate 			zoneList.remove(0);
11287c478bd9Sstevel@tonic-gate 		}
11297c478bd9Sstevel@tonic-gate 		zoneList.add(new Integer(sl.getZoneMean(val)));
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate 		/*
11327c478bd9Sstevel@tonic-gate 		 * Evaluate whether or not this objective is under
11337c478bd9Sstevel@tonic-gate 		 * control.
11347c478bd9Sstevel@tonic-gate 		 */
11357c478bd9Sstevel@tonic-gate 		if ((zone & StatisticOperations.ZONEZ) ==
11367c478bd9Sstevel@tonic-gate 		    StatisticOperations.ZONEZ) {
11377c478bd9Sstevel@tonic-gate 			/*
11387c478bd9Sstevel@tonic-gate 			 * If the objective is GT or LT, then don't
11397c478bd9Sstevel@tonic-gate 			 * return true as long as the objective is
11407c478bd9Sstevel@tonic-gate 			 * satisfied.
11417c478bd9Sstevel@tonic-gate 			 */
11427c478bd9Sstevel@tonic-gate 			if (kve.getOp() == KVOpExpression.LT &&
11437c478bd9Sstevel@tonic-gate 			    (zone & StatisticOperations.ZONET) ==
11447c478bd9Sstevel@tonic-gate 			    StatisticOperations.ZONELT)
11457c478bd9Sstevel@tonic-gate 				return (false);
114682a28c42Sgarypen 
11477c478bd9Sstevel@tonic-gate 			if (kve.getOp() == KVOpExpression.GT &&
11487c478bd9Sstevel@tonic-gate 			    (zone & StatisticOperations.ZONET) ==
11497c478bd9Sstevel@tonic-gate 			    StatisticOperations.ZONEGT)
11507c478bd9Sstevel@tonic-gate 				return (false);
11517c478bd9Sstevel@tonic-gate 			Poold.MON_LOG.log(Severity.INFO,
11527c478bd9Sstevel@tonic-gate 			    elem.toString() +
11537c478bd9Sstevel@tonic-gate 			    " utilization objective not satisfied " +
11547c478bd9Sstevel@tonic-gate 			    toString() + " with utilization " + uf.format(val) +
11557c478bd9Sstevel@tonic-gate 			    " (control zone bounds exceeded)");
11567c478bd9Sstevel@tonic-gate 			return (true);
11577c478bd9Sstevel@tonic-gate 		}
11587c478bd9Sstevel@tonic-gate 		/*
11597c478bd9Sstevel@tonic-gate 		 * Check if our statistics need to be recalculated.
11607c478bd9Sstevel@tonic-gate 		 */
11617c478bd9Sstevel@tonic-gate 		checkShort(mon, elem, val);
11627c478bd9Sstevel@tonic-gate 		return (false);
11637c478bd9Sstevel@tonic-gate 	}
116482a28c42Sgarypen 
11657c478bd9Sstevel@tonic-gate 	/**
11667c478bd9Sstevel@tonic-gate 	 * Calculates the value of a configuration in terms of this
11677c478bd9Sstevel@tonic-gate 	 * objective.
11687c478bd9Sstevel@tonic-gate 	 *
11697c478bd9Sstevel@tonic-gate 	 * Every set must be classified with a control zone when this
11707c478bd9Sstevel@tonic-gate 	 * function is called. The move can be assessed in terms of
11717c478bd9Sstevel@tonic-gate 	 * the control violation type. zone violations which are minor
11727c478bd9Sstevel@tonic-gate 	 * are offered a lower contribution than more significant
11737c478bd9Sstevel@tonic-gate 	 * violations.
11747c478bd9Sstevel@tonic-gate 	 *
11757c478bd9Sstevel@tonic-gate 	 * @param conf Configuration to be scored.
11767c478bd9Sstevel@tonic-gate 	 * @param move Move to be scored.
11777c478bd9Sstevel@tonic-gate 	 * @param elem The element to which the objective applies
11787c478bd9Sstevel@tonic-gate 	 * @throws Exception If an there is an error in execution.
11797c478bd9Sstevel@tonic-gate 	 */
calculate(Configuration conf, Move move, Element elem)11807c478bd9Sstevel@tonic-gate 	public double calculate(Configuration conf, Move move, Element elem)
11817c478bd9Sstevel@tonic-gate 	    throws PoolsException
11827c478bd9Sstevel@tonic-gate 	{
11837c478bd9Sstevel@tonic-gate 		KVOpExpression kve = (KVOpExpression) getExpression();
11847c478bd9Sstevel@tonic-gate 		double ret;
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate 		/*
11877c478bd9Sstevel@tonic-gate 		 * If the move is from the examined element, then
11887c478bd9Sstevel@tonic-gate 		 * check to see if the recipient has any
11897c478bd9Sstevel@tonic-gate 		 * objectives. If not, score the move poorly since we
11907c478bd9Sstevel@tonic-gate 		 * should never want to transfer resources to a
11917c478bd9Sstevel@tonic-gate 		 * recipient with no objectives. If there are
11927c478bd9Sstevel@tonic-gate 		 * objectives, then return the delta between target
11937c478bd9Sstevel@tonic-gate 		 * performance and actual performance for this
11947c478bd9Sstevel@tonic-gate 		 * element.
11957c478bd9Sstevel@tonic-gate 		 *
11967c478bd9Sstevel@tonic-gate 		 * If the move is to the examined element, then check
11977c478bd9Sstevel@tonic-gate 		 * to see if the donor has any objectives. If not,
11987c478bd9Sstevel@tonic-gate 		 * score the move highly, since we want to favour
11997c478bd9Sstevel@tonic-gate 		 * those resources with objectives. If there are
12007c478bd9Sstevel@tonic-gate 		 * objectives, return the delta between actual and
12017c478bd9Sstevel@tonic-gate 		 * target performance.
12027c478bd9Sstevel@tonic-gate 		 *
12037c478bd9Sstevel@tonic-gate 		 * If the element is neither the recipient or the
12047c478bd9Sstevel@tonic-gate 		 * donor of this proposed move, then score the move
12057c478bd9Sstevel@tonic-gate 		 * neutrally as 0.
12067c478bd9Sstevel@tonic-gate 		 */
12077c478bd9Sstevel@tonic-gate 		try {
12087c478bd9Sstevel@tonic-gate 			double val, gap;
12097c478bd9Sstevel@tonic-gate 			StatisticList sl;
121082a28c42Sgarypen 
12117c478bd9Sstevel@tonic-gate 			if (elem.equals(move.getFrom())) {
12127c478bd9Sstevel@tonic-gate 				val = gapSolver.getMonitor().
12137c478bd9Sstevel@tonic-gate 				    getUtilization(move.getFrom());
12147c478bd9Sstevel@tonic-gate 				sl = (StatisticList) gapSolver.getMonitor().
12157c478bd9Sstevel@tonic-gate 				    get(move.getFrom()).get("utilization");
12167c478bd9Sstevel@tonic-gate 				gap = sl.getGap(kve, val) / 100;
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate 				if (gapSolver.getObjectives(move.getTo()) ==
12197c478bd9Sstevel@tonic-gate 				    null) {
12207c478bd9Sstevel@tonic-gate 					/*
12217c478bd9Sstevel@tonic-gate 					 * Moving to a resource with
12227c478bd9Sstevel@tonic-gate 					 * no objectives should always
12237c478bd9Sstevel@tonic-gate 					 * be viewed unfavourably. The
12247c478bd9Sstevel@tonic-gate 					 * degree of favourability is
12257c478bd9Sstevel@tonic-gate 					 * thus bound between 0 and
12267c478bd9Sstevel@tonic-gate 					 * -1. If the source gap is
12277c478bd9Sstevel@tonic-gate 					 * negative, then subtract it
12287c478bd9Sstevel@tonic-gate 					 * from -1 to get the
12297c478bd9Sstevel@tonic-gate 					 * score. If positive,
12307c478bd9Sstevel@tonic-gate 					 * just return -1.
12317c478bd9Sstevel@tonic-gate 					 */
12327c478bd9Sstevel@tonic-gate 					    if (gap < 0) {
12337c478bd9Sstevel@tonic-gate 						    ret = -1 - gap;
12347c478bd9Sstevel@tonic-gate 					    } else {
12357c478bd9Sstevel@tonic-gate 						    ret = -1;
12367c478bd9Sstevel@tonic-gate 					    }
12377c478bd9Sstevel@tonic-gate 				} else {
12387c478bd9Sstevel@tonic-gate 					ret = 0 - gap;
12397c478bd9Sstevel@tonic-gate 				}
12407c478bd9Sstevel@tonic-gate 			} else if (elem.equals(move.getTo())) {
12417c478bd9Sstevel@tonic-gate 				val = gapSolver.getMonitor().
12427c478bd9Sstevel@tonic-gate 				    getUtilization(move.getTo());
12437c478bd9Sstevel@tonic-gate 				sl = (StatisticList) gapSolver.getMonitor().
12447c478bd9Sstevel@tonic-gate 				    get(move.getTo()).get("utilization");
12457c478bd9Sstevel@tonic-gate 				gap = sl.getGap(kve, val) / 100;
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate 				if (gapSolver.getObjectives(move.getFrom()) ==
12487c478bd9Sstevel@tonic-gate 				    null) {
12497c478bd9Sstevel@tonic-gate 					/*
12507c478bd9Sstevel@tonic-gate 					 * Moving from a resource with
12517c478bd9Sstevel@tonic-gate 					 * no objectives should always
12527c478bd9Sstevel@tonic-gate 					 * be viewed favourably. The
12537c478bd9Sstevel@tonic-gate 					 * degree of favourability is
12547c478bd9Sstevel@tonic-gate 					 * thus bound between 0 and
12557c478bd9Sstevel@tonic-gate 					 * 1. If the destination gap
12567c478bd9Sstevel@tonic-gate 					 * is negative, then add to 1
12577c478bd9Sstevel@tonic-gate 					 * to get the score. If
12587c478bd9Sstevel@tonic-gate 					 * positive, just return 1.
12597c478bd9Sstevel@tonic-gate 					 */
12607c478bd9Sstevel@tonic-gate 					if (gap < 0) {
12617c478bd9Sstevel@tonic-gate 						ret = 0 - gap;
12627c478bd9Sstevel@tonic-gate 					} else {
12637c478bd9Sstevel@tonic-gate 						ret = 1;
12647c478bd9Sstevel@tonic-gate 					}
12657c478bd9Sstevel@tonic-gate 				} else {
12667c478bd9Sstevel@tonic-gate 					ret = 0 + gap;
12677c478bd9Sstevel@tonic-gate 				}
12687c478bd9Sstevel@tonic-gate 			} else {
12697c478bd9Sstevel@tonic-gate 				ret = 0;
12707c478bd9Sstevel@tonic-gate 			}
12717c478bd9Sstevel@tonic-gate 		} catch (StaleMonitorException sme) {
12727c478bd9Sstevel@tonic-gate 			/*
12737c478bd9Sstevel@tonic-gate 			 * We should always find a monitor,
12747c478bd9Sstevel@tonic-gate 			 * but if we can't then just assume
12757c478bd9Sstevel@tonic-gate 			 * this is a neutral move and return
12767c478bd9Sstevel@tonic-gate 			 * 0.
12777c478bd9Sstevel@tonic-gate 			 */
12787c478bd9Sstevel@tonic-gate 			ret = 0;
12797c478bd9Sstevel@tonic-gate 		}
12807c478bd9Sstevel@tonic-gate 		Poold.MON_LOG.log(Severity.DEBUG, "ret: " + ret);
12817c478bd9Sstevel@tonic-gate 		return (ret);
12827c478bd9Sstevel@tonic-gate 	}
12837c478bd9Sstevel@tonic-gate 
12847c478bd9Sstevel@tonic-gate 	/**
12857c478bd9Sstevel@tonic-gate 	 * Check whether or not a set's statistics are still useful
12867c478bd9Sstevel@tonic-gate 	 * for making decision..
12877c478bd9Sstevel@tonic-gate 	 *
12887c478bd9Sstevel@tonic-gate 	 * Each set is controlled in terms of the zones of control
12897c478bd9Sstevel@tonic-gate 	 * based in terms of standard deviations from a mean. If the
12907c478bd9Sstevel@tonic-gate 	 * utilization of the set is not fluctuating normally around a
12917c478bd9Sstevel@tonic-gate 	 * mean, these checks will cause the accumulated statistics to
12927c478bd9Sstevel@tonic-gate 	 * be discarded and control suspended until a new sufficient
12937c478bd9Sstevel@tonic-gate 	 * set of data is accumulated.
12947c478bd9Sstevel@tonic-gate 	 *
12957c478bd9Sstevel@tonic-gate 	 * @param mon Resource monitor to examine.
12967c478bd9Sstevel@tonic-gate 	 * @param elem Element to which the resource monitor belongs.
12977c478bd9Sstevel@tonic-gate 	 * @param val Latest monitored value.
12987c478bd9Sstevel@tonic-gate 	 */
checkShort(ResourceMonitor mon, Element elem, double val)12997c478bd9Sstevel@tonic-gate 	private void checkShort(ResourceMonitor mon, Element elem, double val)
13007c478bd9Sstevel@tonic-gate 	{
13017c478bd9Sstevel@tonic-gate 		boolean checkOne = true;
13027c478bd9Sstevel@tonic-gate 		int checkOnePos = 0;
13037c478bd9Sstevel@tonic-gate 		boolean doCheckOne = false;
130482a28c42Sgarypen 
13057c478bd9Sstevel@tonic-gate 		Iterator itZones = zoneList.iterator();
13067c478bd9Sstevel@tonic-gate 		while (itZones.hasNext()) {
13077c478bd9Sstevel@tonic-gate 			int zone = ((Integer) itZones.next()).intValue();
13087c478bd9Sstevel@tonic-gate 			if (doCheckOne) {
13097c478bd9Sstevel@tonic-gate 				if (checkOne) {
13107c478bd9Sstevel@tonic-gate 					if ((zone & StatisticOperations.ZONET)
13117c478bd9Sstevel@tonic-gate 					    != checkOnePos) {
13127c478bd9Sstevel@tonic-gate 						checkOne = false;
13137c478bd9Sstevel@tonic-gate 					}
13147c478bd9Sstevel@tonic-gate 				}
13157c478bd9Sstevel@tonic-gate 			} else {
13167c478bd9Sstevel@tonic-gate 				if (zoneList.size() >= 9) {
13177c478bd9Sstevel@tonic-gate 					checkOnePos = zone &
13187c478bd9Sstevel@tonic-gate 					    StatisticOperations.ZONET;
13197c478bd9Sstevel@tonic-gate 					doCheckOne = true;
13207c478bd9Sstevel@tonic-gate 				}
13217c478bd9Sstevel@tonic-gate 			}
13227c478bd9Sstevel@tonic-gate 		}
13237c478bd9Sstevel@tonic-gate 		if (zoneList.size() >= 9 && checkOne) {
13247c478bd9Sstevel@tonic-gate 			Poold.MON_LOG.log(Severity.INFO,
13257c478bd9Sstevel@tonic-gate 			    elem.toString() +
13267c478bd9Sstevel@tonic-gate 			    " utilization objective statistics reinitialized " +
13277c478bd9Sstevel@tonic-gate 			    toString() + " with utilization " + uf.format(val) +
13287c478bd9Sstevel@tonic-gate 			    " (nine points on same side of mean)");
13297c478bd9Sstevel@tonic-gate 			mon.resetData("utilization");
13307c478bd9Sstevel@tonic-gate 			zoneList.clear();
13317c478bd9Sstevel@tonic-gate 		}
13327c478bd9Sstevel@tonic-gate 	}
13337c478bd9Sstevel@tonic-gate }
1334