flow: perftools
authorSebastien Bourdeauducq <sebastien@milkymist.org>
Wed, 20 Jun 2012 19:59:17 +0000 (21:59 +0200)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Wed, 20 Jun 2012 19:59:17 +0000 (21:59 +0200)
examples/dataflow/structuring.py
migen/flow/perftools.py [new file with mode: 0644]

index 591d7fc6f05093d1be2440abfaceb98a02805259..0525e2337f3a386f9fba7d8fb1d844671d1d0bc1 100644 (file)
@@ -1,13 +1,17 @@
+import networkx as nx
+import matplotlib.pyplot as plt
+
 from migen.flow.network import *
 from migen.actorlib import structuring
 from migen.actorlib.sim import *
 from migen.sim.generic import Simulator
 from migen.sim.icarus import Runner
+from migen.flow import perftools
 
 pack_factor = 5
 
 def source_gen():
-       for i in range(80):
+       for i in range(180):
                yield Token("source", {"value": i})
 
 def sink_gen():
@@ -37,9 +41,16 @@ def main():
        g.add_connection(from_raw, unpacker)
        g.add_connection(unpacker, sink)
        comp = CompositeActor(g)
+       reporter = perftools.DFGReporter(g)
        
-       fragment = comp.get_fragment()
+       fragment = comp.get_fragment() + reporter.get_fragment()
        sim = Simulator(fragment, Runner())
-       sim.run(100)
+       sim.run(1000)
+       
+       g_layout = nx.spectral_layout(g)
+       nx.draw(g, g_layout)
+       nx.draw_networkx_edge_labels(g, g_layout, reporter.get_edge_labels())
+       plt.show()
+
 
 main()
diff --git a/migen/flow/perftools.py b/migen/flow/perftools.py
new file mode 100644 (file)
index 0000000..0ead73d
--- /dev/null
@@ -0,0 +1,70 @@
+from migen.fhdl.structure import *
+from migen.flow.actor import *
+from migen.sim.generic import PureSimulable
+
+class EndpointReporter(PureSimulable):
+       def __init__(self, endpoint):
+               self.endpoint = endpoint
+               self.reset()
+       
+       def reset(self):
+               self.inactive = 0
+               self.ack = 0
+               self.nack = 0
+       
+       # Total number of cycles per token (inverse token rate)
+       def cpt(self):
+               return (self.inactive + self.nack + 1)/self.ack
+       
+       # Inactivity cycles per token (slack)
+       def ipt(self):
+               return self.inactive/self.ack
+       
+       # NAK cycles per token (backpressure)
+       def npt(self):
+               return self.nack/self.ack
+       
+       def report_str(self):
+               if self.ack:
+                       return "C/T={:.2f}\nI/T={:.2f}\nN/T={:.2f}".format(self.cpt(), self.ipt(), self.npt())
+               else:
+                       return "N/A"
+       
+       def do_simulation(self, s):
+               if s.rd(self.endpoint.stb):
+                       if s.rd(self.endpoint.ack):
+                               self.ack += 1
+                       else:
+                               self.nack += 1
+               else:
+                       self.inactive += 1
+
+class DFGReporter:
+       def __init__(self, dfg):
+               assert(not dfg.is_abstract())
+               self.nodepair_to_ep = dict()
+               for u, v, data in dfg.edges_iter(data=True):
+                       if (u, v) in self.nodepair_to_ep:
+                               ep_to_reporter = self.nodepair_to_ep[(u, v)]
+                       else:
+                               ep_to_reporter = dict()
+                               self.nodepair_to_ep[(u, v)] = ep_to_reporter
+                       ep = data["source"]
+                       ep_to_reporter[ep] = EndpointReporter(u.actor.endpoints[ep])
+       
+       def get_fragment(self):
+               frag = Fragment()
+               for v1 in self.nodepair_to_ep.values():
+                       for v2 in v1.values():
+                               frag += v2.get_fragment()
+               return frag
+       
+       def get_edge_labels(self):
+               d = dict()
+               for (u, v), eps in self.nodepair_to_ep.items():
+                       if len(eps) == 1:
+                               d[(u, v)] = list(eps.values())[0].report_str()
+                       else:
+                               d[(u, v)] = "\n".join(ep + ":\n" + reporter.report_str()
+                                       for ep, reporter in eps)
+               return d