aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJack Koenig2017-08-17 17:02:00 -0700
committerAdam Izraelevitz2017-12-29 11:30:44 -0800
commita976ba219f02cea49cdaf9446a691a3731dfa31b (patch)
tree19fd29f174d0b6ba652e8e179e981b7d9a56f1ec /src
parentef61bb94879305a8259daeb6c67f72428bc5d5a4 (diff)
Add NodeCount analysis for helping with performance debugging
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/firrtl/analyses/NodeCount.scala63
1 files changed, 63 insertions, 0 deletions
diff --git a/src/main/scala/firrtl/analyses/NodeCount.scala b/src/main/scala/firrtl/analyses/NodeCount.scala
new file mode 100644
index 00000000..0276f4f5
--- /dev/null
+++ b/src/main/scala/firrtl/analyses/NodeCount.scala
@@ -0,0 +1,63 @@
+// See LICENSE for license details.
+
+package firrtl
+package analyses
+
+import ir._
+import scala.annotation.tailrec
+import scala.collection.JavaConverters._
+
+/** This is not intended to be used as a metric for the size of an actual
+ * circuit, but rather to debug the compiler itself
+ * Works because all FirrtlNodes implement Product (case classes do)
+ */
+class NodeCount private (node: FirrtlNode) {
+
+ // Counts the number of unique objects in a Firrtl graph
+ // There is no IdentityHashSet
+ private val identityMap = new java.util.IdentityHashMap[Any, Boolean]()
+ // This is a strict subset of the keys of identityMap
+ private val regularSet = new collection.mutable.HashSet[Any]
+
+ @tailrec
+ private final def rec(xs: List[Any]): Unit =
+ if (xs.isEmpty) { }
+ else {
+ val node = xs.head
+ require(node.isInstanceOf[Product] || !node.isInstanceOf[FirrtlNode],
+ "Unexpected FirrtlNode that does not implement Product!")
+ val moreToVisit =
+ if (identityMap.containsKey(node)) List.empty
+ else { // Haven't seen yet
+ identityMap.put(node, true)
+ regularSet += node
+ node match { // FirrtlNodes are Products
+ case p: Product => p.productIterator
+ case i: Iterable[Any] => i
+ case _ => List.empty
+ }
+ }
+ rec(moreToVisit ++: xs.tail)
+ }
+ rec(List(node))
+
+ /** Number of nodes that are referentially unique
+ *
+ * !(a eq b)
+ */
+ def unique: Long = identityMap.size
+
+ /** Number of nodes that are different
+ *
+ * !(a == b)
+ */
+ def nonequivalent: Long = regularSet.size
+
+ /** Number of nodes in this NodeCount that are NOT present in that NodeCount */
+ def uniqueFrom(that: NodeCount): Long =
+ this.identityMap.keySet.asScala.count(!that.identityMap.containsKey(_))
+}
+
+object NodeCount {
+ def apply(node: FirrtlNode) = new NodeCount(node)
+}