Skip to content

Commit

Permalink
Merge branch 'multisource-nets' into remove-passthrough-nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
mundya committed Dec 12, 2015
2 parents d068249 + 9fb7cbd commit e1c406f
Show file tree
Hide file tree
Showing 17 changed files with 889 additions and 993 deletions.
46 changes: 29 additions & 17 deletions nengo_spinnaker/builder/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from . import model
from nengo_spinnaker import operators
from nengo_spinnaker.netlist import Net, Netlist
from nengo_spinnaker.netlist import NMNet, Netlist
from nengo_spinnaker.utils import collections as collections_ext
from nengo_spinnaker.utils.keyspaces import KeyspaceContainer

Expand Down Expand Up @@ -325,6 +325,7 @@ def make_netlist(self, *args, **kwargs):
load_functions = collections_ext.noneignoringlist()
before_simulation_functions = collections_ext.noneignoringlist()
after_simulation_functions = collections_ext.noneignoringlist()
constraints = collections_ext.flatinsertionlist()

for op in itertools.chain(itervalues(self.object_operators),
self.extra_operators):
Expand All @@ -334,7 +335,7 @@ def make_netlist(self, *args, **kwargs):

# Otherwise call upon the operator to build vertices for the
# netlist.
vxs, load_fn, pre_fn, post_fn = op.make_vertices(
vxs, load_fn, pre_fn, post_fn, constraint = op.make_vertices(
self, *args, **kwargs
)

Expand All @@ -345,6 +346,9 @@ def make_netlist(self, *args, **kwargs):
before_simulation_functions.append(pre_fn)
after_simulation_functions.append(post_fn)

if constraint is not None:
constraints.append(constraint)

# Construct the groups set
groups = list()
for vxs in itervalues(operator_vertices):
Expand All @@ -358,9 +362,26 @@ def make_netlist(self, *args, **kwargs):
for signal, transmission_parameters in \
self.connection_map.get_signals():
# Get the source and sink vertices
sources = operator_vertices[signal.source]
if not isinstance(sources, collections.Iterable):
sources = (sources, )
original_sources = operator_vertices[signal.source]
if not isinstance(original_sources, collections.Iterable):
original_sources = (original_sources, )

# Filter out any sources which have an `accepts_signal` method and
# return False when this is called with the signal and transmission
# parameters.
sources = list()
for source in original_sources:
# For each source which either doesn't have a
# `transmits_signal` method or returns True when this is called
# with the signal and transmission parameters add a new net to
# the netlist.
if (hasattr(source, "transmits_signal") and not
source.transmits_signal(signal,
transmission_parameters)):
pass # This source is ignored
else:
# Add the source to the final list of sources
sources.append(source)

sinks = collections_ext.flatinsertionlist()
for sink in signal.sinks:
Expand All @@ -377,25 +398,16 @@ def make_netlist(self, *args, **kwargs):
s.accepts_signal(signal, transmission_parameters))

# Create the net(s)
for source in sources:
# For each source which either doesn't have a
# `transmits_signal` method or returns True when this is called
# with the signal and transmission parameters add a new net to
# the netlist.
if (hasattr(source, "transmits_signal") and not
source.transmits_signal(signal,
transmission_parameters)):
continue # No net for this source

nets.append(Net(source, list(sinks),
signal.weight, signal.keyspace))
nets.append(NMNet(sources, list(sinks),
signal.weight, signal.keyspace))

# Return a netlist
return Netlist(
nets=nets,
vertices=vertices,
keyspaces=self.keyspaces,
groups=groups,
constraints=constraints,
load_functions=load_functions,
before_simulation_functions=before_simulation_functions,
after_simulation_functions=after_simulation_functions
Expand Down
6 changes: 3 additions & 3 deletions nengo_spinnaker/builder/netlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@

class netlistspec(collections.namedtuple(
"netlistspec", "vertices, load_function, before_simulation_function, "
"after_simulation_function")):
"after_simulation_function, constraints")):
"""Specification of how an operator should be added to a netlist."""
def __new__(cls, vertices, load_function=None,
before_simulation_function=None,
after_simulation_function=None):
after_simulation_function=None, constraints=None):
return super(netlistspec, cls).__new__(
cls, vertices, load_function, before_simulation_function,
after_simulation_function
after_simulation_function, constraints
)
2 changes: 2 additions & 0 deletions nengo_spinnaker/netlist/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from nengo_spinnaker.netlist.netlist import Netlist
from nengo_spinnaker.netlist.objects import NMNet, Vertex, VertexSlice
169 changes: 37 additions & 132 deletions nengo_spinnaker/netlist.py → nengo_spinnaker/netlist/netlist.py
Original file line number Diff line number Diff line change
@@ -1,120 +1,18 @@
"""Higher and lower level netlist items.
"""
import logging
import rig.netlist
from rig import place_and_route # noqa : F401
from rig.place_and_route.constraints import ReserveResourceConstraint

