/** * Helios, OpenSource Monitoring * Brought to you by the Helios Development Group * * Copyright 2007, Helios Development Group and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. * */ package org.helios.apmrouter.util.perf; import java.lang.management.ManagementFactory; import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import org.helios.apmrouter.jmx.threadinfo.ExtendedThreadManager; import org.helios.apmrouter.util.Binaries; /** * <p>Title: ResourceClock</p> * <p>Description: Resource measurement functional enum for elapsed usages</p> * <p>Company: Helios Development Group LLC</p> * @author Whitehead (nwhitehead AT heliosdev DOT org) * <p><code>org.helios.apmrouter.util.perf.ResourceClock</code></p> */ public enum ResourceClock { /** The elapsed time in ns. */ TIME(Binaries.getBinaryIterator(10).next()), /** The elapsed system CPU time in ns */ SYS_CPU(Binaries.getBinaryIterator(10).next()), /** The elapsed user CPU time in ns */ USER_CPU(Binaries.getBinaryIterator(10).next()), /** The thread blocked time in ms */ BLOCKED_TIME(Binaries.getBinaryIterator(10).next()), /** The number of times the thread was blocked */ BLOCKED_COUNT(Binaries.getBinaryIterator(10).next()), /** The thread waited time in ms */ WAITED_TIME(Binaries.getBinaryIterator(10).next()), /** The number of times the thread waited */ WAITED_COUNT(Binaries.getBinaryIterator(10).next()); /** Decode map to decode the int code to the ResourceClock enum */ public static final Map<Integer, ResourceClock> CODE2ENUM; /** Decode map to decode the ordinal to the ResourceClock enum */ public static final Map<Integer, ResourceClock> ORD2ENUM; /** Decode map to decode the int code to the ResourceClock enum */ public static final Map<String, ResourceClock> CODESTR2ENUM; /** Decode map to decode the ordinal to the ResourceClock enum */ public static final Map<String, ResourceClock> ORDSTR2ENUM; /** Decode map to decode the ordinal to the ResourceClock enum */ public static final Map<String, ResourceClock> ALLSTR2ENUM; /** Decode map to decode the ordinal to the ResourceClock enum */ public static final Map<Integer, ResourceClock> ALL2ENUM; /** Indicates if the extended thread mx bean is installed */ private static final AtomicBoolean extendedThreadMXBean = new AtomicBoolean(false); /** Indicates if thread cpu time is enabled */ private static final AtomicBoolean threadCpuTimeEnabled = new AtomicBoolean(false); /** Indicates if thread contention monitoring is enabled */ private static final AtomicBoolean threadContentionEnabled = new AtomicBoolean(false); /** Indicates if thread cpu time is supported */ public static final boolean cpuTimeSupported = ManagementFactory.getThreadMXBean().isThreadCpuTimeSupported(); /** Indicates if thread contention monitoring is supported */ public static final boolean threadContentionSupported = ManagementFactory.getThreadMXBean().isThreadContentionMonitoringSupported(); static { Binaries.reset(); ResourceClock[] values = ResourceClock.values(); Map<Integer, ResourceClock> tmp = new HashMap<Integer, ResourceClock>(values.length); Map<Integer, ResourceClock> otmp = new HashMap<Integer, ResourceClock>(values.length); Map<String, ResourceClock> tmpStr = new HashMap<String, ResourceClock>(values.length); Map<String, ResourceClock> oTmpStr = new HashMap<String, ResourceClock>(values.length); Map<Integer, ResourceClock> all = new HashMap<Integer, ResourceClock>(values.length*2); Map<String, ResourceClock> allStr = new HashMap<String, ResourceClock>(values.length*2); for(ResourceClock rc: values) { tmp.put(rc.code, rc); otmp.put(rc.ordinal(), rc); oTmpStr.put(Integer.toString(rc.ordinal()), rc); tmpStr.put(Integer.toString(rc.code), rc); allStr.put(Integer.toString(rc.code), rc); allStr.put(Integer.toString(rc.ordinal()), rc); all.put(rc.code, rc); all.put(rc.ordinal(), rc); } CODE2ENUM = Collections.unmodifiableMap(tmp); ORD2ENUM = Collections.unmodifiableMap(otmp); ORDSTR2ENUM = Collections.unmodifiableMap(oTmpStr); CODESTR2ENUM = Collections.unmodifiableMap(tmpStr); ALLSTR2ENUM = Collections.unmodifiableMap(allStr); ALL2ENUM = Collections.unmodifiableMap(all); try { if(!ExtendedThreadManager.isInstalled()) { ExtendedThreadManager.install(); } extendedThreadMXBean.set(ExtendedThreadManager.isInstalled()); } catch (Exception ex) { extendedThreadMXBean.set(false); } } private ResourceClock(int code) { this.code = code; } /** The int decode for the resource */ public final int code; /** * Decodes the passed string to a ResourceClock, trimming and uppercasing the passed value * @param value The value to decode * @return the decoded ResourceClock */ public static ResourceClock forValue(Object value) { if(value==null || value.toString().trim().isEmpty()) throw new RuntimeException("The passed value was null or empty"); Integer vi = toInteger(value); if(vi!=null) { ResourceClock rc = ALL2ENUM.get(vi); if(rc!=null) return rc; throw new RuntimeException("The passed numeric value [" + vi + "] was not a valid Resource"); } String v = value.toString().trim().toUpperCase(); try { return ResourceClock.valueOf(v); } catch (Exception ex) { throw new RuntimeException("The passed value [" + value + "] was not a valid Resource", ex); } } /** * Returns a mask enabled for all the passed resources * @param resources The resources to enable * @return an int but mask with the passed resources enabled, or zero if no resources are passed. */ public static int enableFor(ResourceClock...resources) { int _code = 0; if(resources==null || resources.length==0) return _code; for(ResourceClock rc: resources) { _code = rc.enable(_code); } return _code; } /** * Returns a mask enabled for all the passed resources * @param resources The resources to enable * @return an int but mask with the passed resources enabled, or zero if no resources are passed. */ public static int enableFor(int...resources) { int _code = 0; if(resources==null || resources.length==0) return _code; for(int resource: resources) { ResourceClock rc = ResourceClock.forValue(resource); _code = rc.enable(_code); } return _code; } /** * Returns a mask enabled for all the passed resources * @param resources The resources to enable * @return an int but mask with the passed resources enabled, or zero if no resources are passed. */ public static int enableFor(String...resources) { int _code = 0; if(resources==null || resources.length==0) return _code; for(String resource: resources) { ResourceClock rc = ResourceClock.forValue(resource); _code = rc.enable(_code); } return _code; } /** * Returns an array of resource enums for each resource enabled in the passed mask * @param mask The mask to return the resources for * @return an array of resource enums */ public static ResourceClock[] getEnabledResources(int mask) { Set<ResourceClock> matched = EnumSet.noneOf(ResourceClock.class); for(ResourceClock rc: ResourceClock.values()) { if(rc.isEnabled(mask)) { matched.add(rc); } } return matched.toArray(new ResourceClock[matched.size()]); } /** * Determines if the passed mask has the passed bit turned on. * @param value The bit to test for. * @param mask The bit mask to test * @return true if the passed bitMask value is enabled in the passed bitMask */ public static boolean isEnabledFor(final int value, final int mask) { return (value & mask)!=0; } /** * Enables the current resource in the passed int * @param mask The value int to enable this resource in * @return The passed value enabled for this resource */ public int enable(int mask) { mask = mask | code; return mask; } /** * Disables the current resource in the passed int * @param mask The value int to disable this resource in * @return The passed value disabled for this resource */ public int disable(int mask) { mask = mask ^ code; return mask; } /** * Determines if the passed mask is enabled for the current resource * @param mask The mask to test * @return true if the passed mask is enabled, false otherwise */ public boolean isEnabled(int mask) { return (code & mask)!=0; } public static void main(String[] args) { for(ResourceClock rc: ResourceClock.values()) { log(rc.name() + "\t" + Integer.toBinaryString(rc.code)); } int v = 0; log("=== Enabling Odds ==="); for(ResourceClock rc: ResourceClock.values()) { if(rc.ordinal()%2==0) continue; v = rc.enable(v); log("Enabled for [" + rc.name() + "]:[" + Integer.toBinaryString(v) + "]"); } log("=== Disabling Odds === [" + Arrays.toString(ResourceClock.getEnabledResources(v)) + "]"); for(ResourceClock rc: ResourceClock.values()) { if(rc.ordinal()%2==0) continue; v = rc.disable(v); log("Disabled for [" + rc.name() + "]:[" + Integer.toBinaryString(v) + "]"); } v = 0; log("=== Enabling Evens ==="); for(ResourceClock rc: ResourceClock.values()) { if(rc.ordinal()%2!=0) continue; v = rc.enable(v); log("Enabled for [" + rc.name() + "]:[" + Integer.toBinaryString(v) + "]"); } log("=== Disabling Evens ==="); for(ResourceClock rc: ResourceClock.values()) { if(rc.ordinal()%2!=0) continue; v = rc.disable(v); log("Disabled for [" + rc.name() + "]:[" + Integer.toBinaryString(v) + "]"); } } public static void log(Object msg) { System.out.println(msg); } /** * Converts the passed object to an integer, returning it or null if the conversion cannot be made * @param obj The object to convert * @return the converted integer or null if it could not be converted */ public static Integer toInteger(Object obj) { if(obj==null) return null; try { if(obj instanceof Number) { return ((Number)obj).intValue(); } return Integer.parseInt(obj.toString().trim()); } catch (Exception ex) { return null; } } }