aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSchuyler Eldridge2019-12-18 15:05:02 -0500
committerSchuyler Eldridge2020-02-19 19:47:17 -0500
commita5aeea34d310970e1ea46ccf15155570bed466a8 (patch)
treece43682733aa90f3ec34a4602811ed96a13c71ae /src
parent7ea5b6e2f5660a79296bd627fe255148405123ee (diff)
Add dependency prettyPrint, visualization updates
This adds a prettyPrint method to the DependencyManager to enable textual visualization of the TransformLikes that a DependencyManager determines need to be run. This also cleans up the GraphViz visualization with better edge coloring and now uses the `name` method when labeling graphviz nodes. Signed-off-by: Schuyler Eldridge <schuyler.eldridge@ibm.com>
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/firrtl/options/DependencyManager.scala98
-rw-r--r--src/test/scala/firrtlTests/options/PhaseManagerSpec.scala1
2 files changed, 93 insertions, 6 deletions
diff --git a/src/main/scala/firrtl/options/DependencyManager.scala b/src/main/scala/firrtl/options/DependencyManager.scala
index 99d9c29c..dc23d3ce 100644
--- a/src/main/scala/firrtl/options/DependencyManager.scala
+++ b/src/main/scala/firrtl/options/DependencyManager.scala
@@ -18,6 +18,8 @@ case class DependencyManagerException(message: String, cause: Throwable = null)
* @tparam B the type of the [[firrtl.options.TransformLike TransformLike]]
*/
trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends TransformLike[A] with DependencyAPI[B] {
+ import DependencyManagerUtils.CharSet
+
override lazy val prerequisites = currentState
override lazy val dependents = Seq.empty
@@ -279,15 +281,15 @@ trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends
val connections =
Seq( (prerequisiteGraph, "edge []"),
- (dependentsGraph, """edge [color="#de2d26"]"""),
- (invalidateGraph, "edge [minlen=2,style=dashed,constraint=false]") )
+ (dependentsGraph, """edge [style=bold color="#4292c6"]"""),
+ (invalidateGraph, """edge [minlen=2 style=dashed constraint=false color="#fb6a4a"]""") )
.flatMap{ case (a, b) => toGraphviz(a, b) }
.mkString("\n")
val nodes =
(prerequisiteGraph + dependentsGraph + invalidateGraph + otherDependents)
.getVertices
- .map(v => s"""${transformName(v)} [label="${v.getClass.getName}"]""")
+ .map(v => s"""${transformName(v)} [label="${v.name}"]""")
s"""|digraph DependencyManager {
| graph [rankdir=BT]
@@ -311,8 +313,8 @@ trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends
def rec(pm: DependencyManager[A, B], cm: Seq[String], tab: String = "", id: Int = 0): (String, Int) = {
var offset = id
- val targets = pm._targets.toSeq.map(_.getName).mkString(", ")
- val state = pm._currentState.toSeq.map(_.getName).mkString(", ")
+ val targets = pm._targets.toSeq.map(_.name).mkString(", ")
+ val state = pm._currentState.toSeq.map(_.name).mkString(", ")
val header = s"""|${tab}subgraph cluster_$id {
|$tab label="targets: $targets\\nstate: $state"
@@ -327,7 +329,7 @@ trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends
case a =>
val name = s"""${transformName(a, "_" + id)}"""
sorted += name
- s"""$tab $name [label="${a.getClass.getName}"]"""
+ s"""$tab $name [label="${a.name}"]"""
}.mkString("\n")
(Seq(header, body, s"$tab}").mkString("\n"), offset)
@@ -341,6 +343,57 @@ trait DependencyManager[A, B <: TransformLike[A] with DependencyAPI[B]] extends
|}""".stripMargin
}
+ /** A method that can be overridden to define custom print handling. This is useful if you would like to make some
+ * transform print additional information.
+ * @param tab the current tab setting
+ * @param charSet the character set in use
+ * @param size the number of nodes at the current level of the tree
+ */
+ def customPrintHandling(
+ tab: String,
+ charSet: CharSet,
+ size: Int): Option[PartialFunction[(B, Int), Seq[String]]] = None
+
+ /** Helper utility when recursing during pretty printing
+ * @param tab an indentation string to use for every line of output
+ * @param charSet a collection of characters to use when printing
+ * @param preprocess a partial function that will be used before any other printing logic
+ */
+ def prettyPrintRec(tab: String, charSet: CharSet): Seq[String] = {
+
+ val (l, n, c) = (charSet.lastNode, charSet.notLastNode, charSet.continuation)
+ val last = transformOrder.size - 1
+
+ val defaultHandling: PartialFunction[(B, Int), Seq[String]] = {
+ case (a: DependencyManager[_, _], `last`) =>
+ Seq(s"$tab$l ${a.name}") ++ a.prettyPrintRec(s"""$tab${" " * c.size} """, charSet)
+ case (a: DependencyManager[_, _], _) => Seq(s"$tab$n ${a.name}") ++ a.prettyPrintRec(s"$tab$c ", charSet)
+ case (a, `last`) => Seq(s"$tab$l ${a.name}")
+ case (a, _) => Seq(s"$tab$n ${a.name}")
+ }
+
+ val handling = customPrintHandling(tab, charSet, transformOrder.size) match {
+ case Some(a) => a.orElse(defaultHandling)
+ case None => defaultHandling
+ }
+
+ transformOrder
+ .zipWithIndex
+ .flatMap(handling)
+ }
+
+ /** Textually show the determined transform order
+ * @param tab an indentation string to use for every line of output
+ * @param charSet a collection of characters to use when printing
+ */
+ def prettyPrint(
+ tab: String = "",
+ charSet: DependencyManagerUtils.CharSet = DependencyManagerUtils.PrettyCharSet): String = {
+
+ (Seq(s"$tab$name") ++ prettyPrintRec(tab, charSet)).mkString("\n")
+
+ }
+
}
/** A [[Phase]] that will ensure that some other [[Phase]]s and their prerequisites are executed.
@@ -364,3 +417,36 @@ object PhaseManager {
type PhaseDependency = Dependency[Phase]
}
+
+object DependencyManagerUtils {
+
+ /** A character set used for pretty printing
+ * @see [[PrettyCharSet]]
+ * @see [[ASCIICharSet]]
+ */
+ trait CharSet {
+ /** Used when printing the last node */
+ val lastNode: String
+
+ /** Used when printing a node that is NOT the last */
+ val notLastNode: String
+
+ /** Used while recursing into a node that is NOT the last */
+ val continuation: String
+ }
+
+ /** Uses prettier characters, but possibly not supported by all fonts */
+ object PrettyCharSet extends CharSet {
+ val lastNode = "└──"
+ val notLastNode = "├──"
+ val continuation = "│ "
+ }
+
+ /** Basic ASCII output */
+ object ASCIICharSet extends CharSet {
+ val lastNode = "\\--"
+ val notLastNode = "|--"
+ val continuation = "| "
+ }
+
+}
diff --git a/src/test/scala/firrtlTests/options/PhaseManagerSpec.scala b/src/test/scala/firrtlTests/options/PhaseManagerSpec.scala
index 6f09daf6..b13ee215 100644
--- a/src/test/scala/firrtlTests/options/PhaseManagerSpec.scala
+++ b/src/test/scala/firrtlTests/options/PhaseManagerSpec.scala
@@ -379,6 +379,7 @@ class PhaseManagerSpec extends FlatSpec with Matchers {
val f = new File(d + "/transformOrder.dot")
val w = new PrintWriter(new File(d + "/transformOrder.dot"))
try {
+ info("transform order:\n" + pm.prettyPrint(" "))
w.write(pm.transformOrderToGraphviz())
w.close
maybeToPng(f)