from rig.place_and_route.utils import (build_application_map,
build_routing_tables)
from rig.machine import Cores
from rig.machine_control.utils import sdram_alloc_for_vertices
from six import iteritems

from .partition_and_cluster import identify_clusters
from .utils.itertools import flatten
from nengo_spinnaker.netlist import utils

logger = logging.getLogger(__name__)


class Net(rig.netlist.Net):
"""A net represents connectivity from one vertex (or vertex slice) to many
vertices and vertex slices.
..note::
This extends the Rig :py:class:`~rig.netlist.Netlist` to add Nengo
specific attributes and terms.
Attributes
----------
source : :py:class:`.Vertex` or :py:class:`.VertexSlice`
Vertex or vertex slice which is the source of the net.
sinks : [:py:class:`.Vertex` or :py:class:`.VertexSlice`, ...]
List of vertices and vertex slices which are the sinks of the net.
weight : int
Number of packets transmitted across the net every simulation
time-step.
keyspace : :py:class:`rig.bitfield.BitField`
32-bit bitfield instance that can be used to derive the routing key and
mask for the net.
"""
def __init__(self, source, sinks, weight, keyspace):
"""Create a new net.
See :py:meth:`~rig.netlist.Net.__init__`.
Parameters
----------
keyspace : :py:class:`rig.bitfield.BitField`
32-bit bitfield instance that can be used to derive the routing key
and mask for the net.
"""
# Assert that the keyspace is 32-bits long
if keyspace.length != 32:
raise ValueError(
"keyspace: Must be 32-bits long, not {}".format(
keyspace.length)
)
super(Net, self).__init__(source, sinks, weight)
self.keyspace = keyspace

@property
def as_rig_primitive(self):
"""Return a new :py:class:`rig.netlist.Net` representing this Net."""
return rig.netlist.Net(self.source, self.sinks, self.weight)


class Vertex(object):
"""Represents a nominal unit of computation (a single instance or many
instances of an application running on a SpiNNaker machine) or an external
device that is connected to the SpiNNaker network.
Attributes
----------
application : str or None
Path to application which should be loaded onto SpiNNaker to simulate
this vertex, or None if no application is required.
constraints : [constraint, ...]
The :py:mod:`~rig.place_and_route.constraints` which should be applied
to the placement and routing related to the vertex.
resource : {resource: usage, ...}
Mapping from resource type to the consumption of that resource, in
whatever is an appropriate unit.
cluster : int or None
Index of the cluster the vertex is a part of.
"""
def __init__(self, application=None, resources=dict(), constraints=list()):
"""Create a new Vertex.
"""
self.application = application
self.constraints = list(constraints)
self.resources = dict(resources)
self.cluster = None


class VertexSlice(Vertex):
"""Represents a portion of a nominal unit of computation.
Attributes
----------
application : str or None
Path to application which should be loaded onto SpiNNaker to simulate
this vertex, or None if no application is required.
constraints : [constraint, ...]
The :py:mod:`~rig.place_and_route.constraints` which should be applied
to the placement and routing related to the vertex.
resource : {resource: usage, ...}
Mapping from resource type to the consumption of that resource, in
whatever is an appropriate unit.
slice : :py:class:`slice`
Slice of the unit of computation which is represented by this vertex
slice.
"""
def __init__(self, slice, application=None, resources=dict(),
constraints=list()):
super(VertexSlice, self).__init__(application, resources, constraints)
self.slice = slice


