diff --git a/examples/dataflow/structuring.py b/examples/dataflow/structuring.py index 591d7fc6f..0525e2337 100644 --- a/examples/dataflow/structuring.py +++ b/examples/dataflow/structuring.py @@ -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 index 000000000..0ead73d16 --- /dev/null +++ b/migen/flow/perftools.py @@ -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