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