Index: lutinutil/src/java/org/codelutin/util/ArrayUtil.java diff -u lutinutil/src/java/org/codelutin/util/ArrayUtil.java:1.3 lutinutil/src/java/org/codelutin/util/ArrayUtil.java:1.4 --- lutinutil/src/java/org/codelutin/util/ArrayUtil.java:1.3 Mon Nov 8 13:39:19 2004 +++ lutinutil/src/java/org/codelutin/util/ArrayUtil.java Thu Aug 25 21:16:51 2005 @@ -23,14 +23,15 @@ * Created: 31 oct. 2004 * * @author Benjamin Poussin - * @version $Revision: 1.3 $ + * @version $Revision: 1.4 $ * - * Mise a jour: $Date: 2004/11/08 13:39:19 $ + * Mise a jour: $Date: 2005/08/25 21:16:51 $ * par : $Author: bpoussin $ */ package org.codelutin.util; +import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -97,7 +98,12 @@ } static public Object [] concat(Object [] a, Object [] b){ - Object [] result = new Object[a.length+b.length]; + Object [] result; + if(a.getClass().getComponentType().equals(b.getClass().getComponentType())){ + result = (Object[])Array.newInstance(a.getClass().getComponentType(), a.length+b.length); + } else { + result = new Object[a.length+b.length]; + } System.arraycopy(a, 0, result, 0, a.length); System.arraycopy(b, 0, result, a.length, b.length); return result; Index: lutinutil/src/java/org/codelutin/util/StringUtil.java diff -u lutinutil/src/java/org/codelutin/util/StringUtil.java:1.10 lutinutil/src/java/org/codelutin/util/StringUtil.java:1.11 --- lutinutil/src/java/org/codelutin/util/StringUtil.java:1.10 Wed Jul 6 22:37:50 2005 +++ lutinutil/src/java/org/codelutin/util/StringUtil.java Thu Aug 25 21:16:51 2005 @@ -22,9 +22,9 @@ * * @author POUSSIN Benjamin * Copyright Code Lutin -* @version $Revision: 1.10 $ +* @version $Revision: 1.11 $ * -* Mise a jour: $Date: 2005/07/06 22:37:50 $ +* Mise a jour: $Date: 2005/08/25 21:16:51 $ * par : $Author: bpoussin $ */ package org.codelutin.util; @@ -32,6 +32,7 @@ import java.awt.Color; import java.lang.reflect.Field; import java.text.DateFormat; +import java.text.MessageFormat; import java.text.ParseException; import java.util.Date; @@ -176,4 +177,30 @@ public static Date toDate(String s) throws ParseException{ return DateFormat.getDateInstance().parse(s); } + + static final protected double [] timeFactors = {1000000, 1000, 60, 60, 24}; + static final protected String [] timeUnites = {"ns", "ms", "s", "m", "h", "d"}; + static public String convertTime(long value){ + return convert(value, timeFactors, timeUnites); + } + + static final protected double [] memoryFactors = {1024, 1024, 1024, 1024}; + static final protected String [] memoryUnites = {"o", "Ko", "Mo", "Go", "To"}; + static public String convertMemory(long value){ + return convert(value, memoryFactors, memoryUnites); + } + + static public String convert(long value, double [] factors , String [] unites){ + long sign = value==0?1:value/Math.abs(value); + int i=0; + double tmp = Math.abs(value); + while(i factors[i] ){ + tmp = tmp / factors[i++]; + } + + tmp *= sign; + String result = MessageFormat.format("{0,number,0.###}{1}", tmp, unites[i]); + return result; + } + } Index: lutinutil/src/java/org/codelutin/util/CallAnalyse.java diff -u /dev/null lutinutil/src/java/org/codelutin/util/CallAnalyse.java:1.1 --- /dev/null Thu Aug 25 21:16:56 2005 +++ lutinutil/src/java/org/codelutin/util/CallAnalyse.java Thu Aug 25 21:16:51 2005 @@ -0,0 +1,246 @@ +/* *##% + * Copyright (C) 2005 + * Code Lutin, Cédric Pineau, Benjamin Poussin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * 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 Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *##%*/ + +/* * + * CallAnalyse.java + * + * Created: 25 août 2005 14:09:22 CEST + * + * @author Benjamin POUSSIN + * @version $Revision: 1.1 $ + * + * Last update: $Date: 2005/08/25 21:16:51 $ + * by : $Author: bpoussin $ + */ + +package org.codelutin.util; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.TreeMap; +import org.apache.commons.collections.primitives.ArrayLongList; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** +* 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 +*/ +public class CallAnalyse { // CallAnalyse + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(CallAnalyse.class); + + static private List listThreadStatistics = + new ArrayList(); + + static private ThreadLocal stats = + new ThreadLocal(){ + protected synchronized ThreadStatistics initialValue(){ + ThreadStatistics result = new ThreadStatistics(); + listThreadStatistics.add(result); + return result; + } + }; + + /** + * Permet d'activer les statistiques, pour le thread courant + */ + static public void activate(){ + stats.get().setActivated(true); + } + + /** + * Permet de desactiver les statistiques, pour le thread courant + */ + static public void desactivate(){ + stats.get().setActivated(false); + } + + /** + * Permet de savoir si les statistiques sont activées ou non, pour le + * thread courant + */ + static public boolean isActivate(){ + return stats.get().getActivated(); + } + + /** + * @param name le nom de l'appel a monitorer + */ + static public 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 + */ + static public void exit(String name){ + ThreadStatistics t = stats.get(); + if(t.getActivated()){ + t.get(name).exit(); + } + } + + /** + * Retourne les statistiques pour le thread courant + */ + static public ThreadStatistics getThreadStatistics(){ + return stats.get(); + } + + /** + * Retourne les statistiques pour tous les threads + */ + static public List getAllThreadStatistics(){ + return listThreadStatistics; + } + + static public class ThreadStatistics extends TreeMap{ + 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(); + } + } + + static public class CallStatistics { + 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"); + 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(){ + return sumTime / calls; + } + + public long getMinMemory(){ + return minMemory; + } + public long getMaxMemory(){ + return maxMemory; + } + public long getSumMemory(){ + return sumMemory; + } + public long getAvgMemory(){ + return sumMemory / calls; + } + + protected long getMemory(){ + // runtime.gc(); + return runtime.totalMemory() - runtime.freeMemory(); + } + + 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()) + ")" + ; + } + } + +} // CallAnalyse +