#!/usr/bin/env python2.7 # @date 22 September, 2014 # @author cfuguet import os import shutil import subprocess import arch import faultyprocs import argparse import multiprocessing import math def run(args): """ Execute the distributed bootloader providing permanent fault-recovery on the TSAR platform. Keyword arguments: path -- platform's base directory path outpath -- output's base directory path x -- number of clusters on the X coordinate y -- number of clusters on the Y coordinate nprocs -- number of processors per cluster compileonly -- stops after platform's compilation batchmode -- TTY and FB are only redirected to FILES faultyrouter -- a list containing faulty routers' coordinates (t, x, y) faultymask -- a mask of disabled routers' interfaces faultycore -- a list containing faulty cores' coordinates (x, y, l) debug -- a list with debug's start cycle, PID and MID threads -- number of OpenMP threads firmdebug -- activate the DEBUG compilation mode on software diskimage -- relative or absolute path to the disk image force -- create configuration files (or overwrite them) """ # translate the relative path (if needed) into an absolute path basedir = os.path.abspath(args.path) outdir = os.path.abspath(args.outpath) print "[ run.py ] platform base directory: {0}".format(basedir) print "[ run.py ] output directory: {0}".format(outdir) # 1. generate configuration and ouput directories try: os.makedirs(os.path.join(outdir, "config"), 0755) except OSError: pass # directory already exists => do nothing # 2. generate hard_config.h and fault_config.h files faultpath = os.path.join(outdir, "config/fault_config.h") hardpath = os.path.join(outdir, "config/hard_config.h") xmlpath = os.path.join(outdir, "config/giet.map.xml") if args.linux: dtspath = os.path.join(outdir, "config/platform.dts") else: dtspath = None exist = True exist = exist and os.path.exists(faultpath) exist = exist and os.path.exists(hardpath) exist = exist and os.path.exists(xmlpath) if args.linux: exist = exist and os.path.exists(dtspath) if not args.force and exist: print "[ run.py ] Warning: Reusing existing configuration files. " print "[ run.py ] Script arguments will be ignored (no --force option)" cmd = raw_input('[ run.py ] Would you like to continue (y/n): ') if cmd == 'n': exit(0) if cmd == 'y': pass else: exit(1) else: arch.main(args.x, args.y, args.nprocs, hardpath, xmlpath, dtspath) faultyprocs.generate(args.faultycore, faultpath) # create a log file logfile = open(os.path.join(outdir, "log"), "w") # 3. compile simulator executable dst = os.path.join(basedir, "hard_config.h") if os.path.lexists(dst): os.unlink(dst) os.symlink(hardpath, dst) print "[ run.py ] compiling simulator" command = [] command.extend(['make']) command.extend(['-C', basedir]) subprocess.check_call(command, stdout=logfile, stderr=logfile) # 4. compile distributed boot executable dst = os.path.join(outdir, "config/boot_config.h") if os.path.lexists(dst): os.unlink(dst) os.symlink(os.path.join(basedir, "soft/test/config/boot_config.h"), dst) print "[ run.py ] compiling distributed boot procedure" command = [] command.extend(['make']) command.extend(['-C', os.path.join(basedir, "soft")]) command.extend(["CONFIG=" + outdir]) command.extend(["DEBUG=" + str(args.firmdebug)]) if args.linux: command.extend(["PATCHER_OS=1"]) else: command.extend(["PATCHER_OS=0"]) subprocess.check_call(command, stdout=logfile, stderr=logfile) # stop after compiling when the compile-only option is activated if args.compileonly == True: exit(0) # 5. execute simulator os.environ["DISTRIBUTED_BOOT"] = "1" os.environ["SOCLIB_FB"] = "HEADLESS" if args.batchmode: os.environ["SOCLIB_TTY"] = "FILES" print "[ run.py ] starting simulation" command = [] command.extend([os.path.join(basedir, "simul.x")]) command.extend(["-DSOFT", "soft/build/boot.elf"]) command.extend(["-SOFT", "soft/build/loader.elf"]) command.extend(["-DISK", args.diskimage]) if args.faultyrouter != None: command.extend(["-FAULTY_MASK", str(args.faultymask)]) for f in args.faultyrouter: command.extend(["-FAULTY_ROUTER", str(f[0]), str(f[1]), str(f[2])]) if args.debug != None: command.extend(["-DEBUG", str(args.debug[0])]); command.extend(["-PROCID", str(args.debug[1])]); command.extend(["-MEMCID", str(args.debug[2])]); command.extend(["-IOB", "1"]); if args.ncycles > 0: command.extend(["-NCYCLES", str(args.ncycles)]) elif os.environ.get('SOCLIB_GDB') == None: # the procedure grows linearly with the diameter of the mesh. # maxcycles = 1500000 + (args.x + args.y) * 20000 # command.extend(["-NCYCLES", str(maxcycles)]) command.extend(["-NCYCLES", str(200000000)]) # OpenMP number of threads definition ompthreads = args.threads if ompthreads < 1: ompthreads = math.ceil(float(args.x * args.y) / 4) # be nice and don't use all available processors maxcpu = math.ceil(float(multiprocessing.cpu_count()) * 2/3) if ompthreads > maxcpu: ompthreads = maxcpu command.extend(["-THREADS", str(ompthreads)]) logfile.write("Execute: {0}\n".format(" ".join(command))) logfile.flush() subprocess.check_call(command, stdout=logfile, stderr=logfile) logfile.close() # 6. move simulation terminal output into the target config dir if os.path.lexists("term0"): shutil.copy2("term0", os.path.join(outdir, "term")) # get command-line arguments if __name__ == "__main__": parser = argparse.ArgumentParser(description='Run simulation') parser.add_argument( '--path', '-p', type=str, dest='path', default=os.getcwd(), help='relative or absolute path to the platform') parser.add_argument( '--output', '-o', type=str, dest='outpath', default='./output', help='relative or absolute path to the output directory') parser.add_argument( '--xsize', '-x', type=int, dest='x', default=2, help='# of clusters in a row') parser.add_argument( '--ysize', '-y', type=int, dest='y', default=2, help='# of clusters in a column') parser.add_argument( '--nprocs', '-n', type=int, dest='nprocs', default=4, help='# of processors per cluster') parser.add_argument( '--compile-only', '-c', dest='compileonly', action='store_true', help='generate config files and compile the platform. Do not simulate') parser.add_argument( '--batch-mode', '-b', dest='batchmode', action='store_true', help='run simulation in batch mode: no interactive TTY or FrameBuffer') parser.add_argument( '--faulty-router', '-fr', dest='faultyrouter', action='append', nargs=3, help='ID (T,X,Y) of faulty router. \ The T is 0:CMD, 1:RSP, 2:M2P, 3:P2M, 4:CLACK. \ The three arguments are space-separated. \ (e.g. -fr 2 1 1, router M2P (1,1) is deactivated') parser.add_argument( '--faulty-mask', '-m', dest='faultymask', default=0x1F, help='Disable mask for faulty router interfaces') parser.add_argument( '--faulty-core', '-fc', dest='faultycore', action='append', nargs=3, help='ID (X,Y,L) of faulty processor. \ The three arguments are space-separated. \ (e.g. -fc 0 1 3, core (0,1,3) is deactivated') parser.add_argument( '--debug', '-g', dest='debug', nargs=3, help='needs four arguments: from, procid, memcid') parser.add_argument( '--threads', '-t', type=int, dest='threads', default=1, help='number of OpenMP threads') parser.add_argument( '--firmware-debug', '-fg', dest='firmdebug', default=0, help='activate the DEBUG compilation mode on software') parser.add_argument( '--disk-image', '-di', dest='diskimage', default="/dev/null", help='relative or absolute path to the disk image used by the IOC') parser.add_argument( '--force', '-f', dest='force', action='store_true', help='create configuration files (or overwrite them)') parser.add_argument( '--linux', dest='linux', action='store_true', help='generate linux device tree and compile bootloader ' + 'with linux specifics') parser.add_argument( '--ncycles', type=int, dest='ncycles', default=-1, help='max simulation cycles') run(parser.parse_args()) # vim: tabstop=4 : softtabstop=4 : shiftwidth=4 : expandtab