1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 * ident "%Z%%M% %I% %E% SMI" 27 */ 28 29 package com.sun.solaris.domain.pools; 30 31 import java.math.BigInteger; 32 import java.text.DecimalFormat; 33 import java.util.*; 34 import java.util.logging.*; 35 36 import com.sun.solaris.service.kstat.*; 37 import com.sun.solaris.service.logging.Severity; 38 import com.sun.solaris.domain.pools.*; 39 import com.sun.solaris.service.pools.*; 40 import com.sun.solaris.service.timer.*; 41 42 /** 43 * Regularly samples the objective-related utilization statistics of 44 * the resource in the pool with the given configuration. 45 */ 46 class SystemMonitor implements Monitor 47 { 48 /** 49 * The pool configuration with resources to be monitored. 50 */ 51 private Configuration conf; 52 53 /** 54 * The map of monitored resources.The map is keyed by 55 * resource, with the values being the monitorable instances. 56 */ 57 private Map monitored; 58 59 /** 60 * Default sample interval (milliseconds). 61 */ 62 public static final int DEF_SAMPLE_INT = 15000; 63 64 /** 65 * Sample interval (milliseconds, default 15000). 66 */ 67 private int interval; 68 69 /** 70 * Sample interval property name. 71 */ 72 static final String SAMPLE_INTERVAL_PROP_NAME = 73 "system.poold.monitor-interval"; 74 75 /** 76 * Kstat interface for raw data 77 */ 78 private KstatCtl kc; 79 80 /** 81 * Raw statistics which are sampled each interval. 82 */ 83 private final String stats[] = { "idle", "kernel", "wait", "user" }; 84 85 /** 86 * Timer regulating sampling frequency. 87 */ 88 private RecurringEventTimer timer; 89 90 /** 91 * The number of samples taken. 92 */ 93 private int sampleCount = 0; 94 95 /** 96 * Time the last sample was taken. 97 */ 98 private Date lastSampleTime = null; 99 100 /** 101 * Constructs a new monitor which is not associated with a 102 * specific configuration. 103 */ 104 public SystemMonitor() 105 { 106 this(null); 107 } 108 109 /** 110 * Constructs a new Monitor for monitoring the resources in the 111 * given configuration using the given statistic source. 112 * 113 * @param conf The configuration which is monitored. 114 */ 115 public SystemMonitor(Configuration conf) 116 { 117 this.conf = conf; 118 monitored = new HashMap(); 119 kc = new KstatCtl(); 120 } 121 122 /** 123 * Initialize the monitor with the configuration which is to 124 * be monitored. 125 * 126 * @param conf The configuration which is monitored. 127 * 128 * @throws PoolsException if manipulating the configuration 129 * fails. 130 * @throws StaleMonitorException if the resource monitors 131 * cannot be set. 132 */ 133 public void initialize(Configuration conf) throws PoolsException, 134 StaleMonitorException 135 { 136 Poold.CONF_LOG.log(Severity.DEBUG, "initializing"); 137 this.conf = conf; 138 try { 139 kc.chainUpdate(); 140 } catch (KstatChainUpdateException kcue) { 141 Poold.utility.die(Poold.CONF_LOG, kcue); 142 } 143 144 try { 145 interval = (int)conf.getLongProperty( 146 SAMPLE_INTERVAL_PROP_NAME); 147 } catch (PoolsException pe) { 148 interval = DEF_SAMPLE_INT; 149 } 150 timer = new SimpleRecurringEventTimer(interval); 151 152 setResourceMonitors("pset"); 153 } 154 155 /** 156 * Add all resources of the supplied type in the monitored 157 * configuration to the set of monitored resources. Remove 158 * redundant monitors for resources which no longer exist. 159 * Don't monitor resource sets which are empty. 160 * 161 * @param type The type of the resources to be added 162 */ 163 private void setResourceMonitors(String type) throws PoolsException, 164 StaleMonitorException 165 { 166 Value val = new Value("type", type); 167 168 List valueList = new LinkedList(); 169 valueList.add(val); 170 Iterator resIt = conf.getResources(valueList).iterator(); 171 val.close(); 172 HashSet oldKeys = new HashSet(monitored.keySet()); 173 while (resIt.hasNext()) { 174 Resource res = (Resource)resIt.next(); 175 ResourceMonitor mon = null; 176 boolean activeComponents = false; 177 178 List compList = res.getComponents(null); 179 Iterator compIt = compList.iterator(); 180 while (compIt.hasNext()) { 181 Component comp = (Component) compIt.next(); 182 String status = comp.getStringProperty( 183 "cpu.status"); 184 if (status.compareTo("off-line") != 0 && 185 status.compareTo("powered-off") != 0) { 186 activeComponents = true; 187 break; 188 } 189 } 190 if (activeComponents == false) 191 continue; 192 193 if (monitored.containsKey(res)) { 194 mon = get(res); 195 for (int i = 0; i < stats.length; i++) 196 mon.resetData(stats[i]); 197 } else { 198 mon = new ResourceMonitor(res, 50); 199 for (int i = 0; i < stats.length; i++) { 200 StatisticList sl = new StatisticList( 201 stats[i], 2); 202 mon.put(stats[i], sl); 203 } 204 mon.put("utilization", new StatisticList( 205 "utilization", mon.getMaxSampleSize(), 206 true)); 207 monitored.put(res, mon); 208 } 209 mon.initialize(); 210 oldKeys.remove(res); 211 } 212 monitored.keySet().removeAll(oldKeys); 213 } 214 215 /** 216 * Get the next sample. Before obtaining the sample, the call 217 * will block for the interval which was specified when this 218 * monitor was initialized. 219 * 220 * @throws StaleMonitorException if a statistic cannot be obtained. 221 * @throws PoolsException if there is an error manipulating the 222 * pools configuration. 223 * @throws InterruptedException if the thread is interrupted 224 * while waiting for the sampling time to arrive. The caller 225 * may wish to check other conditions before possibly 226 * reinitiating the sample. 227 */ 228 public void getNext() throws StaleMonitorException, PoolsException, 229 InterruptedException 230 { 231 Poold.MON_LOG.log(Severity.DEBUG, "waiting sampling interval"); 232 233 Date start = lastSampleTime; 234 if (start == null) 235 start = new Date(); 236 237 timer.waitUntilNextFiring(); 238 Date end = new Date(); 239 240 Poold.MON_LOG.log(Severity.DEBUG, "sampling"); 241 Iterator itMon = monitored.values().iterator(); 242 while (itMon.hasNext()) { 243 ResourceMonitor mon = (ResourceMonitor) itMon.next(); 244 List compList = mon.getComponents(); 245 Iterator itComp = compList.iterator(); 246 BigInteger statsv[] = new BigInteger[4]; 247 while (itComp.hasNext()) { 248 Component cpu = (Component) itComp.next(); 249 Kstat kstat = kc.lookup("cpu", 250 (int) cpu.getLongProperty("cpu.sys_id"), 251 "sys"); 252 if (kstat == null) 253 throw new StaleMonitorException(); 254 UnsignedInt64 value; 255 try { 256 kstat.read(); 257 for (int i = 0; i < stats.length; i++) { 258 value = (UnsignedInt64) kstat. 259 getValue("cpu_ticks_" + 260 stats[i]); 261 if (value == null) 262 throw new 263 StaleMonitorException(); 264 if (statsv[i] == null) 265 statsv[i] = value; 266 else 267 statsv[i] = statsv[i]. 268 add(value); 269 } 270 } catch (KstatException ke) { 271 StaleMonitorException sme = 272 new StaleMonitorException(); 273 sme.initCause(ke); 274 Poold.MON_LOG.log(Severity.DEBUG, 275 "configuration necessary due to " 276 + ke); 277 throw(sme); 278 } 279 } 280 if (compList.isEmpty() == false) { 281 for (int i = 0; i < stats.length; i++) { 282 StatisticList sl; 283 sl = (StatisticList) mon.get(stats[i]); 284 sl.add(new UnsignedInt64Statistic( 285 new UnsignedInt64(statsv[i]. 286 divide(new BigInteger( 287 Integer.toString( 288 compList.size())))), 289 start, end)); 290 } 291 } 292 mon.updateDerived(); 293 } 294 295 sampleCount++; 296 lastSampleTime = end; 297 } 298 299 /** 300 * Return the number of samples taken. This is the number of 301 * successful calls to <code>getNext()</code>. 302 */ 303 public int getSampleCount() 304 { 305 return (sampleCount); 306 } 307 308 /** 309 * Return the utilization of the supplied resource. The 310 * utilization is represented as a percentage between 0 311 * and 100. 312 * 313 * @param res A reference to a configuration resource. 314 */ 315 public double getUtilization(Resource res) throws StaleMonitorException 316 { 317 ResourceMonitor mon = get(res); 318 DoubleStatistic util = null; 319 try { 320 util = (DoubleStatistic)mon.getDerivedStatistic( 321 "utilization"); 322 } catch (NoSuchElementException nsee) { 323 util = new DoubleStatistic(new Double(0)); 324 } 325 Poold.MON_LOG.log(Severity.DEBUG, 326 res + " utilization " + util.toString()); 327 return (((Double)util.getValue()).doubleValue()); 328 } 329 330 /** 331 * Return true if the system contains enough sampled data for 332 * monitoring to be worthwhile. 333 */ 334 public boolean isValid() 335 { 336 Iterator itMon = monitored.values().iterator(); 337 while (itMon.hasNext()) { 338 ResourceMonitor mon = (ResourceMonitor) itMon.next(); 339 340 Iterator itSL = mon.values().iterator(); 341 while (itSL.hasNext()) { 342 StatisticList sl = (StatisticList) itSL.next(); 343 if (sl.getName().compareTo("utilization") == 344 0) { 345 if (sl.isValid() == false) 346 return (false); 347 } 348 } 349 } 350 return (true); 351 } 352 353 /** 354 * Return the ResourceMonitor for the supplied Resource 355 * 356 * @throws StaleMonitorException if the ResourceMonitor cannot be found. 357 */ 358 public ResourceMonitor get(Resource res) throws StaleMonitorException 359 { 360 ResourceMonitor rm = (ResourceMonitor)monitored.get(res); 361 362 if (rm == null) 363 throw new StaleMonitorException(); 364 return (rm); 365 } 366 } 367