/*
* Copyright (c) 2013, Abo Akademi University
* 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 Abo Akademi University 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.backends.promela.transform;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import net.sf.orcc.df.Action;
import net.sf.orcc.df.Actor;
import net.sf.orcc.df.Connection;
import net.sf.orcc.df.Network;
import net.sf.orcc.df.Port;
/**
* This class defines what different Actor schedules consume/produce and
* implements the basic functionality of a balance equation
*
* @author Johan Ersfolk
*/
public class ScheduleBalanceEq {
private Set<Scheduler> schedulers;
private Network network;
private Set<NodeInfo> nodeInfoSet = new HashSet<NodeInfo>();
private Map<Connection, ChannelInfo> conToChanMap = new HashMap<Connection, ScheduleBalanceEq.ChannelInfo>();
private Map<Actor, NodeInfo> instToNodeMap = new HashMap<Actor, ScheduleBalanceEq.NodeInfo>();
public class NodeInfo {
Actor actor = null;
Set<ChannelInfo> inChannels = new HashSet<ChannelInfo>();
Set<ChannelInfo> outChannels = new HashSet<ChannelInfo>();
Scheduler scheduler = null;
//Map<Schedule, Map<NodeInfo, Map<Schedule, Set<Integer>>>> balance = new HashMap<Schedule, Map<NodeInfo, Map<Schedule, Set<Integer>>>>();
}
public class ChannelInfo {
NodeInfo srcNode = null;
NodeInfo dstNode = null;
Port sctPort = null;
Port dstPort = null;
Connection connection = null;
Map<Schedule, Integer> nrReads=new HashMap<Schedule, Integer>();
Map<Schedule, Integer> nrWrites=new HashMap<Schedule, Integer>();
int smallestFifoSize=1;
}
public Map<Schedule, Integer> getReads(Connection con) {
return conToChanMap.get(con).nrReads;
}
public Map<Schedule, Integer> getWrites(Connection con) {
return conToChanMap.get(con).nrWrites;
}
public ScheduleBalanceEq(Set<Scheduler> schedulers, Network network) {
this.schedulers=schedulers;
this.network=network;
createTopology();
createChannelRates();
calculateSmallestFifoSize();
//calculateNodeBalances();
calculatePortSizes();
}
public Scheduler getScheduler(Actor a) {
return instToNodeMap.get(a).scheduler;
}
public Set<Actor> getActors() {
return instToNodeMap.keySet();
}
/**
* Return the instance that feed this channel or null if the instance var not generated
* @param Connection con
* @return Instance instance
*/
public Actor getSource(Connection con) {
try {
return conToChanMap.get(con).srcNode.actor;
} catch (NullPointerException e) {
return null;
}
}
public Actor getDestination(Connection con) {
try {
return conToChanMap.get(con).dstNode.actor;
} catch (NullPointerException e) {
return null;
}
}
/**
* Calculates the token rates by the different schedules
*/
private void createChannelRates() {
for(ChannelInfo cInfo : conToChanMap.values()) {
if (cInfo.srcNode!=null) {
for (Schedule sched : cInfo.srcNode.scheduler.getSchedules()) {
try {
int nr = sched.getPortWrites().get(cInfo.sctPort.getName()).size();
cInfo.nrWrites.put(sched, new Integer(nr));
}catch (NullPointerException e) {
cInfo.nrWrites.put(sched, new Integer(0));
}
}
}
if (cInfo.dstNode!=null) {
for (Schedule sched : cInfo.dstNode.scheduler.getSchedules()) {
try {
int nr = sched.getPortReads().get(cInfo.dstPort.getName()).size();
cInfo.nrReads.put(sched, new Integer(nr));
}catch (NullPointerException e) {
cInfo.nrReads.put(sched, new Integer(0));
}
}
}
}
}
private void calculateSmallestFifoSize() {
for(ChannelInfo cInfo : conToChanMap.values()) {
Set<Integer> reads = new HashSet<Integer>();
Set<Integer> writes = new HashSet<Integer>();
if (cInfo.srcNode!=null) {
Actor actor = cInfo.srcNode.actor;
for (Action action : actor.getActions()) {
writes.add(action.getOutputPattern().getNumTokens(cInfo.sctPort));
}
}
if (cInfo.dstNode!=null) {
Actor actor = cInfo.dstNode.actor;
for (Action action : actor.getActions()) {
reads.add(action.getInputPattern().getNumTokens(cInfo.dstPort));
}
}
reads.remove(0); //skip these
writes.remove(0);
reads.add(1); //in case only connected to one actor
writes.add(1);
for (int r : reads) {
for (int w : writes) {
int lcm=lcm(r,w);
if (cInfo.smallestFifoSize<lcm) {
cInfo.smallestFifoSize=lcm;
}
}
}
cInfo.connection.setSize(cInfo.smallestFifoSize);
}
}
private int lcm(int i, int j) {
int mi = i;
int mj = j;
while (mi != mj) {
while (mi < mj) { mi += i; }
while (mi > mj) { mj += j; }
}
return mi;
}
/*private void calculateNodeBalances() {
//step one, neighbors according to queues
for (ChannelInfo ci : conToChanMap.values()) {
for (Schedule s1 : ci.nrReads.keySet()) {
for (Schedule s2 : ci.nrWrites.keySet()) {
}
}
}
}*/
private void calculatePortSizes() {
for (Actor actor : network.getAllActors()) {
for (Action action : actor.getActions()) {
for (Port port : action.getInputPattern().getPorts()) {
int nr = action.getInputPattern().getNumTokens(port);
int curr = port.getNumTokensConsumed();
nr = Math.max(nr, curr);
port.setNumTokensConsumed(nr);
}
for (Port port : action.getOutputPattern().getPorts()) {
int nr = action.getOutputPattern().getNumTokens(port);
int curr = port.getNumTokensProduced();
nr = Math.max(nr, curr);
port.setNumTokensProduced(nr);
}
}
}
}
private void createTopology() {
for (Actor actor : network.getAllActors()) {
NodeInfo newNode = new NodeInfo();
newNode.actor=actor;
instToNodeMap.put(actor, newNode);
nodeInfoSet.add(newNode);
for (Port p : actor.getOutgoingPortMap().keySet()) {
for (Connection con : actor.getOutgoingPortMap().get(p)) {
ChannelInfo cInfo;
if (conToChanMap.containsKey(con)) {
cInfo = conToChanMap.get(con);
} else {
cInfo = new ChannelInfo();
conToChanMap.put(con, cInfo);
}
cInfo.sctPort=p;
cInfo.srcNode=newNode;
cInfo.connection=con;
newNode.outChannels.add(cInfo);
}
}
for (Port p : actor.getIncomingPortMap().keySet()) {
ChannelInfo cInfo;
if (conToChanMap.containsKey(actor.getIncomingPortMap().get(p))) {
cInfo = conToChanMap.get(actor.getIncomingPortMap().get(p));
} else {
cInfo = new ChannelInfo();
conToChanMap.put(actor.getIncomingPortMap().get(p), cInfo);
}
cInfo.dstPort=p;
cInfo.dstNode=newNode;
cInfo.connection=actor.getIncomingPortMap().get(p);
newNode.inChannels.add(cInfo);
}
}
//also connect appropriate schedulers to the nodes
for (Scheduler scheduler : schedulers) {
instToNodeMap.get(scheduler.getActor()).scheduler=scheduler;
}
}
}