/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * ident "%Z%%M% %I% %E% SMI" */ package com.sun.solaris.domain.pools; import java.math.BigInteger; import java.text.DecimalFormat; import java.util.*; import java.util.logging.*; import com.sun.solaris.service.kstat.*; import com.sun.solaris.service.logging.Severity; import com.sun.solaris.domain.pools.*; import com.sun.solaris.service.pools.*; import com.sun.solaris.service.timer.*; /** * Regularly samples the objective-related utilization statistics of * the resource in the pool with the given configuration. */ class SystemMonitor implements Monitor { /** * The pool configuration with resources to be monitored. */ private Configuration conf; /** * The map of monitored resources.The map is keyed by * resource, with the values being the monitorable instances. */ private Map monitored; /** * Default sample interval (milliseconds). */ public static final int DEF_SAMPLE_INT = 15000; /** * Sample interval (milliseconds, default 15000). */ private int interval; /** * Sample interval property name. */ static final String SAMPLE_INTERVAL_PROP_NAME = "system.poold.monitor-interval"; /** * Kstat interface for raw data */ private KstatCtl kc; /** * Raw statistics which are sampled each interval. */ private final String stats[] = { "idle", "kernel", "wait", "user" }; /** * Timer regulating sampling frequency. */ private RecurringEventTimer timer; /** * The number of samples taken. */ private int sampleCount = 0; /** * Time the last sample was taken. */ private Date lastSampleTime = null; /** * Constructs a new monitor which is not associated with a * specific configuration. */ public SystemMonitor() { this(null); } /** * Constructs a new Monitor for monitoring the resources in the * given configuration using the given statistic source. * * @param conf The configuration which is monitored. */ public SystemMonitor(Configuration conf) { this.conf = conf; monitored = new HashMap(); kc = new KstatCtl(); } /** * Initialize the monitor with the configuration which is to * be monitored. * * @param conf The configuration which is monitored. * * @throws PoolsException if manipulating the configuration * fails. * @throws StaleMonitorException if the resource monitors * cannot be set. */ public void initialize(Configuration conf) throws PoolsException, StaleMonitorException { Poold.CONF_LOG.log(Severity.DEBUG, "initializing"); this.conf = conf; try { kc.chainUpdate(); } catch (KstatChainUpdateException kcue) { Poold.utility.die(Poold.CONF_LOG, kcue); } try { interval = (int)conf.getLongProperty( SAMPLE_INTERVAL_PROP_NAME); } catch (PoolsException pe) { interval = DEF_SAMPLE_INT; } timer = new SimpleRecurringEventTimer(interval); setResourceMonitors("pset"); } /** * Add all resources of the supplied type in the monitored * configuration to the set of monitored resources. Remove * redundant monitors for resources which no longer exist. * Don't monitor resource sets which are empty. * * @param type The type of the resources to be added */ private void setResourceMonitors(String type) throws PoolsException, StaleMonitorException { Value val = new Value("type", type); List valueList = new LinkedList(); valueList.add(val); Iterator resIt = conf.getResources(valueList).iterator(); val.close(); HashSet oldKeys = new HashSet(monitored.keySet()); while (resIt.hasNext()) { Resource res = (Resource)resIt.next(); ResourceMonitor mon = null; boolean activeComponents = false; List compList = res.getComponents(null); Iterator compIt = compList.iterator(); while (compIt.hasNext()) { Component comp = (Component) compIt.next(); String status = comp.getStringProperty( "cpu.status"); if (status.compareTo("off-line") != 0 && status.compareTo("powered-off") != 0) { activeComponents = true; break; } } if (activeComponents == false) continue; if (monitored.containsKey(res)) { mon = get(res); for (int i = 0; i < stats.length; i++) mon.resetData(stats[i]); } else { mon = new ResourceMonitor(res, 50); for (int i = 0; i < stats.length; i++) { StatisticList sl = new StatisticList( stats[i], 2); mon.put(stats[i], sl); } mon.put("utilization", new StatisticList( "utilization", mon.getMaxSampleSize(), true)); monitored.put(res, mon); } mon.initialize(); oldKeys.remove(res); } monitored.keySet().removeAll(oldKeys); } /** * Get the next sample. Before obtaining the sample, the call * will block for the interval which was specified when this * monitor was initialized. * * @throws StaleMonitorException if a statistic cannot be obtained. * @throws PoolsException if there is an error manipulating the * pools configuration. * @throws InterruptedException if the thread is interrupted * while waiting for the sampling time to arrive. The caller * may wish to check other conditions before possibly * reinitiating the sample. */ public void getNext() throws StaleMonitorException, PoolsException, InterruptedException { Poold.MON_LOG.log(Severity.DEBUG, "waiting sampling interval"); Date start = lastSampleTime; if (start == null) start = new Date(); timer.waitUntilNextFiring(); Date end = new Date(); Poold.MON_LOG.log(Severity.DEBUG, "sampling"); Iterator itMon = monitored.values().iterator(); while (itMon.hasNext()) { ResourceMonitor mon = (ResourceMonitor) itMon.next(); List compList = mon.getComponents(); Iterator itComp = compList.iterator(); BigInteger statsv[] = new BigInteger[4]; while (itComp.hasNext()) { Component cpu = (Component) itComp.next(); Kstat kstat = kc.lookup("cpu", (int) cpu.getLongProperty("cpu.sys_id"), "sys"); if (kstat == null) throw new StaleMonitorException(); UnsignedInt64 value; try { kstat.read(); for (int i = 0; i < stats.length; i++) { value = (UnsignedInt64) kstat. getValue("cpu_ticks_" + stats[i]); if (value == null) throw new StaleMonitorException(); if (statsv[i] == null) statsv[i] = value; else statsv[i] = statsv[i]. add(value); } } catch (KstatException ke) { StaleMonitorException sme = new StaleMonitorException(); sme.initCause(ke); Poold.MON_LOG.log(Severity.DEBUG, "configuration necessary due to " + ke); throw(sme); } } if (compList.isEmpty() == false) { for (int i = 0; i < stats.length; i++) { StatisticList sl; sl = (StatisticList) mon.get(stats[i]); sl.add(new UnsignedInt64Statistic( new UnsignedInt64(statsv[i]. divide(new BigInteger( Integer.toString( compList.size())))), start, end)); } } mon.updateDerived(); } sampleCount++; lastSampleTime = end; } /** * Return the number of samples taken. This is the number of * successful calls to getNext(). */ public int getSampleCount() { return (sampleCount); } /** * Return the utilization of the supplied resource. The * utilization is represented as a percentage between 0 * and 100. * * @param res A reference to a configuration resource. */ public double getUtilization(Resource res) throws StaleMonitorException { ResourceMonitor mon = get(res); DoubleStatistic util = null; try { util = (DoubleStatistic)mon.getDerivedStatistic( "utilization"); } catch (NoSuchElementException nsee) { util = new DoubleStatistic(new Double(0)); } Poold.MON_LOG.log(Severity.DEBUG, res + " utilization " + util.toString()); return (((Double)util.getValue()).doubleValue()); } /** * Return true if the system contains enough sampled data for * monitoring to be worthwhile. */ public boolean isValid() { Iterator itMon = monitored.values().iterator(); while (itMon.hasNext()) { ResourceMonitor mon = (ResourceMonitor) itMon.next(); Iterator itSL = mon.values().iterator(); while (itSL.hasNext()) { StatisticList sl = (StatisticList) itSL.next(); if (sl.getName().compareTo("utilization") == 0) { if (sl.isValid() == false) return (false); } } } return (true); } /** * Return the ResourceMonitor for the supplied Resource * * @throws StaleMonitorException if the ResourceMonitor cannot be found. */ public ResourceMonitor get(Resource res) throws StaleMonitorException { ResourceMonitor rm = (ResourceMonitor)monitored.get(res); if (rm == null) throw new StaleMonitorException(); return (rm); } }