r3736 - in trunk/src/main/java/fr/ifremer/isisfish: aspect simulator simulator/launcher util
Author: bpoussin Date: 2012-08-27 19:21:00 +0200 (Mon, 27 Aug 2012) New Revision: 3736 Url: http://forge.codelutin.com/repositories/revision/isis-fish/3736 Log: reecrire du cache et des traces pour qu'il n'y ait plus rien de statiques, les informations sont toutes stockees dans le SimualtionContext. Il est possible de faire un getCache().clear() ou getCache().clear(TimeStep) Trace et Cache sont vide lors du remove du SimualtionContext. Added: trunk/src/main/java/fr/ifremer/isisfish/aspect/CacheAspect.java trunk/src/main/java/fr/ifremer/isisfish/aspect/TraceAspect.java trunk/src/main/java/fr/ifremer/isisfish/util/Cache.java Removed: trunk/src/main/java/fr/ifremer/isisfish/aspect/Cache.java trunk/src/main/java/fr/ifremer/isisfish/aspect/Trace.java Modified: trunk/src/main/java/fr/ifremer/isisfish/simulator/SimulationContext.java trunk/src/main/java/fr/ifremer/isisfish/simulator/launcher/InProcessSimulatorLauncher.java trunk/src/main/java/fr/ifremer/isisfish/util/Trace.java Deleted: trunk/src/main/java/fr/ifremer/isisfish/aspect/Cache.java =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/aspect/Cache.java 2012-08-27 15:20:25 UTC (rev 3735) +++ trunk/src/main/java/fr/ifremer/isisfish/aspect/Cache.java 2012-08-27 17:21:00 UTC (rev 3736) @@ -1,306 +0,0 @@ -/* - * #%L - * IsisFish - * - * $Id$ - * $HeadURL$ - * %% - * Copyright (C) 2006 - 2010 Ifremer, 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, see - * <http://www.gnu.org/licenses/gpl-2.0.html>. - * #L% - */ - -package fr.ifremer.isisfish.aspect; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import org.apache.commons.collections.map.ReferenceMap; -import org.apache.commons.lang3.ObjectUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.codehaus.aspectwerkz.annotation.Around; -import org.codehaus.aspectwerkz.annotation.Aspect; -import org.codehaus.aspectwerkz.annotation.Expression; -import org.codehaus.aspectwerkz.definition.Pointcut; -import org.codehaus.aspectwerkz.joinpoint.JoinPoint; -import org.codehaus.aspectwerkz.joinpoint.MethodRtti; -import org.codehaus.aspectwerkz.joinpoint.MethodSignature; -import org.nuiton.topia.persistence.TopiaEntity; - -import fr.ifremer.isisfish.IsisFishRuntimeException; -import fr.ifremer.isisfish.simulator.SimulationContext; -import fr.ifremer.isisfish.types.TimeStep; -import fr.ifremer.isisfish.util.Nocache; - -/** - * Cache aspect. - * - * Created: 25 août 06 22:42:47 - * - * @author poussin - * @version $Revision$ - * - * Last update: $Date$ - * by : $Author$ - */ -@Aspect("perJVM") -public class Cache { - - /** to use log facility, just put in your code: log.info(\"...\"); */ - static private Log log = LogFactory.getLog(Cache.class); - - static private List<Cache> instances = new ArrayList<Cache>(); - - protected long totalCall = 0; - protected long cacheUsed = 0; - - protected Map cache = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.SOFT); -// protected Map cache = new AdaptaptativeCache(1000, 95); - - @Expression("execution(* scripts..*(..))") - Pointcut scriptsMethod; - - public Cache() { - instances.add(this); - } - - /** - * Return trace object from context. - * - * @return trace object from context - */ - protected fr.ifremer.isisfish.util.Trace getTrace() { - SimulationContext context = SimulationContext.get(); - - fr.ifremer.isisfish.util.Trace result = (fr.ifremer.isisfish.util.Trace) context - .getValue(fr.ifremer.isisfish.util.Trace.class.getName()); - - if (result == null) { - throw new IsisFishRuntimeException("No trace object found in context"); - } - - return result; - } - -// @Before("scriptsMethod") -// public void traceBeforeExecute (JoinPoint jp) { -// System.out.println("before !!!"); -// } -// -// @AfterThrowing("scriptsMethod") -// public void traceAfterThrowingExecute (JoinPoint jp) { -// System.out.println("throwing !!!"); -// } -// -// @After("scriptsMethod") -// public void traceAfterExecute (JoinPoint jp) { -// System.out.println("After !!!"); -// } - - - @Around("scriptsMethod") - public Object call(final JoinPoint jp) throws Throwable { - totalCall++; - - Object result = null; - Method method = ((MethodSignature)jp.getSignature()).getMethod(); - if (method.getAnnotation(Nocache.class) != null || - method.getDeclaringClass().getAnnotation(Nocache.class) != null) { - result = realCall(jp); - } else { - Object key = computeKey(jp); - result = cache.get(key); - if (result == null) { - - // computation increment (/ by 0) - // FIXME need to be called, but fail with empty stack - //Method method = ((MethodSignature)jp.getSignature()).getMethod(); - //getTrace().traceAfterComputation(method); - - result = realCall(jp); - // addListenerFor(key); // pas necessaire car on a la date et pour une date donnée rien ne peut changer - if (result != null) { // util pour les methodes retournant void, ne fonctionne pas si on met AND !execute(void *(..)) dans l'aspect. En fait fonction seulement si utilisé avec les traces :( - cache.put(key, result); - } - } else { - cacheUsed++; - } - } - - if (log.isTraceEnabled()) { - log.trace(((MethodSignature)jp.getSignature()).getMethod() - + " args " + Arrays.toString(((MethodRtti)jp.getRtti()).getParameterValues()) - + " result = " + result); - } - return result; - } - - /** - * On fait l'appel reel dans une autre methode pour pouvoir le savoir - * dans les traces - * - * @param jp - * @return ? - * @throws Throwable - */ - protected Object realCall(final JoinPoint jp) throws Throwable { - Object result = jp.proceed(); - return result; - } - - /** - * Attention pour avoir une chaine en sortie on prend la reprensentation - * toString des arguments. Mais en utilisant la methode toString implanté - * dans Object. - * <p> - * Pour les objets de style Number ou String, il faut prendre le vrai - * toString, pour que 2 soit bien egal a 2. - * - * @param jp - * @return ? - */ - protected Object computeKey(JoinPoint jp) { - Method method = ((MethodSignature)jp.getSignature()).getMethod(); - Object[] args = ((MethodRtti)jp.getRtti()).getParameterValues(); - - //String result = method.toString(); - String result = method.getDeclaringClass().getSimpleName() + "." + - method.getName(); - for (Object o : args) { - result += ";"; - if (o instanceof Number || o instanceof String) { - result += o.toString(); - } else if (o instanceof TimeStep) { - result += ((TimeStep)o).getStep(); - } else if (o instanceof TopiaEntity) { - result += ((TopiaEntity)o).getTopiaId().replaceAll("fr.ifremer.isisfish.entities.", ""); - } else { - result += ObjectUtils.identityToString(o); - result = result.replaceAll("org.nuiton.math.matrix.", ""); - } - } - - return result; - -// Method method = ((MethodSignature)jp.getSignature()).getMethod(); -// Object[] args = ((MethodRtti)jp.getRtti()).getParameterValues(); -// -// Object[] keys = new Object[args.length + 1]; -// keys[0] = method; -// System.arraycopy(args, 0, keys, 1, args.length); -// -// MultiKey result = new MultiKey(keys, false); -// -// return result; - } -// protected HashMapMultiKey.Key computeKey(JoinPoint jp) { -// Method method = ((MethodSignature)jp.getSignature()).getMethod(); -// Object[] args = ((MethodRtti)jp.getRtti()).getParameterValues(); -// -// HashMapMultiKey.Key result = new HashMapMultiKey.Key(); -// result.add(method); -// for (Object arg : args) { -// result.add(arg); -// } -// -// return result; -// } - - - /** - * @return Returns the cacheUsed. - */ - static public long getCacheUsed() { - long result = 0; - for (Cache cache : instances) { - result += cache.cacheUsed; - } - return result; - } - - /** - * @return Returns the totalCall. - */ - static public long getTotalCall() { - long result = 0; - for (Cache cache : instances) { - result += cache.totalCall; - } - return result; - } - - /** - * Affiche les statistiques - * - */ - static public String printStatistiqueAndClear() { - StringBuffer result = new StringBuffer(); - for (Cache cache : instances) { - result.append("--- Cache Statistiques ---\n"); - result.append("Total call: " + cache.totalCall + "\n"); - result.append("Cache used: " + cache.cacheUsed + "\n"); - result.append("Cache usage: " + (100*cache.cacheUsed/cache.totalCall) + "%" + "\n"); - result.append("--------------------\n"); - cache.cache.clear(); - } - System.out.println(result.toString()); - instances.clear(); - return result.toString(); - } - -// /** -// * Parcours les elements de la cle et pour ceux du type Entities se -// * met listener pour pouvoir supprimer l'entre du cache lors de leur -// * modification -// * -// * @param key -// */ -// protected void addListenerFor(HashMapMultiKey.Key key) { -// } - - - class AdaptaptativeCache extends LinkedHashMap<String, Object> { - protected int maxMemory = 95; - /** - * - * @param capacity initial capacity - * @param maxMemory maximum memory used (0-100) - */ - public AdaptaptativeCache(int capacity, int maxMemory) { - super(capacity, 0.75f, true); - this.maxMemory = maxMemory; - } - - /* (non-Javadoc) - * @see java.util.LinkedHashMap#removeEldestEntry(java.util.Map.Entry) - */ - @Override - protected boolean removeEldestEntry(Entry<String, Object> eldest) { - double free = 100.0 * Runtime.getRuntime().freeMemory() / Runtime.getRuntime().maxMemory() ; - boolean result = 100 - free > maxMemory; - return result; - } - } -} - - Copied: trunk/src/main/java/fr/ifremer/isisfish/aspect/CacheAspect.java (from rev 3734, trunk/src/main/java/fr/ifremer/isisfish/aspect/Cache.java) =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/aspect/CacheAspect.java (rev 0) +++ trunk/src/main/java/fr/ifremer/isisfish/aspect/CacheAspect.java 2012-08-27 17:21:00 UTC (rev 3736) @@ -0,0 +1,93 @@ +/* + * #%L + * IsisFish + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2006 - 2010 Ifremer, 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, see + * <http://www.gnu.org/licenses/gpl-2.0.html>. + * #L% + */ + +package fr.ifremer.isisfish.aspect; + +import fr.ifremer.isisfish.IsisFishRuntimeException; +import fr.ifremer.isisfish.simulator.SimulationContext; +import fr.ifremer.isisfish.util.Cache; +import java.lang.reflect.Method; +import java.util.Arrays; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.codehaus.aspectwerkz.annotation.Around; +import org.codehaus.aspectwerkz.annotation.Aspect; +import org.codehaus.aspectwerkz.annotation.Expression; +import org.codehaus.aspectwerkz.definition.Pointcut; +import org.codehaus.aspectwerkz.joinpoint.JoinPoint; +import org.codehaus.aspectwerkz.joinpoint.MethodRtti; +import org.codehaus.aspectwerkz.joinpoint.MethodSignature; + +/** + * CacheAspect aspect. + * + * Created: 25 août 06 22:42:47 + * + * @author poussin + * @version $Revision$ + * + * Last update: $Date$ + * by : $Author$ + */ +@Aspect("perJVM") +public class CacheAspect { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(CacheAspect.class); + + @Expression("execution(* scripts..*(..))") + Pointcut scriptsMethod; + + public CacheAspect() { + } + + /** + * Return trace object from context. + * + * @return trace object from context + */ + protected Cache getCache() { + SimulationContext context = SimulationContext.get(); + Cache result = context.getCache(); + return result; + } + + @Around("scriptsMethod") + public Object call(final JoinPoint jp) throws Throwable { + Method method = ((MethodSignature)jp.getSignature()).getMethod(); + Object[] args = ((MethodRtti)jp.getRtti()).getParameterValues(); + Object result = getCache().get(method, args, jp); + + if (log.isTraceEnabled()) { + log.trace(((MethodSignature)jp.getSignature()).getMethod() + + " args " + Arrays.toString(((MethodRtti)jp.getRtti()).getParameterValues()) + + " result = " + result); + } + return result; + } + +} + + Deleted: trunk/src/main/java/fr/ifremer/isisfish/aspect/Trace.java =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/aspect/Trace.java 2012-08-27 15:20:25 UTC (rev 3735) +++ trunk/src/main/java/fr/ifremer/isisfish/aspect/Trace.java 2012-08-27 17:21:00 UTC (rev 3736) @@ -1,127 +0,0 @@ -/* - * #%L - * IsisFish - * - * $Id$ - * $HeadURL$ - * %% - * Copyright (C) 2006 - 2011 Ifremer, Code Lutin, Cédric Pineau, Benjamin Poussin, Chatellier Eric - * %% - * 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, see - * <http://www.gnu.org/licenses/gpl-2.0.html>. - * #L% - */ - -package fr.ifremer.isisfish.aspect; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.codehaus.aspectwerkz.annotation.After; -import org.codehaus.aspectwerkz.annotation.AfterThrowing; -import org.codehaus.aspectwerkz.annotation.Aspect; -import org.codehaus.aspectwerkz.annotation.Before; -import org.codehaus.aspectwerkz.annotation.Expression; -import org.codehaus.aspectwerkz.definition.Pointcut; -import org.codehaus.aspectwerkz.joinpoint.JoinPoint; -import org.codehaus.aspectwerkz.joinpoint.MethodSignature; - -import fr.ifremer.isisfish.IsisFishRuntimeException; -import fr.ifremer.isisfish.simulator.SimulationContext; - -/** - * Permet de tracer les appels aux methodes utilisateur ainsi que l'execution - * a ces methodes. La difference entre les deux est lors de l'utilisation du - * cache les appels seront superieur a l'execution car certaine valeur seront - * reutilisé dans le cache - * - * Created: 25 août 06 22:19:21 - * - * @author poussin - * @version $Revision$ - * - * Last update: $Date$ - * by : $Author$ - */ -@Aspect("perJVM") -public class Trace { - - /** to use log facility, just put in your code: log.info("..."); */ - static private Log log = LogFactory.getLog(Trace.class); - - static private List<Trace> instances = new ArrayList<Trace>(); - - @Expression("execution(* scripts..*(..))" - + " || execution(* simulators..*(..))" - + " || execution(* rules..*(..)) " - + " || execution(* simulationplans..*(..)) " - + " || execution(* formules..*(..))") - Pointcut executeMethod; - - public Trace() { - instances.add(this); - } - - /** - * Return trace object from context. - * - * @return trace object from context - */ - protected fr.ifremer.isisfish.util.Trace getTrace() { - SimulationContext context = SimulationContext.get(); - - fr.ifremer.isisfish.util.Trace result = (fr.ifremer.isisfish.util.Trace) context - .getValue(fr.ifremer.isisfish.util.Trace.class.getName()); - - if (result == null) { - throw new IsisFishRuntimeException("No trace object found in context"); - } - - return result; - } - - @Before("executeMethod") - public void traceBeforeExecute(JoinPoint jp) { - getTrace().traceBefore(); - } - - @AfterThrowing(type = "java.lang.Exception", pointcut = "executeMethod") - public void traceAfterThrowingExecute(JoinPoint jp) { - // si une exeption est leve, il faut faire la meme chose - traceAfterExecute(jp); - } - - @After("executeMethod") - public void traceAfterExecute(JoinPoint jp) { - Method method = ((MethodSignature) jp.getSignature()).getMethod(); - getTrace().traceAfterCall(method); - } - - /** - * Affiche les statistiques - * - * @return statistics as string - */ - public static String printStatistiqueAndClear() { - StringBuffer result = new StringBuffer(); - for (Trace trace : instances) { - result.append(trace.getTrace().printStatisticAndClear()); - } - instances.clear(); - return result.toString(); - } -} Copied: trunk/src/main/java/fr/ifremer/isisfish/aspect/TraceAspect.java (from rev 3734, trunk/src/main/java/fr/ifremer/isisfish/aspect/Trace.java) =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/aspect/TraceAspect.java (rev 0) +++ trunk/src/main/java/fr/ifremer/isisfish/aspect/TraceAspect.java 2012-08-27 17:21:00 UTC (rev 3736) @@ -0,0 +1,104 @@ +/* + * #%L + * IsisFish + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2006 - 2011 Ifremer, Code Lutin, Cédric Pineau, Benjamin Poussin, Chatellier Eric + * %% + * 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, see + * <http://www.gnu.org/licenses/gpl-2.0.html>. + * #L% + */ + +package fr.ifremer.isisfish.aspect; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.codehaus.aspectwerkz.annotation.After; +import org.codehaus.aspectwerkz.annotation.AfterThrowing; +import org.codehaus.aspectwerkz.annotation.Aspect; +import org.codehaus.aspectwerkz.annotation.Before; +import org.codehaus.aspectwerkz.annotation.Expression; +import org.codehaus.aspectwerkz.definition.Pointcut; +import org.codehaus.aspectwerkz.joinpoint.JoinPoint; +import org.codehaus.aspectwerkz.joinpoint.MethodSignature; + +import fr.ifremer.isisfish.IsisFishRuntimeException; +import fr.ifremer.isisfish.simulator.SimulationContext; +import fr.ifremer.isisfish.util.Trace; + +/** + * Permet de tracer les appels aux methodes utilisateur ainsi que l'execution + * a ces methodes. La difference entre les deux est lors de l'utilisation du + * cache les appels seront superieur a l'execution car certaine valeur seront + * reutilisé dans le cache + * + * Created: 25 août 06 22:19:21 + * + * @author poussin + * @version $Revision$ + * + * Last update: $Date$ + * by : $Author$ + */ +@Aspect("perJVM") +public class TraceAspect { + + /** to use log facility, just put in your code: log.info("..."); */ + static private Log log = LogFactory.getLog(TraceAspect.class); + + @Expression("execution(* scripts..*(..))" + + " || execution(* simulators..*(..))" + + " || execution(* rules..*(..)) " + + " || execution(* simulationplans..*(..)) " + + " || execution(* formules..*(..))") + Pointcut executeMethod; + + public TraceAspect() { + } + + /** + * Return trace object from context. + * + * @return trace object from context + */ + protected Trace getTrace() { + SimulationContext context = SimulationContext.get(); + Trace result = context.getTrace(); + return result; + } + + @Before("executeMethod") + public void traceBeforeExecute(JoinPoint jp) { + getTrace().traceBefore(); + } + + @AfterThrowing(type = "java.lang.Exception", pointcut = "executeMethod") + public void traceAfterThrowingExecute(JoinPoint jp) { + // si une exeption est leve, il faut faire la meme chose + traceAfterExecute(jp); + } + + @After("executeMethod") + public void traceAfterExecute(JoinPoint jp) { + Method method = ((MethodSignature) jp.getSignature()).getMethod(); + getTrace().traceAfterCall(method); + } +} Modified: trunk/src/main/java/fr/ifremer/isisfish/simulator/SimulationContext.java =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/simulator/SimulationContext.java 2012-08-27 15:20:25 UTC (rev 3735) +++ trunk/src/main/java/fr/ifremer/isisfish/simulator/SimulationContext.java 2012-08-27 17:21:00 UTC (rev 3736) @@ -25,6 +25,8 @@ package fr.ifremer.isisfish.simulator; +import fr.ifremer.isisfish.aspect.CacheAspect; +import fr.ifremer.isisfish.aspect.TraceAspect; import java.io.File; import java.util.HashMap; import java.util.LinkedHashSet; @@ -39,6 +41,8 @@ import fr.ifremer.isisfish.datastore.SimulationStorage; import fr.ifremer.isisfish.simulator.sensitivity.SensitivityUtils; +import fr.ifremer.isisfish.util.Cache; +import fr.ifremer.isisfish.util.Trace; /** * Keep all information on one simulation. @@ -72,6 +76,10 @@ protected Set<SimulationListener> simulationListeners = new LinkedHashSet<SimulationListener>(); protected ClassLoader classLoader = null; protected File scriptDirectory; + /** l'objet trace qui conserve les donnees statistiques des appels de methodes */ + protected Trace trace; + /** cache used by aspect for this simulation */ + protected Cache cache; /** TopiaContext must be used by rule action to modify data */ protected TopiaContext db = null; @@ -79,7 +87,7 @@ /** TopiaContext must be used to save result */ protected TopiaContext dbResult = null; - /** Cache des variables d'entités. Topia id > map of attributes. */ + /** CacheAspect des variables d'entités. Topia id > map of attributes. */ protected Map<TopiaEntity, SimulationVariable> variablesCache = new HashMap<TopiaEntity, SimulationVariable>(); /** Context value used in equation. */ @@ -107,6 +115,10 @@ */ public static void remove() { SimulationContext current = get(); + current.getCache().clear(); + current.cache = null; + current.getTrace().clear(); + current.trace = null; current.values.clear(); current.classLoader = null; simulationContext.remove(); @@ -190,6 +202,19 @@ this.classLoader = classLoader; } + public Trace getTrace() { + if (trace == null) { + trace = new Trace(); + } + return trace; + } + + public Cache getCache() { + if (cache == null) { + cache = new Cache(); + }return cache; + } + /** * Permet de recuperer une valeur prealablement stocker avec un setValue * @param name le nom de la valeur souhaitée Modified: trunk/src/main/java/fr/ifremer/isisfish/simulator/launcher/InProcessSimulatorLauncher.java =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/simulator/launcher/InProcessSimulatorLauncher.java 2012-08-27 15:20:25 UTC (rev 3735) +++ trunk/src/main/java/fr/ifremer/isisfish/simulator/launcher/InProcessSimulatorLauncher.java 2012-08-27 17:21:00 UTC (rev 3736) @@ -54,9 +54,9 @@ import fr.ifremer.isisfish.IsisFish; import fr.ifremer.isisfish.IsisFishRuntimeException; import fr.ifremer.isisfish.aspect.AspectClassLoader; -import fr.ifremer.isisfish.aspect.Cache; +import fr.ifremer.isisfish.aspect.CacheAspect; import fr.ifremer.isisfish.aspect.RuleAspect; -import fr.ifremer.isisfish.aspect.Trace; +import fr.ifremer.isisfish.aspect.TraceAspect; import fr.ifremer.isisfish.datastore.SimulationStorage; import fr.ifremer.isisfish.datastore.SimulatorStorage; import fr.ifremer.isisfish.simulator.SimulationContext; @@ -354,20 +354,14 @@ // Activation de l'OAP demandée // if (parameters.getUseStatistic() || parameters.getUseOptimization()) { - - // il est necessaire de passer un object trace/cache - // commun, donc on le met dans le context - // pas moyen de le passer autrement plus simplement - fr.ifremer.isisfish.util.Trace traceObject = new fr.ifremer.isisfish.util.Trace(""); - context.setValue(fr.ifremer.isisfish.util.Trace.class.getName(), traceObject); - + if (parameters.getUseStatistic()) { message(control, _("isisfish.message.setting.trace.aspects")); - classLoader.deploy(Trace.class); + classLoader.deploy(TraceAspect.class); } if (parameters.getUseOptimization()) { message(control, _("isisfish.message.setting.cache.aspects")); - classLoader.deploy(Cache.class); + classLoader.deploy(CacheAspect.class); } } @@ -472,11 +466,11 @@ (end - start) / 1000000, "s'.'S")); SimulationParameter param = simulation.getParameter(); if (param.getUseStatistic()) { - String trace = Trace.printStatistiqueAndClear(); + String trace = context.getTrace().printStatisticAndClear(); simulation.getInformation().setStatistic(trace); } if (param.getUseOptimization()) { - String cache = Cache.printStatistiqueAndClear(); + String cache = context.getCache().printStatistiqueAndClear(); simulation.getInformation().setOptimizationUsage(cache); } @@ -487,7 +481,7 @@ } FileUtil.deleteRecursively(simulationBuildDirectory); - // context is used in Trace.printStatistiqueAndClear() + // context is used in TraceAspect.printStatistiqueAndClear() SimulationContext.remove(); } return result; Copied: trunk/src/main/java/fr/ifremer/isisfish/util/Cache.java (from rev 3734, trunk/src/main/java/fr/ifremer/isisfish/aspect/Cache.java) =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/util/Cache.java (rev 0) +++ trunk/src/main/java/fr/ifremer/isisfish/util/Cache.java 2012-08-27 17:21:00 UTC (rev 3736) @@ -0,0 +1,288 @@ +/* + * #%L + * IsisFish + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2006 - 2010 Ifremer, 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, see + * <http://www.gnu.org/licenses/gpl-2.0.html>. + * #L% + */ + +package fr.ifremer.isisfish.util; + +import fr.ifremer.isisfish.IsisFishRuntimeException; +import fr.ifremer.isisfish.simulator.SimulationContext; +import fr.ifremer.isisfish.types.TimeStep; +import java.lang.reflect.Method; +import java.util.Map; +import org.apache.commons.collections.map.ReferenceMap; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.codehaus.aspectwerkz.joinpoint.JoinPoint; +import org.nuiton.topia.persistence.TopiaEntity; + +/** + * Cache utilise pour mettre les resultats de methode durant la simulation + * pour minimiser les appels + * + * Created: 25 août 06 22:42:47 + * + * @author poussin + * @version $Revision$ + * + * Last update: $Date$ + * by : $Author$ + */ +public class Cache { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(Cache.class); + + // la longueur du package pour minimiser la longueur des topiaId + static final private int entityPackageLenght = "fr.ifremer.isisfish.entities.".length(); + // la valeur NULL a utilise a la place de null pour les timeStep + static final private Object NULL = new Object(); + +// static private List<CacheAspect> instances = new ArrayList<CacheAspect>(); + + protected long totalCall = 0; + protected long cacheUsed = 0; + + /** + * map<TimeStep, Map<Key, Value>> + * TimeStep peut etre null via l'objet NULL + * Key est la cle calcule par computeKey + * Value est la valeur du cache + * + * TimeStep est en WEAK pour que des que l'on passe au pas de temps suivant + * ils soit efface de la memoire si plus personne n'a de reference sur + * ce pas de temps. L'autre moyen est de force l'effacement via clear(TimeStep) + * + * Value est en SOFT reference pour que les valeurs soit effacee du cache + * lorsqu'il n'y a plus de place memoire + */ + protected Map cache = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.HARD); +// protected Map cache = new AdaptaptativeCache(1000, 95); + + public Cache() { + } + + /** + * Return trace object from context. + * + * @return trace object from context + */ + protected Trace getTrace() { + SimulationContext context = SimulationContext.get(); + Trace result = context.getTrace(); + return result; + } + + /** + * Recupere pour un pas de temps donnes une valeur calcule pour une cle + * @param step le pas de temps pour lequel on souhaite ajouter (ou null) + * @param key la cle de storage + * @param defaultValue la valeur par defaut a retourner si elle n'est pas en cache + * si defaultValue est une JoinPoint alors un proceed est appele dessus et le + * resultat de l'appel est utiliser comme valeur par defaut + * @return la valeur dans le cache ou defaultValue + */ + public Object get(Method method, Object[] args, Object defaultValue) throws Throwable { + totalCall++; + + Object result = null; + if (method.getAnnotation(Nocache.class) != null || + method.getDeclaringClass().getAnnotation(Nocache.class) != null) { + result = realCall(defaultValue); + } else { + // compute key and keep TimeStep objet + StringBuilder sbKey = new StringBuilder(); + // le pas de temps trouve dans les arguments + TimeStep step = computeKey(sbKey, method, args); + + Object key = sbKey.toString(); + result = get(step, key); + if (result == null) { + + // computation increment (/ by 0) + // FIXME need to be called, but fail with empty stack + //getTrace().traceAfterComputation(method); + + result = realCall(defaultValue); + if (result != null) { // util pour les methodes retournant void, ne fonctionne pas si on met AND !execute(void *(..)) dans l'aspect. En fait fonction seulement si utilisé avec les traces :( + put(step, key, result); + } + } else { + cacheUsed++; + } + } + return result; + } + + protected TimeStep computeKey(StringBuilder sbKey, Method method, Object[] args) { + TimeStep result = null; + sbKey.append(method.getDeclaringClass().getSimpleName()); + sbKey.append("."); + sbKey.append(method.getName()); + for (Object o : args) { + sbKey.append(";"); + if (o == null) { + sbKey.append("null"); + } else if (o instanceof Number || o instanceof String) { + sbKey.append(o.toString()); + } else if (o instanceof TimeStep) { + result = (TimeStep)o; + sbKey.append(((TimeStep)o).getStep()); + } else if (o instanceof TopiaEntity) { + sbKey.append( ((TopiaEntity)o).getTopiaId().substring(entityPackageLenght)); + } else { + // on minimise en prenant que le nom de la classe (pas le package) + sbKey.append(o.getClass().getSimpleName()); + sbKey.append('@'); + // et en lui ajoutant son adresse memoire en Hexa + sbKey.append(Integer.toHexString(System.identityHashCode(o))); + } + } + return result; + } + + protected Map getCacheTimeStep(TimeStep step) { + Object key = step; + if (step == null) { + key = NULL; + } + Map result = (Map)cache.get(key); + if (result == null) { + result = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.SOFT); + cache.put(key, result); + } + return result; + } + + protected Object get(TimeStep step, Object key) { + Object result = null; + Map cacheTimeStep = getCacheTimeStep(step); + if (cacheTimeStep != null) { + result = cacheTimeStep.get(key); + } + return result; + } + + protected void put(TimeStep step, Object key, Object value) { + getCacheTimeStep(step).put(key, value); + } + + /** + * On fait l'appel reel dans une autre methode pour pouvoir le savoir + * dans les traces + * + * @param jp + * @return ? + * @throws Throwable + */ + protected Object realCall(Object defaultValue) throws Throwable { + Object result = defaultValue; + if (defaultValue instanceof JoinPoint) { + result = ((JoinPoint)defaultValue).proceed(); + } + return result; + } + + /** + * remove all values in cache + */ + public void clear() { + cache.clear(); + } + + /** + * remove all values in cache for the specied TimeStep + */ + public void clear(TimeStep step) { + Object key = step; + if (key == null) { + key = NULL; + } + cache.remove(key); + } + + /** + * @return Returns the cacheUsed. + */ + public long getCacheUsed() { + long result = cacheUsed; + return result; + } + + /** + * @return Returns the totalCall. + */ + public long getTotalCall() { + long result = totalCall; + return result; + } + + /** + * Affiche les statistiques + * + */ + public String printStatistiqueAndClear() { + StringBuilder result = new StringBuilder(); + result.append("--- Cache Statistiques ---\n"); + result.append("Total call: ").append(totalCall).append("\n"); + result.append("Cache used: ").append(cacheUsed).append("\n"); + long percent = 0; + if (totalCall != 0) { + percent = 100*cacheUsed/totalCall; + } + result.append("Cache usage: ").append(percent).append("%\n"); + result.append("--------------------\n"); + cache.clear(); + + System.out.println(result.toString()); + return result.toString(); + } + + // EN COURS D'ECRITURE MAIS JAMAIS FINI :( + // l'idee est de prendre la place memoire qu'il y a, mais s'il n'y en + // a plus on commence par enlever les objets les plus vieux +// class AdaptaptativeCache extends LinkedHashMap<String, Object> { +// protected int maxMemory = 95; +// /** +// * +// * @param capacity initial capacity +// * @param maxMemory maximum memory used (0-100) +// */ +// public AdaptaptativeCache(int capacity, int maxMemory) { +// super(capacity, 0.75f, true); +// this.maxMemory = maxMemory; +// } +// +// /* (non-Javadoc) +// * @see java.util.LinkedHashMap#removeEldestEntry(java.util.Map.Entry) +// */ +// @Override +// protected boolean removeEldestEntry(Entry<String, Object> eldest) { +// double free = 100.0 * Runtime.getRuntime().freeMemory() / Runtime.getRuntime().maxMemory() ; +// boolean result = 100 - free > maxMemory; +// return result; +// } +// } +} + + Modified: trunk/src/main/java/fr/ifremer/isisfish/util/Trace.java =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/util/Trace.java 2012-08-27 15:20:25 UTC (rev 3735) +++ trunk/src/main/java/fr/ifremer/isisfish/util/Trace.java 2012-08-27 17:21:00 UTC (rev 3736) @@ -71,17 +71,13 @@ /** heure de depart de l'appel a la methode (avec le temps des autres methodes) */ final static private int STACK_TIME_START_NEST_METHOD = 2; - - protected String name = ""; - /** array : [call's numbers, call do, min time, max time, total time, total time with child]*/ protected Map<String, long[]> statistics = new LinkedHashMap<String, long[]>(); /** array : [nest e call, start time, start time with child] */ protected Stack<long[]> callStack = new Stack<long[]>(); - public Trace(String name) { - this.name = name; + public Trace() { } public long[] getStatistics(Object e) { @@ -93,7 +89,14 @@ } return result; } - + + /** + * Clear current value statistics (all is reset) + */ + public void clear() { + statistics.clear(); + } + public void traceBefore () { // ajout dans le stack long current = System.nanoTime(); @@ -167,7 +170,7 @@ long call = 0; long computation = 0; StringBuffer result = new StringBuffer(); - result.append("--- " + name + " Statistics ---\n"); + result.append("--- " + " Statistics ---\n"); for (String e : statistics.keySet()) { long[] stat = getStatistics(e);
participants (1)
-
bpoussin@users.forge.codelutin.com