def load_application(self, controller, system_info): """Load the netlist to a SpiNNaker machine. Parameters ---------- controller : :py:class:`~rig.machine_control.MachineController` Controller to use to communicate with the machine. """ # 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: (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 = routing_tree_to_tables(self.routes, net_keys) target_lengths = build_routing_table_target_lengths(system_info) routing_tables = minimise_tables(routing_tables, target_lengths) controller.load_routing_tables(routing_tables) # Assign memory to each vertex as required logger.debug("Assigning application memory") self.vertices_memory = sdram_alloc_for_vertices( controller, self.placements, self.allocations) # Call each loading function in turn logger.debug("Loading data") for fn in self.load_functions: fn(self, controller) # Load the applications onto the machine logger.debug("Loading application executables") vertices_applications = { v: v.application for v in self.vertices if v.application is not None } application_map = build_application_map(vertices_applications, self.placements, self.allocations) controller.load_application(application_map)
def load_application(self, controller): """Load the netlist to a SpiNNaker machine. Parameters ---------- controller : :py:class:`~rig.machine_control.MachineController` Controller to use to communicate with the machine. """ # 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} routing_tables = build_routing_tables(self.routes, net_keys) controller.load_routing_tables(routing_tables) # Assign memory to each vertex as required logger.debug("Assigning application memory") self.vertices_memory = sdram_alloc_for_vertices( controller, self.placements, self.allocations ) # Inform the vertices of where that chunk of memory is for vertex, memory in iteritems(self.vertices_memory): x, y = self.placements[vertex] p = self.allocations[vertex][Cores].start controller.write_vcpu_struct_field( "user0", memory.address, x, y, p) # Call each loading function in turn logger.debug("Loading data") for fn in self.load_functions: fn(self, controller) # Load the applications onto the machine logger.debug("Loading application executables") vertices_applications = {v: v.application for v in self.vertices if v.application is not None} application_map = build_application_map( vertices_applications, self.placements, self.allocations ) controller.load_application(application_map)
def load_application(self, controller, system_info): """Load the netlist to a SpiNNaker machine. Parameters ---------- controller : :py:class:`~rig.machine_control.MachineController` Controller to use to communicate with the machine. """ # 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: (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 = routing_tree_to_tables(self.routes, net_keys) target_lengths = build_routing_table_target_lengths(system_info) routing_tables = minimise_tables(routing_tables, target_lengths) controller.load_routing_tables(routing_tables) # Assign memory to each vertex as required logger.debug("Assigning application memory") self.vertices_memory = sdram_alloc_for_vertices( controller, self.placements, self.allocations ) # Call each loading function in turn logger.debug("Loading data") for fn in self.load_functions: fn(self, controller) # Load the applications onto the machine logger.debug("Loading application executables") vertices_applications = {v: v.application for v in self.vertices if v.application is not None} application_map = build_application_map( vertices_applications, self.placements, self.allocations ) controller.load_application(application_map)
def run(self): """Run the simulation.""" # Define the resource requirements of each component in the simulation. vertices_resources = { # Every component runs on exactly one core and consumes a certain # amount of SDRAM to hold configuration data. component: {Cores: 1, SDRAM: component._get_config_size()} for component in self._components } # Work out what SpiNNaker application needs to be loaded for each # component vertices_applications = {component: component._get_kernel() for component in self._components} # Convert the Wire objects into Rig Net objects and create a lookup # from Net to the (key, mask) to use. net_keys = {Net(wire.source, wire.sinks): (wire.routing_key, 0xFFFFFFFF) for wire in self._wires} nets = list(net_keys) # Boot the SpiNNaker machine and interrogate it to determine what # resources (e.g. cores, SDRAM etc.) are available. mc = MachineController(self._hostname) mc.boot() system_info = mc.get_system_info() # Automatically chose which chips and cores to use for each component # and generate routing tables. placements, allocations, application_map, routing_tables = \ place_and_route_wrapper(vertices_resources, vertices_applications, nets, net_keys, system_info) with mc.application(): # Allocate memory for configuration data, tagged by core number. memory_allocations = sdram_alloc_for_vertices(mc, placements, allocations) # Load the configuration data for all components for component, memory in memory_allocations.items(): component._write_config(memory) # Load all routing tables mc.load_routing_tables(routing_tables) # Load all SpiNNaker application kernels mc.load_application(application_map) # Wait for all six cores to reach the 'sync0' barrier mc.wait_for_cores_to_reach_state("sync0", len(self._components)) # Send the 'sync0' signal to start execution and wait for the # simulation to finish. mc.send_signal("sync0") time.sleep(self.length * 0.001) mc.wait_for_cores_to_reach_state("exit", len(self._components)) # Retrieve result data for component, memory in memory_allocations.items(): component._read_results(memory)
def simulate(self, hostname, sim_length=128): """Simulate the current circuit for the specified number of timer ticks. """ # We define the set of ticks for convenience when plotting self.ticks = list(range(sim_length)) # We define our simulation within the following "with" block which # causes the SpiNNaker applications and their associated resources to # be automatically freed at the end of simulation or in the event of # some failure. mc = MachineController(hostname) with mc.application(): # Step 1: Determine what resources are available in the supplied # SpiNNaker machine. system_info = mc.get_system_info() # Step 2: Describe the simulation as a graph of SpiNNaker applications # which Rig will place in the machine # Each device uses a single core and consumes some amount of SDRAM for # config and result data. vertices_resources = { d: {Cores: 1, SDRAM: d.sdram_required(sim_length)} for d in self._devices } vertices_applications = {d: d.app_name for d in self._devices} # We'll make a net for every signal in our circuit. Packets will have # their bottom 31-bits be the unique signal ID and the top bit will # contain the state of the signal (and is thus masked off here) net_keys = {Net(s.source, s.sinks): (s.id, 0x7FFFFFFF) for s in self._signals} nets = list(net_keys) # Step 3: Place and route the application graph we just described placements, allocations, application_map, routing_tables = \ place_and_route_wrapper(vertices_resources, vertices_applications, nets, net_keys, system_info) # Step 4: Allocate SDRAM for each device. We use the # `sdram_alloc_for_vertices` utility method to allocate SDRAM on # the chip each device has been placed on, tagging the allocation # with the core number so the application can discover the # allocation using `sark_tag_ptr`. The returned file-like objects # may then conveniently be used to read/write to this allocated # region of SDRAM. # A dictionary {Device: filelike} is returned. device_sdram_filelikes = sdram_alloc_for_vertices(mc, placements, allocations) # Step 5: Write the config data to SDRAM for all devices. for d in self._devices: d.write_config(device_sdram_filelikes[d], sim_length) # Step 6: Load application binaries and routing tables mc.load_application(application_map) mc.load_routing_tables(routing_tables) # Step 7: Wait for all applications to reach the initial sync0 # barrier and then start the simulation. mc.wait_for_cores_to_reach_state("sync0", len(self._devices)) mc.send_signal("sync0") # Step 8: Wait for the simulation to run and all cores to finish # executing and enter the EXIT state. time.sleep(0.001 * sim_length) mc.wait_for_cores_to_reach_state("exit", len(self._devices)) # Step 9: Retrieve any results and we're done! for d in self._devices: d.read_results(device_sdram_filelikes[d], sim_length)