/******************************************************************************* * 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 "?"; } } }