From: Gary P. <gpa...@gm...> - 2009-07-24 10:28:11
|
These changes prevent the leaking of ThreadLocal variables. Previously the simulation object graphs were created ahead of time and then executed in threads. This effectively resulted in the ThreadLocal variable being placed on the main thread and _not_ the intended simulation thread. Yes, this is BAD. Created a logical separation and ensured that the object graph construction occurs within the simulation thread and not in the main thread. Tested-by: Wiehann Matthysen <wcm...@gm...> Signed-off-by: Gary Pampara <gpa...@gm...> --- .../java/net/sourceforge/cilib/simulator/Main.java | 9 +- .../sourceforge/cilib/simulator/Simulation.java | 202 +++++++------------- .../simulator/{Simulation.java => Simulator.java} | 108 ++++------- .../net/sourceforge/cilib/xml/XMLFileTest.java | 4 +- 4 files changed, 114 insertions(+), 209 deletions(-) copy src/main/java/net/sourceforge/cilib/simulator/{Simulation.java => Simulator.java} (52%) diff --git a/src/main/java/net/sourceforge/cilib/simulator/Main.java b/src/main/java/net/sourceforge/cilib/simulator/Main.java index 452702a..88246cb 100644 --- a/src/main/java/net/sourceforge/cilib/simulator/Main.java +++ b/src/main/java/net/sourceforge/cilib/simulator/Main.java @@ -58,14 +58,13 @@ public final class Main { XMLProblemFactory problemFactory = new XMLProblemFactory(config, (Element) current.getElementsByTagName("problem").item(0)); XMLObjectFactory measurementsFactory = new XMLObjectFactory(config, (Element) current.getElementsByTagName("measurements").item(0)); MeasurementSuite suite = (MeasurementSuite) measurementsFactory.newObject(); - Simulation simulation = new Simulation(algorithmFactory, problemFactory, suite); + Simulator simulator = new Simulator(algorithmFactory, problemFactory, suite); if(progress != null) { - simulation.addProgressListener(progress); + simulator.addProgressListener(progress); } - simulation.initialise(); - simulation.run(); - simulation = null; + simulator.execute(); + simulator = null; System.gc(); } } diff --git a/src/main/java/net/sourceforge/cilib/simulator/Simulation.java b/src/main/java/net/sourceforge/cilib/simulator/Simulation.java index 377dd5c..57dc736 100644 --- a/src/main/java/net/sourceforge/cilib/simulator/Simulation.java +++ b/src/main/java/net/sourceforge/cilib/simulator/Simulation.java @@ -22,9 +22,6 @@ package net.sourceforge.cilib.simulator; import java.lang.reflect.Method; -import java.util.Hashtable; -import java.util.Vector; - import net.sourceforge.cilib.algorithm.Algorithm; import net.sourceforge.cilib.algorithm.AlgorithmEvent; import net.sourceforge.cilib.algorithm.AlgorithmFactory; @@ -34,164 +31,111 @@ import net.sourceforge.cilib.problem.Problem; import net.sourceforge.cilib.problem.ProblemFactory; /** - * <p> - * This class represents a single simulation experiment. The experiment is repeated based on the - * number of samples that the measurement suite requires. In this implementation each experiment is - * run in its own thread. Thus, each experiment is run in parallel for a given simulation. - * </p> - * <p> - * The simulation executes a given algorithm on the given problem. Factories are utilised so that - * the simulation can create as many alogirthms and problems as it needs to run many experiments. - * </p> - * <p> - * The primary purpose of running simulations is to measure the performance of the given algorithm - * on a given problem. For that reason, a simulation accepts a measurement suite which it uses to - * record the performace. - * </p> - * @author Edwin Peer + * A Simulation is a complete simulation that runs as a separate thread. */ -public class Simulation extends Thread implements AlgorithmListener { - private static final long serialVersionUID = 8987667794610802908L; - private MeasurementSuite measurementSuite; - private Algorithm[] algorithms; - private Thread[] threads; - private Vector<ProgressListener> progressListeners; - private Hashtable<Algorithm, Double> progress; - - public Simulation getClone() { - return null; - } +class Simulation extends Thread implements AlgorithmListener { + private static final long serialVersionUID = -3733724215662398762L; + + private final Simulator simulator; + private final AlgorithmFactory algorithmFactory; + private final ProblemFactory problemFactory; + + private Algorithm algorithm; /** - * Creates a new instance of Simulation given an algorithm factory, a problem factory and a - * measurement suite. {@see net.sourceforge.cilib.XMLObjectFactory} - * @param algorithmFactory The algorithm factory. - * @param problemFactory The problem factory. - * @param measurementSuite The measurement suite. + * Create a Simulation with the required dependencies. + * @param simulator The controlling {@code Simulator}. + * @param algorithmFactory The factory that creates {@code Algorithm} instances. + * @param problemFactory The factory that creates {@code Problem} instances. */ - public Simulation(AlgorithmFactory algorithmFactory, ProblemFactory problemFactory, MeasurementSuite measurementSuite) { - - measurementSuite.initialise(); - this.measurementSuite = measurementSuite; - progressListeners = new Vector<ProgressListener>(); - progress = new Hashtable<Algorithm, Double>(); - - algorithms = new Algorithm[measurementSuite.getSamples()]; - threads = new Thread[measurementSuite.getSamples()]; - for (int i = 0; i < measurementSuite.getSamples(); ++i) { - algorithms[i] = algorithmFactory.newAlgorithm(); - threads[i] = new Thread(algorithms[i]); - algorithms[i].addAlgorithmListener(this); - Problem problem = problemFactory.newProblem(); - try { - Class<? extends Object> current = problem.getClass(); - // System.out.println(current.getName()); - while (!current.getSuperclass().equals(Object.class)) { - current = current.getSuperclass(); - // System.out.println(current.getName()); - } - String type = current.getInterfaces()[0].getName(); - // System.out.println("type: " + type); - Class<?> [] parameters = new Class[1]; - parameters[0] = Class.forName(type); - // System.out.println("parameters: " + parameters[0].getName()); - String setMethodName = "set" + type.substring(type.lastIndexOf(".") + 1); - // System.out.println("setMethodName: " + setMethodName); - Method setProblemMethod = algorithms[i].getClass().getMethod(setMethodName, parameters); - // System.out.println("setProblemMethod: " + setProblemMethod.getName()); - setProblemMethod.invoke(algorithms[i], new Object[] {problem}); - } - catch (Exception ex) { - throw new InitialisationException(algorithms[i].getClass().getName() + " does not support problems of type " + problem.getClass().getName()); - } - progress.put(algorithms[i], new Double(0)); - } - } - - public void initialise() { - for (Algorithm algorithm : algorithms) - algorithm.initialise(); + public Simulation(Simulator simulator, AlgorithmFactory algorithmFactory, ProblemFactory problemFactory) { + this.simulator = simulator; + this.algorithmFactory = algorithmFactory; + this.problemFactory = problemFactory; } /** - * Executes all the experiments for this simulation. + * Execute the simulation. */ + @Override public void run() { - for (int i = 0; i < measurementSuite.getSamples(); ++i) { - threads[i].start(); - } - for (int i = 0; i < measurementSuite.getSamples(); ++i) { - try { - threads[i].join(); - } - catch (InterruptedException ex) { - ex.printStackTrace(); + algorithm = algorithmFactory.newAlgorithm(); + algorithm.addAlgorithmListener(this); + + Problem problem = problemFactory.newProblem(); + try { + Class<? extends Object> current = problem.getClass(); + + while (!current.getSuperclass().equals(Object.class)) { + current = current.getSuperclass(); } + + String type = current.getInterfaces()[0].getName(); + Class<?> [] parameters = new Class[1]; + parameters[0] = Class.forName(type); + String setMethodName = "set" + type.substring(type.lastIndexOf(".") + 1); + Method setProblemMethod = algorithm.getClass().getMethod(setMethodName, parameters); + setProblemMethod.invoke(algorithm, new Object[] {problem}); + } + catch (Exception ex) { + throw new InitialisationException(algorithm.getClass().getName() + " does not support problems of type " + problem.getClass().getName()); } - measurementSuite.getOutputBuffer().close(); - measurementSuite = null; - algorithms = null; - progress = null; - progressListeners = null; - threads = null; + + algorithm.initialise(); + algorithm.run(); } /** - * Terminates all the experiments. + * Terminate the current simulation. */ public void terminate() { - for (int i = 0; i < measurementSuite.getSamples(); ++i) { - algorithms[i].terminate(); - } + algorithm.terminate(); } /** - * Adds a listener for progress events. A progress is fired periodically based on the resolution - * of the measurements. {@see ProgressEvent} {@see ProgressListener} - * @param The event listener + * {@inheritDoc} */ - public void addProgressListener(ProgressListener listener) { - progressListeners.add(listener); + @Override + public void algorithmStarted(AlgorithmEvent e) { } /** - * Removes a listener for progress events. - * @param The event listener + * {@inheritDoc} */ - public void removeProgressListener(ProgressListener listener) { - progressListeners.remove(listener); + @Override + public void algorithmFinished(AlgorithmEvent e) { + this.simulator.simulationFinished(this); } - private synchronized void notifyProgress() { - double ave = 0; - for (Double tmp : progress.values()) { - ave += tmp.doubleValue(); - } - - ave /= progress.size(); - - for (ProgressListener listener : progressListeners) { - listener.handleProgressEvent(new ProgressEvent(ave)); - } + /** + * {@inheritDoc} + */ + @Override + public void algorithmTerminated(AlgorithmEvent e) { } - public void algorithmStarted(AlgorithmEvent e) { + /** + * {@inheritDoc} + */ + @Override + public void iterationCompleted(AlgorithmEvent e) { + this.simulator.simulationIterationCompleted(this); } - public void algorithmFinished(AlgorithmEvent e) { - measurementSuite.measure(e.getSource()); - progress.put(e.getSource(), new Double(e.getSource().getPercentageComplete())); - notifyProgress(); + /** + * {@inheritDoc} + */ + @Override + public AlgorithmListener getClone() { + return this; } - public void algorithmTerminated(AlgorithmEvent e) { + /** + * Obtain the {@code Algorithm} of the current {@code Simulation}. + * @return The current {@code Algorithm}. + */ + public Algorithm getAlgorithm() { + return algorithm; } - public void iterationCompleted(AlgorithmEvent e) { - if (e.getSource().getIterations() % measurementSuite.getResolution() == 0) { - measurementSuite.measure(e.getSource()); - progress.put(e.getSource(), new Double(e.getSource().getPercentageComplete())); - notifyProgress(); - } - } } diff --git a/src/main/java/net/sourceforge/cilib/simulator/Simulation.java b/src/main/java/net/sourceforge/cilib/simulator/Simulator.java similarity index 52% copy from src/main/java/net/sourceforge/cilib/simulator/Simulation.java copy to src/main/java/net/sourceforge/cilib/simulator/Simulator.java index 377dd5c..3fc3051 100644 --- a/src/main/java/net/sourceforge/cilib/simulator/Simulation.java +++ b/src/main/java/net/sourceforge/cilib/simulator/Simulator.java @@ -21,27 +21,22 @@ */ package net.sourceforge.cilib.simulator; -import java.lang.reflect.Method; import java.util.Hashtable; import java.util.Vector; import net.sourceforge.cilib.algorithm.Algorithm; -import net.sourceforge.cilib.algorithm.AlgorithmEvent; import net.sourceforge.cilib.algorithm.AlgorithmFactory; -import net.sourceforge.cilib.algorithm.AlgorithmListener; -import net.sourceforge.cilib.algorithm.InitialisationException; -import net.sourceforge.cilib.problem.Problem; import net.sourceforge.cilib.problem.ProblemFactory; /** * <p> * This class represents a single simulation experiment. The experiment is repeated based on the * number of samples that the measurement suite requires. In this implementation each experiment is - * run in its own thread. Thus, each experiment is run in parallel for a given simulation. + * execute in its own thread. Thus, each experiment is execute in parallel for a given simulation. * </p> * <p> * The simulation executes a given algorithm on the given problem. Factories are utilised so that - * the simulation can create as many alogirthms and problems as it needs to run many experiments. + * the simulation can create as many alogirthms and problems as it needs to execute many experiments. * </p> * <p> * The primary purpose of running simulations is to measure the performance of the given algorithm @@ -50,79 +45,44 @@ import net.sourceforge.cilib.problem.ProblemFactory; * </p> * @author Edwin Peer */ -public class Simulation extends Thread implements AlgorithmListener { +public class Simulator { private static final long serialVersionUID = 8987667794610802908L; + private MeasurementSuite measurementSuite; - private Algorithm[] algorithms; - private Thread[] threads; + private Simulation[] simulations; private Vector<ProgressListener> progressListeners; - private Hashtable<Algorithm, Double> progress; - - public Simulation getClone() { - return null; - } + private Hashtable<Simulation, Double> progress; /** - * Creates a new instance of Simulation given an algorithm factory, a problem factory and a + * Creates a new instance of Simulator given an algorithm factory, a problem factory and a * measurement suite. {@see net.sourceforge.cilib.XMLObjectFactory} * @param algorithmFactory The algorithm factory. * @param problemFactory The problem factory. * @param measurementSuite The measurement suite. */ - public Simulation(AlgorithmFactory algorithmFactory, ProblemFactory problemFactory, MeasurementSuite measurementSuite) { - + public Simulator(AlgorithmFactory algorithmFactory, ProblemFactory problemFactory, MeasurementSuite measurementSuite) { measurementSuite.initialise(); this.measurementSuite = measurementSuite; progressListeners = new Vector<ProgressListener>(); - progress = new Hashtable<Algorithm, Double>(); + progress = new Hashtable<Simulation, Double>(); - algorithms = new Algorithm[measurementSuite.getSamples()]; - threads = new Thread[measurementSuite.getSamples()]; + simulations = new Simulation[measurementSuite.getSamples()]; for (int i = 0; i < measurementSuite.getSamples(); ++i) { - algorithms[i] = algorithmFactory.newAlgorithm(); - threads[i] = new Thread(algorithms[i]); - algorithms[i].addAlgorithmListener(this); - Problem problem = problemFactory.newProblem(); - try { - Class<? extends Object> current = problem.getClass(); - // System.out.println(current.getName()); - while (!current.getSuperclass().equals(Object.class)) { - current = current.getSuperclass(); - // System.out.println(current.getName()); - } - String type = current.getInterfaces()[0].getName(); - // System.out.println("type: " + type); - Class<?> [] parameters = new Class[1]; - parameters[0] = Class.forName(type); - // System.out.println("parameters: " + parameters[0].getName()); - String setMethodName = "set" + type.substring(type.lastIndexOf(".") + 1); - // System.out.println("setMethodName: " + setMethodName); - Method setProblemMethod = algorithms[i].getClass().getMethod(setMethodName, parameters); - // System.out.println("setProblemMethod: " + setProblemMethod.getName()); - setProblemMethod.invoke(algorithms[i], new Object[] {problem}); - } - catch (Exception ex) { - throw new InitialisationException(algorithms[i].getClass().getName() + " does not support problems of type " + problem.getClass().getName()); - } - progress.put(algorithms[i], new Double(0)); + simulations[i] = new Simulation(this, algorithmFactory, problemFactory); + progress.put(simulations[i], 0.0); } } - public void initialise() { - for (Algorithm algorithm : algorithms) - algorithm.initialise(); - } - /** * Executes all the experiments for this simulation. */ - public void run() { + public void execute() { for (int i = 0; i < measurementSuite.getSamples(); ++i) { - threads[i].start(); + simulations[i].start(); } for (int i = 0; i < measurementSuite.getSamples(); ++i) { try { - threads[i].join(); + simulations[i].join(); } catch (InterruptedException ex) { ex.printStackTrace(); @@ -130,10 +90,9 @@ public class Simulation extends Thread implements AlgorithmListener { } measurementSuite.getOutputBuffer().close(); measurementSuite = null; - algorithms = null; + simulations = null; progress = null; progressListeners = null; - threads = null; } /** @@ -141,14 +100,14 @@ public class Simulation extends Thread implements AlgorithmListener { */ public void terminate() { for (int i = 0; i < measurementSuite.getSamples(); ++i) { - algorithms[i].terminate(); + simulations[i].terminate(); } } /** * Adds a listener for progress events. A progress is fired periodically based on the resolution * of the measurements. {@see ProgressEvent} {@see ProgressListener} - * @param The event listener + * @param listener The event listener */ public void addProgressListener(ProgressListener listener) { progressListeners.add(listener); @@ -156,7 +115,7 @@ public class Simulation extends Thread implements AlgorithmListener { /** * Removes a listener for progress events. - * @param The event listener + * @param listener The event listener */ public void removeProgressListener(ProgressListener listener) { progressListeners.remove(listener); @@ -175,22 +134,25 @@ public class Simulation extends Thread implements AlgorithmListener { } } - public void algorithmStarted(AlgorithmEvent e) { - } - - public void algorithmFinished(AlgorithmEvent e) { - measurementSuite.measure(e.getSource()); - progress.put(e.getSource(), new Double(e.getSource().getPercentageComplete())); + /** + * Indicate that the provided {@code Simulation} has completed. + * @param simulation The {@code simulation} which has completed. + */ + void simulationFinished(Simulation simulation) { + measurementSuite.measure(simulation.getAlgorithm()); + progress.put(simulation, new Double(simulation.getAlgorithm().getPercentageComplete())); notifyProgress(); } - public void algorithmTerminated(AlgorithmEvent e) { - } - - public void iterationCompleted(AlgorithmEvent e) { - if (e.getSource().getIterations() % measurementSuite.getResolution() == 0) { - measurementSuite.measure(e.getSource()); - progress.put(e.getSource(), new Double(e.getSource().getPercentageComplete())); + /** + * Indicate that the provided {@code Simulation} has completed an iteration. + * @param simulation The {@code Simulation} that has completed an iteration. + */ + void simulationIterationCompleted(Simulation simulation) { + Algorithm algorithm = simulation.getAlgorithm(); + if (algorithm.getIterations() % measurementSuite.getResolution() == 0) { + measurementSuite.measure(simulation.getAlgorithm()); + progress.put(simulation, new Double(algorithm.getPercentageComplete())); notifyProgress(); } } diff --git a/src/test/java/net/sourceforge/cilib/xml/XMLFileTest.java b/src/test/java/net/sourceforge/cilib/xml/XMLFileTest.java index 9e1ab35..1cb0933 100644 --- a/src/test/java/net/sourceforge/cilib/xml/XMLFileTest.java +++ b/src/test/java/net/sourceforge/cilib/xml/XMLFileTest.java @@ -30,7 +30,7 @@ import javax.xml.parsers.ParserConfigurationException; import net.sourceforge.cilib.simulator.MeasurementSuite; import net.sourceforge.cilib.simulator.ProgressListener; import net.sourceforge.cilib.simulator.ProgressText; -import net.sourceforge.cilib.simulator.Simulation; +import net.sourceforge.cilib.simulator.Simulator; import org.junit.Test; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -79,7 +79,7 @@ public class XMLFileTest { XMLProblemFactory problemFactory = new XMLProblemFactory(doc, (Element) current.getElementsByTagName("problem").item(0)); XMLObjectFactory measurementsFactory = new XMLObjectFactory(doc, (Element) current.getElementsByTagName("measurements").item(0)); MeasurementSuite suite = (MeasurementSuite) measurementsFactory.newObject(); - Simulation simulation = new Simulation(algorithmFactory, problemFactory, suite); + Simulator simulation = new Simulator(algorithmFactory, problemFactory, suite); if(progress != null) { simulation.addProgressListener(progress); } -- 1.6.3.3 |