class Netlist(object):
"""A netlist represents a set of executables to run on a SpiNNaker machine
and their communication links.
Expand All @@ -129,6 +27,8 @@ class Netlist(object):
Object containing keyspaces for nets.
groups : [{:py:class:`~.Vertex`, ...}, ...]
List of groups of vertices.
constraints : [contraint, ...]
List of additional constraints.
load_functions : [`fn(netlist, controller)`, ...]
List of functions which will be called to load the model to a SpiNNaker
machine. Each must accept a netlist and a controller.
Expand All @@ -150,14 +50,15 @@ class Netlist(object):
Map of vertices to file-like views of the SDRAM they have been
allocated.
"""
def __init__(self, nets, vertices, keyspaces, groups,
def __init__(self, nets, vertices, keyspaces, groups, constraints=list(),
load_functions=list(), before_simulation_functions=list(),
after_simulation_functions=list()):
# Store given parameters
self.nets = list(nets)
self.vertices = list(vertices)
self.keyspaces = keyspaces
self.groups = list(groups)
self.constraints = list(constraints)
self.load_functions = list(load_functions)
self.before_simulation_functions = list(before_simulation_functions)
self.after_simulation_functions = list(after_simulation_functions)
Expand All @@ -166,20 +67,12 @@ def __init__(self, nets, vertices, keyspaces, groups,
# route.
self.placements = dict()
self.allocations = dict()
self.net_keyspaces = dict()
self.routes = dict()
self.vertices_memory = dict()

def as_rig_arguments(self):
"""Construct arguments for Rig from the Netlist."""
vertices_resources = {v: v.resources for v in self.vertices}
nets = [net.as_rig_primitive for net in self.nets]
constraints = list(flatten(v.constraints for v in self.vertices))
constraints.append(ReserveResourceConstraint(Cores, slice(0, 1)))

return {"vertices_resources": vertices_resources,
"nets": nets,
"constraints": constraints
}
# Add a constraint to keep the monitor processor clear
self.constraints.append(ReserveResourceConstraint(Cores, slice(0, 1)))

def place_and_route(self, machine,
place=place_and_route.place,
Expand Down Expand Up @@ -213,27 +106,39 @@ def place_and_route(self, machine,
"""
# Build a map of vertices to the resources they require, get a list of
# constraints.
args = self.as_rig_arguments()
vertices_resources = args["vertices_resources"]
constraints = args["constraints"]
vertices_resources = {v: v.resources for v in self.vertices}

# Perform placement and allocation
self.placements = place(vertices_resources, self.nets,
machine, constraints, **place_kwargs)
self.allocations = allocate(vertices_resources, self.nets, machine,
constraints, self.placements,
place_nets = list(utils.get_nets_for_placement(self.nets))
self.placements = place(vertices_resources, place_nets, machine,
self.constraints, **place_kwargs)
self.allocations = allocate(vertices_resources, place_nets, machine,
self.constraints, self.placements,
**allocate_kwargs)

# Identify clusters and modify keyspaces and vertices appropriately
identify_clusters(self.placements, self.nets, self.groups)
# Identify clusters and modify vertices appropriately
utils.identify_clusters(self.groups, self.placements)

# Get the nets for routing
(route_nets,
vertices_resources, # Can safely overwrite the resource dictionary
extended_placements,
extended_allocations,
derived_nets) = utils.get_nets_for_routing(
vertices_resources, self.nets, self.placements, self.allocations)

# Get a map from the nets we will route with to keyspaces
self.net_keyspaces = utils.get_net_keyspaces(self.placements,
derived_nets)

# Fix all keyspaces
self.keyspaces.assign_fields()

# Finally, route all nets
self.routes = route(vertices_resources, self.nets, machine,
constraints, self.placements, self.allocations,
**route_kwargs)
# Finally, route all nets using the extended resource dictionary,
# placements and allocations.
self.routes = route(vertices_resources, route_nets, machine,
self.constraints, extended_placements,
extended_allocations, **route_kwargs)

def load_application(self, controller):
"""Load the netlist to a SpiNNaker machine.
Expand All @@ -246,9 +151,9 @@ def load_application(self, controller):
# Build and load the routing tables, first by building a mapping from
# nets to keys and masks.
logger.debug("Loading routing tables")
net_keys = {n: (n.keyspace.get_value(tag=self.keyspaces.routing_tag),
n.keyspace.get_mask(tag=self.keyspaces.routing_tag))
for n in self.nets}
net_keys = {n: (ks.get_value(tag=self.keyspaces.routing_tag),
ks.get_mask(tag=self.keyspaces.routing_tag))
for n, ks in iteritems(self.net_keyspaces)}
routing_tables = build_routing_tables(self.routes, net_keys)
controller.load_routing_tables(routing_tables)

Expand Down
Loading

0 comments on commit e1c406f

Please sign in to comment.