/*
* Copyright (c) 2010-2011, IETR/INSA of Rennes
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the IETR/INSA of Rennes nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
package net.sf.orcc.simulators.slow;
import static net.sf.orcc.OrccLaunchConstants.DEFAULT_FIFO_SIZE;
import static net.sf.orcc.OrccLaunchConstants.ENABLE_TRACES;
import static net.sf.orcc.OrccLaunchConstants.FIFO_SIZE;
import static net.sf.orcc.OrccLaunchConstants.NO_DISPLAY;
import static net.sf.orcc.OrccLaunchConstants.PROJECT;
import static net.sf.orcc.OrccLaunchConstants.TRACES_FOLDER;
import static net.sf.orcc.OrccLaunchConstants.XDF_FILE;
import static net.sf.orcc.simulators.SimulatorsConstants.FRAMES_NUMBER;
import static net.sf.orcc.simulators.SimulatorsConstants.GOLDEN_REFERENCE;
import static net.sf.orcc.simulators.SimulatorsConstants.GOLDEN_REFERENCE_FILE;
import static net.sf.orcc.simulators.SimulatorsConstants.INPUT_STIMULUS;
import static net.sf.orcc.simulators.SimulatorsConstants.LOOP_NUMBER;
import static net.sf.orcc.simulators.SimulatorsConstants.OUTPUT_FILE;
import static net.sf.orcc.simulators.SimulatorsConstants.PROFILE;
import static net.sf.orcc.simulators.SimulatorsConstants.PROFILE_FOLDER;
import static net.sf.orcc.simulators.SimulatorsConstants.TYPE_RESIZER;
import static net.sf.orcc.simulators.SimulatorsConstants.TYPE_RESIZER_CAST_BOOLTOINT;
import static net.sf.orcc.simulators.SimulatorsConstants.TYPE_RESIZER_CAST_NATIVEPORTS;
import static net.sf.orcc.simulators.SimulatorsConstants.TYPE_RESIZER_CAST_TO2NBITS;
import static net.sf.orcc.simulators.SimulatorsConstants.TYPE_RESIZER_CAST_TO32BITS;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.SwingUtilities;
import net.sf.orcc.df.Actor;
import net.sf.orcc.df.Connection;
import net.sf.orcc.df.Network;
import net.sf.orcc.df.Port;
import net.sf.orcc.df.transform.Instantiator;
import net.sf.orcc.df.transform.NetworkFlattener;
import net.sf.orcc.df.transform.TypeResizer;
import net.sf.orcc.graph.Vertex;
import net.sf.orcc.ir.util.ActorInterpreter;
import net.sf.orcc.simulators.AbstractSimulator;
import net.sf.orcc.simulators.SimulatorDescriptor;
import net.sf.orcc.simulators.runtime.impl.GenericDisplay;
import net.sf.orcc.simulators.runtime.impl.GenericSource;
import net.sf.orcc.simulators.runtime.impl.GenericWriter;
import net.sf.orcc.simulators.runtime.std.video.impl.Display;
import net.sf.orcc.tools.stats.StatisticsPrinter;
import net.sf.orcc.util.FilesManager;
import net.sf.orcc.util.OrccLogger;
import net.sf.orcc.util.OrccUtil;
import net.sf.orcc.util.util.EcoreHelper;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
/**
* This class implements a simulator using a slow, visitor-based approach.
*
* @author Matthieu Wipliez
* @author Pierre-Laurent Lagalaye
*
*/
public class SlowSimulator extends AbstractSimulator {
private boolean enableTraces;
private boolean enableTypeResizer;
private String goldenReferenceFile;
private boolean hasGoldenReference;
protected Map<Actor, ActorInterpreter> interpreters;
private int loopsNumber;
private boolean noDisplay;
private boolean profile;
protected IProject project;
private String stimulusFile;
private String outputFile;
private String traceFolder;
private String profileFolder;
private final Boolean[] typeResizer = { false, false, false, false };
protected List<IFolder> vtlFolders;
protected String xdfFile;
/**
* Visit the network graph for building the required topology. Edges of the
* graph correspond to the connections between the actors. These connections
* should be implemented as FIFOs of specific size as defined in the CAL
* model or a common default size.
*
* @param graph
*/
@SuppressWarnings("unchecked")
public void connectNetwork(Network network) {
for (Connection connection : network.getConnections()) {
Actor src = connection.getSource().getAdapter(Actor.class);
Actor tgt = connection.getTarget().getAdapter(Actor.class);
Port srcPort = connection.getSourcePort();
Port tgtPort = connection.getTargetPort();
Integer fifoSize = connection.getSize();
int size = fifoSize == null ? getAttribute(FIFO_SIZE, DEFAULT_FIFO_SIZE) : fifoSize;
if (src == null || tgt == null || srcPort == null
|| tgtPort == null) {
OrccLogger.warnln("The connection " + connection + " cannot "
+ "be connected to a pair of actors.");
break;
}
String name = src.getName() + "." + srcPort.getName() + " --> "
+ tgt.getName() + "." + tgtPort.getName();
SimulatorFifo fifo = new SimulatorFifo(srcPort.getType(), size,
traceFolder, name, enableTraces, profile);
tgtPort.setAttribute("fifo", fifo);
List<SimulatorFifo> fifos;
if (srcPort.hasAttribute("fifo")) {
fifos = (List<SimulatorFifo>) srcPort.getAttribute("fifo")
.getObjectValue();
} else {
fifos = new ArrayList<SimulatorFifo>();
srcPort.setAttribute("fifo", fifos);
}
fifos.add(fifo);
connection.setAttribute("fifo", fifo);
}
// print a warning message if there are some unconnected ports
for (Actor actor : network.getAllActors()) {
// check input ports
for (Port port : actor.getInputs()) {
if (port.getAttribute("fifo") == null) {
OrccLogger.warnln("Unconnected Input Port ["
+ port.getName() + "] on Actor "
+ actor.getSimpleName());
}
}
// check output ports
for (Port port : actor.getOutputs()) {
if (port.getAttribute("fifo") == null) {
OrccLogger.warnln("Unconnected Output Port ["
+ port.getName() + "] on Actor "
+ actor.getSimpleName());
}
}
}
}
/**
* Visits the network and creates one interpreter per actor.
*
* @param network
* the network
*/
protected void createInterpreters(Network network) {
for (Vertex vertex : network.getChildren()) {
Actor actor = vertex.getAdapter(Actor.class);
ConnectedActorInterpreter interpreter = new ConnectedActorInterpreter(
actor);
interpreters.put(actor, interpreter);
}
}
protected void initializeNetwork(Network network) {
GenericSource.setInputStimulus(stimulusFile);
GenericSource.setNbLoops(loopsNumber);
GenericWriter.setOutputFile(outputFile);
if (hasGoldenReference) {
GenericDisplay.setGoldenReference(goldenReferenceFile);
}
if (noDisplay) {
GenericDisplay.setDisplayDisabled();
}
for (Vertex vertex : network.getChildren()) {
Actor actor = vertex.getAdapter(Actor.class);
ActorInterpreter interpreter = interpreters.get(actor);
interpreter.initialize();
}
}
@Override
protected void initializeOptions() {
stimulusFile = getAttribute(INPUT_STIMULUS, "");
String outputDir = getAttribute(OUTPUT_FILE, "");
outputFile = outputDir.equals("") ? "" : outputDir + "/orcc-simulation-out";
hasGoldenReference = getAttribute(GOLDEN_REFERENCE, false);
goldenReferenceFile = getAttribute(GOLDEN_REFERENCE_FILE, "");
xdfFile = getAttribute(XDF_FILE, "");
String name = getAttribute(PROJECT, "");
enableTraces = getAttribute(ENABLE_TRACES, false);
traceFolder = getAttribute(TRACES_FOLDER, "");
profile = getAttribute(PROFILE, false);
profileFolder = getAttribute(PROFILE_FOLDER, "");
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
project = root.getProject(name);
vtlFolders = OrccUtil.getOutputFolders(project);
loopsNumber = getAttribute(LOOP_NUMBER, DEFAULT_NB_LOOPS);
GenericDisplay.nbFrames = getAttribute(FRAMES_NUMBER, DEFAULT_NB_FRAMES);
noDisplay = getAttribute(NO_DISPLAY, false);
enableTypeResizer = getAttribute(TYPE_RESIZER, false);
typeResizer[0] = getAttribute(TYPE_RESIZER_CAST_TO2NBITS, false);
typeResizer[1] = getAttribute(TYPE_RESIZER_CAST_TO32BITS, false);
typeResizer[2] = getAttribute(TYPE_RESIZER_CAST_NATIVEPORTS, false);
typeResizer[3] = getAttribute(TYPE_RESIZER_CAST_BOOLTOINT, false);
stopRequested = false;
statusCode = 0;
}
/**
* Kill simulator descriptors and close the display with associated objects
* if necessary
*/
protected void killDescriptors() {
Runnable killer = new Runnable() {
@Override
public void run() {
SimulatorDescriptor.killDescriptors();
Display.clearAll();
}
};
SwingUtilities.invokeLater(killer);
}
@Override
public void run() {
try {
killDescriptors();
interpreters = new HashMap<Actor, ActorInterpreter>();
IFile file = OrccUtil.getFile(project, xdfFile,
OrccUtil.NETWORK_SUFFIX);
ResourceSet set = new ResourceSetImpl();
Network network = EcoreHelper.getEObject(set, file);
// full instantiation (no more instances)
new Instantiator(true).doSwitch(network);
// flattens network
new NetworkFlattener().doSwitch(network);
// if required, use the type sizer transformation
if (enableTypeResizer) {
new TypeResizer(typeResizer[0], typeResizer[1], typeResizer[2],
typeResizer[3]).doSwitch(network);
}
// create interpreters, connect network, initialize, and run
createInterpreters(network);
connectNetwork(network);
initializeNetwork(network);
SimulationEndOrigin returnStatus = runNetwork(network);
killDescriptors();
if (returnStatus == SimulationEndOrigin.EXTERNALSTOP) {
OrccLogger
.traceln("Simulation aborted (from application control).");
} else {
OrccLogger.traceln("End of simulation");
OrccLogger.traceln("Simulation returned status code "
+ statusCode);
}
if (profile) {
CharSequence content = new StatisticsPrinter().getContent(network);
FilesManager.writeFile(content, profileFolder, network.getSimpleName() + ".csv");
}
} finally {
// clean up to prevent memory leak
interpreters = null;
}
}
protected SimulationEndOrigin runNetwork(Network network) {
boolean hasExecuted;
do {
hasExecuted = false;
for (Vertex vertex : network.getChildren()) {
int nbFiring = 0;
Actor actor = vertex.getAdapter(Actor.class);
ActorInterpreter interpreter = interpreters.get(actor);
while (interpreter.schedule()) {
// check for cancelation
if (isStopped()) {
return SimulationEndOrigin.EXTERNALSTOP;
}
nbFiring++;
}
hasExecuted |= (nbFiring > 0);
// check for cancelation
if (isStopped()) {
return SimulationEndOrigin.EXTERNALSTOP;
}
}
} while (hasExecuted);
return SimulationEndOrigin.NORMALEND;
}
}