From 1026e429095b1b6054fe81022bdeb173d7eccb47 Mon Sep 17 00:00:00 2001 From: Joshua Bakita Date: Sat, 24 Oct 2020 18:15:13 -0400 Subject: Fixup the case study script New features: - Checks arguments - Checks that we're root first - Checks if task launches succeed - Checks that a case study is not already running Fixes: - Removes invalid uses of sudo - Fixes use of ',' rather than ';' in resctrl specification - Fixes PID determination - Always launches Level-C tasks as asynchronous threads Additionally converts the whole file to only use spaces and to be directly executable. --- run_case_study.py | 274 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 185 insertions(+), 89 deletions(-) mode change 100644 => 100755 run_case_study.py (limited to 'run_case_study.py') diff --git a/run_case_study.py b/run_case_study.py old mode 100644 new mode 100755 index bcbaca6..eff06fe --- a/run_case_study.py +++ b/run_case_study.py @@ -1,3 +1,5 @@ +#!/usr/bin/python3 +# Make sure to run this as root!!!!! import os import sys import re @@ -5,35 +7,78 @@ import csv import time import subprocess +A_SUITE = 1 +A_BIN = 2 +A_CRIT = 3 +A_PERIOD = 5 + +P_CORE = 0 +P_CRIT = 1 +P_T1_ID = 2 +P_T2_ID = 5 + +T_ID = 0 +T_BIN = 1 +T_PERIOD = 2 +T_CCX = 3 + +CRIT_LEVEL_C = 2 + all_pids=[] def run(command): print(command) os.system(command) + def addpid(pid): with open("./pids.txt", "a") as f: f.write(str(pid) + "\n") +def ID2PID(lookupID): + res = None + # Find benchmark PID (avoid getting shell or numactl PID) + try: + res = subprocess.check_output("pgrep -af " + lookupID + " | grep -v numactl | cut -d ' ' -f 1", shell=True) + except: + res = None + if res: + # Ignore the newline + return res.decode("utf-8").strip() + else: + return None - -def main(): +def main(pathName): with open("./pids.txt", "w") as f: f.write("") - pathName = sys.argv[1] tacle_pairs_path = "./all_pairs" tacle_baseline_path = "./baseline" dis_path = "./dis" + # List of lists + # Each list represents the parameters for a task as: + # [id, suite, binary name, criticality level (0-base), pet us (unused), period ms, wss (unused)] all_tasks = [] + # List of lists + # Each list represents the parameters for a pairing as: + # [core, criticality level (0-base), task 1 ID, task 1 name (unused), task 1 period, task 2 ID, task 2 name, task 2 period] + # if task 1 ID = task 2 ID, it's not actually a pair at all levelAB = [] levelC = [] levelC_s = [] - dis_inputs = dict() - dis_inputs["field"] = "./gen_input.py field inputs/Field/in0 2097152" - dis_inputs["matrix"] = "gen_input.py matrix inputs/Matrix/in0 2097152" - dis_inputs["neighborhood"] = "./gen_input.py neighborhood inputs/Neighborhood/in0 2097152" - dis_inputs["pointer"] = "./gen_input.py pointer inputs/Pointer/in0 2097152" - dis_inputs["transitive"] = "./gen_input.py transitive inputs/Transitive/in0 2097152" - dis_inputs["update"] = "./gen_input.py update inputs/Update/in0 2097152" + input_cmd = {} + # Load input command for each binary + with open("baseline/tacleNames.txt") as f: + for benchName in f: + # TACLeBench doesn't need inputs + input_cmd[benchName.strip()] = "echo ' '" + with open("SD-VBS/sd-vbsNames.txt") as f: + for line in f: + name, cmd = line.split(maxsplit=1) + input_cmd[name.replace("./", "")] = cmd.replace("./", "./SD-VBS/").strip() + with open("dis/dis2MbInNames.txt") as f: + for line in f: + name, cmd = line.split(maxsplit=1) + input_cmd[name.replace("./", "")] = cmd.replace("./", "./dis/").strip() + # Load task specifications with open(pathName+"/all_tasks.csv", "r") as csv_file: csv_reader = csv.reader(csv_file, delimiter = ',') line = 0 @@ -56,6 +101,7 @@ def main(): for row in csv_reader: if(len(row) < 3): continue + # Start of a cluster - read definition if(row[0] == "threaded" or row[0] == "solo"): threaded = row[0] == "threaded" if(row[1] == "4"): @@ -63,6 +109,7 @@ def main(): else: ccx = "0" continue + # Start of a thread speficication if(row[0] != "task id" and row[0] != ""): row.append(ccx) if(threaded): @@ -71,9 +118,9 @@ def main(): row.append("s") levelC.append(row) line += 1 + ### Allocate Cache Ways ### run('mount -t resctrl resctrl /sys/fs/resctrl') - run('sudo echo "L3:0=0000,1=0000,2=0000,3=0000" > sudo /sys/fs/resctrl/schemata') - +# run('echo "L3:0=0000,1=0000,2=0000,3=0000" > /sys/fs/resctrl/schemata') with open(pathName+"/l3alloc.csv", "r") as csv_file: csv_reader = csv.reader(csv_file, delimiter = ',') line = 0 @@ -86,109 +133,158 @@ def main(): # Level C allocation if(core == 1): run("mkdir -p /sys/fs/resctrl/level-c-ccx-0") - run('sudo echo "L3:0=' + ("%0.4x" % (int("1"*way_C, 2))) + ',1=0000,2=0000,3=0000" > sudo /sys/fs/resctrl/level-c-ccx-0/schemata') + run('echo "L3:0=' + ("%0.4x" % (int("1"*way_C, 2))) + ';1=0000;2=0000;3=0000" > /sys/fs/resctrl/level-c-ccx-0/schemata') if(core == 4): run("mkdir -p /sys/fs/resctrl/level-c-ccx-1") - run('sudo echo "L3:0=0000, 1=' + ("%0.4x" % (int("1"*way_C, 2))) + ',2=0000,3=0000" > sudo /sys/fs/resctrl/level-c-ccx-1/schemata') + run('echo "L3:0=0000;1=' + ("%0.4x" % (int("1"*way_C, 2))) + ';2=0000;3=0000" > /sys/fs/resctrl/level-c-ccx-1/schemata') run('mkdir -p /sys/fs/resctrl/level-ab-core-' + str(core)) if(core < 4): - run('sudo echo "L3:0=' + ("%0.4x" % (int("1"*way_AB + "0"*(16-way_AB), 2))) + ',1=0000,2=0000,3=0000" > sudo /sys/fs/resctrl/level-ab-core-' + str(core) + '/schemata') + run('echo "L3:0=' + ("%0.4x" % (int("1"*way_AB + "0"*(16-way_AB), 2))) + ';1=0000;2=0000;3=0000" > /sys/fs/resctrl/level-ab-core-' + str(core) + '/schemata') else: - run('sudo echo "L3:0=0000,1=' + ("%0.4x" % (int("1"*way_AB + "0"*(16-way_AB), 2))) + ',2=0000,3=0000" > sudo /sys/fs/resctrl/level-ab-core-' + str(core) + '/schemata') + run('echo "L3:0=0000;1=' + ("%0.4x" % (int("1"*way_AB + "0"*(16-way_AB), 2))) + ';2=0000;3=0000" > /sys/fs/resctrl/level-ab-core-' + str(core) + '/schemata') line += 1 - run("sudo rm -rf /dev/shm/*") + ### Cleanup Old State ### + run("rm -rf /dev/shm/*") pairID = 0 i = 0 - for task in levelAB: - task1 = int(task[2]) - task2 = int(task[5]) - name1 = all_tasks[task1][2] - name2 = all_tasks[task2][2] - if(name1 == "rijndael_e"): - name1 = "rijndael_enc" - - if(name2 == "rijndael_e"): - name2 = "rijndael_enc" - period1 = all_tasks[task1][5] - period2 = all_tasks[task2][5] - suite1 = all_tasks[task1][1] - suite2 = all_tasks[task2][1] - core = task[0] - criticality = task[1] + ### Dispatch all the Level-A and -B paired and unpaired tasks ### + for pairing in levelAB: + if i > 2: + break + i += 1 + + task1 = int(pairing[P_T1_ID]) + task2 = int(pairing[P_T2_ID]) + # Lookup periods and binary location + name1 = all_tasks[task1][A_BIN] + name2 = all_tasks[task2][A_BIN] + period1 = all_tasks[task1][A_PERIOD] + period2 = all_tasks[task2][A_PERIOD] + suite1 = all_tasks[task1][A_SUITE] + suite2 = all_tasks[task2][A_SUITE] + core = pairing[P_CORE] + criticality = pairing[P_CRIT] binary = "" binary1 = "" binary2 = "" arg = "" - if(task1 == task2): - arg = " NULL -1 " + core + " NULL 0 " + period1 + " " + criticality - - if(suite1 == "TACLe"): - binary = "./baseline/bin/" + name1 + arg + # If the IDs match, this isn't a pair at all + if task1 == task2: + if suite1 == "TACLe": + binary = "./baseline/bin/" + name1 + elif suite1 == "SD-VBS": + binary = "./SD-VBS/" + name1 + elif suite1 == "DIS": + binary = "./dis/" + name1 else: - binary = dis_inputs[name1] + " | ./dis/" + name1 + arg - proc = subprocess.Popen([binary], shell = True) - #print(binary + " &" ) - pid = proc.pid - run("sudo echo " + str(pid) + " > sudo /sys/fs/resctrl/level-ab-core-" + core + "/tasks") - addpid(pid) - else: - pairID += 1 - arg1 = " NULL -1 " + core + " 0 NULL NULL 0 " + str(pairID) + " " + period1 + " " + criticality - arg2 = " NULL -1 " + str(int(core)+16) + " 0 NULL NULL 0 " + str(pairID) + " " + period2 + " " + criticality + print("Invalid suite name " + suite1 + " in Level-A/-B tasks! Exiting...") + exit(1) - if(suite1 == "TACLe"): - binary1 = "./all_pairs/bin/" + name1 + arg1 - binary2 = "./all_pairs/bin/" + name2 + arg2 + lookupID = name1 + task1 + if ID2PID(lookupID): + print("ERROR: Task ID {} is already running! Did you end the previous case study?".format(lookupID)) + exit(1) + # Arg format: + arg = " " + lookupID + " -1 " + core + " NULL 0 " + period1 + " " + criticality + bench_tsk = subprocess.Popen(input_cmd[name1] + " | numactl --interleave=all " + binary + arg, shell = True) + pid_str = ID2PID(lookupID) + if not pid_str: + print("Unable to launch {} as a solo task! Exiting...".format(name1)) + exit(1) + # Add this task to the appropriate cache partition (Class of Service in Intel CAT terms) + run("echo " + pid_str + " > /sys/fs/resctrl/level-ab-core-" + core + "/tasks") + addpid(pid_str) + else: + if suite1 == "TACLe": + binary1 = "./all_pairs/bin/" + name1 + binary2 = "./all_pairs/bin/" + name2 + elif suite1 == "SD-VBS": + binary1 = "./SD-VBS/" + name1 + "_all" + binary2 = "./SD-VBS/" + name2 + "_all" + elif suite1 == "DIS": + binary1 = "./dis/" + name1 + "_all" + binary2 = "./dis/" + name2 + "_all" else: - binary1 = dis_inputs[name1] + " | ./dis/" + name1 + "_all" + arg1 - binary2 = dis_inputs[name2] + " | ./dis/" + name2 + "_all" + arg2 - proc1 = subprocess.Popen(["sudo numactl --membind=0 " + binary1], shell = True) - proc2 = subprocess.Popen(["sudo numactl --membind=1 " + binary2], shell = True) - #print("sudo numactl --membind=0 " + binary1 + " &") - #print("sudo numactl --membind=1 " + binary2 + " &") - pid1 = proc2.pid + 1 - pid2 = proc2.pid + 3 - - run("sudo echo " + str(pid1) + " > sudo /sys/fs/resctrl/level-ab-core-" + core + "/tasks") - run("sudo echo " + str(pid2) + " > sudo /sys/fs/resctrl/level-ab-core-" + core + "/tasks") - addpid(pid1) - addpid(pid2) + print("Invalid suite name " + suite1 + " in Level-A/-B tasks! Exiting...") + exit(1) + pairID += 1 # Used for sem/shm identification in the pair task + thread = str(int(core) + 16) # How Linux numbers SMT threads on the 3950X + lookupID1 = name1 + str(task1) + lookupID2 = name2 + str(task2) + if ID2PID(lookupID1) or ID2PID(lookupID2): + print("ERROR: Part of the pair containing task IDs {} and {} is already running! Did you end the previous case study?".format(lookupID1, lookupID2)) + exit(1) + # Arg format: <0 other core> + arg1 = " " + lookupID1 + " -1 " + core + " 0 NULL NULL 0 " + str(pairID) + " " + period1 + " " + criticality + arg2 = " " + lookupID2 + " -1 " + thread + " 0 NULL NULL 0 " + str(pairID) + " " + period2 + " " + criticality + bench_tsk1 = subprocess.Popen(input_cmd[name1] + "| numactl --membind=0 " + binary1 + arg1, shell = True) + bench_tsk2 = subprocess.Popen(input_cmd[name2] + "| numactl --membind=1 " + binary2 + arg2, shell = True) + # Find benchmark PID (avoid getting shell or numactl PID) + pid1_str = ID2PID(lookupID1) + pid2_str = ID2PID(lookupID2) + if not pid1_str or not pid2_str: + print("Unable to launch {} and {} in a pair! Exiting...".format(name1, name2)) + exit(1) + # Add this task to the appropriate cache partition (Class of Service in Intel CAT terms) + run("echo " + pid1_str + " > /sys/fs/resctrl/level-ab-core-" + core + "/tasks") + run("echo " + pid2_str + " > /sys/fs/resctrl/level-ab-core-" + core + "/tasks") + addpid(pid1_str) + addpid(pid2_str) + + i = 0 + ### Dispatch all the Level-C tasks ### for task in levelC: - continue - i+=1 - if(i>8): + if i > 2: break - tid = int(task[0]) - name = all_tasks[tid][2] - period = all_tasks[tid][5] - suite = all_tasks[tid][1] - ccx = task[3] - threaded = task[4] == "t" - arg = "" + i += 1 - if(name == "rijndael_e"): - name = "rijndael_enc" - if(not threaded): - arg = " NULL -1 " + ccx + " NULL 0 " + period + " 2" - else: - pairID += 1 - arg = " NULL -1 " + ccx + " 0 NULL NULL 0 " + str(pairID) + " " + period + " 2" - if(suite1 == "TACLe"): - binary = "./baseline/bin/" + name1 + arg + tid = int(task[T_ID]) + name = all_tasks[tid][A_BIN] + period = all_tasks[tid][A_PERIOD] + suite = all_tasks[tid][A_SUITE] + ccx = task[T_CCX] + + if suite == "TACLe": + binary = "./baseline/bin/" + name + elif suite == "SD-VBS": + binary = "./SD-VBS/" + name + elif suite == "DIS": + binary = "./dis/" + name else: - binary = dis_inputs[name1] + " | ./dis/" + name1 + "_all" + arg + print("Invalid suite name " + suite + " in Level-A/-B tasks! Exiting...") + exit(1) + # XXX XXX XXX: FIXME when LITMUS is fixed + core = str(int(ccx)*4 + 1); - print(binary + " &") - proc = subprocess.Popen([binary + " &"], shell = True) - pid = proc.pid - run("sudo echo " + str(pid) + " > sudo /sys/fs/resctrl/level-ab-ccx-" + ccx + "/tasks") + lookupID = name + str(tid) + if ID2PID(lookupID): + print("ERROR: Task ID {} is already running! Did you end the previous case study?".format(lookupID)) + exit(1) + # Arg format: + arg = " " + lookupID + " -1 " + core + " NULL 0 " + period + " " + str(CRIT_LEVEL_C) + bench_tsk = subprocess.Popen(input_cmd[name] + " | numactl --interleave=all " + binary + arg, shell=True) + # Find benchmark PID (avoid getting shell or numactl PID) + pid_str = ID2PID(lookupID) + if not pid_str: + print("Unable to launch {} as a Level-C thread! Exiting...".format(name)) + exit(1) + # Add this task to the appropriate cache partition (Class of Service in Intel CAT terms) + run("echo " + pid_str + " > /sys/fs/resctrl/level-c-ccx-" + ccx + "/tasks") + addpid(pid_str) #os.system("/playpen/mc2/liblitmus/release_ts") #os.system("ls") time.sleep(3) if __name__ == "__main__": - main() + if len(sys.argv) < 2: + print("Usage: " + sys.argv[0] + " ") + exit(1) + if os.geteuid() != 0: + print("You must run this script as root to enable cache isolation and access LITMUS-RT.") + exit(1) + pathName = sys.argv[1] + main(pathName) -- cgit v1.2.2