#!/usr/bin/env python

import argparse
from subprocess import call

import os, sys
sys.path.append(os.getcwd() + "/configs/fault_injector")

from FaultParser import *
from ControlFaultParser import *

from threading import Thread

parser = argparse.ArgumentParser(description='Gem5')
parser.add_argument('-b', '--benchmarks', type=str, dest='benchmarks',
                    required=True, nargs='+',
                    help='Benchmark set for the simulation')

parser.add_argument('-i', '--fault-input', type=str, dest='faultInput',
                    nargs='+', help='Fault source files')

parser.add_argument('-ci', '--control-fault-input', type=str,
                    dest='controlFaultInput', nargs='+',
                    help='Control fault source files')

parser.add_argument('-df', '--debug-flags', type=str,
                    dest='debugFlags',
                    help='Gem5 debug flags for debugging purpose')

parser.add_argument('-o', '--options', type=str, dest='options',
                    help='Options for the binary benchmark')

parser.add_argument('-mt', '--multithread', dest='multithread',
                    action='store_true',
                    help='Set it to enable multithreaded simulation')
parser.set_defaults(multithread=False)

args = parser.parse_args()

def startBPUFaultedSim(benchmark, fault):
    cmd = ["./build/ALPHA/gem5.opt",
        "--stats-file", statFolder + "/" +
        fault.label + ".txt",
        "configs/fault_injector/injector_system.py",
        "-fe",
        "-b", benchmark,
        "-l", fault.label,
        "-sb", fault.stuckBit,
        "-f", fault.field,
        "-e", fault.entry,
        "-fsb", fault.stuckBit,
        "-bp", fault.bitPosition,
        "-tb", fault.tickBegin,
        "-te", fault.tickEnd]

    if args.debugFlags is not None:
        cmd.insert(1, "--debug-flags=" + args.debugFlags)

    call(cmd)

def startBPUControlFaultedSim(statFolder, fname, benchmark, cft, cfa):
    cmd = ["./build/ALPHA/gem5.opt",
        "--stats-file", statFolder + "/" +
        fname,
        "configs/fault_injector/injector_system.py",
        "-fe",
        "-b", benchmark,
        "-l", "control-fault_" + fname,
        "-cft", cft,
        "-cfa", cfa ]

    call(cmd)

if __name__ == '__main__':
    # Run a simulation for each specified benchmark program
    for benchmark in args.benchmarks:
        print "\n\nRunning " + benchmark + " GOLDEN\n"

        # Create a folder to store stats releated to the current benchmark
        statFolder = benchmark.split("/")[-1]
        if not os.path.exists("m5out/" + statFolder):
            os.makedirs("m5out/" + statFolder)

        if args.options != None:
            benchmark = " ".join([benchmark, args.options])

        # Run Golden simulation
        cmd = ["./build/ALPHA/gem5.opt",
            "--stats-file", statFolder + "/" +
            "GOLDEN.txt",
            "configs/fault_injector/injector_system.py",
            "-b", benchmark ]

        call(cmd)

        # Read all fault input files
        if args.faultInput is not None:
            for inputFile in args.faultInput:
                fp = FaultParser(inputFile)

                if args.multithread:
                    tpool = []

                while fp.hasNext():
                    # Load the next fault entry
                    fe = fp.next()

                    print "\n\nRunning " + benchmark + " with fault:\n" + \
                        str(fe)

                    if args.multithread:
                        # Run faulted simulation on an indipendent thread
                        t = Thread(target=startBPUFaultedSim,
                            args=(benchmark, fe))
                        tpool.append(t)
                        t.start()
                    else:
                        startBPUFaultedSim(benchmark, fe);

                # Join on the generated thread pool
                if args.multithread:
                    for t in tpool:
                        t.join()

        if args.controlFaultInput is not None:
            for inputFile in args.controlFaultInput:
                fname = inputFile.split("/")[-1]

                parser = ControlFaultParser()
                parser.parseFile(inputFile)

                print "\n\nRunning " + benchmark + " with fault:\n" + \
                    "control-fault@" + str(inputFile)

                # Run faulted simulation
                cmd = ["./build/ALPHA/gem5.opt",
                    "--stats-file", statFolder + "/" +
                    fname,
                    "configs/fault_injector/injector_system.py",
                    "-fe",
                    "-b", benchmark,
                    "-l", "control-fault_" + fname,
                    "-cft", parser.getTrigger().strip(),
                    "-cfa", parser.getAction().strip() ]

                call(cmd)

@@ -1953,16 +1953,23 @@
 rk, 
-cft, cfa
+trigger, action
 ):%0A 
@@ -2211,19 +2211,23 @@
 %22-cft%22, 
-cft
+trigger
 ,%0A      
@@ -2240,13 +2240,111 @@
 a%22, 
-cfa %5D
+action %5D%0A%0A    if args.debugFlags is not None:%0A        cmd.insert(1, %22--debug-flags=%22 + args.debugFlags)
 %0A%0A  
@@ -4507,228 +4507,337 @@
     
-# Run faulted simulation%0A                cmd = %5B%22./build/ALPHA/gem5.opt%22,%0A                    %22--stats-file%22, statFolder + %22/%22 +%0A                    fname,%0A                    %22configs/fault_injector/injector_system.py%22,
+if args.multithread:%0A                    # Run faulted simulation on an indipendent thread%0A                    t = Thread(target=startBPUControlFaultedSim,%0A                        args=(statFolder, fname, benchmark,%0A                            parser.getTrigger().strip(),%0A                            parser.getAction().strip()))
 %0A   
@@ -4845,38 +4845,47 @@
                 
-%22-fe%22,
+tpool.append(t)
 %0A               
@@ -4889,32 +4889,25 @@
         
-%22-b%22, benchmark,
+t.start()
 %0A       
@@ -4919,42 +4919,88 @@
     
-    %22-l%22, %22c
+else:%0A                    startBPUC
 ontrol
--f
+F
 ault
-_%22 + fname
+edSim(statFolder, fname, benchmark
 ,%0A  
@@ -5017,23 +5017,19 @@
         
-%22-cft%22,
+   
  parser.
@@ -5070,23 +5070,19 @@
         
-%22-cfa%22,
+   
  parser.
@@ -5100,18 +5100,17 @@
 .strip()
- %5D
+)
 %0A%0A      
@@ -5111,26 +5111,142 @@
             
-    call(cmd
+# Join on the generated thread pool%0A            if args.multithread:%0A                for t in tpool:%0A                    t.join(
 )%0A

add multithread support for control fault simulation