![JAR search and dependency download from the Maven repository](/logo.png)
patterntesting.runtime.monitor.ProfileStatistic Maven / Gradle / Ivy
Go to download
PatternTesting Runtime (patterntesting-rt) is the runtime component for
the PatternTesting framework. It provides the annotations and base classes
for the PatternTesting testing framework (e.g. patterntesting-check,
patterntesting-concurrent or patterntesting-exception) but can be also
used standalone for classpath monitoring or profiling.
It uses AOP and AspectJ to perform this feat.
The newest version!
/*
* $Id: ProfileStatistic.java,v 1.31 2009/12/28 10:07:23 oboehm Exp $
*
* Copyright (c) 2008 by Oliver Boehm
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express orimplied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* (c)reated 22.12.2008 by oliver ([email protected])
*/
package patterntesting.runtime.monitor;
import java.io.*;
import java.lang.management.ManagementFactory;
import java.lang.reflect.*;
import java.net.*;
import java.util.*;
import java.util.jar.*;
import javax.management.*;
import javax.management.openmbean.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.impl.LogFactoryImpl;
import org.aspectj.lang.Signature;
import patterntesting.annotation.check.runtime.MayReturnNull;
import patterntesting.runtime.annotation.DontProfileMe;
import patterntesting.runtime.util.*;
/**
* This is constructed as a thin layer around com.jamonapi.MonitorFactory for
* the needs of patterntesting. The reason for this layer is that sometimes you
* don't want to minimize the use of other libraries. So this implementation
* provides also an implementation if the JaMon library is missing.
*
* @see com.jamonapi.MonitorFactory
* @author oliver
* @since 22.12.2008
* @version $Revision: 1.31 $
*/
public class ProfileStatistic extends Thread implements ProfileStatisticMBean {
/** The Constant mbeanName. */
public static final ObjectName mbeanName;
private static final ProfileStatistic instance;
private static final Log log = LogFactoryImpl.getLog(ProfileStatistic.class);
private static final SimpleProfileMonitor rootMonitor;
private static final boolean jamonAvailable;
///// initialization //////////////////////////////////////////////////
/**
* rootMonitor *must* be initialized before isJamon24Available() is called.
* Otherwise you'll get a NullPointerException because in
* Jamon24Available() rootMonitor will be accessed (so rootMonitor must
* be initialized before!)
*/
static {
mbeanName = createObjectName();
rootMonitor = new SimpleProfileMonitor();
jamonAvailable = isJamonAvailable();
instance = new ProfileStatistic();
}
/**
* It is only tested for Jamon 2.4 and 2.7 so we look for it
*
* @return true if Jamon 2.4 or 2.7 was found
*/
protected static boolean isJamonAvailable() {
try {
String resource = "/com/jamonapi/MonitorFactory.class";
URL classURL = ProfileStatistic.class.getResource(resource);
URI jarURI = ClasspathHelper.getParent(classURL.toURI(), resource);
JarFile jarfile = ClasspathMonitor.whichResourceJar(jarURI);
Manifest manifest = jarfile.getManifest();
Attributes attributes = manifest.getMainAttributes();
String version = attributes.getValue("version");
if (version.equalsIgnoreCase("JAMon 2.7")) {
log.info("JAMon 2.7 available for profiling");
return true;
} else if (version.equalsIgnoreCase("JAMon 2.4")) {
log.info("JAMon 2.4 available for profiling");
return true;
} else {
log.info(version
+ " not supported (only JAMon 2.4 and 2.7), using simple profiling");
return false;
}
} catch (Exception e) {
// if JAMon is not in classpath we come with a NPE to here
log.info("JAMon not available, using simple profiling");
return false;
}
}
private static ObjectName createObjectName() {
String name = "patterntesting.runtime.monitor:type=ProfileStatistic";
ObjectName objectName = null;
try {
objectName = new ObjectName(name);
} catch (MalformedObjectNameException e) {
log.info("can't create object name + '" + name + "'");
}
return objectName;
}
/**
* Instantiates a new profile statistic.
*/
protected ProfileStatistic() {
this.registerAsMBean();
}
private void registerAsMBean() {
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
try {
server.registerMBean(this, mbeanName);
log.info(mbeanName + " successful registered as MBean");
} catch (Exception e) {
log.info(e);
}
}
/**
* Gets the single instance of ProfileStatistic.
*
* @return single instance of ProfileStatistic
*/
public static ProfileStatistic getInstance() {
return instance;
}
/**
* You can register the instance as shutdown hook. If the VM is
* terminated the profile values are logged and dumped to a CSV file in the
* tmp directory.
*
* @see #logStatistic()
* @see #dumpStatistic()
*/
public static void addAsShutdownHook() {
Runtime.getRuntime().addShutdownHook(instance);
if (log.isDebugEnabled()) {
log.debug(instance + " registered as shutdown hook");
}
}
/**
* We can't reset all ProfileMonitors - we must keep the empty
* monitors with 0 hits to see which methods or constructors are
* never called.
*/
public void reset() {
List labels = new ArrayList();
ProfileMonitor[] monitors = getMonitors();
for (int i = 0; i < monitors.length; i++) {
if (monitors[i].getHits() == 0) {
labels.add(monitors[i].getLabel());
}
}
if (jamonAvailable) {
JamonMonitorFactory.reset();
JamonMonitorFactory.addMonitors(labels);
} else {
rootMonitor.reset();
rootMonitor.addChildren(labels);
}
}
/**
* For each constructor and for each method of the given class a
* ProfileMonitor is initialized. This is done to be able to find
* constructors and methods which are are never used (i.e. their
* hit count is zero).
*
* @param cl the given class
*/
public static void init(Class> cl) {
if (log.isTraceEnabled()) {
log.trace("initializing monitors for " + cl + "...");
}
init(cl, cl.getMethods());
init(cl.getConstructors());
}
/**
* Only methods of the given class but not the methods of the superclass
* are initialized for profiling.
*
* @param cl
* @param methods
*/
private static void init(Class> cl, Method[] methods) {
for (int i = 0; i < methods.length; i++) {
Class> declaring = methods[i].getDeclaringClass();
if (cl.equals(declaring)) {
init(methods[i]);
} else if (log.isTraceEnabled()) {
log.trace(methods[i] + " not defined in " + cl
+ " -> no monitor initialized");
}
}
}
private static void init(Method method) {
if (method.getAnnotation(DontProfileMe.class) != null) {
if (log.isTraceEnabled()) {
log.trace("@DontProfileMe " + method + " is ignored");
}
return;
}
Signature sig = SignatureHelper.getAsSignature(method);
ProfileMonitor mon = getMonitor(sig);
if (log.isTraceEnabled()) {
log.trace(mon + " initialized");
}
}
private static void init(Constructor>[] ctors) {
for (int i = 0; i < ctors.length; i++) {
init(ctors[i]);
}
}
private static void init(Constructor> ctor) {
if (ctor.getAnnotation(DontProfileMe.class) != null) {
if (log.isTraceEnabled()) {
log.trace("@DontProfileMe " + ctor + " is ignored");
}
return;
}
Signature sig = SignatureHelper.getAsSignature(ctor);
ProfileMonitor mon = getMonitor(sig);
if (log.isTraceEnabled()) {
log.trace(mon + " initialized");
}
}
///// business logic (measurement, statistics and more) ///////////////
/**
* This method is called when the PerformanceMonitor is registered as
* shutdown hook.
*
* @see java.lang.Thread#run()
*/
@Override
public void run() {
dumpStatistic();
}
/**
* Start.
*
* @param sig the sig
*
* @return the profile monitor
*/
public static ProfileMonitor start(Signature sig) {
ProfileMonitor mon = null;
if (jamonAvailable) {
mon = JamonMonitorFactory.getMonitor(sig);
} else {
SimpleProfileMonitor parent = getSimpleProfileMonitor(sig);
mon = new SimpleProfileMonitor(sig, parent);
}
mon.start();
return mon;
}
private static ProfileMonitor getMonitor(Signature sig) {
if (jamonAvailable) {
return JamonMonitorFactory.getMonitor(sig);
} else {
return getSimpleProfileMonitor(sig);
}
}
private static SimpleProfileMonitor getSimpleProfileMonitor(Signature sig) {
SimpleProfileMonitor monitor = rootMonitor.getMonitor(sig);
if (monitor == null) {
monitor = new SimpleProfileMonitor(sig, rootMonitor);
}
return monitor;
}
private static ProfileMonitor[] getMonitors() {
if (jamonAvailable) {
return JamonMonitorFactory.getMonitors();
} else {
return rootMonitor.getMonitors();
}
}
/**
* Gets the sorted monitors.
*
* @return monitors sorted after total time (descending order)
*/
protected static ProfileMonitor[] getSortedMonitors() {
ProfileMonitor[] monitors = getMonitors();
Arrays.sort(monitors);
return monitors;
}
private ProfileMonitor getMaxHitsMonitor() {
ProfileMonitor[] monitors = getMonitors();
ProfileMonitor max = monitors[0];
for (int i = 1; i < monitors.length; i++) {
if (monitors[i].getHits() > max.getHits()) {
max = monitors[i];
}
}
return max;
}
/**
* @see patterntesting.runtime.monitor.ProfileStatisticMBean#getMaxHits()
*/
public int getMaxHits() {
return getMaxHitsMonitor().getHits();
}
/**
* @see patterntesting.runtime.monitor.ProfileStatisticMBean#getMaxHitsLabel()
*/
public String getMaxHitsLabel() {
return getMaxHitsMonitor().getLabel();
}
/**
* @see patterntesting.runtime.monitor.ProfileStatisticMBean#getMaxHitsStatistic()
*/
public String getMaxHitsStatistic() {
return getMaxHitsMonitor().toShortString();
}
private ProfileMonitor getMaxTotalMonitor() {
ProfileMonitor[] monitors = getMonitors();
ProfileMonitor max = monitors[0];
for (int i = 1; i < monitors.length; i++) {
if (monitors[i].getTotal() > max.getTotal()) {
max = monitors[i];
}
}
return max;
}
/**
* @see patterntesting.runtime.monitor.ProfileStatisticMBean#getMaxTotal()
*/
public double getMaxTotal() {
return getMaxTotalMonitor().getTotal();
}
/**
* @see patterntesting.runtime.monitor.ProfileStatisticMBean#getMaxTotalLabel()
*/
public String getMaxTotalLabel() {
return getMaxTotalMonitor().getLabel();
}
/**
* @see patterntesting.runtime.monitor.ProfileStatisticMBean#getMaxTotalStatistic()
*/
public String getMaxTotalStatistic() {
return getMaxTotalMonitor().toShortString();
}
private ProfileMonitor getMaxAvgMonitor() {
ProfileMonitor[] monitors = getMonitors();
ProfileMonitor max = monitors[0];
for (int i = 1; i < monitors.length; i++) {
if (monitors[i].getAvg() > max.getAvg()) {
max = monitors[i];
}
}
return max;
}
/**
* @see patterntesting.runtime.monitor.ProfileStatisticMBean#getMaxAvg()
*/
public double getMaxAvg() {
return getMaxAvgMonitor().getAvg();
}
/**
* @see patterntesting.runtime.monitor.ProfileStatisticMBean#getMaxAvgLabel()
*/
public String getMaxAvgLabel() {
return getMaxAvgMonitor().getLabel();
}
/**
* @see patterntesting.runtime.monitor.ProfileStatisticMBean#getMaxAvgStatistic()
*/
public String getMaxAvgStatistic() {
return getMaxAvgMonitor().toShortString();
}
private ProfileMonitor getMaxMaxMonitor() {
ProfileMonitor[] monitors = getMonitors();
ProfileMonitor max = monitors[0];
for (int i = 1; i < monitors.length; i++) {
if (monitors[i].getMax() > max.getMax()) {
max = monitors[i];
}
}
return max;
}
/**
* @see patterntesting.runtime.monitor.ProfileStatisticMBean#getMaxMax()
*/
public double getMaxMax() {
return getMaxMaxMonitor().getMax();
}
/**
* @see patterntesting.runtime.monitor.ProfileStatisticMBean#getMaxMaxLabel()
*/
public String getMaxMaxLabel() {
return getMaxMaxMonitor().getLabel();
}
/**
* @see patterntesting.runtime.monitor.ProfileStatisticMBean#getMaxMaxStatistic()
*/
public String getMaxMaxStatistic() {
return getMaxMaxMonitor().toShortString();
}
/**
* @see patterntesting.runtime.monitor.ProfileStatisticMBean#getStatistics()
*/
@SuppressWarnings("unchecked")
public TabularData getStatistics() {
try {
String[] itemNames = { "Label", "Units", "Hits", "Avg", "Total",
"Min", "Max", "Active", "AvgActive", "MaxActive",
"FirstAccess", "LastAccess" };
String[] itemDescriptions = { "method name", "time unit (e.g. ms)",
"number of hits", "average time", "total time",
"minimal time", "maximal time", "active threads",
"average number of threads", "maximal number of threads",
"first access", "last access" };
OpenType[] itemTypes = { SimpleType.STRING, SimpleType.STRING,
SimpleType.INTEGER, SimpleType.DOUBLE, SimpleType.DOUBLE,
SimpleType.DOUBLE, SimpleType.DOUBLE, SimpleType.DOUBLE,
SimpleType.DOUBLE, SimpleType.DOUBLE, SimpleType.DATE,
SimpleType.DATE };
CompositeType rowType = new CompositeType("propertyType",
"property entry", itemNames, itemDescriptions, itemTypes);
TabularType tabularType = new TabularType("propertyTabularType",
"properties tabular", rowType, itemNames);
TabularDataSupport data = new TabularDataSupport(tabularType);
ProfileMonitor[] monitors = getSortedMonitors();
if (monitors == null) {
log.warn("can't find monitors");
return null;
}
for (int i = 0; i < monitors.length; i++) {
Map map = new HashMap();
map.put("Label", monitors[i].getLabel());
map.put("Units", monitors[i].getUnits());
map.put("Hits", monitors[i].getHits());
map.put("Avg", monitors[i].getAvg());
map.put("Total", monitors[i].getTotal());
map.put("Min", monitors[i].getMin());
map.put("Max", monitors[i].getMax());
map.put("Active", monitors[i].getActive());
map.put("AvgActive", monitors[i].getAvgActive());
map.put("MaxActive", monitors[i].getMaxActive());
map.put("FirstAccess", monitors[i].getFirstAccess());
map.put("LastAccess", monitors[i].getLastAccess());
CompositeDataSupport compData = new CompositeDataSupport(
rowType, map);
data.put(compData);
}
return data;
} catch (OpenDataException e) {
log.error("can't create TabularData for log settings", e);
return null;
}
}
/**
* @see patterntesting.runtime.monitor.ProfileStatisticMBean#logStatistic()
*/
public void logStatistic() {
log.info("----- Profile Statistic -----");
ProfileMonitor[] monitors = getSortedMonitors();
for (ProfileMonitor profMon : monitors) {
log.info(profMon);
}
}
/**
* @see patterntesting.runtime.monitor.ProfileStatisticMBean#dumpStatistic()
*/
public void dumpStatistic() {
try {
File dumpFile = File.createTempFile("profile", ".csv");
BufferedWriter writer = new BufferedWriter(new FileWriter(dumpFile));
ProfileMonitor[] monitors = getSortedMonitors();
writer.write(monitors[0].toCsvHeadline());
writer.newLine();
for (ProfileMonitor profMon : monitors) {
writer.write(profMon.toCsvString());
writer.newLine();
}
writer.close();
log.info("profiling data dumped to " + dumpFile);
} catch (IOException ioe) {
log.info("can't dump statistic (" + ioe + ")");
}
}
/**
* Do you want to look for the monitor of a given method? Use this
* method here.
*
* @param clazz the clazz
* @param method the method name, including parameter
* e.g. "getProfileMonitor(Class,String)"
*
* @return monitor of the given class or null
*/
@MayReturnNull
public ProfileMonitor getProfileMonitor(Class> clazz, String method) {
return this.getProfileMonitor(clazz.getName() + "." + method);
}
/**
* Do you want to look for the monitor of a given method? Use this
* method here.
*
* @param signature e.g. "hello.World(String[])"
*
* @return monitor for the given signature or null
*/
@MayReturnNull
public ProfileMonitor getProfileMonitor(String signature) {
for (ProfileMonitor profMon : getMonitors()) {
if (signature.equals(profMon.getLabel())) {
return profMon;
}
}
log.trace("no ProfileMonitor for " + signature + " found");
return null;
}
/**
* @see java.lang.Thread#toString()
*/
@Override
public String toString() {
return mbeanName.toString();
}
}
/**
* $Log: ProfileStatistic.java,v $
* Revision 1.31 2009/12/28 10:07:23 oboehm
* missing Javadocs completed
*
* Revision 1.30 2009/12/19 22:34:09 oboehm
* trailing spaces removed
*
* Revision 1.29 2009/09/25 14:49:43 oboehm
* javadocs completed with the help of JAutodoc
*
* Revision 1.28 2009/09/18 13:54:52 oboehm
* javadoc warnings fixed
*
* Revision 1.27 2009/09/03 14:10:06 oboehm
* support for JAMon 2.7 added
*
* $Source: /cvsroot/patterntesting/PatternTesting08/patterntesting-rt/src/main/java/patterntesting/runtime/monitor/ProfileStatistic.java,v $
*/
© 2015 - 2025 Weber Informatics LLC | Privacy Policy