Skip to content

Commit

Permalink
Commit on the runtime of simulations and synchronizations with displays
Browse files Browse the repository at this point in the history
- all the management done with ExecutorService (for simulations) and
volatile boolean variables (for the rendition of displays) is replaced
by (simpler) semaphores;
- The acquisition of the semaphores now occur at more relevant places
(allowing to synchronize also the 2D/3D renderer threads for a more
accurate synchronization -- see #124).
- Each simulation now keeps its own thread throughout the experiment:
easier for debugging, and also makes it possible to define ThreadLocal
variables in shared objects (in skills, for instance) that will remain
attached to the simulation

*** LOTS OF TESTS ARE NECESSARY TO ENSURE THAT IT CAN BE A GOOD
FOUNDATION FOR THE GAMA RUNTIME ***

Known issues:
- no time out is set (yet) for the acquisition of the semaphore, which
can potentially lead to infinite loop/wait when the rendition is not
done properly
- the max. number of threads to use for the execution of simulations is
not (yet) respected
- errors are visible in the console when exiting GAMA and a simulation
is running.
- the release of signals from the semaphores is not fair (yet).
- the problem where a chart in 2d slows down all the other displays when
the mouse or keyboard events are targeted to it is not (yet) solved.
  • Loading branch information
AlexisDrogoul committed Mar 21, 2024
1 parent 90a39b1 commit c379aba
Show file tree
Hide file tree
Showing 19 changed files with 525 additions and 258 deletions.
31 changes: 16 additions & 15 deletions gama.core/src/gama/core/common/interfaces/IDisplaySurface.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/*******************************************************************************************************
*
* IDisplaySurface.java, in gama.core, is part of the source code of the GAMA modeling and simulation platform
* .
* (v.2024-06).
*
* (c) 2007-2024 UMI 209 UMMISCO IRD/SU & Partners (IRIT, MIAT, TLU, CTU)
* (c) 2007-2024 UMI 209 UMMISCO IRD/SU & Partners (IRIT, MIAT, ESPACE-DEV, CTU)
*
* Visit https://github.com/gama-platform/gama for license information and contacts.
*
Expand All @@ -15,6 +15,7 @@
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.util.Collection;
import java.util.concurrent.Semaphore;

import org.locationtech.jts.geom.Envelope;

Expand All @@ -23,8 +24,8 @@
import gama.core.metamodel.shape.GamaPoint;
import gama.core.metamodel.shape.IShape;
import gama.core.outputs.LayeredDisplayData;
import gama.core.outputs.LayeredDisplayOutput;
import gama.core.outputs.LayeredDisplayData.DisplayDataListener;
import gama.core.outputs.LayeredDisplayOutput;
import gama.core.outputs.layers.IEventLayerListener;
import gama.core.runtime.IScope.IGraphicsScope;
import gama.gaml.statements.draw.DrawingAttributes;
Expand Down Expand Up @@ -108,9 +109,19 @@ public interface OpenGL extends IDisplaySurface {
BufferedImage getImage(int width, int height);

/**
* Asks the surface to update its display, optionnaly forcing it to do so (if it is paused, for instance)
* Asks the surface to update its display, optionnaly forcing it to do so (if it is paused, for instance). A
* synchronizer (possibly null) is passed, that needs to be released when the physical display is done
**/
void updateDisplay(boolean force);
void updateDisplay(boolean force, Semaphore synchronizer);

/**
* Update display.
*
* @param force the force
*/
default void updateDisplay(final boolean force) {
updateDisplay(force, null);
}

/**
* Sets a concrete menu manager to be used for displaying menus on this surface
Expand Down Expand Up @@ -325,16 +336,6 @@ default GamaPoint getModelCoordinatesFrom(final int xOnScreen, final int yOnScre
*/
int getFPS();

/**
* @return true if the surface is considered as "realized" (i.e. displayed on the UI)
*/
// boolean isRealized();

/**
* @return true if the surface has been "rendered" (i.e. all the layers have been displayed)
*/
// boolean isRendered();

/**
* @return true if the surface has been 'disposed' already
*/
Expand Down
4 changes: 1 addition & 3 deletions gama.core/src/gama/core/kernel/experiment/BatchAgent.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import gama.annotations.precompiler.GamlAnnotations.doc;
import gama.annotations.precompiler.GamlAnnotations.experiment;
import gama.core.common.interfaces.IKeyword;
import gama.core.common.interfaces.IScopedStepable;
import gama.core.kernel.batch.exploration.AExplorationAlgorithm;
import gama.core.kernel.batch.optimization.AOptimizationAlgorithm;
import gama.core.kernel.experiment.IParameter.Batch;
Expand Down Expand Up @@ -331,8 +330,7 @@ public IMap<ParametersSet, Map<String, List<Object>>> launchSimulationsWithSolut
while (pop.hasScheduledSimulations() && !dead) {
// We step all the simulations
pop.step(getScope());
for (final IScopedStepable st : new ArrayList<>(pop.getActiveStepables())) {
final SimulationAgent agent = (SimulationAgent) st;
for (final SimulationAgent agent : new ArrayList<>(pop.getRunningSimulations())) {
ParametersSet ps = simToParameter.get(agent);
currentSolution = new ParametersSet(ps);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/*******************************************************************************************************
*
* SimulationPopulation.java, in gama.core, is part of the source code of the GAMA modeling and simulation platform
* .
* (v.2024-06).
*
* (c) 2007-2024 UMI 209 UMMISCO IRD/SU & Partners (IRIT, MIAT, TLU, CTU)
* (c) 2007-2024 UMI 209 UMMISCO IRD/SU & Partners (IRIT, MIAT, ESPACE-DEV, CTU)
*
* Visit https://github.com/gama-platform/gama for license information and contacts.
*
Expand All @@ -17,7 +17,6 @@
import java.util.Set;

import gama.core.common.interfaces.IKeyword;
import gama.core.common.interfaces.IScopedStepable;
import gama.core.kernel.experiment.ExperimentAgent;
import gama.core.kernel.experiment.ExperimentPlan;
import gama.core.metamodel.agent.IAgent;
Expand All @@ -28,8 +27,9 @@
import gama.core.runtime.GAMA;
import gama.core.runtime.IScope;
import gama.core.runtime.concurrent.GamaExecutorService;
import gama.core.runtime.concurrent.SimulationRunner;
import gama.core.runtime.concurrent.GamaExecutorService.Caller;
import gama.core.runtime.concurrent.ISimulationRunner;
import gama.core.runtime.concurrent.SimulationRunner;
import gama.core.runtime.exceptions.GamaRuntimeException;
import gama.core.util.GamaListFactory;
import gama.core.util.IList;
Expand All @@ -48,7 +48,7 @@ public class SimulationPopulation extends GamaPopulation<SimulationAgent> {
private SimulationAgent currentSimulation;

/** The runner. */
private final SimulationRunner runner;
private final ISimulationRunner runner;

/**
* Instantiates a new simulation population.
Expand Down Expand Up @@ -109,7 +109,8 @@ protected void fireAgentRemoved(final IScope scope, final IAgent old) {

@Override
public void initializeFor(final IScope scope) {
super.initializeFor(scope);
computeTopology(scope);
if (topology != null) { topology.initialize(scope, this); }
this.currentAgentIndex = 0;
}

Expand Down Expand Up @@ -250,7 +251,7 @@ public void unscheduleSimulation(final SimulationAgent sim) {
*
* @return the number of active stepables
*/
public Set<IScopedStepable> getActiveStepables() { return runner.getStepable(); }
public Set<SimulationAgent> getRunningSimulations() { return runner.getStepable(); }

/**
* Gets the number of active threads.
Expand Down
18 changes: 1 addition & 17 deletions gama.core/src/gama/core/outputs/AbstractOutput.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public abstract class AbstractOutput extends Symbol implements IOutput {
private IScope outputScope;

/** The permanent. */
boolean paused, open, permanent = false;
volatile boolean paused, open, permanent, disposed = false;

/** The is user created. */
private boolean isUserCreated = true;
Expand All @@ -58,12 +58,6 @@ public abstract class AbstractOutput extends Symbol implements IOutput {
/** The virtual. */
final boolean virtual;

/** The rendered. */
volatile boolean rendered;

/** The disposed. */
protected boolean disposed = false;

/** The view. */
protected IGamaView view;

Expand Down Expand Up @@ -247,9 +241,6 @@ void setPermanent() {
permanent = true;
}

@Override
public void setRendered(final boolean b) { rendered = b; }

/**
* Checks if is permanent.
*
Expand All @@ -275,13 +266,6 @@ protected boolean shouldOpenView() {
@Override
public IGamaView getView() { return view; }

@Override
public boolean isRendered() {
if (view != null && !view.isVisible()) return true;
if (!this.isRefreshable() || !this.isOpen() || this.isPaused()) return true;
return rendered;
}

@Override
public void dispose() {
if (disposed) return;
Expand Down
35 changes: 7 additions & 28 deletions gama.core/src/gama/core/outputs/AbstractOutputManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import gama.core.util.GamaMapFactory;
import gama.core.util.IMap;
import gama.dev.DEBUG;
import gama.dev.THREADS;
import gama.gaml.compilation.ISymbol;
import gama.gaml.compilation.Symbol;
import gama.gaml.descriptions.IDescription;
Expand Down Expand Up @@ -63,7 +62,8 @@ public abstract class AbstractOutputManager extends Symbol implements IOutputMan
LayoutStatement layout;

/** The outputs. */
protected final Map<String, IOutput> outputs = GamaMapFactory.synchronizedOrderedMap();
protected final Map<String, IOutput> outputs = GamaMapFactory.create();
// GamaMapFactory.synchronizedOrderedMap();

// protected final IList<MonitorOutput> monitors = GamaListFactory.create();

Expand Down Expand Up @@ -118,12 +118,7 @@ public void add(final IOutput output) {
hasMonitors |= output instanceof MonitorOutput;
if (output.isVirtual()) {
virtualOutputs.put(output.getId(), output);
}
// else if (output instanceof MonitorOutput monitor
// && GamaPreferences.Interface.CORE_MONITOR_PARAMETERS.getValue()) {
// monitors.add(monitor);
// }
else {
} else {
synchronized (outputs) {
outputs.put(output.getId(), output);
}
Expand All @@ -137,10 +132,9 @@ public synchronized void dispose() {
// AD: explicit addition of an ArrayList to prevent dispose errors
// (when outputs remove themselves from the list)
GAMA.desynchronizeFrontmostExperiment();
synchronized (outputs) {
for (final IOutput output : new ArrayList<>(outputs.values())) { output.dispose(); }
}
// for (final IOutput output : new ArrayList<>(monitors)) { output.dispose(); }
// synchronized (outputs) {
for (final IOutput output : new ArrayList<>(outputs.values())) { output.dispose(); }
// }
clear();
} catch (final Exception e) {
e.printStackTrace();
Expand Down Expand Up @@ -303,27 +297,12 @@ protected boolean initialStep(final IScope scope, final IOutput output) {

@Override
public boolean step(final IScope scope) {
getOutputs().forEach((n, each) -> { each.setRendered(false); });
outputs.forEach((name, each) -> {
if (each instanceof LayeredDisplayOutput ldo) { ldo.linkScopeWithGraphics(); }
if (each.isRefreshable() && each.getScope().step(each).passed()) { each.update(); }
});
if (GAMA.isSynchronized() && !inInitPhase) {
while (!allOutputsRendered()) {
THREADS.WAIT(20, "The outputs are not rendered yet", "AbstractOutputManager.step() interrupted");
}
}
evaluateAutoSave(scope);
return true;
}

/**
* All outputs rendered.
*
* @return true, if successful
*/
protected boolean allOutputsRendered() {
for (IOutput each : outputs.values()) { if (!each.isRendered()) return false; }
evaluateAutoSave(scope);
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,6 @@ public AbstractValuedDisplayOutput(final IDescription desc) {
expressionText = getValue() == null ? "" : getValue().serializeToGaml(false);
}

@Override
public boolean isRendered() { return true; }

/**
* Gets the last value.
*
Expand Down
54 changes: 28 additions & 26 deletions gama.core/src/gama/core/outputs/IOutput.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

/**
* This interface represents the objects, declared in a model, which perform various types of computations and return
* information supposed to be displayed or saved during simulations. Outputs are not in charge of displaying/outputting
* information supposed to be displayed during simulations. Outputs are not in charge of displaying/outputting
* information on a concrete support, only computing it. They however control whatever concrete support they represent
* (opening, closing, pausing, updating and refreshing it).
*
Expand Down Expand Up @@ -48,8 +48,8 @@ public interface IOutput extends ISymbol, IStepable, IScoped {
boolean isPaused();

/**
* In response to this message, the output is supposed to open its concrete support, whether it is a view or a file.
* Sending open() to an already opened output should not have any effect.
* In response to this message, the output is supposed to open its concrete support. Sending open() to an already
* opened output should not have any effect.
*/
void open();

Expand All @@ -61,8 +61,8 @@ public interface IOutput extends ISymbol, IStepable, IScoped {
boolean isOpen();

/**
* In response to this message, the output is supposed to close its concrete support, whether it is a view or a
* file. A closed output cannot resume its operations unless 'open()' is called again.
* In response to this message, the output is supposed to close its concrete support. A closed output cannot resume
* its operations unless 'open()' is called again.
*/
void close();

Expand Down Expand Up @@ -100,7 +100,7 @@ public interface IOutput extends ISymbol, IStepable, IScoped {

/**
* Returns the original name of the output (as it has been declared by the modeler). This name can be changed later
* to accomoadate different display configuration in the UI
* to accomodate different display configuration in the UI
*
* @return the string representing the original (unaltered) name of the output as defined by the modeler
*/
Expand All @@ -109,7 +109,7 @@ public interface IOutput extends ISymbol, IStepable, IScoped {
/**
* Returns the identifier (should be unique) of this output
*
* @return a string representing the unique identifier of this output (especially important for UI outputs)
* @return a string representing the unique identifier of this output
*/
String getId();

Expand All @@ -131,8 +131,8 @@ public interface IOutput extends ISymbol, IStepable, IScoped {
void setUserCreated(boolean b);

/**
* If only one output of this kind is allowed in the UI (i.e. there can only be one instance of the corresponding
* view), the output should return true
* If only one output of this kind is allowed (i.e. there can only be one instance of the corresponding concrete
* support), the output should return true
*
* @return true if only one view for this kind of output is possible, false otherwise
*/
Expand All @@ -156,31 +156,33 @@ public interface IOutput extends ISymbol, IStepable, IScoped {
boolean isVirtual();

/**
* Checks if is auto save.
* Checks if is auto save. This default method always returns false.
*
* @return true, if is auto save
*/
default boolean isAutoSave() { return false; }

/**
* Returns the GamaView associated with this output
*/

IGamaView getView();

/**
* Checks if is rendered.
* Returns the GamaView associated with this output, if any
*
* @return true, if is rendered
* @return an instance of IGamaView or null if no view is associated to this output
*/
boolean isRendered();

/**
* Sets the rendered.
*
* @param b
* the new rendered
*/
void setRendered(boolean b);
IGamaView getView();
//
// /**
// * Checks if this output has been rendered. This default method always returns true.
// *
// * @return true, if is rendered
// */
// default boolean isRendered() { return true; }
//
// /**
// * Sent by the view or any other representation of this output, to say whether it has been rendered already or not
// *
// * @param b
// * the new rendered
// */
// default void setRendered(final boolean b) {}

}
Loading

0 comments on commit c379aba

Please sign in to comment.