org.nuiton.util.CallAnalyse Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of nuiton-utils Show documentation
Show all versions of nuiton-utils Show documentation
Library of usefull classes to be used in any project.
/*
* #%L
* Nuiton Utils
* %%
* Copyright (C) 2004 - 2010 CodeLutin
* %%
* This program 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 3 of the
* License, or (at your option) any later version.
*
* This program 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 General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
package org.nuiton.util;
import org.apache.commons.collections.primitives.ArrayLongList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/**
* Cette classe permet de faire des analyses sur les appels de methode
* En debut de methode on appelle la methode {@link #enter}, et en fin de methode
* la methode {@link #exit}.
*
* Ensuite on peut récuperer les statistiques par Thread ou de tous les threads
*
* On a comme statistique
*
* - le temps d'execution
*
- la memore utilisé
*
- le nombre d'appels
*
*
* @author Benjamin Poussin - [email protected]
* @see TimeLog
* Created: 25 aout 2005 14:09:22 CEST
*/
public class CallAnalyse { // CallAnalyse
/**
* Logger.
*/
private static final Log log = LogFactory.getLog(CallAnalyse.class);
static private List listThreadStatistics =
new ArrayList();
static private ThreadLocal stats =
new ThreadLocal() {
@Override
protected synchronized ThreadStatistics initialValue() {
ThreadStatistics result = new ThreadStatistics();
listThreadStatistics.add(result);
return result;
}
};
/**
* Permet d'activer les statistiques, pour le thread courant
*/
public static void activate() {
stats.get().setActivated(true);
}
/**
* Permet de desactiver les statistiques, pour le thread courant
*/
public static void desactivate() {
stats.get().setActivated(false);
}
/**
* Permet de savoir si les statistiques sont activées ou non, pour le
* thread courant
* @return FIXME
*/
public static boolean isActivate() {
return stats.get().getActivated();
}
/**
* @param name le nom de l'appel a monitorer
*/
public static void enter(String name) {
ThreadStatistics t = stats.get();
if (t.getActivated()) {
t.get(name).enter();
}
}
/**
* Indique la sortie de l'appel, name doit avoir ete utilisé lors d'un enter
*
* @param name le nom de l'appel a monitorer, doit etre identique a
* celui utilisé pour la methode enter
*/
public static void exit(String name) {
ThreadStatistics t = stats.get();
if (t.getActivated()) {
t.get(name).exit();
}
}
/**
* @return the statistics for the current thread
*/
public static ThreadStatistics getThreadStatistics() {
return stats.get();
}
/**
* @return the statistics for all threads
*/
public static List getAllThreadStatistics() {
return listThreadStatistics;
}
public static class ThreadStatistics extends TreeMap {
/** */
private static final long serialVersionUID = -36051448464013504L;
protected boolean activated = false;
public boolean getActivated() {
return activated;
}
public void setActivated(boolean activated) {
this.activated = activated;
}
public CallStatistics get(String name) {
CallStatistics result = super.get(name);
if (result == null) {
put(name, result = new CallStatistics(name));
}
return result;
}
public String toString() {
return values().toString();
}
}
/**
* This method will get all the statistics from all the threads and put it
* all together in a {@link Map} which key is the name of the watched
* element and the value is its instance of {@link CallStatisticsSummary}
*
* @return A map with all collected statistics
*/
public static Map getSummary() {
Map results = new HashMap();
for (ThreadStatistics stats : CallAnalyse.getAllThreadStatistics()) {
for (String name : stats.keySet()) {
CallStatisticsSummary stat = results.get(name);
if (stat == null) {
stat = new CallStatisticsSummary(name);
results.put(name, stat);
}
stat.addCallStats(stats.get(name));
}
}
return results;
}
/**
* CallStatistics is the class which handles values on excecution time and
* memory usage.
* Each CallStatistics object is for one particular name.
*
* @author bpoussin
*/
public static class CallStatistics implements Cloneable {
protected String name = null;
protected long calls = 0;
protected long minTime = Long.MAX_VALUE;
protected long maxTime = Long.MIN_VALUE;
protected long sumTime = 0;
protected long minMemory = Long.MAX_VALUE;
protected long maxMemory = Long.MIN_VALUE;
protected long sumMemory = 0;
/**
* pile contenant le temps de appel, util pour les appels recursifs
*/
protected ArrayLongList times = new ArrayLongList();
protected ArrayLongList memories = new ArrayLongList();
protected Runtime runtime = Runtime.getRuntime();
public CallStatistics(String name) {
this.name = name;
}
public void enter() {
times.add(System.nanoTime());
memories.add(getMemory());
}
public void exit() {
calls++;
if (times.size() == 0) {
log.info("To many exit call for " + name);
return;
}
long time = times.removeElementAt(times.size() - 1);
time = System.nanoTime() - time;
if (time < minTime || minTime == Long.MAX_VALUE) {
minTime = time;
}
if (time > maxTime) {
maxTime = time;
}
sumTime += time;
long memory = memories.removeElementAt(memories.size() - 1);
memory = getMemory() - memory;
if (memory < minMemory || minMemory == Long.MAX_VALUE) {
minMemory = memory;
}
if (memory > maxMemory) {
maxMemory = memory;
}
sumMemory += memory;
}
public String getName() {
return name;
}
public long getCalls() {
return calls;
}
public long getMinTime() {
return minTime;
}
public long getMaxTime() {
return maxTime;
}
public long getSumTime() {
return sumTime;
}
public long getAvgTime() {
if (calls == 0) {
return 0;
} else {
return sumTime / calls;
}
}
public long getMinMemory() {
return minMemory;
}
public long getMaxMemory() {
return maxMemory;
}
public long getSumMemory() {
return sumMemory;
}
public long getAvgMemory() {
if (calls == 0) {
return 0;
} else {
return sumMemory / calls;
}
}
protected long getMemory() {
// runtime.gc();
return runtime.totalMemory() - runtime.freeMemory();
}
@Override
public String toString() {
return getName() + " calls=" + getCalls()
+ " time=" + StringUtil.convertTime(getSumTime())
+ "(" + StringUtil.convertTime(getMinTime()) + "/" + StringUtil.convertTime(getAvgTime()) + "/" + StringUtil.convertTime(getMaxTime()) + ")"
+ " memory=" + StringUtil.convertMemory(getSumMemory())
+ "(" + StringUtil.convertMemory(getMinMemory()) + "/" + StringUtil.convertMemory(getAvgMemory()) + "/" + StringUtil.convertMemory(getMaxMemory()) + ")"
;
}
} //CallStatistics
/**
* This class is collecting data from different CallStatistics classes by
* using the method {@link #addCallStats(org.nuiton.util.CallAnalyse.CallStatistics)}.
*
* @author thimel
*/
public static class CallStatisticsSummary extends CallStatistics {
public CallStatisticsSummary(String name) {
super(name);
}
/**
* This methods read the given {@link CallStatistics} and add values to
* its own
*
* @param other an other CallStatistics object
*/
public void addCallStats(CallStatistics other) {
if (other == null || this.equals(other)) {
return;
}
calls += other.getCalls();
if (other.getMinTime() < minTime || minTime == Long.MAX_VALUE) {
minTime = other.getMinTime();
}
if (other.getMaxTime() > maxTime) {
maxTime = other.getMaxTime();
}
sumTime += other.getSumTime();
if (other.getMinMemory() < minMemory || minMemory == Long.MAX_VALUE) {
minMemory = other.getMinMemory();
}
if (other.getMaxMemory() > maxMemory) {
maxMemory = other.getMaxMemory();
}
sumMemory += other.getSumMemory();
}
} //CallStatisticsSummary
} // CallAnalyse