def main(args=None): parser = argparse.ArgumentParser( description="Print a summary of basic SpiNNaker machine " "and BMP information") parser.add_argument("--version", "-V", action="version", version="%(prog)s {}".format(rig.__version__)) parser.add_argument("hostname", type=str, help="hostname or IP of SpiNNaker system or BMP") args = parser.parse_args(args) # Determine what type of machine this is and print information accordingly try: mc = MachineController(args.hostname) info = mc.get_software_version(255, 255) if "SpiNNaker" in info.version_string: for line in get_spinnaker_info(mc): print(line) elif "BMP" in info.version_string: bc = BMPController(args.hostname) for line in get_bmp_info(bc): print(line) else: sys.stderr.write("{}: error: unknown architecture '{}'\n".format( parser.prog, info.version_string)) return 2 except TimeoutError: sys.stderr.write("{}: error: command timed out\n".format( parser.prog)) return 1 return 0
def main(args=None): parser = argparse.ArgumentParser( description="Print the contents of IOBUF for a specified core") parser.add_argument("--version", "-V", action="version", version="%(prog)s {}".format(rig.__version__)) parser.add_argument("hostname", type=str, help="hostname or IP of SpiNNaker system") parser.add_argument("x", type=int, help="the X coordinate of the chip") parser.add_argument("y", type=int, help="the Y coordinate of the chip") parser.add_argument("p", type=int, help="the processor number") args = parser.parse_args(args) try: mc = MachineController(args.hostname) info = mc.get_software_version(255, 255) if "SpiNNaker" in info.version_string: sys.stdout.write(mc.get_iobuf(args.p, args.x, args.y)) else: sys.stderr.write("{}: error: unknown architecture '{}'\n".format( parser.prog, info.version_string.strip("\x00"))) return 2 except TimeoutError: sys.stderr.write("{}: error: command timed out\n".format(parser.prog)) return 1 return 0
def connect2Machine(self): self.mc = MachineController(DEF_HOST) if BOOT_MACHINE is True: if self.mc.boot() is True: print "Machine is now booted..." else: print "Machine is already booted..." self.machineInfo = self.mc.get_system_info()
def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setupUi(self) self.setCentralWidget(self.mdiArea) self.statusTxt = QtGui.QLabel("") self.dagFile = QtGui.QLabel("") self.statusBar().addWidget(self.dagFile) self.statusBar().addWidget(self.statusTxt) self.vis = visWidget(self.mdiArea) self.vis.setGeometry(0, 0, 1024, 1024) #self.vis.scale(0.5,0.5) # put in half size self.vis.hide() self.action_Visualiser.setCheckable(True) #self.action_Visualiser.setChecked(False) self.connect(self.action_Quit, QtCore.SIGNAL("triggered()"), QtCore.SLOT("Quit()")) self.connect(self.action_Load_XML, QtCore.SIGNAL("triggered()"), QtCore.SLOT("loadXML()")) self.connect(self.action_Visualiser, QtCore.SIGNAL("triggered()"), QtCore.SLOT("showVisualiser()")) self.connect(self.action_Send_and_Init, QtCore.SIGNAL("triggered()"), QtCore.SLOT("sendAndInit()")) self.connect(self.actionInspect_SpinConf, QtCore.SIGNAL("triggered()"), QtCore.SLOT("testSpin1()")) self.connect(self.actionSet_Tick, QtCore.SIGNAL("triggered()"), QtCore.SLOT("getSimulationTick()")) self.connect(self.actionStart, QtCore.SIGNAL("triggered()"), QtCore.SLOT("startSim()")) self.connect(self.actionStop, QtCore.SIGNAL("triggered()"), QtCore.SLOT("stopSim()")) self.simTick = 1000000 # default value that yield 1second resolution self.output = None # this is a list of list of dict that contains target dependency data """ self.srcTarget = dict() # this similar to self.output, but just contains target for SOURCE node # (as a dict of a list), e.g: from dag0020, srcTarget = {0: [4,3,2]} """ self.srcTarget = list( ) # now scrTarget becomes simpler, because we don't send the trigger's payload self.sdp = sdpComm() self.sdp.histUpdate.connect(self.vis.updateHist) self.mc = MachineController(DEF_HOST) if BOOT_MACHINE is True: if self.mc.boot() is True: print "Machine is now booted..." else: print "Machine is already booted..." self.machineInfo = self.mc.get_system_info() """ self.mc.iptag_set(0,'192.168.240.2',17892,0,0) # prepare iptag for myTub, because boot in rig doesn't provide this if DEF_HOST=='192.168.240.1': self.statusTxt.setText("Using SpiNN-5 board at {}".format(DEF_HOST)) else: self.statusTxt.setText("Using SpiNN-3 board at {}".format(DEF_HOST)) """ self.setGeometry(0, 0, 1024, 1024)
def __init__(self, MACHINE_IP, parent=None): super(mainWidget, self).__init__(parent) self.setGeometry(0, 0, 640, 480) self.setWindowTitle("SpiNNaker Chips Visualizer") # get info from rig: mc = MachineController(MACHINE_IP) mc.boot() mInfo = mc.get_system_info() w = mInfo.width h = mInfo.height chipList = mInfo.keys() self.vis = visWidget(w, h, chipList, self) self.vis.setGeometry(0, 0, self.width(), self.height())
def main(args=None): parser = argparse.ArgumentParser(description="Boot a SpiNNaker board") parser.add_argument("--version", "-V", action="version", version="%(prog)s {}".format(rig.__version__)) parser.add_argument("hostname", type=str, help="hostname or IP of SpiNNaker system") # Automatically build a list of available machine parameters by inspecting # boot module. type_group = parser.add_mutually_exclusive_group() for dict_name in dir(boot): if dict_name.endswith(BOOT_OPTION_POSTFIX): type_name = dict_name[:-len(BOOT_OPTION_POSTFIX)] option_name = "--{}".format(type_name) option_dict = getattr(boot, dict_name) option_help = "use predefined boot options for a {} board".format( type_name) type_group.add_argument(option_name, action="store_const", const=option_dict, default={}, dest="board_options", help=option_help) args = parser.parse_args(args) # Attempt to boot the machine mc = MachineController(args.hostname) try: if mc.boot(**args.board_options): return 0 else: # The machine was already booted. sys.stderr.write("{}: error: machine already booted.\n".format( parser.prog)) return 1 except SpiNNakerBootError as e: # The machine could not be booted for some reason; show an appropriate # message sys.stderr.write("{}: error: {}\n".format(parser.prog, str(e))) return 2
def run_job(job_args, job_kwargs, ip_file_filename): # Reason for destroying the job reason = None # Create the job try: job = Job(*job_args, **job_kwargs) except (OSError, IOError, ProtocolError, ProtocolTimeoutError) as e: info(t.red("Could not connect to server: {}".format(e))) return 6 try: # Wait for it to become ready, keeping the user informed along the # way code, reason = wait_for_job_ready(job) if code != 0: return code # Machine is now ready write_ips_to_csv(job.connections, ip_file_filename) # Boot the machine if required if MachineController is not None and args.boot: update("Job {}: Booting...", t.yellow, job.id) mc = MachineController(job.hostname) mc.boot(job.width, job.height) update("Job {}: Ready!", t.green, job.id) # Either run the user's application or just print the details. if not args.command: print_info(job.machine_name, job.connections, job.width, job.height, ip_file_filename) return 0 return run_command(args.command, job.id, job.machine_name, job.connections, job.width, job.height, ip_file_filename) finally: # Destroy job and disconnect client if args.no_destroy: job.close() else: job.destroy(reason)
class MainWindow(QtGui.QMainWindow, QtMainWindow.Ui_qtMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setupUi(self) self.setCentralWidget(self.mdiArea) self.statusTxt = QtGui.QLabel("") self.dagFile = QtGui.QLabel("") self.statusBar().addWidget(self.dagFile) self.statusBar().addWidget(self.statusTxt) self.vis = visWidget(self.mdiArea) self.vis.setGeometry(0, 0, 1024, 1024) #self.vis.scale(0.5,0.5) # put in half size self.vis.hide() self.action_Visualiser.setCheckable(True) #self.action_Visualiser.setChecked(False) self.connect(self.action_Quit, QtCore.SIGNAL("triggered()"), QtCore.SLOT("Quit()")) self.connect(self.action_Load_XML, QtCore.SIGNAL("triggered()"), QtCore.SLOT("loadXML()")) self.connect(self.action_Visualiser, QtCore.SIGNAL("triggered()"), QtCore.SLOT("showVisualiser()")) self.connect(self.action_Send_and_Init, QtCore.SIGNAL("triggered()"), QtCore.SLOT("sendAndInit()")) self.connect(self.actionInspect_SpinConf, QtCore.SIGNAL("triggered()"), QtCore.SLOT("testSpin1()")) self.connect(self.actionSet_Tick, QtCore.SIGNAL("triggered()"), QtCore.SLOT("getSimulationTick()")) self.connect(self.actionStart, QtCore.SIGNAL("triggered()"), QtCore.SLOT("startSim()")) self.connect(self.actionStop, QtCore.SIGNAL("triggered()"), QtCore.SLOT("stopSim()")) self.simTick = 1000000 # default value that yield 1second resolution self.output = None # this is a list of list of dict that contains target dependency data """ self.srcTarget = dict() # this similar to self.output, but just contains target for SOURCE node # (as a dict of a list), e.g: from dag0020, srcTarget = {0: [4,3,2]} """ self.srcTarget = list( ) # now scrTarget becomes simpler, because we don't send the trigger's payload self.sdp = sdpComm() self.sdp.histUpdate.connect(self.vis.updateHist) self.mc = MachineController(DEF_HOST) if BOOT_MACHINE is True: if self.mc.boot() is True: print "Machine is now booted..." else: print "Machine is already booted..." self.machineInfo = self.mc.get_system_info() """ self.mc.iptag_set(0,'192.168.240.2',17892,0,0) # prepare iptag for myTub, because boot in rig doesn't provide this if DEF_HOST=='192.168.240.1': self.statusTxt.setText("Using SpiNN-5 board at {}".format(DEF_HOST)) else: self.statusTxt.setText("Using SpiNN-3 board at {}".format(DEF_HOST)) """ self.setGeometry(0, 0, 1024, 1024) @QtCore.pyqtSlot() def Quit(self): # TODO: clean up... self.close() @QtCore.pyqtSlot() def showVisualiser(self): if self.action_Visualiser.isChecked() is True: #self.vis = visWidget(self.mdiArea) # cuman buat sejarah kalau dulu aku letakkan di sini! #self.vis.setGeometry(0,0,1024,1024) self.vis.sceneTimer.start(500) self.vis.show() else: self.vis.hide() self.vis.sceneTimer.stop() @QtCore.pyqtSlot() def loadXML(self): print "Loading XML..." fullPathFileName = QtGui.QFileDialog.getOpenFileName( self, "Open XML file", "./", "*.xml") if not fullPathFileName: print "Cancelled!" else: # Then ask for the appropriate map cbItem = tg2spinMap.keys() # simTick, ok = QtGui.QInputDialog.getInt(self, "Simulation Tick", "Enter Simulation Tick in microsecond", self.simTick, DEF_MIN_TIMER_TICK, 10000000, 1) mapItem, ok = QtGui.QInputDialog.getItem( self, "Select Map", "Which map will be used?", cbItem, 0, False) if ok is True: print "Will use", mapItem # self.initMap(mapItem) self.TGmap = tg2spinMap[str(mapItem)] else: print "Cancelled!" return fi = QtCore.QFileInfo() fi.setFile(fullPathFileName) fn = fi.fileName() self.dagFile.setText("Using {}".format(fn)) print "Processing ", fullPathFileName parser = xml.sax.make_parser() # turn off namespace parser.setFeature(xml.sax.handler.feature_namespaces, 0) # override the default ContextHandler Handler = tgxmlHandler() parser.setContentHandler(Handler) parser.parse(str(fullPathFileName)) if SHOW_PARSING_RESULT: showParsingResult(Handler) """ Let's put the c-like struct as a list: Let's create a variable cfg, which is a list of a dict. Then, let's create a variable dag, which is a list of cfg. Hence, dag is a list of a list of a dict. """ dag = list() for nodes in Handler.Nodes: cfg = list() srcPayload = list() srcFound = False for target in nodes.Target: dct = dict() dct['nodeID'] = nodes.Id dct['destID'] = target.destId dct['nPkt'] = target.nPkt dct['nDependant'] = target.nDependant for d in range(target.nDependant): srcIDkey = "dep{}_srcID".format(d) nTriggerPktkey = "dep{}_nTriggerPkt".format(d) dct[srcIDkey] = target.Dep[d].srcId dct[nTriggerPktkey] = target.Dep[d].nTriggerPkt # also search for SOURCE dependant if target.Dep[d].srcId == DEF_SOURCE_ID: srcFound = True srcPayload.append(target.Dep[d].nTriggerPkt) cfg.append(dct) # and put the payload to the current word in the dict if srcFound: self.srcTarget.append(nodes.Id) # self.srcTarget[nodes.Id] = srcPayload --> ini yang lama sebelum aku REVISI dag.append(cfg) self.output = dag #self.output = experiment_dag0020() # for debugging: print "SpiNNaker usage :", self.TGmap print "TG configuration :", self.output print "Source Target :", self.srcTarget @QtCore.pyqtSlot() def testSpin1(self): """ send a request to dump tgsdp configuration data sendSDP(self, flags, tag, dp, dc, dax, day, cmd, seq, arg1, arg2, arg3, bArray): """ f = NO_REPLY t = DEF_SEND_IPTAG p = DEF_SDP_CONF_PORT c = DEF_SDP_CORE m = TGPKT_HOST_ASK_REPORT for item in self.TGmap: if item != -1 and item != DEF_SOURCE_ID: x, y = getChipXYfromID(self.TGmap, item) #print "Sending a request to <{},{}:{}>".format(x,y,c) self.sdp.sendSDP(f, t, p, c, x, y, m, 0, 0, 0, 0, None) time.sleep(DEF_SDP_TIMEOUT) @QtCore.pyqtSlot() def sendAndInit(self): """ will send aplx to corresponding chip and initialize/configure the chip Assuming that the board has been booted? """ if self.output == None: QtGui.QMessageBox.information(self, "Information", "No valid network structure yet!") return # First, need to translate from node-ID to chip position <x,y>, including the SOURCE and SINK node # use self.TGmap print "Do translation from node to chip..." self.xSrc, self.ySrc = getChipXYfromID(self.TGmap, DEF_SOURCE_ID) appCores = dict() for item in self.TGmap: if item != -1 and item != DEF_SOURCE_ID: x, y = getChipXYfromID(self.TGmap, item) appCores[(x, y)] = [DEF_APP_CORE] print "Application cores :", appCores allChips = dict() for item in CHIP_LIST_48: allChips[(item[0], item[1])] = [DEF_MON_CORE] print "Monitor cores :", allChips # Second, send the aplx (tgsdp.aplx and srcsink.aplx) to the corresponding chip # example: mc.load_application("bla_bla_bla.aplx", {(0,0):[1,2,10,17]}, app_id=16) # so, the chip is a tupple and cores is in a list!!! # Do you want something nice? Use QFileDialog print "Send iptag...", self.mc.iptag_set( DEF_TUBO_IPTAG, '192.168.240.2', DEF_TUBO_PORT, 0, 0 ) # prepare iptag for myTub, because boot in rig doesn't provide this self.mc.iptag_set(DEF_REPORT_IPTAG, '192.168.240.2', DEF_REPORT_PORT, 0, 0) if DEF_HOST == '192.168.240.1': self.statusTxt.setText( "Using SpiNN-5 board at {}".format(DEF_HOST)) else: self.statusTxt.setText( "Using SpiNN-3 board at {}".format(DEF_HOST)) print "done!" print "Send the aplxs to the corresponding chips...", srcsinkaplx = "/local/new_home/indi/Projects/P/Graceful_TG_SDP_virtualenv/src/aplx/srcsink.aplx" tgsdpaplx = "/local/new_home/indi/Projects/P/Graceful_TG_SDP_virtualenv/src/aplx/tgsdp.aplx" monaplx = "/local/new_home/indi/Projects/P/Graceful_TG_SDP_virtualenv/src/aplx/monitor.aplx" self.mc.load_application(srcsinkaplx, {(self.xSrc, self.ySrc): [DEF_APP_CORE]}, app_id=APPID_SRCSINK) self.mc.load_application(tgsdpaplx, appCores, app_id=APPID_TGSDP) self.mc.load_application(monaplx, allChips, app_id=APPID_MONITOR) print "done!" # Debugging: why some chips generate WDOG? self.sdp.sendPing(self.TGmap) # Third, send the configuration to the corresponding node print "Sending the configuration data to the corresponding chip...", for node in self.output: # self.output should be a list of a list of a dict #print "Node =",node time.sleep( DEF_SDP_TIMEOUT ) # WEIRD!!!! If I remove this, then node-0 will be corrupted!!! self.sdp.sendConfig(self.TGmap, node) print "done!" print "Sending special configuration to SOURCE/SINK node...", # TODO: send the source target list!!! self.sdp.sendSourceTarget( self.TGmap, self.srcTarget) # butuh TGmap karena butuh xSrc dan ySrc print "done! ---------- WAIT, Abaikan nilai payload-nya!!!! ------------" # NOTE: di bagian sdp.sendSourceTarget() tidak aku ubah untuk akomodasi hal tersebut!!!!!!!!! # Jadi, sangat tergantung srcsink.c untuk betulin-nya!!!! print "Sending network map...", self.sdp.sendChipMap(self.TGmap) print "done! SpiNNaker is ready for TGSDP simulation (set tick if necessary)!" # TODO: 1. Baca P2P table # 2. Petakan dan kirim ke tgsdpvis.py. Nanti tgsdpvis.py akan memberi warna apasihini = self.mc.get_system_info() p2p_tables = {(x, y): self.mc.get_p2p_routing_table(x, y) for x, y in self.mc.get_system_info()} #for c in apasihini.chips(): # print c @QtCore.pyqtSlot() def getSimulationTick(self): simTick, ok = QtGui.QInputDialog.getInt( self, "Simulation Tick", "Enter Simulation Tick in microsecond", self.simTick, DEF_MIN_TIMER_TICK, 10000000, 1) if ok is True: print "Sending tick {} microseconds".format(simTick) self.simTick = simTick self.sdp.sendSimTick(self.xSrc, self.ySrc, simTick) @QtCore.pyqtSlot() def startSim(self): self.actionStop.setEnabled(True) self.actionStart.setEnabled(False) self.sdp.sendStartCmd(self.xSrc, self.ySrc) @QtCore.pyqtSlot() def stopSim(self): self.actionStop.setEnabled(False) self.actionStart.setEnabled(True) # self.sdp.sendStopCmd(self.xSrc, self.ySrc) #-> only to SOURCE/SINK node self.sdp.sendStopCmd(self.xSrc, self.ySrc, self.TGmap) #-> to all nodes
class MainWindow(QtGui.QMainWindow, QtMainWindow.Ui_qtMainWindow): def __init__(self, cli_param, parent=None): super(MainWindow, self).__init__(parent) self.setupUi(self) self.setCentralWidget(self.mdiArea) self.statusTxt = QtGui.QLabel("") self.dagFile = QtGui.QLabel("") self.statusBar().addWidget(self.dagFile) self.statusBar().addWidget(self.statusTxt) # connect to the machine if len(cli_param) > 1: ip = cli_param[1] if len(cli_param) > 2: self.myPC = cli_param[2] else: self.myPC = DEF_MYPC else: ip, ok = QtGui.QInputDialog.getText(None, "Connect to SpiNNaker", "Please specify machine IP", QtGui.QLineEdit.Normal, DEF_HOST) if ok is False: ip = '' print "Using machine at", ip self.mc = MachineController(ip) if BOOT_MACHINE is True: if self.mc.boot() is True: print "Machine is now booted..." else: print "Machine is already booted..." # then use machineInfo to build the map self.mInfo = self.mc.get_system_info() wMachine = self.mInfo.width hMachine = self.mInfo.height self.chipList = self.mInfo.keys() print "Found", len(self.chipList), "active chips:" """ self.mc.iptag_set(0,'192.168.240.2',17892,0,0) # prepare iptag for myTub, because boot in rig doesn't provide this if DEF_HOST=='192.168.240.1': self.statusTxt.setText("Using SpiNN-5 board at {}".format(DEF_HOST)) else: self.statusTxt.setText("Using SpiNN-3 board at {}".format(DEF_HOST)) """ #self.vis = visWidget(wMachine, hMachine, self.chipList, self.mdiArea) # for known dead chips on certain boards knownDeadChips = [] if (len(self.chipList) % 48) != 0: # dead chip is detected lst = QtGui.QInputDialog.getText( self, "Dead chip is detected", "Please provide chip coordinate in () separated by space", QtGui.QLineEdit.Normal, "(0,2)") knownDeadChips = getDeadChipList(lst) self.tgvisWidget = visWidget(wMachine, hMachine, self.chipList, knownDeadChips) self.vis = tgViever(self.tgvisWidget) #self.vis.setGeometry(0,0,1024,1024) #self.vis.scale(0.5,0.5) # put in half size self.vis.hide() self.action_Visualiser.setCheckable(True) #self.action_Visualiser.setChecked(False) self.connect(self.action_Quit, QtCore.SIGNAL("triggered()"), QtCore.SLOT("Quit()")) self.connect(self.action_Load_XML, QtCore.SIGNAL("triggered()"), QtCore.SLOT("loadXML()")) self.connect(self.action_Visualiser, QtCore.SIGNAL("triggered()"), QtCore.SLOT("showVisualiser()")) self.connect(self.action_Send_and_Init, QtCore.SIGNAL("triggered()"), QtCore.SLOT("sendAndInit()")) self.connect(self.actionInspect_SpinConf, QtCore.SIGNAL("triggered()"), QtCore.SLOT("testSpin1()")) self.connect(self.actionSet_Tick, QtCore.SIGNAL("triggered()"), QtCore.SLOT("getSimulationTick()")) self.connect(self.actionStart, QtCore.SIGNAL("triggered()"), QtCore.SLOT("startSim()")) self.connect(self.actionStop, QtCore.SIGNAL("triggered()"), QtCore.SLOT("stopSim()")) # 22 March 2017 - 11:48 - Buat experiment ambil data untuk paper self.timer = QtCore.QTimer(self) #self.timer.setInterval(60000) # one minute experiment self.timer.timeout.connect(self.timeout) # Simulation parameters self.simTick = 1000000 # default value that yield 1second resolution self.runningTime = 0 # 0 means runs forever self.dag = None # this is a list of list of dict that contains target dependency data """ self.srcTarget = dict() # this similar to self.dag, but just contains target for SOURCE node # (as a dict of a list), e.g: from dag0020, srcTarget = {0: [4,3,2]} """ self.srcTarget = list( ) # now scrTarget becomes simpler, because we don't send the trigger's payload self.sdp = sdpComm(self.chipList, ip) self.sdp.histUpdate.connect(self.vis.updateHist) self.setGeometry(0, 0, 1024, 1024) @QtCore.pyqtSlot() def timeout(self): """ Ini buat ambil data. Setelah jalan 1 menit, otomatis stop. Kemudian lihat iobuf dari srcsink node! :return: """ self.stopSim() self.timer.stop() def closeEvent(self, e): self.vis.close() e.accept() @QtCore.pyqtSlot() def Quit(self): # TODO: clean up... self.close() @QtCore.pyqtSlot() def showVisualiser(self): if self.action_Visualiser.isChecked() is True: #self.vis = visWidget(self.mdiArea) # cuman buat sejarah kalau dulu aku letakkan di sini! #self.vis.setGeometry(0,0,1024,1024) self.vis.animate() #self.vis.sceneTimer.start(500) self.vis.show() else: self.vis.deanimate() self.vis.hide() #self.vis.sceneTimer.stop() def buildMap(self): """ Let's build map correctly :input: self.dag :output: self.TGmap """ def readTGmap(self, fname, chipList, numNode): """ Read TGmap configuration from the given fname :param fname: .tgmap configuration file :param chipList: a dict() that contains all active chip coordinate in the machine :return: list() if success, otherwise None """ result = None ok = False with open(fname, 'r') as fid: dct = dict() nodeFound = 0 for line in fid: #print "line:", line idFromXY = getChipIDfromXY(line) if idFromXY is not None: dct.update(idFromXY) nodeFound += 1 if len(dct) > 0: print "Found", nodeFound, "nodes (including SRC/SINK)" result = [-1 for _ in range(len(chipList))] for i in range(len(chipList)): try: result[i] = dct[chipList[i]] except KeyError: result[i] = -1 if nodeFound == numNode + 1: ok = True return result, ok @QtCore.pyqtSlot() def loadXML(self): print "Loading XML..." fullPathFileName = QtGui.QFileDialog.getOpenFileName( self, "Open XML file", "./", "*.xml") if not fullPathFileName: print "Cancelled!" else: fi = QtCore.QFileInfo() fi.setFile(fullPathFileName) fn = fi.fileName() self.dagFile.setText("Using {}".format(fn)) print "Processing ", fullPathFileName parser = xml.sax.make_parser() # turn off namespace parser.setFeature(xml.sax.handler.feature_namespaces, 0) # override the default ContextHandler Handler = tgxmlHandler() parser.setContentHandler(Handler) parser.parse(str(fullPathFileName)) if SHOW_PARSING_RESULT: showParsingResult(Handler) """ Let's put the c-like struct as a list: Let's create a variable cfg, which is a list of a dict. Then, let's create a variable dag, which is a list of cfg. Hence, dag is a list of a list of a dict. """ dag = list() for nodes in Handler.Nodes: cfg = list() srcPayload = list() srcFound = False for target in nodes.Target: dct = dict() dct['nodeID'] = nodes.Id dct['destID'] = target.destId dct['nPkt'] = target.nPkt dct['nDependant'] = target.nDependant for d in range(target.nDependant): srcIDkey = "dep{}_srcID".format(d) nTriggerPktkey = "dep{}_nTriggerPkt".format(d) dct[srcIDkey] = target.Dep[d].srcId dct[nTriggerPktkey] = target.Dep[d].nTriggerPkt # also search for SOURCE dependant if target.Dep[d].srcId == DEF_SOURCE_ID: srcFound = True srcPayload.append(target.Dep[d].nTriggerPkt) cfg.append(dct) # and put the payload to the current word in the dict if srcFound: self.srcTarget.append(nodes.Id) # self.srcTarget[nodes.Id] = srcPayload --> ini yang lama sebelum aku REVISI dag.append(cfg) self.dag = dag #self.dag = experiment_dag0020() # for debugging: #print "SpiNNaker usage :", self.TGmap if SHOW_PARSING_RESULT: print "TG configuration :", self.dag #print len(self.dag) print "Source Target :", self.srcTarget # then load the TGmap configuration file tgmapConfigFile = QtGui.QFileDialog.getOpenFileName( self, "Open TGmap file", "./", "*.tgmap") if not tgmapConfigFile: print "Cancelled!" self.dag = None self.srcTarget = list() return tgmap, ok = self.readTGmap(tgmapConfigFile, self.chipList, len(self.dag)) if tgmap is None: print "Failed to get correct TGmap configuration!" # then cancel the operation and reset self.dag = None self.srcTarget = list() return else: if ok: #print tgmap print "Loaded tgmap from:", tgmapConfigFile self.TGmap = tgmap else: print "Missing node is detected! Maybe dead chip?" # then cancel the operation and reset self.dag = None self.srcTarget = list() """ # Then ask for the appropriate map cbItem = tg2spinMap.keys(); # simTick, ok = QtGui.QInputDialog.getInt(self, "Simulation Tick", "Enter Simulation Tick in microsecond", self.simTick, DEF_MIN_TIMER_TICK, 10000000, 1) mapItem, ok = QtGui.QInputDialog.getItem(self, "Select Map", "Which map will be used?", cbItem, 0, False) if ok is True: print "Will use",mapItem,':',tg2spinMap[str(mapItem)] # self.initMap(mapItem) self.TGmap = tg2spinMap[str(mapItem)] else: print "Cancelled!" return """ # continue with send and init? contSendInit = QtGui.QMessageBox.question( self, "Continue", "Continue with Send and Init?", QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel) if contSendInit == QtGui.QMessageBox.Ok: self.sendAndInit() else: QtGui.QMessageBox.information( self, "Done", "Loading XML and TGmap is done! You can continue with Send and Init!" ) @QtCore.pyqtSlot() def testSpin1(self): """ send a request to dump tgsdp configuration data sendSDP(self, flags, tag, dp, dc, dax, day, cmd, seq, arg1, arg2, arg3, bArray): """ f = NO_REPLY t = DEF_SEND_IPTAG p = DEF_SDP_CONF_PORT c = DEF_SDP_CORE m = TGPKT_HOST_ASK_REPORT for item in self.TGmap: if item != -1 and item != DEF_SOURCE_ID: x, y = getChipXYfromID(self.TGmap, item, self.chipList) #print "Sending a request to <{},{}:{}>".format(x,y,c) self.sdp.sendSDP(f, t, p, c, x, y, m, 0, 0, 0, 0, None) time.sleep(DEF_SDP_TIMEOUT) @QtCore.pyqtSlot() def sendAndInit(self): """ will send aplx to corresponding chip and initialize/configure the chip Assuming that the board has been booted? """ if self.dag == None: QtGui.QMessageBox.information(self, "Information", "No valid network structure yet!") return # First, need to translate from node-ID to chip position <x,y>, including the SOURCE and SINK node # use self.TGmap print "Doing translation from node to chip..." self.xSrc, self.ySrc = getChipXYfromID(self.TGmap, DEF_SOURCE_ID, self.chipList) appCores = dict() for item in self.TGmap: if item != -1 and item != DEF_SOURCE_ID: x, y = getChipXYfromID(self.TGmap, item, self.chipList) appCores[(x, y)] = [DEF_APP_CORE] if SHOW_PARSING_RESULT: print "Application cores :", appCores allChips = dict() for item in self.chipList: allChips[(item[0], item[1])] = [DEF_MON_CORE] if SHOW_PARSING_RESULT: print "Monitor cores :", allChips # Second, send the aplx (tgsdp.aplx and srcsink.aplx) to the corresponding chip # example: mc.load_application("bla_bla_bla.aplx", {(0,0):[1,2,10,17]}, app_id=16) # so, the chip is a tupple and cores is in a list!!! # Do you want something nice? Use QFileDialog if ENABLE_IPTAG: print "Send iptag..." self.mc.iptag_set( DEF_TUBO_IPTAG, self.myPC, DEF_TUBO_PORT, 0, 0 ) # prepare iptag for myTub, because boot in rig doesn't provide this self.mc.iptag_set(DEF_REPORT_IPTAG, self.myPC, DEF_REPORT_PORT, 0, 0) print "Send the aplxs to the corresponding chips...", srcsinkaplx = "/local/new_home/indi/Projects/P/Graceful_TG_SDP_virtualenv/src/aplx/srcsink.aplx" tgsdpaplx = "/local/new_home/indi/Projects/P/Graceful_TG_SDP_virtualenv/src/aplx/tgsdp.aplx" monaplx = "/local/new_home/indi/Projects/P/Graceful_TG_SDP_virtualenv/src/aplx/monitor.aplx" self.mc.load_application(srcsinkaplx, {(self.xSrc, self.ySrc): [DEF_APP_CORE]}, app_id=APPID_SRCSINK) self.mc.load_application(tgsdpaplx, appCores, app_id=APPID_TGSDP) self.mc.load_application(monaplx, allChips, app_id=APPID_MONITOR) time.sleep(5) self.mc.send_signal('sync0', app_id=APPID_SRCSINK) self.mc.send_signal('sync0', app_id=APPID_TGSDP) self.mc.send_signal('sync0', app_id=APPID_MONITOR) print "done!" # Debugging: why some chips generate WDOG? self.sdp.sendPing(self.TGmap) # Third, send the configuration to the corresponding node print "Sending the configuration data to the corresponding chip...", for node in self.dag: # self.dag should be a list of a list of a dict #print "Node =",node time.sleep( DEF_SDP_TIMEOUT ) # WEIRD!!!! If I remove this, then node-0 will be corrupted!!! self.sdp.sendConfig(self.TGmap, node) print "done!" print "Sending special configuration to SOURCE/SINK node...", # TODO: send the source target list!!! self.sdp.sendSourceTarget( self.TGmap, self.srcTarget) # butuh TGmap karena butuh xSrc dan ySrc print "done! ---------- WAIT, Abaikan nilai payload-nya!!!! ------------" # NOTE: di bagian sdp.sendSourceTarget() tidak aku ubah untuk akomodasi hal tersebut!!!!!!!!! # Jadi, sangat tergantung srcsink.c untuk betulin-nya!!!! print "Sending network map...", self.sdp.sendChipMap(self.TGmap) print "done! SpiNNaker is ready for TGSDP simulation (set tick if necessary)!" QtGui.QMessageBox.information( self, "Done", "SpiNNaker is ready for TGSDP simulation (set tick if necessary)!") # TODO: 1. Baca P2P table # 2. Petakan dan kirim ke tgsdpvis.py. Nanti tgsdpvis.py akan memberi warna apasihini = self.mc.get_system_info() p2p_tables = {(x, y): self.mc.get_p2p_routing_table(x, y) for x, y in self.mc.get_system_info()} #for c in apasihini.chips(): # print c @QtCore.pyqtSlot() def getSimulationTick(self): simTick, ok = QtGui.QInputDialog.getInt( self, "Simulation Tick", "Enter Simulation Tick in microsecond", self.simTick, DEF_MIN_TIMER_TICK, 1000, 1) if ok is True: print "Sending tick {} microseconds".format(simTick) self.simTick = simTick self.sdp.sendSimTick(self.xSrc, self.ySrc, simTick) @QtCore.pyqtSlot() def startSim(self): # First ask, for how long msLong, ok = QtGui.QInputDialog.getInt( self, "Running Time", "Enter simulation running time (in ms)", 60000, DEF_MIN_RUNNING_TIME, DEF_MAX_RUNNING_TIME, 1) if ok: self.runningTime = msLong self.actionStop.setEnabled(True) self.actionStart.setEnabled(False) self.sdp.sendStartCmd(self.xSrc, self.ySrc) print "Starting simulation..." # untuk ambil data, buat timer: if self.runningTime > 0: print "Set interval to", self.runningTime, "ms" self.timer.setInterval(self.runningTime) self.timer.start() @QtCore.pyqtSlot() def stopSim(self): if self.timer.isActive(): self.timer.stop() self.actionStop.setEnabled(False) self.actionStart.setEnabled(True) # self.sdp.sendStopCmd(self.xSrc, self.ySrc) #-> only to SOURCE/SINK node self.sdp.sendStopCmd(self.xSrc, self.ySrc, self.TGmap) #-> to all nodes print "Experimen selesai. Sekarang lihat iobuf core-1 di chip<0,0> (srcsink node)" QtGui.QMessageBox.information( self, "Experiment Done!", "Look the result at iobuf core-1 in chip<0,0> (srcsink node)!")
def __init__(self, hostname_or_machine_controller): """Create a new network experiment on a particular SpiNNaker machine. Example usage:: >>> import sys >>> from network_tester import Experiment >>> e = Experiment(sys.argv[1]) # Takes hostname as a CLI argument The experimental parameters can be set by setting attributes of the :py:class:`Experiment` instance like so:: >>> e = Experiment(...) >>> # Set the probability of a packet being generated at the source >>> # of each net every timestep >>> e.probability = 1.0 Parameters ---------- hostname_or_machine_controller : \ str or :py:class:`rig.machine_control.MachineController` The hostname or :py:class:`~rig.machine_control.MachineController` of a SpiNNaker machine to run the experiment on. """ if isinstance(hostname_or_machine_controller, str): self._mc = MachineController(hostname_or_machine_controller) else: self._mc = hostname_or_machine_controller # A cached reference to the SpiNNaker machine the experiment will run # in. To be accessed via .machine which automatically fetches the # machine the first time it is requested. self._machine = None # A set of placements, allocations and routes for the # traffic-generating/consuming vertices. self._placements = None self._allocations = None self._routes = None # The experimental group currently being defined. Set and cleared on # entry and exit of Group context-managers. self._cur_group = None # A list of experimental groups which have been defined self._groups = [] # A list of vertices in the experiment self._vertices = [] # A list of nets in the experiment self._nets = [] # Holds the value of every option along with any special cases. # If a value can have per-node or per-group exceptions it is stored as # a dictionary with keys (group, vert_or_net) with the value being # defined as below. Otherwise, the value is just stored immediately in # the _values dictionary. The list below gives the order of priority # for definitions. # * (None, None) The global default # * (group, None) The default for a particular experimental group # * (None, vertex) The default for a particular vertex # * (None, net) The default for a particular net # * (group, vertex) The value for a particular vertex in a specific # group # * (group, net) The value for a particular net in a specific group # {option: value or {(group, vert_or_net): value, ...}, ...} self._values = { "seed": {(None, None): None}, "timestep": {(None, None): 0.001}, "warmup": {(None, None): 0.0}, "duration": {(None, None): 1.0}, "cooldown": {(None, None): 0.0}, "flush_time": {(None, None): 0.01}, "record_interval": {(None, None): 0.0}, "probability": {(None, None): 1.0}, "burst_period": {(None, None): 0.0}, "burst_duty": {(None, None): 0.0}, "burst_phase": {(None, None): 0.0}, "use_payload": {(None, None): False}, "consume_packets": {(None, None): True}, "router_timeout": {(None, None): None}, "reinject_packets": {(None, None): False}, } # All counters are global-only options and default to False. for counter in Counters: self._values["record_{}".format(counter.name)] = False
if __name__ == "__main__": # Parse the arguments parser = argparse.ArgumentParser() parser.add_argument("routing_table") parser.add_argument("out_file") parser.add_argument("target_length", type=int, default=0, nargs='?') parser.add_argument("--memory-profile", type=str) args = parser.parse_args() # Load and minimise all routing tables print("Reading routing tables...") with open(args.routing_table, "rb") as f: uncompressed = common.read_routing_tables(f) # Talk to the machine mc = MachineController("192.168.1.1") mc.send_signal("stop") # Convert the tables into the appropriate formats chip_data = { chip: pack_table(table, args.target_length) for chip, table in iteritems(uncompressed) } # Allocate memory on the machine chip_mem = {(x, y): mc.sdram_alloc_as_filelike(len(data), x=x, y=y, tag=1) for (x, y), data in iteritems(chip_data)} # Build the targets dictionary targets = {chip: {1} for chip in iterkeys(chip_mem)}
class Simulator(object): """SpiNNaker simulator for Nengo models. The simulator period determines how much data will be stored on SpiNNaker and is the maximum length of simulation allowed before data is transferred between the machine and the host PC. If the period is set to `None` function of time Nodes will not be optimised and probes will be disabled. For any other value simulation lengths of less than or equal to the period will be in real-time, longer simulations will be possible but will include short gaps when data is transferred between SpiNNaker and the host. :py:meth:`~.close` should be called when the simulator will no longer be used. This will close all sockets used to communicate with the SpiNNaker machine and will leave the machine in a clean state. Failure to call `close` may result in later failures. Alternatively `with` may be used:: sim = nengo_spinnaker.Simulator(network) with sim: sim.run(10.0) """ _open_simulators = set() @classmethod def _add_simulator(cls, simulator): cls._open_simulators.add(simulator) @classmethod def _remove_simulator(cls, simulator): cls._open_simulators.remove(simulator) def __init__(self, network, dt=0.001, period=10.0, timescale=1.0, hostname=None, use_spalloc=None, allocation_fudge_factor=0.6): """Create a new Simulator with the given network. Parameters ---------- period : float or None Duration of one period of the simulator. This determines how much memory will be allocated to store precomputed and probed data. timescale : float Scaling factor to apply to the simulation, e.g., a value of `0.5` will cause the simulation to run at half real-time. hostname : string or None Hostname of the SpiNNaker machine to use; if None then the machine specified in the config file will be used. use_spalloc : bool or None Allocate a SpiNNaker machine for the simulator using ``spalloc``. If None then the setting specified in the config file will be used. Other Parameters ---------------- allocation_fudge_factor: Fudge factor to allocate more cores than really necessary when using `spalloc` to ensure that (a) there are sufficient "live" cores in the allocated machine, (b) there is sufficient room for a good place and route solution. This should generally be more than 0.1 (10% more cores than necessary) to account for the usual rate of missing chips. """ # Add this simulator to the set of open simulators Simulator._add_simulator(self) # Create the IO controller io_cls = getconfig(network.config, Simulator, "node_io", Ethernet) io_kwargs = getconfig(network.config, Simulator, "node_io_kwargs", dict()) self.io_controller = io_cls(**io_kwargs) # Calculate the machine timestep, this is measured in microseconds # (hence the 1e6 scaling factor). self.timescale = timescale machine_timestep = int((dt / timescale) * 1e6) # Determine the maximum run-time self.max_steps = None if period is None else int(period / dt) self.steps = 0 # Steps simulated # If the simulator is in "run indefinite" mode (i.e., max_steps=None) # then we modify the builders to ignore function of time Nodes and # probes. builder_kwargs = self.io_controller.builder_kwargs if self.max_steps is None: raise NotImplementedError # Create a model from the network, using the IO controller logger.debug("Building model") start_build = time.time() self.model = Model(dt=dt, machine_timestep=machine_timestep, decoder_cache=get_default_decoder_cache()) self.model.build(network, **builder_kwargs) logger.info("Build took {:.3f} seconds".format(time.time() - start_build)) self.model.decoder_cache.shrink() self.dt = self.model.dt self._closed = False # Whether the simulator has been closed or not self.host_sim = self._create_host_sim() # Holder for probe data self.data = {} # Holder for profiling data self.profiler_data = {} # Convert the model into a netlist logger.info("Building netlist") start = time.time() self.netlist = self.model.make_netlist(self.max_steps or 0) # Determine whether to use a spalloc machine or not if use_spalloc is None: # Default is to not use spalloc; this is indicated by either the # absence of the option in the config file OR the option being set # to false. use_spalloc = (rc.has_option("spinnaker_machine", "use_spalloc") and rc.getboolean("spinnaker_machine", "use_spalloc")) # Create a controller for the machine and boot if necessary self.job = None if not use_spalloc or hostname is not None: # Use the specified machine rather than trying to get one # allocated. if hostname is None: hostname = rc.get("spinnaker_machine", "hostname") else: # Attempt to get a machine allocated to us from spalloc import Job # Determine how many boards to ask for (assuming 16 usable cores # per chip and 48 chips per board). n_cores = self.netlist.n_cores * (1.0 + allocation_fudge_factor) n_boards = int(np.ceil((n_cores / 16.) / 48.)) # Request the job self.job = Job(n_boards) logger.info("Allocated job ID %d...", self.job.id) # Wait until we're given the machine logger.info("Waiting for machine allocation...") self.job.wait_until_ready() # spalloc recommends a slight delay before attempting to boot the # machine, later versions of spalloc server may relax this # requirement. time.sleep(5.0) # Store the hostname hostname = self.job.hostname logger.info("Using %d board(s) of \"%s\" (%s)", len(self.job.boards), self.job.machine_name, hostname) self.controller = MachineController(hostname) self.controller.boot() # Get a system-info object to place & route against logger.info("Getting SpiNNaker machine specification") system_info = self.controller.get_system_info() # Place & Route logger.info("Placing and routing") self.netlist.place_and_route( system_info, place=getconfig(network.config, Simulator, 'placer', rig.place_and_route.place), place_kwargs=getconfig(network.config, Simulator, 'placer_kwargs', {}), ) logger.info("{} cores in use".format(len(self.netlist.placements))) chips = set(six.itervalues(self.netlist.placements)) logger.info("Using {}".format(chips)) # Prepare the simulator against the placed, allocated and routed # netlist. self.io_controller.prepare(self.model, self.controller, self.netlist) # Load the application logger.info("Loading application") self.netlist.load_application(self.controller, system_info) # Check if any cores are in bad states if self.controller.count_cores_in_state( ["exit", "dead", "watchdog", "runtime_exception"]): for vertex, (x, y) in six.iteritems(self.netlist.placements): p = self.netlist.allocations[vertex][Cores].start status = self.controller.get_processor_status(p, x, y) if status.cpu_state is not AppState.sync0: print("Core ({}, {}, {}) in state {!s}".format( x, y, p, status)) print(self.controller.get_iobuf(p, x, y)) raise Exception("Unexpected core failures.") logger.info("Preparing and loading machine took {:3f} seconds".format( time.time() - start)) logger.info("Setting router timeout to 16 cycles") for x, y in system_info.chips(): with self.controller(x=x, y=y): data = self.controller.read(0xf1000000, 4) self.controller.write(0xf1000000, data[:-1] + b'\x10') def __enter__(self): """Enter a context which will close the simulator when exited.""" # Return self to allow usage like: # # with nengo_spinnaker.Simulator(model) as sim: # sim.run(1.0) return self def __exit__(self, exception_type, exception_value, traceback): """Exit a context and close the simulator.""" self.close() def run(self, time_in_seconds): """Simulate for the given length of time.""" # Determine how many steps to simulate for steps = int(np.round(float(time_in_seconds) / self.dt)) self.run_steps(steps) def run_steps(self, steps): """Simulate a give number of steps.""" while steps > 0: n_steps = min((steps, self.max_steps)) self._run_steps(n_steps) steps -= n_steps def _run_steps(self, steps): """Simulate for the given number of steps.""" if self._closed: raise Exception("Simulator has been closed and can't be used to " "run further simulations.") if steps is None: if self.max_steps is not None: raise Exception( "Cannot run indefinitely if a simulator period was " "specified. Create a new simulator with Simulator(model, " "period=None) to perform indefinite time simulations.") else: assert steps <= self.max_steps # Prepare the simulation self.netlist.before_simulation(self, steps) # Wait for all cores to hit SYNC0 (either by remaining it or entering # it from init) self._wait_for_transition(AppState.init, AppState.sync0, self.netlist.n_cores) self.controller.send_signal("sync0") # Get a new thread for the IO io_thread = self.io_controller.spawn() # Run the simulation try: # Prep exp_time = steps * self.dt / self.timescale io_thread.start() # Wait for all cores to hit SYNC1 self._wait_for_transition(AppState.sync0, AppState.sync1, self.netlist.n_cores) logger.info("Running simulation...") self.controller.send_signal("sync1") # Execute the local model host_steps = 0 start_time = time.time() run_time = 0.0 local_timestep = self.dt / self.timescale while run_time < exp_time: # Run a step self.host_sim.step() run_time = time.time() - start_time # If that step took less than timestep then spin time.sleep(0.0001) while run_time < host_steps * local_timestep: time.sleep(0.0001) run_time = time.time() - start_time finally: # Stop the IO thread whatever occurs io_thread.stop() # Wait for cores to re-enter sync0 self._wait_for_transition(AppState.run, AppState.sync0, self.netlist.n_cores) # Retrieve simulation data start = time.time() logger.info("Retrieving simulation data") self.netlist.after_simulation(self, steps) logger.info("Retrieving data took {:3f} seconds".format(time.time() - start)) # Increase the steps count self.steps += steps def _wait_for_transition(self, from_state, desired_to_state, num_verts): while True: # If no cores are still in from_state, stop if self.controller.count_cores_in_state(from_state) == 0: break # Wait a bit time.sleep(1.0) # Check if any cores haven't exited cleanly num_ready = self.controller.wait_for_cores_to_reach_state( desired_to_state, num_verts, timeout=5.0) if num_ready != num_verts: # Loop through all placed vertices for vertex, (x, y) in six.iteritems(self.netlist.placements): p = self.netlist.allocations[vertex][Cores].start status = self.controller.get_processor_status(p, x, y) if status.cpu_state is not desired_to_state: print("Core ({}, {}, {}) in state {!s}".format( x, y, p, status.cpu_state)) print(self.controller.get_iobuf(p, x, y)) raise Exception("Unexpected core failures before reaching %s " "state." % desired_to_state) def _create_host_sim(self): # change node_functions to reflect time # TODO: improve the reference simulator so that this is not needed # by adding a realtime option node_functions = {} node_info = dict(start=None) for node in self.io_controller.host_network.all_nodes: if callable(node.output): old_func = node.output if node.size_in == 0: def func(t, f=old_func): now = time.time() if node_info['start'] is None: node_info['start'] = now t = (now - node_info['start']) * self.timescale return f(t) else: def func(t, x, f=old_func): now = time.time() if node_info['start'] is None: node_info['start'] = now t = (now - node_info['start']) * self.timescale return f(t, x) node.output = func node_functions[node] = old_func # Build the host simulator host_sim = nengo.Simulator(self.io_controller.host_network, dt=self.dt) # reset node functions for node, func in node_functions.items(): node.output = func return host_sim def close(self): """Clean the SpiNNaker board and prevent further simulation.""" if not self._closed: # Stop the application self._closed = True self.io_controller.close() self.controller.send_signal("stop") # Destroy the job if we allocated one if self.job is not None: self.job.destroy() # Remove this simulator from the list of open simulators Simulator._remove_simulator(self) def trange(self, dt=None): return np.arange(1, self.steps + 1) * (self.dt or dt)
def __init__(self, network, dt=0.001, period=10.0, timescale=1.0, hostname=None, use_spalloc=None, allocation_fudge_factor=0.6): """Create a new Simulator with the given network. Parameters ---------- period : float or None Duration of one period of the simulator. This determines how much memory will be allocated to store precomputed and probed data. timescale : float Scaling factor to apply to the simulation, e.g., a value of `0.5` will cause the simulation to run at half real-time. hostname : string or None Hostname of the SpiNNaker machine to use; if None then the machine specified in the config file will be used. use_spalloc : bool or None Allocate a SpiNNaker machine for the simulator using ``spalloc``. If None then the setting specified in the config file will be used. Other Parameters ---------------- allocation_fudge_factor: Fudge factor to allocate more cores than really necessary when using `spalloc` to ensure that (a) there are sufficient "live" cores in the allocated machine, (b) there is sufficient room for a good place and route solution. This should generally be more than 0.1 (10% more cores than necessary) to account for the usual rate of missing chips. """ # Add this simulator to the set of open simulators Simulator._add_simulator(self) # Create the IO controller io_cls = getconfig(network.config, Simulator, "node_io", Ethernet) io_kwargs = getconfig(network.config, Simulator, "node_io_kwargs", dict()) self.io_controller = io_cls(**io_kwargs) # Calculate the machine timestep, this is measured in microseconds # (hence the 1e6 scaling factor). self.timescale = timescale machine_timestep = int((dt / timescale) * 1e6) # Determine the maximum run-time self.max_steps = None if period is None else int(period / dt) self.steps = 0 # Steps simulated # If the simulator is in "run indefinite" mode (i.e., max_steps=None) # then we modify the builders to ignore function of time Nodes and # probes. builder_kwargs = self.io_controller.builder_kwargs if self.max_steps is None: raise NotImplementedError # Create a model from the network, using the IO controller logger.debug("Building model") start_build = time.time() self.model = Model(dt=dt, machine_timestep=machine_timestep, decoder_cache=get_default_decoder_cache()) self.model.build(network, **builder_kwargs) logger.info("Build took {:.3f} seconds".format(time.time() - start_build)) self.model.decoder_cache.shrink() self.dt = self.model.dt self._closed = False # Whether the simulator has been closed or not self.host_sim = self._create_host_sim() # Holder for probe data self.data = {} # Holder for profiling data self.profiler_data = {} # Convert the model into a netlist logger.info("Building netlist") start = time.time() self.netlist = self.model.make_netlist(self.max_steps or 0) # Determine whether to use a spalloc machine or not if use_spalloc is None: # Default is to not use spalloc; this is indicated by either the # absence of the option in the config file OR the option being set # to false. use_spalloc = ( rc.has_option("spinnaker_machine", "use_spalloc") and rc.getboolean("spinnaker_machine", "use_spalloc")) # Create a controller for the machine and boot if necessary self.job = None if not use_spalloc or hostname is not None: # Use the specified machine rather than trying to get one # allocated. if hostname is None: hostname = rc.get("spinnaker_machine", "hostname") else: # Attempt to get a machine allocated to us from spalloc import Job # Determine how many boards to ask for (assuming 16 usable cores # per chip and 48 chips per board). n_cores = self.netlist.n_cores * (1.0 + allocation_fudge_factor) n_boards = int(np.ceil((n_cores / 16.) / 48.)) # Request the job self.job = Job(n_boards) logger.info("Allocated job ID %d...", self.job.id) # Wait until we're given the machine logger.info("Waiting for machine allocation...") self.job.wait_until_ready() # spalloc recommends a slight delay before attempting to boot the # machine, later versions of spalloc server may relax this # requirement. time.sleep(5.0) # Store the hostname hostname = self.job.hostname logger.info("Using %d board(s) of \"%s\" (%s)", len(self.job.boards), self.job.machine_name, hostname) self.controller = MachineController(hostname) self.controller.boot() # Get a system-info object to place & route against logger.info("Getting SpiNNaker machine specification") system_info = self.controller.get_system_info() # Place & Route logger.info("Placing and routing") self.netlist.place_and_route( system_info, place=getconfig(network.config, Simulator, 'placer', rig.place_and_route.place), place_kwargs=getconfig(network.config, Simulator, 'placer_kwargs', {}), ) logger.info("{} cores in use".format(len(self.netlist.placements))) chips = set(six.itervalues(self.netlist.placements)) logger.info("Using {}".format(chips)) # Prepare the simulator against the placed, allocated and routed # netlist. self.io_controller.prepare(self.model, self.controller, self.netlist) # Load the application logger.info("Loading application") self.netlist.load_application(self.controller, system_info) # Check if any cores are in bad states if self.controller.count_cores_in_state(["exit", "dead", "watchdog", "runtime_exception"]): for vertex, (x, y) in six.iteritems(self.netlist.placements): p = self.netlist.allocations[vertex][Cores].start status = self.controller.get_processor_status(p, x, y) if status.cpu_state is not AppState.sync0: print("Core ({}, {}, {}) in state {!s}".format( x, y, p, status)) print(self.controller.get_iobuf(p, x, y)) raise Exception("Unexpected core failures.") logger.info("Preparing and loading machine took {:3f} seconds".format( time.time() - start )) logger.info("Setting router timeout to 16 cycles") for x, y in system_info.chips(): with self.controller(x=x, y=y): data = self.controller.read(0xf1000000, 4) self.controller.write(0xf1000000, data[:-1] + b'\x10')
class MainWindow(QtGui.QMainWindow, QtMainWindow.Ui_QtMainWindow): """ It inherits QMainWindow and uses pyuic4-generated python files from the .ui """ pltDataRdy = pyqtSignal(list) # for streaming data to the plotter/calibrator def __init__(self, mIP=None, logFName=None, parent=None): super(MainWindow, self).__init__(parent) self.setupUi(self) self.setCentralWidget(self.mdiArea); self.statusTxt = QtGui.QLabel("") self.statusBar().addWidget(self.statusTxt) # load setting self.loadSettings() # if machine IP is provided, check if it is booted and/or if the profiler has been loaded if mIP is not None: self.mIP = mIP self.checkSpiNN4() else: self.mIP = None self.connect(self.actionShow_Chips, SIGNAL("triggered()"), SLOT("showChips()")) """ Scenario: - sw and pw send data to MainWindow - MainWindow do the averaging on sw data, then send avg_sw and pw to plotter At the same time, MainWindow store the data """ #-------------------- GUI setup --------------------- # Dump raw data in arduConsole widget (cw). self.cw = ifaceArduSpiNN(logFName,self) self.subWinConsole = QtGui.QMdiSubWindow(self) self.subWinConsole.setWidget(self.cw) self.mdiArea.addSubWindow(self.subWinConsole) self.subWinConsole.setGeometry(0,0,self.cw.width(),500) self.cw.show() # Power plot widget (pw). self.pw = Pwidget(self) self.subWinPW = QtGui.QMdiSubWindow(self) self.subWinPW.setWidget(self.pw) self.mdiArea.addSubWindow(self.subWinPW) self.subWinPW.setGeometry(self.cw.width()+10,0,760,500) self.pw.show() # SpiNNaker profiler plot widget (sw). self.sw = Swidget(self) self.subWinSW = QtGui.QMdiSubWindow(self) self.subWinSW.setWidget(self.sw) self.mdiArea.addSubWindow(self.subWinSW) self.subWinSW.setGeometry(self.subWinPW.x(), self.subWinPW.y()+self.subWinPW.height(),760,500) self.sw.show() # initially, we don't show chip visualizer self.vis = None # SIGNAL-SLOT connection self.cw.spinUpdate.connect(self.sw.readPltData) self.cw.arduUpdate.connect(self.pw.readPltData) # just for debugging: # self.cw.arduUpdate.connect(self.readArduData) # self.cw.spinUpdate.connect(self.readSpinData) def loadSettings(self): """ Load configuration setting from file. Let's use INI format and UserScope :return: """ #init value self.conf = config() #if used before, then load from previous one; otherwise, it use the initial value above self.settings = QSettings(QSettings.IniFormat, QSettings.UserScope, "APT", "SpiNN-4 Power Profiler") self.conf.xPos,ok = self.settings.value(self.conf.xPosKey, self.conf.xPos).toInt() self.conf.yPos,ok = self.settings.value(self.conf.yPosKey, self.conf.yPos).toInt() self.conf.width,ok = self.settings.value(self.conf.widthKey, self.conf.width).toInt() self.conf.height,ok = self.settings.value(self.conf.heightKey, self.conf.height).toInt() #print "isWritable?", self.settings.isWritable() #print "conf filename", self.settings.fileName() #then apply to self self.setGeometry(self.conf.xPos, self.conf.yPos, self.conf.width, self.conf.height) def checkSpiNN4(self, alwaysAsk=True): #return #go out immediately for experiment with Basab """ if the MainWindow class is called with an IP, then check if the machine is ready """ loadProfiler = False # first, check if the machine is booted print "Check the machine: ", self.mc = MachineController(self.mIP) bootByMe = self.mc.boot() # if bootByMe is true, then the machine is booted by readSpin4Pwr.py, otherwise it is aleady booted # if rig cannot boot the machine (eq. the machine is not connected or down), the you'll see error # message in the arduConsole if bootByMe is False: print "it is booted already!" else: print "it is now booted!" loadProfiler = True alwaysAsk = False # because the machine is just booted, then force it load profiler # second, ask if profilers need to be loaded cpustat = self.mc.get_processor_status(1,0,0) #core-1 in chip <0,0> profName = cpustat.app_name profState = int(cpustat.cpu_state) profVersion = cpustat.user_vars[0] # read from sark.vcpu->user0 #print "Profiler name: ", profName #print "Profiler state: ", profState #print "Profiler version: ", profVersion if profName.upper()==DEF.REQ_PROF_NAME.upper() and profState==7 and profVersion==DEF.REQ_PROF_VER: print "Required profiler.aplx is running!" loadProfiler = False else: if alwaysAsk: askQ = raw_input('Load the correct profiler.aplx? [Y/n]') if len(askQ) == 0 or askQ.upper() == 'Y': loadProfiler = True else: loadProfiler = False print "[WARNING] profiler.aplx is not ready or invalid version" # third, load the profilers if loadProfiler: # then load the correct profiler version print "Loading profiler from", DEF.REQ_PROF_APLX # populate all chips in the board chips = self.mc.get_system_info().keys() dest = dict() for c in chips: dest[c] = [1] # the profiler.aplx goes to core-1 self.mc.load_application(DEF.REQ_PROF_APLX, dest, app_id=DEF.REQ_PROF_APLX_ID) print "Profilers are sent to SpiNN4!" else: print "No valid profiler! This program might not work correctly!" # Last but important: MAKE SURE IPTAG 3 IS SET iptag = self.mc.iptag_get(DEF.REPORT_IPTAG,0,0) if iptag.addr is '0.0.0.0' or iptag.port is not DEF.REPORT_IPTAG: #iptag DEF.REPORT_IPTAG is not defined yet self.mc.iptag_set(DEF.REPORT_IPTAG, DEF.HOST_PC, DEF.RECV_PORT, 0, 0) @pyqtSlot() def reactiveShopCipMenu(self): self.actionShow_Chips.setEnabled(True) del self.subWinVis @pyqtSlot() def showChips(self): """ Show chip layout :return: """ if self.mIP is None: """ i.e., the IP is not defined when this menu is clicked """ # first, ask the IP of the machine mIP, ok = QtGui.QInputDialog.getText(self, "SpiNN4 Location", "SpiNN4 IP address", QtGui.QLineEdit.Normal, DEF.MACHINE) if ok is True: self.mIP = mIP self.checkSpiNN4(False) # after this, self.mc is available # then open the widget mInfo = self.mc.get_system_info() w = mInfo.width h = mInfo.height chipList = mInfo.keys() #self.vis = visWidget(w, h, chipList) # Segmentation fault self.vis = visWidget(w, h, chipList, self) self.subWinVis = QtGui.QMdiSubWindow(self) self.subWinVis.setWidget(self.vis) self.mdiArea.addSubWindow(self.subWinVis) #self.subWinVis.setGeometry(self.subWinPW.x(), self.subWinPW.y()+self.subWinPW.height(),760,500) # connect to the source of temperature data # masih salah: self.cw.spinUpdate.connect(self.vis.readSpinData) self.vis.show() # and disable the menu item self.actionShow_Chips.setEnabled(False) # the menu will be reset to enable if the widget is closed self.vis.visWidgetTerminated.connect(self.reactiveShopCipMenu) """ ######################### GUI callback ########################### """ # readSpinData and readArduData are just for debugging @pyqtSlot(list) def readSpinData(self, prfData): """ Read profiler data and prepare for saving. prfData is a list of 48 "Integer" item that should be decoded as: freq, nActive, temp Hence, fmt = "<2BH" """ #print len(prfData) #print type(prfData[0]) #return fmt = "<2BH" #fmt = "<H2B" print "{", for i in range(len(prfData)): cpu = struct.pack("<I",prfData[i]) #print "0x%x " % cpu, #f,nA,T = struct.unpack(fmt, prfData[i]) f,nA,T = struct.unpack(fmt, cpu) #print "[{},{},{}]".format(f,nA,T), if i < (len(prfData)-1): print "[{},{},{}],".format(f, nA, T), else: print "[{},{},{}]".format(f, nA, T), print "}" @pyqtSlot(list) def readArduData(self, pwrData): """ Read power data from Arduino and prepare for saving. """ def closeEvent(self, event): #print "x, y, w, h =",self.x(),self.y(),self.width(),self.height() # save the current configuration self.settings = QSettings(QSettings.IniFormat, QSettings.UserScope, "APT", "SpiNN-4 Power Profiler") self.settings.setValue(self.conf.xPosKey, self.x()) self.settings.setValue(self.conf.yPosKey, self.y()) self.settings.setValue(self.conf.widthKey, self.width()) self.settings.setValue(self.conf.heightKey, self.height()) self.settings.sync() #print "Conf saved!" # Notify ifaceArduSpiNN to stop the thread: self.cw.stop() # to avoid QThread being destroyed while thread is still running event.accept()
def checkSpiNN4(self, alwaysAsk=True): #return #go out immediately for experiment with Basab """ if the MainWindow class is called with an IP, then check if the machine is ready """ loadProfiler = False # first, check if the machine is booted print "Check the machine: ", self.mc = MachineController(self.mIP) bootByMe = self.mc.boot() # if bootByMe is true, then the machine is booted by readSpin4Pwr.py, otherwise it is aleady booted # if rig cannot boot the machine (eq. the machine is not connected or down), the you'll see error # message in the arduConsole if bootByMe is False: print "it is booted already!" else: print "it is now booted!" loadProfiler = True alwaysAsk = False # because the machine is just booted, then force it load profiler # second, ask if profilers need to be loaded cpustat = self.mc.get_processor_status(1,0,0) #core-1 in chip <0,0> profName = cpustat.app_name profState = int(cpustat.cpu_state) profVersion = cpustat.user_vars[0] # read from sark.vcpu->user0 #print "Profiler name: ", profName #print "Profiler state: ", profState #print "Profiler version: ", profVersion if profName.upper()==DEF.REQ_PROF_NAME.upper() and profState==7 and profVersion==DEF.REQ_PROF_VER: print "Required profiler.aplx is running!" loadProfiler = False else: if alwaysAsk: askQ = raw_input('Load the correct profiler.aplx? [Y/n]') if len(askQ) == 0 or askQ.upper() == 'Y': loadProfiler = True else: loadProfiler = False print "[WARNING] profiler.aplx is not ready or invalid version" # third, load the profilers if loadProfiler: # then load the correct profiler version print "Loading profiler from", DEF.REQ_PROF_APLX # populate all chips in the board chips = self.mc.get_system_info().keys() dest = dict() for c in chips: dest[c] = [1] # the profiler.aplx goes to core-1 self.mc.load_application(DEF.REQ_PROF_APLX, dest, app_id=DEF.REQ_PROF_APLX_ID) print "Profilers are sent to SpiNN4!" else: print "No valid profiler! This program might not work correctly!" # Last but important: MAKE SURE IPTAG 3 IS SET iptag = self.mc.iptag_get(DEF.REPORT_IPTAG,0,0) if iptag.addr is '0.0.0.0' or iptag.port is not DEF.REPORT_IPTAG: #iptag DEF.REPORT_IPTAG is not defined yet self.mc.iptag_set(DEF.REPORT_IPTAG, DEF.HOST_PC, DEF.RECV_PORT, 0, 0)
""" A Rig-based program which loads a binary onto a SpiNNaker core which then adds two numbers together which have been loaded into SDRAM. """ import sys import random import struct from rig.machine_control import MachineController # Control the SpiNNaker machine whose hostname is given on the command line. We # assume the machine has already been booted, e.g. with rig-boot. mc = MachineController(sys.argv[1]) # Allocate space for the two 32-bit numbers to add together and the 32-bit # result. sdram_addr = mc.sdram_alloc(12, x=0, y=0, tag=1) # Pick two random numbers to be added together and write them to SDRAM num_a = random.getrandbits(30) num_b = random.getrandbits(30) data = struct.pack("<II", num_a, num_b) mc.write(sdram_addr, data, x=0, y=0) # Load the adder application onto core 1 of chip (0, 0). mc.load_application("adder.aplx", {(0, 0): {1}}) # Wait for the application to finish mc.wait_for_cores_to_reach_state("exit", 1)
parser.add_argument("out_file") parser.add_argument("target_length", type=int, default=0, nargs='?') parser.add_argument("--memory-profile", type=str) args = parser.parse_args() # Load and minimise all routing tables print("Reading routing tables...") with open(args.routing_table, "rb") as f: uncompressed = common.read_routing_tables(f) # Request a SpiNNaker machine print("Waiting for SpiNNaker machine...") with spalloc.Job(args.width, args.height) as job: # Talk to the machine print("Booting...") mc = MachineController(job.hostname) mc.boot() mc.discover_connections() # Convert the tables into the appropriate formats chip_data = {chip: pack_table(table, args.target_length) for chip, table in iteritems(uncompressed)} # Allocate memory on the machine chip_mem = { (x, y): mc.sdram_alloc_as_filelike(len(data), x=x, y=y, tag=1) for (x, y), data in iteritems(chip_data) } # Build the targets dictionary targets = {chip: {1} for chip in iterkeys(chip_mem)}
""" A Rig-based program which loads a binary onto a SpiNNaker core which then adds two numbers together which have been loaded into SDRAM. """ import sys import random import struct from rig.machine_control import MachineController # Control the SpiNNaker machine whose hostname is given on the command line. We # assume the machine has already been booted, e.g. with rig-boot. mc = MachineController(sys.argv[1]) # Make sure the "stop" signal is sent, regardless of whether something crashes # or if we exit normally. with mc.application(): # Allocate space for the two 32-bit numbers to add together and the 32-bit # result. sdram = mc.sdram_alloc_as_filelike(12, x=0, y=0, tag=1) # Pick two random numbers to be added together and write them to SDRAM num_a = random.getrandbits(30) num_b = random.getrandbits(30) data = struct.pack("<II", num_a, num_b) sdram.write(data) # Load the adder application onto core 1 of chip (0, 0). mc.load_application("adder.aplx", {(0, 0): {1}})
def main(argv=None): t = Terminal(stream=sys.stderr) cfg = config.read_config() parser = argparse.ArgumentParser( description="Request (and allocate) a SpiNNaker machine.") parser.add_argument("--version", "-V", action="version", version=__version__) parser.add_argument("--quiet", "-q", action="store_true", default=False, help="suppress informational messages") parser.add_argument("--debug", action="store_true", default=False, help="enable additional diagnostic information") parser.add_argument("--no-destroy", "-D", action="store_true", default=False, help="do not destroy the job on exit") if MachineController is not None: parser.add_argument("--boot", "-B", action="store_true", default=False, help="boot the machine once powered on") allocation_args = parser.add_argument_group( "allocation requirement arguments") allocation_args.add_argument("what", nargs="*", default=[], type=int, metavar="WHAT", help="what to allocate: nothing or 1 " "requests 1 SpiNN-5 board, NUM requests " "at least NUM SpiNN-5 boards, WIDTH " "HEIGHT means WIDTHxHEIGHT triads of " "SpiNN-5 boards and X Y Z requests a " "board the specified logical board " "coordinate.") allocation_args.add_argument("--resume", "-r", type=int, help="if given, resume keeping the " "specified job alive rather than " "creating a new job (all allocation " "requirements will be ignored)") allocation_args.add_argument("--machine", "-m", nargs="?", default=cfg["machine"], help="only allocate boards which are part " "of a specific machine, or any machine " "if no machine is given " "(default: %(default)s)") allocation_args.add_argument("--tags", "-t", nargs="*", metavar="TAG", default=cfg["tags"] or ["default"], help="only allocate boards which have (at " "least) the specified flags " "(default: {})".format(" ".join(cfg["tags"] or []))) allocation_args.add_argument("--min-ratio", type=float, metavar="RATIO", default=cfg["min_ratio"], help="when allocating by number of boards, " "require that the allocation be at " "least as square as this ratio " "(default: %(default)s)") allocation_args.add_argument("--max-dead-boards", type=int, metavar="NUM", default=(-1 if cfg["max_dead_boards"] is None else cfg["max_dead_boards"]), help="boards allowed to be " "dead in the allocation, or -1 to allow " "any number of dead boards " "(default: %(default)s)") allocation_args.add_argument("--max-dead-links", type=int, metavar="NUM", default=(-1 if cfg["max_dead_links"] is None else cfg["max_dead_links"]), help="inter-board links allowed to be " "dead in the allocation, or -1 to allow " "any number of dead links " "(default: %(default)s)") allocation_args.add_argument( "--require-torus", "-w", action="store_true", default=cfg["require_torus"], help="require that the allocation contain " "torus (a.k.a. wrap-around) " "links {}".format("(default)" if cfg["require_torus"] else "")) allocation_args.add_argument( "--no-require-torus", "-W", action="store_false", dest="require_torus", help="do not require that the allocation " "contain torus (a.k.a. wrap-around) " "links {}".format("" if cfg["require_torus"] else "(default)")) command_args = parser.add_argument_group("command wrapping arguments") command_args.add_argument("--command", "-c", nargs=argparse.REMAINDER, help="execute the specified command once boards " "have been allocated and deallocate the " "boards when the application exits ({} and " "{hostname} are substituted for the chip " "chip at (0, 0)'s hostname, {w} and " "{h} give the dimensions of the SpiNNaker " "machine in chips, {ethernet_ips} is a " "temporary file containing a CSV with " "three columns: x, y and hostname giving " "the hostname of each Ethernet connected " "SpiNNaker chip)") server_args = parser.add_argument_group("spalloc server arguments") server_args.add_argument("--owner", default=cfg["owner"], help="by convention, the email address of the " "owner of the job (default: %(default)s)") server_args.add_argument("--hostname", "-H", default=cfg["hostname"], help="hostname or IP of the spalloc server " "(default: %(default)s)") server_args.add_argument("--port", "-P", default=cfg["port"], type=int, help="port number of the spalloc server " "(default: %(default)s)") server_args.add_argument( "--keepalive", type=int, metavar="SECONDS", default=(-1 if cfg["keepalive"] is None else cfg["keepalive"]), help="the interval at which to require " "keepalive messages to be sent to " "prevent the server cancelling the " "job, or -1 to not require keepalive " "messages (default: %(default)s)") server_args.add_argument("--reconnect-delay", default=cfg["reconnect_delay"], type=float, metavar="SECONDS", help="seconds to wait before " "reconnecting to the server if the " "connection is lost (default: %(default)s)") server_args.add_argument("--timeout", default=cfg["timeout"], type=float, metavar="SECONDS", help="seconds to wait for a response " "from the server (default: %(default)s)") args = parser.parse_args(argv) # Fail if no owner is defined (unless resuming) if not args.owner and args.resume is None: parser.error( "--owner must be specified (typically your email address)") # Fail if server not specified if args.hostname is None: parser.error("--hostname of spalloc server must be specified") # Set universal job arguments job_kwargs = { "hostname": args.hostname, "port": args.port, "reconnect_delay": args.reconnect_delay if args.reconnect_delay >= 0.0 else None, "timeout": args.timeout if args.timeout >= 0.0 else None, } if args.resume: job_args = [] job_kwargs.update({ "resume_job_id": args.resume, }) else: # Make sure 'what' takes the right form if len(args.what) not in (0, 1, 2, 3): parser.error("expected either no arguments, one argument, NUM, " "two arguments, WIDTH HEIGHT, or three arguments " "X Y Z") # Unpack arguments for the job and server job_args = args.what job_kwargs.update({ "owner": args.owner, "keepalive": args.keepalive if args.keepalive >= 0.0 else None, "machine": args.machine, "tags": args.tags if args.machine is None else None, "min_ratio": args.min_ratio, "max_dead_boards": args.max_dead_boards if args.max_dead_boards >= 0.0 else None, "max_dead_links": args.max_dead_links if args.max_dead_links >= 0.0 else None, "require_torus": args.require_torus, }) # Set debug level if args.debug: logging.basicConfig(level=logging.DEBUG) # Create temporary file in which to write CSV of all board IPs _, ip_file_filename = tempfile.mkstemp(".csv", "spinnaker_ips_") def info(msg): if not args.quiet: t.stream.write("{}\n".format(msg)) # Reason for destroying the job reason = None try: # Create the job try: job = Job(*job_args, **job_kwargs) except (OSError, IOError) as e: info(t.red("Could not connect to server: {}".format(e))) return 6 try: # Wait for it to become ready, keeping the user informed along the # way old_state = None cur_state = job.state while True: # Show debug info on state-change if old_state != cur_state: if cur_state == JobState.queued: info( t.update( t.yellow("Job {}: Waiting in queue...".format( job.id)))) elif cur_state == JobState.power: info( t.update( t.yellow( "Job {}: Waiting for power on...".format( job.id)))) elif cur_state == JobState.ready: # Here we go! break elif cur_state == JobState.destroyed: # Exit with error state try: reason = job.reason except (IOError, OSError): reason = None if reason is not None: info( t.update( t.red("Job {}: Destroyed: {}".format( job.id, reason)))) else: info(t.red("Job {}: Destroyed.".format(job.id))) return 1 elif cur_state == JobState.unknown: info( t.update( t.red("Job {}: Job not recognised by server.". format(job.id)))) return 2 else: info( t.update( t.red( "Job {}: Entered an unrecognised state {}." .format(job.id, cur_state)))) return 3 try: old_state = cur_state cur_state = job.wait_for_state_change(cur_state) except KeyboardInterrupt: # Gracefully terminate from keyboard interrupt info( t.update( t.red("Job {}: Keyboard interrupt.".format( job.id)))) reason = "Keyboard interrupt." return 4 # Machine is now ready write_ips_to_csv(job.connections, ip_file_filename) # Boot the machine if required if MachineController is not None and args.boot: info(t.update(t.yellow("Job {}: Booting...".format(job.id)))) mc = MachineController(job.hostname) mc.boot(job.width, job.height) info(t.update(t.green("Job {}: Ready!".format(job.id)))) # Either run the user's application or just print the details. if args.command: return run_command(args.command, job.id, job.machine_name, job.connections, job.width, job.height, ip_file_filename) else: print_info(job.machine_name, job.connections, job.width, job.height, ip_file_filename) return 0 finally: # Destroy job and disconnect client if args.no_destroy: job.close() else: job.destroy(reason) finally: # Delete IP address list file os.remove(ip_file_filename)
def __init__(self, network, dt=0.001, period=10.0, timescale=1.0): """Create a new Simulator with the given network. Parameters ---------- period : float or None Duration of one period of the simulator. This determines how much memory will be allocated to store precomputed and probed data. timescale : float Scaling factor to apply to the simulation, e.g., a value of `0.5` will cause the simulation to run at half real-time. """ # Add this simulator to the set of open simulators Simulator._add_simulator(self) # Create a controller for the machine and boot if necessary hostname = rc.get("spinnaker_machine", "hostname") machine_width = rc.getint("spinnaker_machine", "width") machine_height = rc.getint("spinnaker_machine", "height") self.controller = MachineController(hostname) self.controller.boot(machine_width, machine_height) # Create the IO controller io_cls = getconfig(network.config, Simulator, "node_io", Ethernet) io_kwargs = getconfig(network.config, Simulator, "node_io_kwargs", dict()) self.io_controller = io_cls(**io_kwargs) # Calculate the machine timestep, this is measured in microseconds # (hence the 1e6 scaling factor). self.timescale = timescale machine_timestep = int((dt / timescale) * 1e6) # Determine the maximum run-time self.max_steps = None if period is None else int(period / dt) self.steps = 0 # Steps simulated # If the simulator is in "run indefinite" mode (i.e., max_steps=None) # then we modify the builders to ignore function of time Nodes and # probes. builder_kwargs = self.io_controller.builder_kwargs if self.max_steps is None: raise NotImplementedError # Create a model from the network, using the IO controller logger.debug("Building model") start_build = time.time() self.model = Model(dt=dt, machine_timestep=machine_timestep, decoder_cache=get_default_decoder_cache()) self.model.build(network, **builder_kwargs) forced_removals = get_force_removal_passnodes(network) optimise_out_passthrough_nodes(self.model, self.io_controller.passthrough_nodes, network.config, forced_removals) logger.info("Build took {:.3f} seconds".format(time.time() - start_build)) self.model.decoder_cache.shrink() self.dt = self.model.dt self._closed = False # Whether the simulator has been closed or not self.host_sim = self._create_host_sim() # Holder for probe data self.data = {} # Holder for profiling data self.profiler_data = {} # Convert the model into a netlist logger.info("Building netlist") start = time.time() self.netlist = self.model.make_netlist(self.max_steps or 0) # Get a system-info object to place & route against logger.info("Getting SpiNNaker machine specification") system_info = self.controller.get_system_info() # Place & Route logger.info("Placing and routing") self.netlist.place_and_route( system_info, place=getconfig(network.config, Simulator, 'placer', rig.place_and_route.place), place_kwargs=getconfig(network.config, Simulator, 'placer_kwargs', {}), ) logger.info("{} cores in use".format(len(self.netlist.placements))) chips = set(six.itervalues(self.netlist.placements)) logger.info("Using {}".format(chips)) # Prepare the simulator against the placed, allocated and routed # netlist. self.io_controller.prepare(self.model, self.controller, self.netlist) # Load the application logger.info("Loading application") self.netlist.load_application(self.controller, system_info) # Check if any cores are in bad states if self.controller.count_cores_in_state(["exit", "dead", "watchdog", "runtime_exception"]): for vertex in self.netlist.vertices: x, y = self.netlist.placements[vertex] p = self.netlist.allocations[vertex][Cores].start status = self.controller.get_processor_status(p, x, y) if status.cpu_state is not AppState.sync0: print("Core ({}, {}, {}) in state {!s}".format( x, y, p, status.cpu_state)) raise Exception("Unexpected core failures.") logger.info("Preparing and loading machine took {:3f} seconds".format( time.time() - start )) logger.info("Setting router timeout to 16 cycles") for x in range(machine_width): for y in range(machine_height): with self.controller(x=x, y=y): if (x, y) in system_info: data = self.controller.read(0xf1000000, 4) self.controller.write(0xf1000000, data[:-1] + b'\x10')
class Simulator(object): """SpiNNaker simulator for Nengo models. The simulator period determines how much data will be stored on SpiNNaker and is the maximum length of simulation allowed before data is transferred between the machine and the host PC. If the period is set to `None` function of time Nodes will not be optimised and probes will be disabled. For any other value simulation lengths of less than or equal to the period will be in real-time, longer simulations will be possible but will include short gaps when data is transferred between SpiNNaker and the host. :py:meth:`~.close` should be called when the simulator will no longer be used. This will close all sockets used to communicate with the SpiNNaker machine and will leave the machine in a clean state. Failure to call `close` may result in later failures. Alternatively `with` may be used:: sim = nengo_spinnaker.Simulator(network) with sim: sim.run(10.0) """ _open_simulators = set() @classmethod def _add_simulator(cls, simulator): cls._open_simulators.add(simulator) @classmethod def _remove_simulator(cls, simulator): cls._open_simulators.remove(simulator) def __init__(self, network, dt=0.001, period=10.0, timescale=1.0, hostname=None, use_spalloc=None, allocation_fudge_factor=0.6): """Create a new Simulator with the given network. Parameters ---------- period : float or None Duration of one period of the simulator. This determines how much memory will be allocated to store precomputed and probed data. timescale : float Scaling factor to apply to the simulation, e.g., a value of `0.5` will cause the simulation to run at half real-time. hostname : string or None Hostname of the SpiNNaker machine to use; if None then the machine specified in the config file will be used. use_spalloc : bool or None Allocate a SpiNNaker machine for the simulator using ``spalloc``. If None then the setting specified in the config file will be used. Other Parameters ---------------- allocation_fudge_factor: Fudge factor to allocate more cores than really necessary when using `spalloc` to ensure that (a) there are sufficient "live" cores in the allocated machine, (b) there is sufficient room for a good place and route solution. This should generally be more than 0.1 (10% more cores than necessary) to account for the usual rate of missing chips. """ # Add this simulator to the set of open simulators Simulator._add_simulator(self) # Create the IO controller io_cls = getconfig(network.config, Simulator, "node_io", Ethernet) io_kwargs = getconfig(network.config, Simulator, "node_io_kwargs", dict()) self.io_controller = io_cls(**io_kwargs) # Calculate the machine timestep, this is measured in microseconds # (hence the 1e6 scaling factor). self.timescale = timescale machine_timestep = int((dt / timescale) * 1e6) # Determine the maximum run-time self.max_steps = None if period is None else int(period / dt) self.steps = 0 # Steps simulated # If the simulator is in "run indefinite" mode (i.e., max_steps=None) # then we modify the builders to ignore function of time Nodes and # probes. builder_kwargs = self.io_controller.builder_kwargs if self.max_steps is None: raise NotImplementedError # Create a model from the network, using the IO controller logger.debug("Building model") start_build = time.time() self.model = Model(dt=dt, machine_timestep=machine_timestep, decoder_cache=get_default_decoder_cache()) self.model.build(network, **builder_kwargs) logger.info("Build took {:.3f} seconds".format(time.time() - start_build)) self.model.decoder_cache.shrink() self.dt = self.model.dt self._closed = False # Whether the simulator has been closed or not self.host_sim = self._create_host_sim() # Holder for probe data self.data = {} # Holder for profiling data self.profiler_data = {} # Convert the model into a netlist logger.info("Building netlist") start = time.time() self.netlist = self.model.make_netlist(self.max_steps or 0) # Determine whether to use a spalloc machine or not if use_spalloc is None: # Default is to not use spalloc; this is indicated by either the # absence of the option in the config file OR the option being set # to false. use_spalloc = ( rc.has_option("spinnaker_machine", "use_spalloc") and rc.getboolean("spinnaker_machine", "use_spalloc")) # Create a controller for the machine and boot if necessary self.job = None if not use_spalloc or hostname is not None: # Use the specified machine rather than trying to get one # allocated. if hostname is None: hostname = rc.get("spinnaker_machine", "hostname") else: # Attempt to get a machine allocated to us from spalloc import Job # Determine how many boards to ask for (assuming 16 usable cores # per chip and 48 chips per board). n_cores = self.netlist.n_cores * (1.0 + allocation_fudge_factor) n_boards = int(np.ceil((n_cores / 16.) / 48.)) # Request the job self.job = Job(n_boards) logger.info("Allocated job ID %d...", self.job.id) # Wait until we're given the machine logger.info("Waiting for machine allocation...") self.job.wait_until_ready() # spalloc recommends a slight delay before attempting to boot the # machine, later versions of spalloc server may relax this # requirement. time.sleep(5.0) # Store the hostname hostname = self.job.hostname logger.info("Using %d board(s) of \"%s\" (%s)", len(self.job.boards), self.job.machine_name, hostname) self.controller = MachineController(hostname) self.controller.boot() # Get a system-info object to place & route against logger.info("Getting SpiNNaker machine specification") system_info = self.controller.get_system_info() # Place & Route logger.info("Placing and routing") self.netlist.place_and_route( system_info, place=getconfig(network.config, Simulator, 'placer', rig.place_and_route.place), place_kwargs=getconfig(network.config, Simulator, 'placer_kwargs', {}), ) logger.info("{} cores in use".format(len(self.netlist.placements))) chips = set(six.itervalues(self.netlist.placements)) logger.info("Using {}".format(chips)) # Prepare the simulator against the placed, allocated and routed # netlist. self.io_controller.prepare(self.model, self.controller, self.netlist) # Load the application logger.info("Loading application") self.netlist.load_application(self.controller, system_info) # Check if any cores are in bad states if self.controller.count_cores_in_state(["exit", "dead", "watchdog", "runtime_exception"]): for vertex, (x, y) in six.iteritems(self.netlist.placements): p = self.netlist.allocations[vertex][Cores].start status = self.controller.get_processor_status(p, x, y) if status.cpu_state is not AppState.sync0: print("Core ({}, {}, {}) in state {!s}".format( x, y, p, status)) print(self.controller.get_iobuf(p, x, y)) raise Exception("Unexpected core failures.") logger.info("Preparing and loading machine took {:3f} seconds".format( time.time() - start )) logger.info("Setting router timeout to 16 cycles") for x, y in system_info.chips(): with self.controller(x=x, y=y): data = self.controller.read(0xf1000000, 4) self.controller.write(0xf1000000, data[:-1] + b'\x10') def __enter__(self): """Enter a context which will close the simulator when exited.""" # Return self to allow usage like: # # with nengo_spinnaker.Simulator(model) as sim: # sim.run(1.0) return self def __exit__(self, exception_type, exception_value, traceback): """Exit a context and close the simulator.""" self.close() def run(self, time_in_seconds): """Simulate for the given length of time.""" # Determine how many steps to simulate for steps = int(np.round(float(time_in_seconds) / self.dt)) self.run_steps(steps) def run_steps(self, steps): """Simulate a give number of steps.""" while steps > 0: n_steps = min((steps, self.max_steps)) self._run_steps(n_steps) steps -= n_steps def _run_steps(self, steps): """Simulate for the given number of steps.""" if self._closed: raise Exception("Simulator has been closed and can't be used to " "run further simulations.") if steps is None: if self.max_steps is not None: raise Exception( "Cannot run indefinitely if a simulator period was " "specified. Create a new simulator with Simulator(model, " "period=None) to perform indefinite time simulations." ) else: assert steps <= self.max_steps # Prepare the simulation self.netlist.before_simulation(self, steps) # Wait for all cores to hit SYNC0 (either by remaining it or entering # it from init) self._wait_for_transition(AppState.init, AppState.sync0, self.netlist.n_cores) self.controller.send_signal("sync0") # Get a new thread for the IO io_thread = self.io_controller.spawn() # Run the simulation try: # Prep exp_time = steps * self.dt / self.timescale io_thread.start() # Wait for all cores to hit SYNC1 self._wait_for_transition(AppState.sync0, AppState.sync1, self.netlist.n_cores) logger.info("Running simulation...") self.controller.send_signal("sync1") # Execute the local model host_steps = 0 start_time = time.time() run_time = 0.0 local_timestep = self.dt / self.timescale while run_time < exp_time: # Run a step self.host_sim.step() run_time = time.time() - start_time # If that step took less than timestep then spin time.sleep(0.0001) while run_time < host_steps * local_timestep: time.sleep(0.0001) run_time = time.time() - start_time finally: # Stop the IO thread whatever occurs io_thread.stop() # Wait for cores to re-enter sync0 self._wait_for_transition(AppState.run, AppState.sync0, self.netlist.n_cores) # Retrieve simulation data start = time.time() logger.info("Retrieving simulation data") self.netlist.after_simulation(self, steps) logger.info("Retrieving data took {:3f} seconds".format( time.time() - start )) # Increase the steps count self.steps += steps def _wait_for_transition(self, from_state, desired_to_state, num_verts): while True: # If no cores are still in from_state, stop if self.controller.count_cores_in_state(from_state) == 0: break # Wait a bit time.sleep(1.0) # Check if any cores haven't exited cleanly num_ready = self.controller.wait_for_cores_to_reach_state( desired_to_state, num_verts, timeout=5.0) if num_ready != num_verts: # Loop through all placed vertices for vertex, (x, y) in six.iteritems(self.netlist.placements): p = self.netlist.allocations[vertex][Cores].start status = self.controller.get_processor_status(p, x, y) if status.cpu_state is not desired_to_state: print("Core ({}, {}, {}) in state {!s}".format( x, y, p, status.cpu_state)) print(self.controller.get_iobuf(p, x, y)) raise Exception("Unexpected core failures before reaching %s " "state." % desired_to_state) def _create_host_sim(self): # change node_functions to reflect time # TODO: improve the reference simulator so that this is not needed # by adding a realtime option node_functions = {} node_info = dict(start=None) for node in self.io_controller.host_network.all_nodes: if callable(node.output): old_func = node.output if node.size_in == 0: def func(t, f=old_func): now = time.time() if node_info['start'] is None: node_info['start'] = now t = (now - node_info['start']) * self.timescale return f(t) else: def func(t, x, f=old_func): now = time.time() if node_info['start'] is None: node_info['start'] = now t = (now - node_info['start']) * self.timescale return f(t, x) node.output = func node_functions[node] = old_func # Build the host simulator host_sim = nengo.Simulator(self.io_controller.host_network, dt=self.dt) # reset node functions for node, func in node_functions.items(): node.output = func return host_sim def close(self): """Clean the SpiNNaker board and prevent further simulation.""" if not self._closed: # Stop the application self._closed = True self.io_controller.close() self.controller.send_signal("stop") # Destroy the job if we allocated one if self.job is not None: self.job.destroy() # Remove this simulator from the list of open simulators Simulator._remove_simulator(self) def trange(self, dt=None): return np.arange(1, self.steps + 1) * (self.dt or dt)
def main(args=None): parser = argparse.ArgumentParser( description="List all applications running on a SpiNNaker machine") parser.add_argument("--version", "-V", action="version", version="%(prog)s {}".format(rig.__version__)) parser.add_argument("hostname", type=str, help="hostname or IP of SpiNNaker system") parser.add_argument("x", type=int, nargs="?", help="the X coordinate of the chip to list") parser.add_argument("y", type=int, nargs="?", help="the Y coordinate of the chip to list") parser.add_argument("p", type=int, nargs="?", help="the core number to list") parser.add_argument("--app-id", "-a", type=str, action="append", help="show only applications with an application " "ID matching the supplied regex") parser.add_argument("--name", "-n", type=str, action="append", help="list only cores running the application " "whose name matches the supplied regex") parser.add_argument("--state", "-s", type=str, action="append", help="list only cores in states matching the " "supplied regex") args = parser.parse_args(args) if args.x is not None and args.y is None: parser.error("both or neither of 'x' and 'y' must be specified") try: mc = MachineController(args.hostname) info = mc.get_software_version(255, 255) if "SpiNNaker" in info.version_string: print("X Y P State Application App ID") print("--- --- --- ----------------- ---------------- ------") for (x, y, core, state, runtime_exception, application, app_id) \ in get_process_list(mc, args.x, args.y, args.p, args.app_id, args.name, args.state): print("{:3d} {:3d} {:3d} " "{:17s} " "{:16s} " "{:6d} " "{:s}".format( x, y, core, state.name, application, app_id, runtime_exception.name if runtime_exception else "")) else: sys.stderr.write("{}: error: unknown architecture '{}'\n".format( parser.prog, info.version_string.strip("\x00"))) return 2 except TimeoutError: sys.stderr.write("{}: error: command timed out\n".format(parser.prog)) return 1 return 0
""" A Rig-based program which boots a SpiNNaker machine and loads the "hello world" SpiNNaker binary onto it. """ import sys from rig.machine_control import MachineController # Control the SpiNNaker machine whose hostname is given on the command line mc = MachineController(sys.argv[1]) # To boot the machine, we take its network dimensions as command line # arguments. mc.boot(int(sys.argv[2]), int(sys.argv[3])) # Load the hello world application onto core 1 of chip (0, 0). mc.load_application("hello.aplx", {(0, 0): {1}}) # Wait for the application to finish mc.wait_for_cores_to_reach_state("exit", 1) # Print out the message printed by the application print(mc.get_iobuf(x=0, y=0, p=1)) # Free up any SpiNNaker resources mc.send_signal("stop")
class Simulator(object): """SpiNNaker simulator for Nengo models. The simulator period determines how much data will be stored on SpiNNaker and is the maximum length of simulation allowed before data is transferred between the machine and the host PC. If the period is set to `None` function of time Nodes will not be optimised and probes will be disabled. For any other value simulation lengths of less than or equal to the period will be in real-time, longer simulations will be possible but will include short gaps when data is transferred between SpiNNaker and the host. :py:meth:`~.close` should be called when the simulator will no longer be used. This will close all sockets used to communicate with the SpiNNaker machine and will leave the machine in a clean state. Failure to call `close` may result in later failures. Alternatively `with` may be used:: sim = nengo_spinnaker.Simulator(network) with sim: sim.run(10.0) """ _open_simulators = set() @classmethod def _add_simulator(cls, simulator): cls._open_simulators.add(simulator) @classmethod def _remove_simulator(cls, simulator): cls._open_simulators.remove(simulator) def __init__(self, network, dt=0.001, period=10.0): """Create a new Simulator with the given network. Parameters ---------- period : float or None Duration of one period of the simulator. This determines how much memory will be allocated to store precomputed and probed data. """ # Add this simulator to the set of open simulators Simulator._add_simulator(self) # Create a controller for the machine and boot if necessary hostname = rc.get("spinnaker_machine", "hostname") machine_width = rc.getint("spinnaker_machine", "width") machine_height = rc.getint("spinnaker_machine", "height") self.controller = MachineController(hostname) test_and_boot(self.controller, hostname, machine_width, machine_height) # Create the IO controller io_cls = getconfig(network.config, Simulator, "node_io", Ethernet) io_kwargs = getconfig(network.config, Simulator, "node_io_kwargs", dict()) self.io_controller = io_cls(**io_kwargs) # Determine the maximum run-time self.max_steps = None if period is None else int(period / dt) self.steps = 0 # Steps simulated # Create the IO controller. Function of time nodes are only enabled if # the simulator period is not None. io_cls = getconfig(network.config, Simulator, "node_io", Ethernet) io_kwargs = getconfig(network.config, Simulator, "node_io_kwargs", dict()) self.io_controller = io_cls( function_of_time_nodes=self.max_steps is not None, **io_kwargs ) # Create a model from the network, using the IO controller. Probes are # only built if the simulator period is not None. logger.debug("Building model") start_build = time.time() self.model = Model(dt, decoder_cache=get_default_decoder_cache()) self.model.build(network, build_probes=self.max_steps is not None, **self.io_controller.builder_kwargs) model_optimisations.remove_childless_filters(self.model) logger.info("Build took {:.3f} seconds".format(time.time() - start_build)) self.model.decoder_cache.shrink() self.dt = self.model.dt self._closed = False # Whether the simulator has been closed or not self._running = False self._halt = False self.host_sim = self._create_host_sim() # Holder for probe data self.data = {} # Holder for profiling data self.profiler_data = {} # Convert the model into a netlist logger.info("Building netlist") start = time.time() self.netlist = self.model.make_netlist(self.max_steps or 0) # Get a machine object to place & route against logger.info("Getting SpiNNaker machine specification") machine = self.controller.get_machine() # Place & Route logger.info("Placing and routing") self.netlist.place_and_route(machine) logger.info("{} cores in use".format(len(self.netlist.placements))) chips = set(six.itervalues(self.netlist.placements)) logger.info("Using {}".format(chips)) # Prepare the simulator against the placed, allocated and routed # netlist. self.io_controller.prepare(self.model, self.controller, self.netlist) # Load the application logger.info("Loading application") self.netlist.load_application(self.controller) # Check if any cores are in bad states if self.controller.count_cores_in_state(["exit", "dead", "watchdog", "runtime_exception"]): for vertex in self.netlist.vertices: x, y = self.netlist.placements[vertex] p = self.netlist.allocations[vertex][Cores].start status = self.controller.get_processor_status(p, x, y) if status.cpu_state is not AppState.sync0: print("Core ({}, {}, {}) in state {!s}".format( x, y, p, status.cpu_state)) raise Exception("Unexpected core failures.") logger.info("Preparing and loading machine took {:3f} seconds".format( time.time() - start )) logger.info("Setting router timeout to 16 cycles") for x in range(machine_width): for y in range(machine_height): with self.controller(x=x, y=y): if (x, y) in machine: data = self.controller.read(0xf1000000, 4) self.controller.write(0xf1000000, data[:-1] + b'\x10') def __enter__(self): """Enter a context which will close the simulator when exited.""" # Return self to allow usage like: # # with nengo_spinnaker.Simulator(model) as sim: # sim.run(1.0) return self def __exit__(self, exception_type, exception_value, traceback): """Exit a context and close the simulator.""" self.close() def run(self, time_in_seconds): """Simulate for the given length of time.""" if time_in_seconds is not None: # Determine how many steps to simulate for steps = int(np.round(float(time_in_seconds) / self.dt)) self.run_steps(steps) else: self._run_steps(None) def run_steps(self, steps): """Simulate a give number of steps.""" if steps is not None and self.max_steps is not None: # Fixed time simulation in either fixed-period or indefinite mode while steps > 0: n_steps = min((steps, self.max_steps)) self._run_steps(n_steps) steps -= n_steps else: self._run_steps(steps) def _run_steps(self, steps): """Simulate for the given number of steps.""" if self._closed: raise Exception("Simulator has been closed and can't be used to " "run further simulations.") if self.max_steps is not None: # The simulator is in "fixed-period, fixed-duration" mode. assert steps <= self.max_steps # Prepare the simulation self.netlist.before_simulation(self, steps) # Wait for all cores to hit SYNC0 self.controller.wait_for_cores_to_reach_state( "sync0", len(self.netlist.vertices) ) self.controller.send_signal("sync0") # Get a new thread for the IO io_thread = self.io_controller.spawn() # Run the simulation self._running = True try: # Prep exp_time = steps * (self.model.machine_timestep / float(1e6)) io_thread.start() # Wait for all cores to hit SYNC1 self.controller.wait_for_cores_to_reach_state( "sync1", len(self.netlist.vertices) ) logger.info("Running simulation...") self.controller.send_signal("sync1") # Execute the local model host_steps = 0 start_time = time.time() run_time = 0.0 while run_time < exp_time: # Run a step self.host_sim.step() run_time = time.time() - start_time # If that step took less than timestep then spin time.sleep(0.0001) while run_time < host_steps * self.dt: time.sleep(0.0001) run_time = time.time() - start_time finally: # Stop the IO thread whatever occurs io_thread.stop() # Check if any cores are in bad states if self.controller.count_cores_in_state(["dead", "watchdog", "runtime_exception"]): for vertex in self.netlist.vertices: x, y = self.netlist.placements[vertex] p = self.netlist.allocations[vertex][Cores].start status = self.controller.get_processor_status(p, x, y) if status.cpu_state is not AppState.sync0: print("Core ({}, {}, {}) in state {!s}".format( x, y, p, status.cpu_state)) raise Exception("Unexpected core failures.") # Retrieve simulation data start = time.time() logger.info("Retrieving simulation data") self.netlist.after_simulation(self, steps) logger.info("Retrieving data took {:3f} seconds".format( time.time() - start )) # Increase the steps count self.steps += steps else: # The simulator is in "indefinite duration" mode. if steps is not None: raise ValueError("Cannot run an indefinite duration simulator " "for a fixed period of time.") # Prepare the simulation self.netlist.before_simulation(self, None) # Get a new thread for the IO io_thread = self.io_controller.spawn() if not self._running: # If not already running then start things up self.controller.wait_for_cores_to_reach_state( "sync0", len(self.netlist.vertices) ) self.controller.send_signal("sync0") self._running = True else: # Otherwise continue a running simulation self.controller.send_signal("cont") # Allow the local simulator to run self._halt = False # Run the simulation try: # Prep io_thread.start() # Wait for all cores to hit SYNC1 self.controller.wait_for_cores_to_reach_state( "sync1", len(self.netlist.vertices) ) logger.info("Running simulation...") self.controller.send_signal("sync1") # Execute the local model host_steps = 0 start_time = time.time() run_time = 0.0 while not self._halt: # Run a step self.host_sim.step() run_time = time.time() - start_time # If that step took less than timestep then spin time.sleep(0.0001) while run_time < host_steps * self.dt: time.sleep(0.0001) run_time = time.time() - start_time finally: # Stop the IO thread whatever occurs io_thread.stop() def stop(self): """Stop a continuously running simulation.""" self._halt = True def _create_host_sim(self): # change node_functions to reflect time # TODO: improve the reference simulator so that this is not needed # by adding a realtime option node_functions = {} node_info = dict(start=None) for node in self.io_controller.host_network.all_nodes: if callable(node.output): old_func = node.output if node.size_in == 0: def func(t, f=old_func): now = time.time() if node_info['start'] is None: node_info['start'] = now return f(now - node_info['start']) else: def func(t, x, f=old_func): now = time.time() if node_info['start'] is None: node_info['start'] = now return f(now - node_info['start'], x) node.output = func node_functions[node] = old_func # Build the host simulator host_sim = nengo.Simulator(self.io_controller.host_network, dt=self.dt) # reset node functions for node, func in node_functions.items(): node.output = func return host_sim def close(self): """Clean the SpiNNaker board and prevent further simulation.""" # Stop the application self._closed = True if not self._halt: self.stop() self.io_controller.close() self.controller.send_signal("stop") # Remove this simulator from the list of open simulators Simulator._remove_simulator(self) def trange(self, dt=None): return np.arange(1, self.steps + 1) * (self.dt or dt)
def __init__(self, network, dt=0.001, period=10.0, timescale=1.0, hostname=None, use_spalloc=None, allocation_fudge_factor=0.6): """Create a new Simulator with the given network. Parameters ---------- period : float or None Duration of one period of the simulator. This determines how much memory will be allocated to store precomputed and probed data. timescale : float Scaling factor to apply to the simulation, e.g., a value of `0.5` will cause the simulation to run at half real-time. hostname : string or None Hostname of the SpiNNaker machine to use; if None then the machine specified in the config file will be used. use_spalloc : bool or None Allocate a SpiNNaker machine for the simulator using ``spalloc``. If None then the setting specified in the config file will be used. Other Parameters ---------------- allocation_fudge_factor: Fudge factor to allocate more cores than really necessary when using `spalloc` to ensure that (a) there are sufficient "live" cores in the allocated machine, (b) there is sufficient room for a good place and route solution. This should generally be more than 0.1 (10% more cores than necessary) to account for the usual rate of missing chips. """ # Add this simulator to the set of open simulators Simulator._add_simulator(self) # Create the IO controller io_cls = getconfig(network.config, Simulator, "node_io", Ethernet) io_kwargs = getconfig(network.config, Simulator, "node_io_kwargs", dict()) self.io_controller = io_cls(**io_kwargs) # Calculate the machine timestep, this is measured in microseconds # (hence the 1e6 scaling factor). self.timescale = timescale machine_timestep = int((dt / timescale) * 1e6) # Determine the maximum run-time self.max_steps = None if period is None else int(period / dt) self.steps = 0 # Steps simulated # If the simulator is in "run indefinite" mode (i.e., max_steps=None) # then we modify the builders to ignore function of time Nodes and # probes. builder_kwargs = self.io_controller.builder_kwargs if self.max_steps is None: raise NotImplementedError # Create a model from the network, using the IO controller logger.debug("Building model") start_build = time.time() self.model = Model(dt=dt, machine_timestep=machine_timestep, decoder_cache=get_default_decoder_cache()) self.model.build(network, **builder_kwargs) logger.info("Build took {:.3f} seconds".format(time.time() - start_build)) self.model.decoder_cache.shrink() self.dt = self.model.dt self._closed = False # Whether the simulator has been closed or not self.host_sim = self._create_host_sim() # Holder for probe data self.data = {} # Holder for profiling data self.profiler_data = {} # Convert the model into a netlist logger.info("Building netlist") start = time.time() self.netlist = self.model.make_netlist(self.max_steps or 0) # Determine whether to use a spalloc machine or not if use_spalloc is None: # Default is to not use spalloc; this is indicated by either the # absence of the option in the config file OR the option being set # to false. use_spalloc = (rc.has_option("spinnaker_machine", "use_spalloc") and rc.getboolean("spinnaker_machine", "use_spalloc")) # Create a controller for the machine and boot if necessary self.job = None if not use_spalloc or hostname is not None: # Use the specified machine rather than trying to get one # allocated. if hostname is None: hostname = rc.get("spinnaker_machine", "hostname") else: # Attempt to get a machine allocated to us from spalloc import Job # Determine how many boards to ask for (assuming 16 usable cores # per chip and 48 chips per board). n_cores = self.netlist.n_cores * (1.0 + allocation_fudge_factor) n_boards = int(np.ceil((n_cores / 16.) / 48.)) # Request the job self.job = Job(n_boards) logger.info("Allocated job ID %d...", self.job.id) # Wait until we're given the machine logger.info("Waiting for machine allocation...") self.job.wait_until_ready() # spalloc recommends a slight delay before attempting to boot the # machine, later versions of spalloc server may relax this # requirement. time.sleep(5.0) # Store the hostname hostname = self.job.hostname logger.info("Using %d board(s) of \"%s\" (%s)", len(self.job.boards), self.job.machine_name, hostname) self.controller = MachineController(hostname) self.controller.boot() # Get a system-info object to place & route against logger.info("Getting SpiNNaker machine specification") system_info = self.controller.get_system_info() # Place & Route logger.info("Placing and routing") self.netlist.place_and_route( system_info, place=getconfig(network.config, Simulator, 'placer', rig.place_and_route.place), place_kwargs=getconfig(network.config, Simulator, 'placer_kwargs', {}), ) logger.info("{} cores in use".format(len(self.netlist.placements))) chips = set(six.itervalues(self.netlist.placements)) logger.info("Using {}".format(chips)) # Prepare the simulator against the placed, allocated and routed # netlist. self.io_controller.prepare(self.model, self.controller, self.netlist) # Load the application logger.info("Loading application") self.netlist.load_application(self.controller, system_info) # Check if any cores are in bad states if self.controller.count_cores_in_state( ["exit", "dead", "watchdog", "runtime_exception"]): for vertex, (x, y) in six.iteritems(self.netlist.placements): p = self.netlist.allocations[vertex][Cores].start status = self.controller.get_processor_status(p, x, y) if status.cpu_state is not AppState.sync0: print("Core ({}, {}, {}) in state {!s}".format( x, y, p, status)) print(self.controller.get_iobuf(p, x, y)) raise Exception("Unexpected core failures.") logger.info("Preparing and loading machine took {:3f} seconds".format( time.time() - start)) logger.info("Setting router timeout to 16 cycles") for x, y in system_info.chips(): with self.controller(x=x, y=y): data = self.controller.read(0xf1000000, 4) self.controller.write(0xf1000000, data[:-1] + b'\x10')
def __init__(self, network, dt=0.001, period=10.0): """Create a new Simulator with the given network. Parameters ---------- period : float or None Duration of one period of the simulator. This determines how much memory will be allocated to store precomputed and probed data. """ # Add this simulator to the set of open simulators Simulator._add_simulator(self) # Create a controller for the machine and boot if necessary hostname = rc.get("spinnaker_machine", "hostname") machine_width = rc.getint("spinnaker_machine", "width") machine_height = rc.getint("spinnaker_machine", "height") self.controller = MachineController(hostname) test_and_boot(self.controller, hostname, machine_width, machine_height) # Create the IO controller io_cls = getconfig(network.config, Simulator, "node_io", Ethernet) io_kwargs = getconfig(network.config, Simulator, "node_io_kwargs", dict()) self.io_controller = io_cls(**io_kwargs) # Determine the maximum run-time self.max_steps = None if period is None else int(period / dt) self.steps = 0 # Steps simulated # Create the IO controller. Function of time nodes are only enabled if # the simulator period is not None. io_cls = getconfig(network.config, Simulator, "node_io", Ethernet) io_kwargs = getconfig(network.config, Simulator, "node_io_kwargs", dict()) self.io_controller = io_cls( function_of_time_nodes=self.max_steps is not None, **io_kwargs ) # Create a model from the network, using the IO controller. Probes are # only built if the simulator period is not None. logger.debug("Building model") start_build = time.time() self.model = Model(dt, decoder_cache=get_default_decoder_cache()) self.model.build(network, build_probes=self.max_steps is not None, **self.io_controller.builder_kwargs) model_optimisations.remove_childless_filters(self.model) logger.info("Build took {:.3f} seconds".format(time.time() - start_build)) self.model.decoder_cache.shrink() self.dt = self.model.dt self._closed = False # Whether the simulator has been closed or not self._running = False self._halt = False self.host_sim = self._create_host_sim() # Holder for probe data self.data = {} # Holder for profiling data self.profiler_data = {} # Convert the model into a netlist logger.info("Building netlist") start = time.time() self.netlist = self.model.make_netlist(self.max_steps or 0) # Get a machine object to place & route against logger.info("Getting SpiNNaker machine specification") machine = self.controller.get_machine() # Place & Route logger.info("Placing and routing") self.netlist.place_and_route(machine) logger.info("{} cores in use".format(len(self.netlist.placements))) chips = set(six.itervalues(self.netlist.placements)) logger.info("Using {}".format(chips)) # Prepare the simulator against the placed, allocated and routed # netlist. self.io_controller.prepare(self.model, self.controller, self.netlist) # Load the application logger.info("Loading application") self.netlist.load_application(self.controller) # Check if any cores are in bad states if self.controller.count_cores_in_state(["exit", "dead", "watchdog", "runtime_exception"]): for vertex in self.netlist.vertices: x, y = self.netlist.placements[vertex] p = self.netlist.allocations[vertex][Cores].start status = self.controller.get_processor_status(p, x, y) if status.cpu_state is not AppState.sync0: print("Core ({}, {}, {}) in state {!s}".format( x, y, p, status.cpu_state)) raise Exception("Unexpected core failures.") logger.info("Preparing and loading machine took {:3f} seconds".format( time.time() - start )) logger.info("Setting router timeout to 16 cycles") for x in range(machine_width): for y in range(machine_height): with self.controller(x=x, y=y): if (x, y) in machine: data = self.controller.read(0xf1000000, 4) self.controller.write(0xf1000000, data[:-1] + b'\x10')
class Experiment(object): """Defines a network experiment to be run on a SpiNNaker machine. An experiment consists of a fixed set of 'vertices' (:py:meth:`.new_vertex`) connected together by 'nets' (:py:meth:`.new_net`). Vertices correspond with SpiNNaker application cores running artificial traffic generators and the nets correspond with traffic flows between cores. An experiment is broken up into 'groups' (:py:meth:`.new_group`), during which the traffic generators produce packets according to a specified traffic pattern. Within each group, metrics, such as packet counts, may be recorded. Though the placement of vertices and the routing of nets is fixed throughout an experiment, the rate and pattern with which which packets are produced can be varied between groups allowing, for example, different traffic patterns to be tested. When the experiment is :py:meth:`.run`, appropriately-configured traffic generator applications will be loaded onto SpiNNaker and, after the experiment completes, the results are read back ready for analysis. """ def __init__(self, hostname_or_machine_controller): """Create a new network experiment on a particular SpiNNaker machine. Example usage:: >>> import sys >>> from network_tester import Experiment >>> e = Experiment(sys.argv[1]) # Takes hostname as a CLI argument The experimental parameters can be set by setting attributes of the :py:class:`Experiment` instance like so:: >>> e = Experiment(...) >>> # Set the probability of a packet being generated at the source >>> # of each net every timestep >>> e.probability = 1.0 Parameters ---------- hostname_or_machine_controller : \ str or :py:class:`rig.machine_control.MachineController` The hostname or :py:class:`~rig.machine_control.MachineController` of a SpiNNaker machine to run the experiment on. """ if isinstance(hostname_or_machine_controller, str): self._mc = MachineController(hostname_or_machine_controller) else: self._mc = hostname_or_machine_controller # A cached reference to the SpiNNaker machine the experiment will run # in. To be accessed via .machine which automatically fetches the # machine the first time it is requested. self._machine = None # A set of placements, allocations and routes for the # traffic-generating/consuming vertices. self._placements = None self._allocations = None self._routes = None # The experimental group currently being defined. Set and cleared on # entry and exit of Group context-managers. self._cur_group = None # A list of experimental groups which have been defined self._groups = [] # A list of vertices in the experiment self._vertices = [] # A list of nets in the experiment self._nets = [] # Holds the value of every option along with any special cases. # If a value can have per-node or per-group exceptions it is stored as # a dictionary with keys (group, vert_or_net) with the value being # defined as below. Otherwise, the value is just stored immediately in # the _values dictionary. The list below gives the order of priority # for definitions. # * (None, None) The global default # * (group, None) The default for a particular experimental group # * (None, vertex) The default for a particular vertex # * (None, net) The default for a particular net # * (group, vertex) The value for a particular vertex in a specific # group # * (group, net) The value for a particular net in a specific group # {option: value or {(group, vert_or_net): value, ...}, ...} self._values = { "seed": {(None, None): None}, "timestep": {(None, None): 0.001}, "warmup": {(None, None): 0.0}, "duration": {(None, None): 1.0}, "cooldown": {(None, None): 0.0}, "flush_time": {(None, None): 0.01}, "record_interval": {(None, None): 0.0}, "probability": {(None, None): 1.0}, "burst_period": {(None, None): 0.0}, "burst_duty": {(None, None): 0.0}, "burst_phase": {(None, None): 0.0}, "use_payload": {(None, None): False}, "consume_packets": {(None, None): True}, "router_timeout": {(None, None): None}, "reinject_packets": {(None, None): False}, } # All counters are global-only options and default to False. for counter in Counters: self._values["record_{}".format(counter.name)] = False def new_vertex(self, name=None): """Create a new :py:class:`Vertex`. A vertex corresponds with a SpiNNaker application core and can produce or consume SpiNNaker packets. Example:: >>> # Create three vertices >>> v0 = e.new_vertex() >>> v1 = e.new_vertex() >>> v2 = e.new_vertex() The experimental parameters for each vertex can also be overridden individually if desired:: >>> # Nets sourced at vertex v2 will transmit with 50% probability >>> # each timestep >>> v2.probability = 0.5 Parameters ---------- name *Optional.* A name for the vertex. If not specified the vertex will be given a number as its name. This name will be used in results tables. Returns ------- :py:class:`Vertex` An object representing the vertex. """ v = Vertex(self, name if name is not None else len(self._vertices)) self._vertices.append(v) # Adding a new vertex invalidates any existing placement solution self.placements = None return v def new_net(self, source, sinks, weight=1.0, name=None): """Create a new net. A net represents a flow of SpiNNaker packets from one source vertex to many sink vertices. For example:: >>> # A net with v0 as a source and v1 as a sink. >>> n0 = e.new_net(v0, v1) >>> # Another net with v0 as a source and both v1 and v2 as sinks. >>> n1 = e.new_net(v0, [v1, v2]) The experimental parameters for each net can also be overridden individually if desired. This will take precedence over any overridden values set for the source vertex of the net. For example:: >>> # Net n0 will generate a packet in 80% of timesteps >>> n0.probability = 0.8 Parameters ---------- source : :py:class:`Vertex` The source :py:class:`Vertex` of the net. A stream of packets will be generated by this vertex and sent to all sinks. Only :py:class:`Vertex` objects created by this :py:class:`Experiment` may be used. sinks : :py:class:`Vertex` or [:py:class:`Vertex`, ...] The sink :py:class:`Vertex` or list of sink vertices for the net. Only :py:class:`Vertex` objects created by this :py:class:`Experiment` may be used. weight : float *Optional.* A hint for place and route tools indicating the relative amount of traffic that may flow through this net. This number is not used by the traffic generator. name *Optional.* A name for the net. If not specified the net will be given a number as its name. This name will be used in results tables. Returns ------- :py:class:`Net` An object representing the net. """ if name is None: name = len(self._nets) n = Net(self, name, source, sinks, weight) # Adding a new net invalidates any routing solution. self.routes = None self._nets.append(n) return n def new_group(self, name=None): """Define a new experimental group. The experiment can be divided up into groups where the traffic pattern generated (but not the structure of connectivity) varies for each group. Results are recorded separately for each group and the network is drained of packets between groups. The returned :py:class:`Group` object can be used as a context manager within which experimental parameters specific to that group may be set, including per-vertex and per-net parameters. Note that parameters set globally for the experiment in particular group do not take precedence over per-vertex or per-net parameter settings. For example:: >>> with e.new_group(): ... # Overrides default probability of sending a packet within ... # the group. ... e.probability = 0.5 ... # Overrides the probability for v2 within the group ... v2.probability = 0.25 ... # Overrides the probability for n0 within the group ... n0.probability = 0.4 Parameters ---------- name *Optional.* A name for the group. If not specified the group will be given a number as its name. This name will be used in results tables. Returns ------- :py:class:`Group` An object representing the group. """ g = Group(self, name if name is not None else len(self._groups)) self._groups.append(g) return g def run(self, app_id=0x42, create_group_if_none_exist=True, ignore_deadline_errors=False): """Run the experiment on SpiNNaker and return the results. If placements, allocations or routes have not been provided, the vertices and nets will be automatically placed, allocated and routed using the default algorithms in Rig. Following placement, the experimental parameters are loaded onto the machine and each experimental group is executed in turn. Results are recorded by the machine and at the end of the experiment are read back. .. warning:: Though a global synchronisation barrier is used between the execution of each group, the timers in each vertex may drift out of sync during each group's execution. Further, the barrier synchronisation does not give any guarantees about how closely-synchronised the timers will be at the start of each run. Parameters ---------- app_id : int *Optional.* The SpiNNaker application ID to use for the experiment. create_group_if_none_exist : bool *Optional.* If True (the default), a single group will be automatically created if none have been defined with :py:meth:`.new_group`. This is the most sensible behaviour for most applications. If you *really* want to run an experiment with no experimental groups (where no traffic will ever be generated and no results recorded), you can set this option to False. ignore_deadline_errors : bool If True, any realtime deadline-missed errors will no longer cause this method to raise an exception. Other errors will still cause an exception to be raised. This option is useful when running experiments which involve over-saturating packet sinks or the network in some experimental groups. Returns ------- :py:class:`Results` If no vertices reported errors, the experimental results are returned. See the :py:class:`Results` object for details. Raises ------ NetworkTesterError A :py:exc:`NetworkTesterError` is raised if any vertices reported an error. The most common error is likely to be a 'deadline missed' error as a result of the experimental timestep being too short or the load on some vertices too high in extreme circumstances. Other types of error indicate far more severe problems. Any results recorded during the run will be included in the ``results`` attribute of the exception. See the :py:class:`Results` object for details. """ # Sensible default: Create a single experimental group if none defined. if create_group_if_none_exist and len(self._groups) == 0: self.new_group() # Place and route the vertices (if required) self.place_and_route() # Add nodes to unused chips to access router registers/counters (if # necessary). (vertices, router_access_vertices, placements, allocations, routes) = \ self._add_router_recording_vertices() # Assign a unique routing key to each net net_keys = {net: num << 8 for num, net in enumerate(self._nets)} routing_tables = build_routing_tables( routes, {net: (key, 0xFFFFFF00) for net, key in iteritems(net_keys)}) network_tester_binary = pkg_resources.resource_filename( "network_tester", "binaries/network_tester.aplx") reinjector_binary = pkg_resources.resource_filename( "network_tester", "binaries/reinjector.aplx") # Specify the appropriate binary for the network tester vertices. application_map = build_application_map( {vertex: network_tester_binary for vertex in vertices}, placements, allocations) # Get the set of source and sink nets for each vertex. Also sets an # explicit ordering of the sources/sinks within each. # {vertex: [source_or_sink, ...], ...} vertices_source_nets = {v: [] for v in vertices} vertices_sink_nets = {v: [] for v in vertices} for net in self._nets: vertices_source_nets[net.source].append(net) for sink in net.sinks: vertices_sink_nets[sink].append(net) vertices_records = self._get_vertex_record_lookup( vertices, router_access_vertices, placements, vertices_source_nets, vertices_sink_nets) # Fill out the set of commands for each vertex vertices_commands = { vertex: self._construct_vertex_commands( vertex=vertex, source_nets=vertices_source_nets[vertex], sink_nets=vertices_sink_nets[vertex], net_keys=net_keys, records=[cntr for obj, cntr in vertices_records[vertex]], router_access_vertex=vertex in router_access_vertices) for vertex in vertices } # The data size for the results from each vertex total_num_samples = sum(g.num_samples for g in self._groups) vertices_result_size = { vertex: ( # The error flag (one word) 1 + # One word per recorded value per sample. (total_num_samples * len(vertices_records[vertex])) ) * 4 for vertex in vertices} # The raw result data for each vertex. vertices_result_data = {} # Actually load and run the experiment on the machine. with self._mc.application(app_id): # Allocate SDRAM. This is enough to fit the commands and also any # recored results. vertices_sdram = {} logger.info("Allocating SDRAM...") for vertex in vertices: size = max( # Size of commands (with length prefix) vertices_commands[vertex].size, # Size of results (plus the flags) vertices_result_size[vertex], ) x, y = placements[vertex] p = allocations[vertex][Cores].start vertices_sdram[vertex] = self._mc.sdram_alloc_as_filelike( size, x=x, y=y, tag=p) # Load each vertex's commands logger.info("Loading {} bytes of commands...".format( sum(c.size for c in itervalues(vertices_commands)))) for vertex, sdram in iteritems(vertices_sdram): sdram.write(vertices_commands[vertex].pack()) # Load routing tables logger.info("Loading routing tables...") self._mc.load_routing_tables(routing_tables) # Load the packet-reinjection application if used. This must be # completed before the main application since it creates a tagged # memory allocation. if self._reinjection_used(): logger.info("Loading packet-reinjection application...") self._mc.load_application(reinjector_binary, {xy: set([1]) for xy in self.machine}) # Load the application logger.info("Loading application on to {} cores...".format( len(vertices))) self._mc.load_application(application_map) # Run through each experimental group next_barrier = "sync0" for group_num, group in enumerate(self._groups): # Reach the barrier before the run starts logger.info("Waiting for barrier...") num_at_barrier = self._mc.wait_for_cores_to_reach_state( next_barrier, len(vertices), timeout=2.0) assert num_at_barrier == len(vertices), \ "Not all cores reached the barrier " \ "before {}.".format(group) self._mc.send_signal(next_barrier) next_barrier = "sync1" if next_barrier == "sync0" else "sync0" # Give the run time to complete warmup = self._get_option_value("warmup", group) duration = self._get_option_value("duration", group) cooldown = self._get_option_value("cooldown", group) flush_time = self._get_option_value("flush_time", group) total_time = warmup + duration + cooldown + flush_time logger.info( "Running group {} ({} of {}) for {} seconds...".format( group.name, group_num + 1, len(self._groups), total_time)) time.sleep(total_time) # Wait for all cores to exit after their final run logger.info("Waiting for barrier...") num_at_barrier = self._mc.wait_for_cores_to_reach_state( "exit", len(vertices), timeout=2.0) assert num_at_barrier == len(vertices), \ "Not all cores reached the final barrier." # Read recorded data back logger.info("Reading back {} bytes of results...".format( sum(itervalues(vertices_result_size)))) for vertex, sdram in iteritems(vertices_sdram): sdram.seek(0) vertices_result_data[vertex] = \ sdram.read(vertices_result_size[vertex]) # Process read results results = Results(self, self._vertices, self._nets, vertices_records, router_access_vertices, placements, routes, vertices_result_data, self._groups) if any(not e.is_deadline if ignore_deadline_errors else True for e in results.errors): logger.error( "Experiment completed with errors: {}".format(results.errors)) raise NetworkTesterError(results) else: logger.info("Experiment completed successfully") return results def place_and_route(self, constraints=None, place=place, place_kwargs={}, allocate=allocate, allocate_kwargs={}, route=route, route_kwargs={}): """Place and route the vertices and nets in the current experiment, if required. If extra control is required over placement and routing of vertices and nets in an experiment, this method allows additional constraints and custom placement, allocation and routing options and algorithms to be used. The result of placement, allocation and routing can be found in :py:attr:`placements`, :py:attr:`allocations` and :py:attr:`routes` respectively. If even greater control is required, :py:attr:`placements`, :py:attr:`allocations` and :py:attr:`routes` may be set explicitly. Once these attributes have been set, this method will not alter them. Since many applications will not care strongly about placement, allocation and routing, this method is called implicitly by :py:meth:`.run`. Parameters ---------- constraints : [constraint, ...] A list of additional constraints to apply. A :py:class:`rig.place_and_route.constraints.ReserveResourceConstraint` will be applied to reserve the monitor processor on top of this constraint. place : placer A Rig-API complaint placement algorithm. place_kwargs : dict Additional algorithm-specific keyword arguments to supply to the placer. allocate : allocator A Rig-API complaint allocation algorithm. allocate_kwargs : dict Additional algorithm-specific keyword arguments to supply to the allocator. route : router A Rig-API complaint route algorithm. route_kwargs : dict Additional algorithm-specific keyword arguments to supply to the router. """ # Each traffic generator consumes a core and a negligible amount of # memory. vertices_resources = {vertex: {Cores: 1} for vertex in self._vertices} # Reserve the monitor processor for each chip constraints = constraints or [] constraints += [ReserveResourceConstraint(Cores, slice(0, 1))] # Reserve a core for packet reinjection on each chip (if required) if self._reinjection_used(): constraints += [ReserveResourceConstraint(Cores, slice(1, 2))] if self.placements is None: logger.info("Placing vertices...") self.placements = place(vertices_resources=vertices_resources, nets=self._nets, machine=self.machine, constraints=constraints, **place_kwargs) self.allocations = None self.routes = None if self.allocations is None: logger.info("Allocating vertices...") self.allocations = allocate(vertices_resources=vertices_resources, nets=self._nets, machine=self.machine, constraints=constraints, placements=self.placements, **allocate_kwargs) self.routes = None if self.routes is None: logger.info("Routing vertices...") self.routes = route(vertices_resources=vertices_resources, nets=self._nets, machine=self.machine, constraints=constraints, placements=self.placements, allocations=self.allocations, **allocate_kwargs) @property def placements(self): """A dictionary {:py:class:`Vertex`: (x, y), ...}, or None. Defines the chip on which each vertex will be placed during the experiment. Note that the placement must define the position of *every* vertex. If None, calling :py:meth:`.run` or :py:meth:`.place_and_route` will cause all vertices to be placed automatically. Setting this attribute will also set :py:attr:`.allocations` and :py:attr:`.routes` to None. Any placement must be valid for the :py:class:`~rig.machine.Machine` specified by the :py:attr:`.machine` attribute. Core 0 must always be reserved for the monitor processor and, if packet reinjection is used or recorded (see :py:attr:`Experiment.reinject_packets`), core 1 must also be reserved for the packet reinjection application. See also :py:func:`rig.place_and_route.place`. """ return self._placements @placements.setter def placements(self, value): self._placements = value self.allocation = None self.routes = None @property def allocations(self): """A dictionary {:py:class:`Vertex`: {resource: slice}, ...} or None. Defines the resources allocated to each vertex. This must include exactly 1 unit of the :py:class:`~rig.machine.Cores` resource. Note that the allocation must define the resource allocation of *every* vertex. If None, calling :py:meth:`.run` or :py:meth:`.place_and_route` will cause all vertices to have their resources allocated automatically. Setting this attribute will also set :py:attr:`.routes` to None. Any allocation must be valid for the :py:class:`~rig.machine.Machine` specified by the :py:attr:`.machine` attribute. Core 0 must always be reserved for the monitor processor and, if packet reinjection is used or recorded (see :py:attr:`Experiment.reinject_packets`), core 1 must also be reserved for the packet reinjection application. See also :py:func:`rig.place_and_route.allocate`. """ return self._allocations @allocations.setter def allocations(self, value): self._allocations = value self.routes = None @property def routes(self): """A dictionary {:py:class:`Net`: \ :py:class:`rig.place_and_route.routing_tree.RoutingTree`, ...} or None. Defines the route used for each net. Note that the route must be defined for *every* net. If None, calling :py:meth:`.run` or :py:meth:`.place_and_route` will cause all nets to be routed automatically. See also :py:func:`rig.place_and_route.route`. """ return self._routes @routes.setter def routes(self, value): self._routes = value def _any_router_registers_used(self): """Are any router registers (including reinjection counters) being recorded or configured during the experiment?""" return (any(self._get_option_value("record_{}".format(counter.name)) for counter in Counters if counter.router_counter) or self._get_option_value("router_timeout") is not None or any(self._get_option_value("router_timeout", g) is not None for g in self._groups) or self._reinjection_used()) def _reinjection_used(self): """Is dropped packet reinjection used (or recorded) in the experiment? """ return (any(self._get_option_value("record_{}".format(counter.name)) for counter in Counters if counter.reinjector_counter) or self._get_option_value("reinject_packets") or any(self._get_option_value("reinject_packets", g) for g in self._groups)) @property def machine(self): """The :py:class:`~rig.machine.Machine` object describing the SpiNNaker system under test. This property caches the machine description read from the machine to avoid repeatedly polling the SpiNNaker system. """ if self._machine is None: logger.info("Getting SpiNNaker machine information...") self._machine = self._mc.get_machine() return self._machine @machine.setter def machine(self, value): self._machine = value def _construct_vertex_commands(self, vertex, source_nets, sink_nets, net_keys, records, router_access_vertex): """For internal use. Produce the Commands for a particular vertex. Parameters ---------- vertex : :py:class:`.Vertex` The vertex to pack source_nets : [:py:class:`.Net`, ...] The nets which are sourced at this vertex. sink_nets : [:py:class:`.Net`, ...] The nets which are sunk at this vertex. net_keys : {:py:class:`.Net`: key, ...} A mapping from net to routing key. records : [counter, ...] The set of counters this vertex records router_access_vertex : bool Should this vertex be used to configure router/reinjector parameters. """ commands = Commands() # Set up the sources and sinks for the vertex commands.num(len(source_nets), len(sink_nets)) for source_num, source_net in enumerate(source_nets): commands.source_key(source_num, net_keys[source_net]) for sink_num, sink_net in enumerate(sink_nets): commands.sink_key(sink_num, net_keys[sink_net]) # Generate commands for each experimental group for group in self._groups: # Set general parameters for the group commands.seed(self._get_option_value("seed", group)) commands.timestep(self._get_option_value("timestep", group)) commands.record_interval(self._get_option_value("record_interval", group)) # Set per-source parameters for the group for source_num, source_net in enumerate(source_nets): commands.burst( source_num, self._get_option_value("burst_period", group, source_net), self._get_option_value("burst_duty", group, source_net), self._get_option_value("burst_phase", group, source_net)) commands.probability( source_num, self._get_option_value("probability", group, source_net)) commands.payload( source_num, self._get_option_value("use_payload", group, source_net)) # Synchronise before running the group commands.barrier() # Turn on reinjection as required if router_access_vertex: commands.reinject( self._get_option_value("reinject_packets", group)) # Turn off consumption as required commands.consume( self._get_option_value("consume_packets", group, vertex)) # Set the router timeout router_timeout = self._get_option_value("router_timeout", group) if router_timeout is not None and router_access_vertex: if isinstance(router_timeout, integer_types): commands.router_timeout(router_timeout) else: commands.router_timeout(*router_timeout) # warming up without recording data commands.record() commands.run(self._get_option_value("warmup", group)) # Run the actual experiment and record results commands.record(*records) commands.run(self._get_option_value("duration", group)) # Run without recording (briefly) after the experiment to allow # for clock skew between cores. commands.record() # Record nothing during cooldown commands.run(self._get_option_value("cooldown", group)) # Restore router timeout, turn consumption back on and reinjection # back off after the run commands.consume(True) if router_timeout is not None and router_access_vertex: commands.router_timeout_restore() if router_access_vertex: commands.reinject(False) # Drain the network of any remaining packets commands.sleep(self._get_option_value("flush_time", group)) # Finally, terminate commands.exit() return commands def _add_router_recording_vertices(self): """Adds extra vertices to chips with no other vertices to facilitate recording or setting of router counters and registers, if necessary. Returns ------- (vertices, router_access_vertices, placements, allocations, routes) vertices is a list containing all vertices (including any added for router-recording purposes). router_access_vertices is set of vertices which are responsible for recording router counters or setting router registers on their core. placements, allocations and routes are updated sets of placements accounting for any new router-recording vertices. """ # Make a local list of vertices, placements and allocations in the # model. This may be extended with extra vertices for recording router # counter values. vertices = self._vertices[:] placements = self.placements.copy() allocations = self.allocations.copy() routes = self.routes.copy() # Not actually modified at present router_access_vertices = set() # The set of chips (x, y) which have a core allocated to recording # router counters. recorded_chips = set() # If router information is being recorded or the router registers are # changed, a vertex must be assigned on every chip to access these # registers. if self._any_router_registers_used(): # Assign the job of recording/setting router registers to an # arbitrary vertex on every chip which already has vertices on it. for vertex, placement in iteritems(self.placements): if placement not in recorded_chips: router_access_vertices.add(vertex) recorded_chips.add(placement) # If there are chips without any vertices allocated, new # router-access-only vertices must be added. num_extra_vertices = 0 for xy in self.machine: if xy not in recorded_chips: # Create a new vertex for recording of router data only. num_extra_vertices += 1 vertex = Vertex(self, "router access {}, {}".format(*xy)) router_access_vertices.add(vertex) recorded_chips.add(xy) placements[vertex] = xy allocations[vertex] = {Cores: slice(2, 3)} vertices.append(vertex) logger.info( "{} vertices added to access router registers".format( num_extra_vertices)) return (vertices, router_access_vertices, placements, allocations, routes) def _get_vertex_record_lookup(self, vertices, router_access_vertices, placements, vertices_source_nets, vertices_sink_nets): """Generates a lookup from vertex to a list of counters that vertex records. Parameters ---------- vertices : [:py:class:`.Vertex`, ...] router_access_vertices : set([:py:class:`.Vertex`, ...]) placements : {:py:class:`.Vertex`: (x, y), ...} vertices_source_nets : {:py:class:`.Vertex`: [net, ...], ...} vertices_sink_nets : {:py:class:`.Vertex`: [net, ...], ...} Returns ------- vertices_records : {vertex: [(object, counter), ...], ...} For each vertex, gives an ordered-list of the things recorded by that vertex. For router counters, object will be a tuple (x, y) indicating which chip that counter is responsible for. For non-router counters, object will be the Net associated with the counter. """ # Get the set of recorded counters for each vertex # {vertex, [counter, ...]} vertices_records = {} for vertex in vertices: records = [] # Add any router-counters if this vertex is recording them if vertex in router_access_vertices: xy = placements[vertex] for counter in Counters: if ((counter.router_counter or counter.reinjector_counter) and self._get_option_value( "record_{}".format(counter.name))): records.append((xy, counter)) # Add any source counters for counter in Counters: if (counter.source_counter and self._get_option_value( "record_{}".format(counter.name))): for net in vertices_source_nets[vertex]: records.append((net, counter)) # Add any sink counters for counter in Counters: if (counter.sink_counter and self._get_option_value( "record_{}".format(counter.name))): for net in vertices_sink_nets[vertex]: records.append((net, counter)) vertices_records[vertex] = records return vertices_records def _get_option_value(self, option, group=None, vert_or_net=None): """For internal use. Get an option's value for a given group/vertex/net.""" values = self._values[option] if isinstance(values, dict): if isinstance(vert_or_net, Net): vertex = vert_or_net.source net = vert_or_net else: vertex = vert_or_net global_value = values[(None, None)] group_value = values.get((group, None), global_value) vertex_value = values.get((None, vertex), group_value) group_vertex_value = values.get((group, vertex), vertex_value) if isinstance(vert_or_net, Net): net_value = values.get((None, net), group_vertex_value) group_net_value = values.get((group, net), net_value) return group_net_value else: return group_vertex_value else: return values def _set_option_value(self, option, value, group=None, vert_or_net=None): """For internal use. Set an option's value for a given group/vertex/net. """ values = self._values[option] if isinstance(values, dict): values[(group, vert_or_net)] = value else: if group is not None or vert_or_net is not None: raise ValueError( "Cannot set {} option on a group-by-group, " "vertex-by-vertex or net-by-net basis.".format(option)) self._values[option] = value class _Option(object): """A descriptor which provides access to the _values dictionary.""" def __init__(self, option): self.option = option def __get__(self, obj, type=None): return obj._get_option_value(self.option, obj._cur_group) def __set__(self, obj, value): return obj._set_option_value(self.option, value, obj._cur_group) seed = _Option("seed") timestep = _Option("timestep") warmup = _Option("warmup") duration = _Option("duration") cooldown = _Option("cooldown") flush_time = _Option("flush_time") record_local_multicast = _Option("record_local_multicast") record_external_multicast = _Option("record_external_multicast") record_local_p2p = _Option("record_local_p2p") record_external_p2p = _Option("record_external_p2p") record_local_nearest_neighbour = _Option("record_local_nearest_neighbour") record_external_nearest_neighbour = _Option( "record_external_nearest_neighbour") record_local_fixed_route = _Option("record_local_fixed_route") record_external_fixed_route = _Option("record_external_fixed_route") record_dropped_multicast = _Option("record_dropped_multicast") record_dropped_p2p = _Option("record_dropped_p2p") record_dropped_nearest_neighbour = _Option( "record_dropped_nearest_neighbour") record_dropped_fixed_route = _Option("record_dropped_fixed_route") record_counter12 = _Option("record_counter12") record_counter13 = _Option("record_counter13") record_counter14 = _Option("record_counter14") record_counter15 = _Option("record_counter15") record_reinjected = _Option("record_reinjected") record_reinject_overflow = _Option("record_reinject_overflow") record_reinject_missed = _Option("record_reinject_missed") record_sent = _Option("record_sent") record_blocked = _Option("record_blocked") record_received = _Option("record_received") record_interval = _Option("record_interval") burst_period = _Option("burst_period") burst_duty = _Option("burst_duty") burst_phase = _Option("burst_phase") probability = _Option("probability") use_payload = _Option("use_payload") consume_packets = _Option("consume_packets") router_timeout = _Option("router_timeout") reinject_packets = _Option("reinject_packets")
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)
import sys import pkg_resources import struct import time from rig.machine_control import MachineController from rig.routing_table import RoutingTableEntry, Routes binary = pkg_resources.resource_filename("network_tester", "binaries/network_tester.aplx") mc = MachineController(sys.argv[1]) with mc.application(0x42): num_samples = 1 num_vals = 4 commands = [ 0x04, 2500, # NT_CMD_TIMESTEP (1.25us is the shortest for 1 in/out) 0x10, (1 << 16) | (1 << 24), # NT_CMD_RECORD MC sent,received 0x11, 0, # NT_CMD_RECORD_INTERVAL: 0 0x06, 0x0202, # NT_CMD_NUM: One source, one sink 0x0020, 0xFFFFFFFF, # NT_CMD_PROBABILITY[0] 1 0x0024, 0xBEEF0000, # NT_CMD_SOURCE_KEY[0] 0x0032, 0xBEEF0000, # NT_CMD_SINK_KEY[0]
parser.add_argument("out_file") parser.add_argument("target_length", type=int, default=0, nargs='?') parser.add_argument("--memory-profile", type=str) args = parser.parse_args() # Load and minimise all routing tables print("Reading routing tables...") with open(args.routing_table, "rb") as f: uncompressed = common.read_routing_tables(f) # Request a SpiNNaker machine print("Waiting for SpiNNaker machine...") with spalloc.Job(args.width, args.height) as job: # Talk to the machine print("Booting...") mc = MachineController(job.hostname) mc.boot() mc.discover_connections() # Convert the tables into the appropriate formats chip_data = { chip: pack_table(table, args.target_length) for chip, table in iteritems(uncompressed) } # Allocate memory on the machine chip_mem = {(x, y): mc.sdram_alloc_as_filelike(len(data), x=x, y=y, tag=1) for (x, y), data in iteritems(chip_data)}
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)
from rig.machine_control import MachineController import sys import random if len(sys.argv) < 2: print "Usage: python gen_tgmap.py <MACHINE_IP>" sys.exit(1) mc = MachineController(sys.argv[1]) mInfo = mc.get_system_info() chips_org = mInfo.keys() chips_srt = mInfo.keys() chips_srt.sort() chips_rnd = mInfo.keys() random.shuffle(chips_rnd) if len(chips_org) != 144: print "Dead chip(s) detected...!" sys.exit(1) # then select some chips and assign the id to them # Node ID from 0 to 119 # tgmap 1 with open("map_srt.tgmap", "w") as f1: i = 0 f1.write("(0,0)=65535\n") for c in chips_srt: if i == 120: break if c != (0, 0):
def __init__(self, cli_param, parent=None): super(MainWindow, self).__init__(parent) self.setupUi(self) self.setCentralWidget(self.mdiArea) self.statusTxt = QtGui.QLabel("") self.dagFile = QtGui.QLabel("") self.statusBar().addWidget(self.dagFile) self.statusBar().addWidget(self.statusTxt) # connect to the machine if len(cli_param) > 1: ip = cli_param[1] if len(cli_param) > 2: self.myPC = cli_param[2] else: self.myPC = DEF_MYPC else: ip, ok = QtGui.QInputDialog.getText(None, "Connect to SpiNNaker", "Please specify machine IP", QtGui.QLineEdit.Normal, DEF_HOST) if ok is False: ip = '' print "Using machine at", ip self.mc = MachineController(ip) if BOOT_MACHINE is True: if self.mc.boot() is True: print "Machine is now booted..." else: print "Machine is already booted..." # then use machineInfo to build the map self.mInfo = self.mc.get_system_info() wMachine = self.mInfo.width hMachine = self.mInfo.height self.chipList = self.mInfo.keys() print "Found", len(self.chipList), "active chips:" """ self.mc.iptag_set(0,'192.168.240.2',17892,0,0) # prepare iptag for myTub, because boot in rig doesn't provide this if DEF_HOST=='192.168.240.1': self.statusTxt.setText("Using SpiNN-5 board at {}".format(DEF_HOST)) else: self.statusTxt.setText("Using SpiNN-3 board at {}".format(DEF_HOST)) """ #self.vis = visWidget(wMachine, hMachine, self.chipList, self.mdiArea) # for known dead chips on certain boards knownDeadChips = [] if (len(self.chipList) % 48) != 0: # dead chip is detected lst = QtGui.QInputDialog.getText( self, "Dead chip is detected", "Please provide chip coordinate in () separated by space", QtGui.QLineEdit.Normal, "(0,2)") knownDeadChips = getDeadChipList(lst) self.tgvisWidget = visWidget(wMachine, hMachine, self.chipList, knownDeadChips) self.vis = tgViever(self.tgvisWidget) #self.vis.setGeometry(0,0,1024,1024) #self.vis.scale(0.5,0.5) # put in half size self.vis.hide() self.action_Visualiser.setCheckable(True) #self.action_Visualiser.setChecked(False) self.connect(self.action_Quit, QtCore.SIGNAL("triggered()"), QtCore.SLOT("Quit()")) self.connect(self.action_Load_XML, QtCore.SIGNAL("triggered()"), QtCore.SLOT("loadXML()")) self.connect(self.action_Visualiser, QtCore.SIGNAL("triggered()"), QtCore.SLOT("showVisualiser()")) self.connect(self.action_Send_and_Init, QtCore.SIGNAL("triggered()"), QtCore.SLOT("sendAndInit()")) self.connect(self.actionInspect_SpinConf, QtCore.SIGNAL("triggered()"), QtCore.SLOT("testSpin1()")) self.connect(self.actionSet_Tick, QtCore.SIGNAL("triggered()"), QtCore.SLOT("getSimulationTick()")) self.connect(self.actionStart, QtCore.SIGNAL("triggered()"), QtCore.SLOT("startSim()")) self.connect(self.actionStop, QtCore.SIGNAL("triggered()"), QtCore.SLOT("stopSim()")) # 22 March 2017 - 11:48 - Buat experiment ambil data untuk paper self.timer = QtCore.QTimer(self) #self.timer.setInterval(60000) # one minute experiment self.timer.timeout.connect(self.timeout) # Simulation parameters self.simTick = 1000000 # default value that yield 1second resolution self.runningTime = 0 # 0 means runs forever self.dag = None # this is a list of list of dict that contains target dependency data """ self.srcTarget = dict() # this similar to self.dag, but just contains target for SOURCE node # (as a dict of a list), e.g: from dag0020, srcTarget = {0: [4,3,2]} """ self.srcTarget = list( ) # now scrTarget becomes simpler, because we don't send the trigger's payload self.sdp = sdpComm(self.chipList, ip) self.sdp.histUpdate.connect(self.vis.updateHist) self.setGeometry(0, 0, 1024, 1024)
if __name__ == "__main__": # Construct the test table RTE = RoutingTableEntry table = [ RTE({Routes.north, Routes.north_east}, 0b0000, 0b1111), RTE({Routes.east}, 0b0001, 0b1111), RTE({Routes.south_west}, 0b0101, 0b1111), RTE({Routes.north, Routes.north_east}, 0b1000, 0b1111), RTE({Routes.east}, 0b1001, 0b1111), RTE({Routes.south_west}, 0b1110, 0b1111), RTE({Routes.north, Routes.north_east}, 0b1100, 0b1111), RTE({Routes.south, Routes.south_west}, 0b0100, 0b1111), ] # Talk to the machine mc = MachineController("192.168.1.1") with mc.application(57): # Write the table table into memory on chip (0, 0) print("Loading tables...") with mc(x=0, y=0): mem = mc.sdram_alloc_as_filelike(len(table) * 16 + 12, tag=1) mem.write(pack_table(table, 57)) # Load the application print("Loading app...") mc.load_application("./rt_minimise.aplx", {(0, 0): {1}}) # Wait until this does something interesting print("Minimising...") ready = mc.wait_for_cores_to_reach_state("exit", 1, timeout=5.0) if ready < 1:
if __name__ == "__main__": # Construct the test table RTE = RoutingTableEntry table = [ RTE({Routes.north, Routes.north_east}, 0b0000, 0b1111), RTE({Routes.east}, 0b0001, 0b1111), RTE({Routes.south_west}, 0b0101, 0b1111), RTE({Routes.north, Routes.north_east}, 0b1000, 0b1111), RTE({Routes.east}, 0b1001, 0b1111), RTE({Routes.south_west}, 0b1110, 0b1111), RTE({Routes.north, Routes.north_east}, 0b1100, 0b1111), RTE({Routes.south, Routes.south_west}, 0b0100, 0b1111), ] # Talk to the machine mc = MachineController("192.168.1.1") mc.send_signal("stop") # Write the table table into memory on chip (0, 0) print("Loading tables...") with mc(x=0, y=0): mem = mc.sdram_alloc_as_filelike(len(table)*16 + 8, tag=1) mem.write(pack_table(table, 0)) # Load the application print("Loading app...") mc.load_application("./ordered_covering_profiled.aplx", {(0, 0): {1}}) # Wait until this does something interesting print("Minimising...") ready = mc.wait_for_cores_to_reach_state("exit", 1, timeout=5.0)
from rig.links import Links from rig.geometry import spinn5_chip_coord, spinn5_fpga_link from network_tester import Experiment, to_csv # Show detailed logging information import logging logging.basicConfig(level=logging.DEBUG) ################################################################################ # Experiment definition ################################################################################ # Run the experiment against the machine given on the commandline mc = MachineController(sys.argv[1]) e = Experiment(mc) # If some links are dead they will not be included in the experiment. if list(e.system_info.dead_links()): print("WARNING: {} dead links!".format( len(list(e.system_info.dead_links())))) # Number of cores to use on each chip for sending/receiving packets num_cores = 16 # Create num_cores cores on each chip in the machine. # {(x, y): [v, ...], ...} chip_cores = {(x, y): [e.new_core(x, y) for _ in range(num_cores)] for x, y in e.system_info}