/*******************************************************************************
* Copyright 2012 Analog Devices, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
package com.analog.lyric.dimple.schedulers.dependencyGraph;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import com.analog.lyric.dimple.exceptions.DimpleException;
import com.analog.lyric.dimple.model.core.INode;
import com.analog.lyric.dimple.schedulers.dependencyGraph.helpers.Edge;
import com.analog.lyric.dimple.schedulers.dependencyGraph.helpers.LastUpdateGraph;
import com.analog.lyric.dimple.schedulers.scheduleEntry.EdgeScheduleEntry;
import com.analog.lyric.dimple.schedulers.scheduleEntry.IScheduleEntry;
import com.analog.lyric.dimple.schedulers.scheduleEntry.NodeScheduleEntry;
/*
* A single node in the StaticDependencyGraph.
* Corresponds to an IScheduleEntry object.
*/
public class StaticDependencyGraphNode
{
private int _phase;
private List<StaticDependencyGraphNode> _dependents = new ArrayList<StaticDependencyGraphNode>();
private int _numDependencies;
private int _numDependenciesLeft;
private IScheduleEntry _scheduleEntry;
private int _id = -1;
private static class Sentinel extends StaticDependencyGraphNode
{
private Sentinel()
{
super(bogusEntry());
}
// HACK to shut up null warnings
@NonNullByDefault(false)
private static IScheduleEntry bogusEntry()
{
return null;
}
@Override
public boolean isSentinel()
{
return true;
}
}
/*
* Provide empty constructor so we can generate a sentinel object for telling a thread
* when to stop working.
*/
private StaticDependencyGraphNode(IScheduleEntry entry)
{
_dependents = Collections.EMPTY_LIST;
_scheduleEntry = entry;
}
public static StaticDependencyGraphNode createSentinel()
{
return new Sentinel();
}
/*
* The constructor will set up dependencies.
* <p>
* @scheduleEntry must be either a {@link EdgeScheduleEntry} or a {@link NodeScheduleEntry}
*/
StaticDependencyGraphNode(IScheduleEntry scheduleEntry, LastUpdateGraph lastUpdateGraph, int id)
{
_phase = 0;
_scheduleEntry = scheduleEntry;
_id = id;
//retrievew all directed edges associated with this schedule entry.
//Will be all in/out edges for a node update. Will be all input edges
//except for one and an output edge for an edge update.
ArrayList<Edge> edges = lastUpdateGraph.getEdges(scheduleEntry);
//For each edge we find the last DependencyGraphNode that used that edge
//as an input or output.
for (Edge e : edges)
{
StaticDependencyGraphNode lastNode = lastUpdateGraph.getLastNode(e);
if (lastNode != null)
{
//Since someone has previously touched this edge, add myself as
//a dependent. My phase will be the largest phase before me + 1
_phase = Math.max(lastNode._phase+1, _phase);
lastNode.addDependent(this);
//Also increment the number of dependencies I have.
_numDependencies++;
_numDependenciesLeft++;
}
//Set self as last node to use this edge.
lastUpdateGraph.setLastNode(e,this);
}
}
/*
* Add a dependent.
*/
public void addDependent(StaticDependencyGraphNode node)
{
_dependents.add(node);
}
/*
* Retrieve the node associated with the schedule entry.
*/
public INode getNode()
{
if (_scheduleEntry instanceof EdgeScheduleEntry)
return ((EdgeScheduleEntry)_scheduleEntry).getNode();
else if (_scheduleEntry instanceof NodeScheduleEntry)
return ((NodeScheduleEntry)_scheduleEntry).getNode();
else
throw new DimpleException("Not supported");
}
/*
* Retrieve the dependent at the specified index.
*/
public StaticDependencyGraphNode getDependent(int num)
{
return _dependents.get(num);
}
/*
* Get the number of dependents.
*/
public int getNumDependents()
{
return _dependents.size();
}
/*
* The ID is used for plotting.
*/
public int getId()
{
return _id;
}
/*
* The schedule entry to be updated with this node.
*/
public IScheduleEntry getScheduleEntry()
{
return _scheduleEntry;
}
/*
* Indicates when this node can be updated.
*/
public int getPhase()
{
return _phase;
}
public int getNumDependenciesLeft()
{
return _numDependenciesLeft;
}
public void setNumDependenciesLeft(int num)
{
_numDependenciesLeft = num;
}
public int getNumDependencies()
{
return _numDependencies;
}
public boolean isSentinel()
{
return false;
}
/**
* Generate label for dependency node.
* @since 0.08
*/
public String getLabel()
{
switch (_scheduleEntry.type())
{
case EDGE:
{
EdgeScheduleEntry entry = (EdgeScheduleEntry)_scheduleEntry;
return String.format("[%s] -> %d -> [%s]",
entry.getNode(), entry.getPortNum(), entry.getPort().getSiblingNode());
}
case NODE:
{
NodeScheduleEntry entry = (NodeScheduleEntry)_scheduleEntry;
return String.format("[%s]", entry.getNode());
}
default:
return "?";
}
}
}