/// <summary> /// find the max latency /// </summary> /// <param name="sort">sorted list of vertices</param> /// <param name="graph">delay graph</param> /// <param name="registered">hash table of registered vertices</param> /// <returns>number of cycles</returns> internal static long FindMaxLatencyCore(IEnumerable <DelayGraphVertex> sort, DelayGraph graph, HashSet <DelayGraphVertex> registered) { long maxLatencyCost = 0; var table = new WaveFrontDictionary <long>(); foreach (var v in sort) { var inEdges = graph.GetForwardInEdges(v); var outEdges = graph.GetForwardOutEdges(v); int myRefCount = outEdges.Count(); // first, consume predecessor's wavefront data, if any long myCost = 0; foreach (var e in inEdges) { var p = e.Source; var c = table.Use(p); // default for long is 0 // copy data into myData myCost = Math.Max(myCost, c); } // then add v's latency cost myCost += GetLatencyCost(v, registered); // register myCost into table table.Define(v, myRefCount, myCost); // update maxLatencyCost if v has no outEdges if (myRefCount == 0 && maxLatencyCost < myCost) { maxLatencyCost = myCost; } } return(maxLatencyCost); }
/// <summary> /// Serializes a DelayGraph object to GraphML format. /// </summary> /// <param name="graph">DelayGraph to serialize</param> /// <param name="filePath">Path to write serialized delay graph</param> internal void Serialize(DelayGraph graph, string filePath) { _graph = graph; if (Path.GetExtension(filePath) != ".graphml") { filePath += ".graphml"; } using (StreamWriter outfile = new StreamWriter(filePath)) { // add file XML file header, graph header, properties, and parse info outfile.WriteLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); outfile.WriteLine("<!-- This file was generated from the DelayGraph object. -->"); outfile.WriteLine("<graphml xmlns=\"http://graphml.graphdrawing.org/xmlns\""); outfile.WriteLine(" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""); outfile.WriteLine(" xsi:schemaLocation=\"http://graphml.graphdrawing.org/xmlns"); outfile.WriteLine(" http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd\">"); SerializeVertexAndEdgeProperties(outfile); outfile.WriteLine(" <graph id=\"G\" edgedefault=\"directed\""); outfile.WriteLine(String.Format(CultureInfo.InvariantCulture, " parse.nodes=\"{0}\" parse.edges=\"{1}\"", _graph.VertexCount, _graph.EdgeCount)); outfile.WriteLine(" parse.nodeids=\"canonical\" parse.edgeids=\"canonical\""); // not including max indegree and max outdegree of nodes...I don't think we need to include this outfile.WriteLine(" parse.order=\"nodesfirst\">"); SerializeVertices(outfile); SerializeEdges(outfile); outfile.WriteLine(" </graph>"); outfile.WriteLine("</graphml>"); } }
/// <summary> /// Loads a DelayGraph object into memory from the specified serialized file. /// Uses native .NET formatters to deserialize the object. /// </summary> /// <param name="filepath">Path to a serialized DelayGraph object. This should be a binary file</param> /// <returns>Reconstructed DelayGraph object</returns> internal static DelayGraph DeserializeFromBinary(string filepath) { IFormatter formatter = new BinaryFormatter(); Stream stream = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.Read); DelayGraph dg = (DelayGraph)formatter.Deserialize(stream); stream.Close(); return(dg); }
/// <summary> /// find and return vertices without incoming forward edges /// </summary> /// <param name="graph">the delay graph</param> /// <returns>enumerable of vertices</returns> private static IEnumerable <DelayGraphVertex> FindTopoSortSeeds(DelayGraph graph) { foreach (var v in graph.Vertices) { if (!graph.GetForwardInEdges(v).Any()) { yield return(v); } } }
private static IEnumerable <DelayGraphVertex> GetFanouts(DelayGraphVertex v, DelayGraph graph) { IEnumerable <DelayGraphEdge> edges; if (graph.TryGetOutEdges(v, out edges)) { return(edges.Select(e => e.Target)); } return(Enumerable.Empty <DelayGraphVertex>()); }
/// <summary> /// minimum clock period due to edge delay values /// </summary> /// <param name="graph">a delay graph</param> /// <returns>a value</returns> internal static int MinClockPeriod(DelayGraph graph) { int maxPeriod = 0; foreach (var edge in graph.Edges) { maxPeriod = Math.Max(maxPeriod, edge.Delay); } return(maxPeriod); }
/// <summary> /// constructor for build DG solution /// </summary> /// <param name="graph">a delay graph</param> /// <param name="registeredTerminals">a hashset of nodes needing registered</param> internal DelayGraphSolution( DelayGraph graph, HashSet <DelayGraphVertex> registeredTerminals) { // for testing purposes Graph = graph; RegisteredTerminals = registeredTerminals; FoundComboCycle = false; Slack = 0; Score = null; }
/// <summary> /// Serializes a delay graph into a binary file using native .NET formatters. /// </summary> /// <param name="graph">DelayGraph to serialize</param> /// <param name="filePath">Path to write serialized delay graph</param> internal void Serialize(DelayGraph graph, string filePath) { _graph = graph; if (Path.GetExtension(filePath) != ".bin") { filePath += ".bin"; } IFormatter formatter = new BinaryFormatter(); Stream stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None); formatter.Serialize(stream, _graph); stream.Close(); }
/// <summary> /// return a topologically sorted ienumerable of vertices - according to only non-feedback edges /// </summary> /// <param name="graph">the delay graph</param> /// <returns>an enumerable of vertices, sorted in forward edge topological ordering</returns> internal static IEnumerable <DelayGraphVertex> TopologicalSort(DelayGraph graph) { var sorted = new LinkedList <DelayGraphVertex>(); var visited = new Dictionary <DelayGraphVertex, VisitState>(); var todo = FindTopoSortSeeds(graph); foreach (var v in todo) { if (!TopoIterative(v, sorted, visited, graph)) { throw new Exception("Unexpected bad topological seed"); } } return(sorted); }
/// <summary> /// Recreates a DelayGraph object from a graphml file. /// TODO: verify the graphml against a schema /// </summary> /// <param name="graphml">location of the graphml file on disk</param> /// <returns>Deserialized DelayGraph object</returns> internal static DelayGraph DeserializeFromGraphMl(string graphml) { XDocument doc = XDocument.Load(graphml); var nmsp = "{http://graphml.graphdrawing.org/xmlns}"; DelayGraph delayGraph = new DelayGraph(); if (doc.Root != null) { var graph = doc.Root.Element(nmsp + "graph"); var nodeIdToVertexMap = RecreateVertices(graph, nmsp, delayGraph); RecreateEdges(graph, nmsp, nodeIdToVertexMap, delayGraph); } return(delayGraph); }
/// <summary> /// prune edges from same source/target, keeping the strongr edge /// </summary> /// <param name="graph">a delay graph</param> /// <returns>whether DG has changed</returns> internal static bool PruneEdges(DelayGraph graph) { bool changed = false; foreach (var vertex in graph.Vertices) { IEnumerable <DelayGraphEdge> edges; if (!graph.TryGetOutEdges(vertex, out edges)) { continue; } if (edges.Count() < 2) { continue; } // check for redundant out edges var targets = new Dictionary <DelayGraphVertex, DelayGraphEdge>(); foreach (var edge in edges.ToList()) { DelayGraphEdge prevEdge; if (targets.TryGetValue(edge.Target, out prevEdge)) { // decide which edge to keep and which to delete if (prevEdge.Delay >= edge.Delay) { // keep prev edge graph.RemoveEdge(edge); } else { targets[edge.Target] = edge; graph.RemoveEdge(prevEdge); } changed = true; } else { targets[edge.Target] = edge; } } } return(changed); }
/// <summary> /// a constructor for DG solution /// </summary> /// <param name="solutionName">The name of this solution</param> /// <param name="graph">a delay graph</param> /// <param name="registeredTerminals">vertices which are registered</param> /// <param name="targetClockPeriod">target clock period in PS</param> internal DelayGraphSolution( string solutionName, DelayGraph graph, HashSet <DelayGraphVertex> registeredTerminals, int targetClockPeriod) { Graph = graph; RegisteredTerminals = registeredTerminals; int errors = FixSolutionForSiblingVertices(); if (errors > 0) { Console.WriteLine("Warning: There are " + errors + " errors in inconsistent input assignments in " + solutionName); } bool foundCycle; int clockPeriod = EstimatePeriod(out foundCycle); if (foundCycle) { // try to fix cycles and then recalc period FixSolutionForComboCycles(); clockPeriod = EstimatePeriod(out foundCycle); Console.WriteLine("Warning: Fixing combo cycles in " + solutionName); } FoundComboCycle = foundCycle; Slack = targetClockPeriod - clockPeriod; long throughput, latency, registers; SumCosts(out throughput, out latency, out registers); Score = new ScoreCard(throughput, latency, registers); }
private static Dictionary <String, DelayGraphVertex> RecreateVertices(XElement graph, String nmsp, DelayGraph delayGraph) { var nodeIdToVertexMap = new Dictionary <String, DelayGraphVertex>(); var vertexType = typeof(DelayGraphVertex); // todo: update this map if new properties are added...or use "CreatePropertyTypeMap" below var propertyToTypeMap = new Dictionary <String, Type>() { { "VertexId", typeof(int) }, { "NodeType", typeof(int) }, { "NodeUniqueId", typeof(int) }, { "ThroughputCostIfRegistered", typeof(long) }, { "LatencyCostIfRegistered", typeof(long) }, { "RegisterCostIfRegistered", typeof(long) }, { "IsRegistered", typeof(bool) }, { "IsInputTerminal", typeof(bool) }, { "IsOutputTerminal", typeof(bool) }, { "DisallowRegister", typeof(bool) } }; // get the nodes foreach (var node in graph.Elements(nmsp + "node")) { // create new vertex var vertex = new DelayGraphVertex(); var id = (string)node.Attribute("id"); nodeIdToVertexMap.Add(id, vertex); // populate the fields of the node foreach (var data in node.Elements()) { var key = (string)data.Attribute("key"); dynamic contents = Convert.ChangeType(data.Value, propertyToTypeMap[key], CultureInfo.InvariantCulture); vertexType.GetProperty(key).SetValue(vertex, contents); } // add the node to the graph delayGraph.AddVertex(vertex); } return(nodeIdToVertexMap); }
/// <summary> /// find and return the maximum cyclic throughput cost /// </summary> /// <param name="sort">topological sorted enumerable of vertices</param> /// <param name="graph">a delay graph</param> /// <param name="registered">a hash set containing registered vertices</param> /// <returns>a value representing maximum throughput cost of all cycles</returns> internal static long FindMaxThroughputCostCore(IEnumerable <DelayGraphVertex> sort, DelayGraph graph, HashSet <DelayGraphVertex> registered) { long maxCycleCost = 0; var table = new WaveFrontDictionary <Dictionary <DelayGraphVertex, long> >(); foreach (var v in sort) { var inEdges = graph.GetForwardInEdges(v); var outEdges = graph.GetForwardOutEdges(v); var feedbackInEdges = graph.GetFeedbackInEdges(v); var feedbackOutEdges = graph.GetFeedbackOutEdges(v); int myRefCount = outEdges.Count(); long cost = GetThroughputCost(v, registered); Dictionary <DelayGraphVertex, long> myData = null; // first, consume predecessor's wavefront data, if any foreach (var e in inEdges) { var p = e.Source; var data = table.Use(p); if (data == null) { continue; } // copy data into myData myData = GetOrMakeMyData(table, v, myRefCount, myData); UpdateMaxData(myData, data); } if (cost > 0 && myData != null) { // incr all costs in myData by cost foreach (var p in myData.Keys.ToList()) { myData[p] += cost; } } if (feedbackInEdges.Any()) { // v is start of cycle - enter v into myData myData = GetOrMakeMyData(table, v, myRefCount, myData); myData[v] = cost; } if (myData == null) { continue; } // update max cycle cost foreach (var e in feedbackOutEdges) { var p = e.Target; long cycleCost; if (myData.TryGetValue(p, out cycleCost) && cycleCost > maxCycleCost) { maxCycleCost = cycleCost; } } } return(maxCycleCost); }
/// <summary> /// group vertices which are inputs and outputs of common node ids /// </summary> /// <param name="graph">the delay graph</param> /// <param name="grouped">hash set of vertices which are grouped</param> /// <returns>list of lists of related vertices</returns> internal static IEnumerable <IEnumerable <DelayGraphVertex> > FindVertexGroups(DelayGraph graph, out HashSet <DelayGraphVertex> grouped) { // group vertices which are inputs and outputs of common node ids together // there are 3 types of vertices: IsRegistered, (!IsRegistered && IsInputTerminal), (!IsRegisted && !IsInputTerminal) // ignore IsRegistered vertices, and group the other types by common node id and types grouped = new HashSet <DelayGraphVertex>(); var inputs = graph.Vertices.Where(v => !v.IsRegistered && v.IsInputTerminal); var inputGroups = GroupVerticesByNodeId(inputs, grouped); var outputs = graph.Vertices.Where(v => !v.IsRegistered && !v.IsInputTerminal); var outputGroups = GroupVerticesByNodeId(outputs, grouped); return(inputGroups.Concat(outputGroups)); }
/// <summary> /// Iterative version of topological sort, of forward edges only /// </summary> /// <param name="v">a delay graph vertex</param> /// <param name="sorted">linked list of sorted list of vertices</param> /// <param name="visited">to keep track of vertices that have been visited previously</param> /// <param name="graph">the delay graph</param> /// <returns>return true iff v is processed as unvisited</returns> private static bool TopoIterative(DelayGraphVertex v, LinkedList <DelayGraphVertex> sorted, Dictionary <DelayGraphVertex, VisitState> visited, DelayGraph graph) { // add v to visited first, and if it is already visited, then bail if (visited.ContainsKey(v)) { return(false); } var stack = new Stack <DelayGraphVertex>(); visited[v] = VisitState.Queued; stack.Push(v); while (stack.Any()) { var curr = stack.Peek(); var status = visited[curr]; if (status == VisitState.Queued) { // first ever visit, queue all outgoing vertices visited[curr] = VisitState.Visiting; var outEdges = graph.GetForwardOutEdges(curr); foreach (var e in outEdges.Reverse()) { var next = e.Target; VisitState nextStatus; if (!visited.TryGetValue(next, out nextStatus) || nextStatus == VisitState.Queued) { // not visited yet, or previously queued, queue next visited[next] = VisitState.Queued; stack.Push(next); } else if (nextStatus == VisitState.Visiting) { // found a cycle - not supposed to happen - there is no good topological sort with cycles return(false); } // othewise: visited, no need to queue it again } } else if (status == VisitState.Visiting) { // second visit - all fanout have been processed already visited[curr] = VisitState.Visited; sorted.AddFirst(curr); stack.Pop(); } else { // visited - previously added to sorted already, just pop it stack.Pop(); } } return(true); }
/// <summary> /// Detect cycles in the vertices /// </summary> /// <param name="graph">a delay graph</param> /// <returns>list of lists of vertices</returns> internal static List <List <DelayGraphVertex> > DetectCycles(DelayGraph graph) { return(TarjanCycleDetect(graph.Vertices, getFanouts: (v => GetFanouts(v, graph)))); }
/// <summary> /// return a topologically sorted (according to non-feedback edges only) list of vertices /// </summary> /// <param name="v">a vertex</param> /// <param name="sorted">linked list of sorted list of vertices</param> /// <param name="visited">to keep track of vertices that have been visited previously</param> /// <param name="graph">the delay graph</param> /// <returns>return true iff v is processed as unvisited </returns> private static bool TopoRecursive(DelayGraphVertex v, LinkedList <DelayGraphVertex> sorted, HashSet <DelayGraphVertex> visited, DelayGraph graph) { // add v to visited first, and if it is already visited, then bail if (visited.Add(v)) { var outEdges = graph.GetForwardOutEdges(v); foreach (var e in outEdges) { TopoRecursive(e.Target, sorted, visited, graph); } // all fanout have been visited and added to sorted list - add v to start of sorted list sorted.AddFirst(v); return(true); } return(false); }
private static void RecreateEdges(XElement graph, String nmsp, Dictionary <String, DelayGraphVertex> nodeIdToVertexMap, DelayGraph delayGraph) { // get the edges foreach (var edge in graph.Elements(nmsp + "edge")) { var source = nodeIdToVertexMap[(string)edge.Attribute("source")]; var sink = nodeIdToVertexMap[(string)edge.Attribute("target")]; int delay = 0; bool isFeedback = false; var isDelay = true; // this should only execute twice foreach (var data in edge.Elements()) { if (isDelay) { delay = (int)data; isDelay = false; continue; } isFeedback = (bool)data; } var newEdge = new DelayGraphEdge(source, sink, delay, isFeedback); delayGraph.AddEdge(newEdge); } }
public static void Main(string[] args) { var algorithms = new List <Tuple <string, ILatencyAssignment> > { new Tuple <string, ILatencyAssignment>("asap", new LatencyAssignmentAsap()), new Tuple <string, ILatencyAssignment>("greedy", new LatencyAssignmentGreedy()), // add your own latency assigner here }; if (args.Length != 2) { Console.WriteLine("Error: Expecting two arguments and not " + args.Length); Console.WriteLine("Usage: RegisterPlacement.exe <Data Set Directory Root> <Directory For Scorecard>"); Console.WriteLine("This program explores subdirectories of <Data Set Directory Root> to find delay graph data sets to try with register placement algorithms."); Console.WriteLine("Various metrics are printed into the <Directory For Scorecard>."); return; } if (!Directory.Exists(args[0])) { Console.WriteLine("Error: Directory does not exist: " + args[0]); return; } string rootDataSetDir = Path.GetFullPath(args[0]); // convert from relative to absolute List <DataSet> dataSets = new List <DataSet>(); FindDataSets(rootDataSetDir, dataSets); if (!dataSets.Any()) { Console.WriteLine("Warning: No data sets found. Make sure DelayGraph*.graphml and corresponding DelayGraphOriginalGoals*.xml files exist somewhere in this hierarchy: " + args[0]); } string scoreCardDirectoy = args[1]; if (!Directory.Exists(scoreCardDirectoy)) { Directory.CreateDirectory(scoreCardDirectoy); } var algorithmNames = algorithms.Select(kv => kv.Item1).ToList(); foreach (var algorithmName in algorithmNames) { string filePath = GetScoreCardPath(scoreCardDirectoy, algorithmName); if (File.Exists(filePath)) { File.Delete(filePath); } using (StreamWriter stream = File.CreateText(filePath)) { stream.WriteLine("GraphPath, ThroughputCost, LatencyCost, RegisterCost, Slack, TargetPeriod, ResultingPeriod, ExecutionTime(ms)"); // column headers } } string dotDirectory = "DotFiles"; if (!Directory.Exists(dotDirectory)) { Directory.CreateDirectory(dotDirectory); } var overallScoreCards = new Dictionary <string, LatencyAssignerScoreCard>(); var isBest = new Dictionary <string, int>(); var isBestOrTied = new Dictionary <string, int>(); var failedTable = new Dictionary <string, int>(); foreach (var algorithmName in algorithms.Select(kv => kv.Item1)) { overallScoreCards[algorithmName] = new LatencyAssignerScoreCard(); isBest[algorithmName] = 0; isBestOrTied[algorithmName] = 0; failedTable[algorithmName] = 0; } int idx = 0; // index for test cases for debugging Stopwatch sw = new Stopwatch(); foreach (DataSet dataSet in dataSets) { foreach (var graphAndGoal in dataSet.GraphsAndGoalsFilePaths) { idx++; DelayGraph.DelayGraph graph = DelayGraphGraphMlSerializer.DeserializeFromGraphMl(graphAndGoal.GraphPath); XDocument doc = XDocument.Load(graphAndGoal.GoalPath); XElement clockRateElement = doc.Root.Element("TargetClockPeriodInPicoSeconds"); int originalTargetClockRate = int.Parse(clockRateElement.Value); if (DelayGraphSolution.PruneEdges(graph)) { Console.WriteLine("Successfully removed redundant edges in graph"); } int minClockPeriod = DelayGraphSolution.MinClockPeriod(graph); if (minClockPeriod > originalTargetClockRate) { originalTargetClockRate = minClockPeriod; } bool failed = false; var scoreCards = new Dictionary <string, LatencyAssignerScoreCard>(); foreach (var tuple in algorithms) { string algorithmName = tuple.Item1; var algorithm = tuple.Item2; sw.Restart(); HashSet <DelayGraphVertex> registeredTerminals = algorithm.Execute(graph, originalTargetClockRate); double milliseconds = sw.Elapsed.TotalMilliseconds; sw.Stop(); var solutionName = Path.GetFileNameWithoutExtension(graphAndGoal.GraphPath) + "." + algorithmName; DelayGraphSolution solution = new DelayGraphSolution(solutionName, graph, registeredTerminals, originalTargetClockRate); // for debugging var dotFileName = solutionName + ".dot"; var dotFilePath = Path.Combine(dotDirectory, dotFileName); solution.PrintDotFile(dotFilePath); bool cycle; int period = solution.EstimatePeriod(out cycle); if (cycle) { period = int.MaxValue; } int slack = originalTargetClockRate - period; if (slack < 0) { failed = true; failedTable[algorithmName]++; } long throughputCost, latencyCost, registerCost; solution.SumCosts( throughputTotalCost: out throughputCost, latencyTotalCost: out latencyCost, registersTotalCost: out registerCost); var scoreCard = new LatencyAssignerScoreCard(); scoreCard.RegisterResult(throughputCost, latencyCost, registerCost, period, slack, milliseconds); scoreCards[algorithmName] = scoreCard; } TabulateAndPrintReports(algorithmNames, scoreCardDirectoy, overallScoreCards, isBest, isBestOrTied, graphAndGoal, originalTargetClockRate, failed, scoreCards); } } PrintSummaryReport(algorithmNames, scoreCardDirectoy, overallScoreCards, isBest, isBestOrTied, failedTable); Console.WriteLine("Scorecards written to: " + Path.GetFullPath(scoreCardDirectoy)); Debug.WriteLine("Scorecards written to: " + Path.GetFullPath(scoreCardDirectoy)); }
/// <summary> /// compute the max latency cost from input to outputs of all forward paths /// </summary> /// <param name="graph">a delay graph</param> /// <param name="registered">a registered table</param> /// <returns>number of latency cycles</returns> internal static long FindMaxLatency(DelayGraph graph, HashSet <DelayGraphVertex> registered) { var sort = TopologicalSort(graph); return(FindMaxLatencyCore(sort, graph, registered)); }