diff options
author | Joshua Bakita <jbakita@cs.unc.edu> | 2020-10-24 18:15:13 -0400 |
---|---|---|
committer | Joshua Bakita <jbakita@cs.unc.edu> | 2020-10-24 18:15:13 -0400 |
commit | 1026e429095b1b6054fe81022bdeb173d7eccb47 (patch) | |
tree | f20244062650df30809cacc7bb720b85a78c0356 | |
parent | 3975bcd4ada118ac66be630b17fd8407aad8ffd8 (diff) |
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.
-rwxr-xr-x[-rw-r--r--] | run_case_study.py | 274 |
1 files changed, 185 insertions, 89 deletions
diff --git a/run_case_study.py b/run_case_study.py index bcbaca6..eff06fe 100644..100755 --- a/run_case_study.py +++ b/run_case_study.py | |||
@@ -1,3 +1,5 @@ | |||
1 | #!/usr/bin/python3 | ||
2 | # Make sure to run this as root!!!!! | ||
1 | import os | 3 | import os |
2 | import sys | 4 | import sys |
3 | import re | 5 | import re |
@@ -5,35 +7,78 @@ import csv | |||
5 | import time | 7 | import time |
6 | import subprocess | 8 | import subprocess |
7 | 9 | ||
10 | A_SUITE = 1 | ||
11 | A_BIN = 2 | ||
12 | A_CRIT = 3 | ||
13 | A_PERIOD = 5 | ||
14 | |||
15 | P_CORE = 0 | ||
16 | P_CRIT = 1 | ||
17 | P_T1_ID = 2 | ||
18 | P_T2_ID = 5 | ||
19 | |||
20 | T_ID = 0 | ||
21 | T_BIN = 1 | ||
22 | T_PERIOD = 2 | ||
23 | T_CCX = 3 | ||
24 | |||
25 | CRIT_LEVEL_C = 2 | ||
26 | |||
8 | all_pids=[] | 27 | all_pids=[] |
9 | def run(command): | 28 | def run(command): |
10 | print(command) | 29 | print(command) |
11 | os.system(command) | 30 | os.system(command) |
31 | |||
12 | def addpid(pid): | 32 | def addpid(pid): |
13 | with open("./pids.txt", "a") as f: | 33 | with open("./pids.txt", "a") as f: |
14 | f.write(str(pid) + "\n") | 34 | f.write(str(pid) + "\n") |
35 | def ID2PID(lookupID): | ||
36 | res = None | ||
37 | # Find benchmark PID (avoid getting shell or numactl PID) | ||
38 | try: | ||
39 | res = subprocess.check_output("pgrep -af " + lookupID + " | grep -v numactl | cut -d ' ' -f 1", shell=True) | ||
40 | except: | ||
41 | res = None | ||
42 | if res: | ||
43 | # Ignore the newline | ||
44 | return res.decode("utf-8").strip() | ||
45 | else: | ||
46 | return None | ||
15 | 47 | ||
16 | 48 | def main(pathName): | |
17 | def main(): | ||
18 | with open("./pids.txt", "w") as f: | 49 | with open("./pids.txt", "w") as f: |
19 | f.write("") | 50 | f.write("") |
20 | 51 | ||
21 | pathName = sys.argv[1] | ||
22 | tacle_pairs_path = "./all_pairs" | 52 | tacle_pairs_path = "./all_pairs" |
23 | tacle_baseline_path = "./baseline" | 53 | tacle_baseline_path = "./baseline" |
24 | dis_path = "./dis" | 54 | dis_path = "./dis" |
55 | # List of lists | ||
56 | # Each list represents the parameters for a task as: | ||
57 | # [id, suite, binary name, criticality level (0-base), pet us (unused), period ms, wss (unused)] | ||
25 | all_tasks = [] | 58 | all_tasks = [] |
59 | # List of lists | ||
60 | # Each list represents the parameters for a pairing as: | ||
61 | # [core, criticality level (0-base), task 1 ID, task 1 name (unused), task 1 period, task 2 ID, task 2 name, task 2 period] | ||
62 | # if task 1 ID = task 2 ID, it's not actually a pair at all | ||
26 | levelAB = [] | 63 | levelAB = [] |
27 | levelC = [] | 64 | levelC = [] |
28 | levelC_s = [] | 65 | levelC_s = [] |
29 | dis_inputs = dict() | 66 | input_cmd = {} |
30 | dis_inputs["field"] = "./gen_input.py field inputs/Field/in0 2097152" | 67 | # Load input command for each binary |
31 | dis_inputs["matrix"] = "gen_input.py matrix inputs/Matrix/in0 2097152" | 68 | with open("baseline/tacleNames.txt") as f: |
32 | dis_inputs["neighborhood"] = "./gen_input.py neighborhood inputs/Neighborhood/in0 2097152" | 69 | for benchName in f: |
33 | dis_inputs["pointer"] = "./gen_input.py pointer inputs/Pointer/in0 2097152" | 70 | # TACLeBench doesn't need inputs |
34 | dis_inputs["transitive"] = "./gen_input.py transitive inputs/Transitive/in0 2097152" | 71 | input_cmd[benchName.strip()] = "echo ' '" |
35 | dis_inputs["update"] = "./gen_input.py update inputs/Update/in0 2097152" | 72 | with open("SD-VBS/sd-vbsNames.txt") as f: |
73 | for line in f: | ||
74 | name, cmd = line.split(maxsplit=1) | ||
75 | input_cmd[name.replace("./", "")] = cmd.replace("./", "./SD-VBS/").strip() | ||
76 | with open("dis/dis2MbInNames.txt") as f: | ||
77 | for line in f: | ||
78 | name, cmd = line.split(maxsplit=1) | ||
79 | input_cmd[name.replace("./", "")] = cmd.replace("./", "./dis/").strip() | ||
36 | 80 | ||
81 | # Load task specifications | ||
37 | with open(pathName+"/all_tasks.csv", "r") as csv_file: | 82 | with open(pathName+"/all_tasks.csv", "r") as csv_file: |
38 | csv_reader = csv.reader(csv_file, delimiter = ',') | 83 | csv_reader = csv.reader(csv_file, delimiter = ',') |
39 | line = 0 | 84 | line = 0 |
@@ -56,6 +101,7 @@ def main(): | |||
56 | for row in csv_reader: | 101 | for row in csv_reader: |
57 | if(len(row) < 3): | 102 | if(len(row) < 3): |
58 | continue | 103 | continue |
104 | # Start of a cluster - read definition | ||
59 | if(row[0] == "threaded" or row[0] == "solo"): | 105 | if(row[0] == "threaded" or row[0] == "solo"): |
60 | threaded = row[0] == "threaded" | 106 | threaded = row[0] == "threaded" |
61 | if(row[1] == "4"): | 107 | if(row[1] == "4"): |
@@ -63,6 +109,7 @@ def main(): | |||
63 | else: | 109 | else: |
64 | ccx = "0" | 110 | ccx = "0" |
65 | continue | 111 | continue |
112 | # Start of a thread speficication | ||
66 | if(row[0] != "task id" and row[0] != ""): | 113 | if(row[0] != "task id" and row[0] != ""): |
67 | row.append(ccx) | 114 | row.append(ccx) |
68 | if(threaded): | 115 | if(threaded): |
@@ -71,9 +118,9 @@ def main(): | |||
71 | row.append("s") | 118 | row.append("s") |
72 | levelC.append(row) | 119 | levelC.append(row) |
73 | line += 1 | 120 | line += 1 |
121 | ### Allocate Cache Ways ### | ||
74 | run('mount -t resctrl resctrl /sys/fs/resctrl') | 122 | run('mount -t resctrl resctrl /sys/fs/resctrl') |
75 | run('sudo echo "L3:0=0000,1=0000,2=0000,3=0000" > sudo /sys/fs/resctrl/schemata') | 123 | # run('echo "L3:0=0000,1=0000,2=0000,3=0000" > /sys/fs/resctrl/schemata') |
76 | |||
77 | with open(pathName+"/l3alloc.csv", "r") as csv_file: | 124 | with open(pathName+"/l3alloc.csv", "r") as csv_file: |
78 | csv_reader = csv.reader(csv_file, delimiter = ',') | 125 | csv_reader = csv.reader(csv_file, delimiter = ',') |
79 | line = 0 | 126 | line = 0 |
@@ -86,109 +133,158 @@ def main(): | |||
86 | # Level C allocation | 133 | # Level C allocation |
87 | if(core == 1): | 134 | if(core == 1): |
88 | run("mkdir -p /sys/fs/resctrl/level-c-ccx-0") | 135 | run("mkdir -p /sys/fs/resctrl/level-c-ccx-0") |
89 | 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') | 136 | 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') |
90 | 137 | ||
91 | if(core == 4): | 138 | if(core == 4): |
92 | run("mkdir -p /sys/fs/resctrl/level-c-ccx-1") | 139 | run("mkdir -p /sys/fs/resctrl/level-c-ccx-1") |
93 | 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') | 140 | 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') |
94 | run('mkdir -p /sys/fs/resctrl/level-ab-core-' + str(core)) | 141 | run('mkdir -p /sys/fs/resctrl/level-ab-core-' + str(core)) |
95 | if(core < 4): | 142 | if(core < 4): |
96 | 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') | 143 | 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') |
97 | else: | 144 | else: |
98 | 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') | 145 | 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') |
99 | line += 1 | 146 | line += 1 |
100 | run("sudo rm -rf /dev/shm/*") | 147 | ### Cleanup Old State ### |
148 | run("rm -rf /dev/shm/*") | ||
101 | pairID = 0 | 149 | pairID = 0 |
102 | i = 0 | 150 | i = 0 |
103 | for task in levelAB: | 151 | ### Dispatch all the Level-A and -B paired and unpaired tasks ### |
104 | task1 = int(task[2]) | 152 | for pairing in levelAB: |
105 | task2 = int(task[5]) | 153 | if i > 2: |
106 | name1 = all_tasks[task1][2] | 154 | break |
107 | name2 = all_tasks[task2][2] | 155 | i += 1 |
108 | if(name1 == "rijndael_e"): | 156 | |
109 | name1 = "rijndael_enc" | 157 | task1 = int(pairing[P_T1_ID]) |
110 | 158 | task2 = int(pairing[P_T2_ID]) | |
111 | if(name2 == "rijndael_e"): | 159 | # Lookup periods and binary location |
112 | name2 = "rijndael_enc" | 160 | name1 = all_tasks[task1][A_BIN] |
113 | period1 = all_tasks[task1][5] | 161 | name2 = all_tasks[task2][A_BIN] |
114 | period2 = all_tasks[task2][5] | 162 | period1 = all_tasks[task1][A_PERIOD] |
115 | suite1 = all_tasks[task1][1] | 163 | period2 = all_tasks[task2][A_PERIOD] |
116 | suite2 = all_tasks[task2][1] | 164 | suite1 = all_tasks[task1][A_SUITE] |
117 | core = task[0] | 165 | suite2 = all_tasks[task2][A_SUITE] |
118 | criticality = task[1] | 166 | core = pairing[P_CORE] |
167 | criticality = pairing[P_CRIT] | ||
119 | binary = "" | 168 | binary = "" |
120 | binary1 = "" | 169 | binary1 = "" |
121 | binary2 = "" | 170 | binary2 = "" |
122 | arg = "" | 171 | arg = "" |
123 | if(task1 == task2): | 172 | # If the IDs match, this isn't a pair at all |
124 | arg = " NULL -1 " + core + " NULL 0 " + period1 + " " + criticality | 173 | if task1 == task2: |
125 | 174 | if suite1 == "TACLe": | |
126 | if(suite1 == "TACLe"): | 175 | binary = "./baseline/bin/" + name1 |
127 | binary = "./baseline/bin/" + name1 + arg | 176 | elif suite1 == "SD-VBS": |
177 | binary = "./SD-VBS/" + name1 | ||
178 | elif suite1 == "DIS": | ||
179 | binary = "./dis/" + name1 | ||
128 | else: | 180 | else: |
129 | binary = dis_inputs[name1] + " | ./dis/" + name1 + arg | 181 | print("Invalid suite name " + suite1 + " in Level-A/-B tasks! Exiting...") |
130 | proc = subprocess.Popen([binary], shell = True) | 182 | exit(1) |
131 | #print(binary + " &" ) | ||
132 | pid = proc.pid | ||
133 | run("sudo echo " + str(pid) + " > sudo /sys/fs/resctrl/level-ab-core-" + core + "/tasks") | ||
134 | addpid(pid) | ||
135 | else: | ||
136 | pairID += 1 | ||
137 | arg1 = " NULL -1 " + core + " 0 NULL NULL 0 " + str(pairID) + " " + period1 + " " + criticality | ||
138 | arg2 = " NULL -1 " + str(int(core)+16) + " 0 NULL NULL 0 " + str(pairID) + " " + period2 + " " + criticality | ||
139 | 183 | ||
140 | if(suite1 == "TACLe"): | 184 | lookupID = name1 + task1 |
141 | binary1 = "./all_pairs/bin/" + name1 + arg1 | 185 | if ID2PID(lookupID): |
142 | binary2 = "./all_pairs/bin/" + name2 + arg2 | 186 | print("ERROR: Task ID {} is already running! Did you end the previous case study?".format(lookupID)) |
187 | exit(1) | ||
188 | # Arg format: <unique name> <infinite loops> <core> <NULL runID> <no output> <period> <crit lvl> | ||
189 | arg = " " + lookupID + " -1 " + core + " NULL 0 " + period1 + " " + criticality | ||
190 | bench_tsk = subprocess.Popen(input_cmd[name1] + " | numactl --interleave=all " + binary + arg, shell = True) | ||
191 | pid_str = ID2PID(lookupID) | ||
192 | if not pid_str: | ||
193 | print("Unable to launch {} as a solo task! Exiting...".format(name1)) | ||
194 | exit(1) | ||
195 | # Add this task to the appropriate cache partition (Class of Service in Intel CAT terms) | ||
196 | run("echo " + pid_str + " > /sys/fs/resctrl/level-ab-core-" + core + "/tasks") | ||
197 | addpid(pid_str) | ||
198 | else: | ||
199 | if suite1 == "TACLe": | ||
200 | binary1 = "./all_pairs/bin/" + name1 | ||
201 | binary2 = "./all_pairs/bin/" + name2 | ||
202 | elif suite1 == "SD-VBS": | ||
203 | binary1 = "./SD-VBS/" + name1 + "_all" | ||
204 | binary2 = "./SD-VBS/" + name2 + "_all" | ||
205 | elif suite1 == "DIS": | ||
206 | binary1 = "./dis/" + name1 + "_all" | ||
207 | binary2 = "./dis/" + name2 + "_all" | ||
143 | else: | 208 | else: |
144 | binary1 = dis_inputs[name1] + " | ./dis/" + name1 + "_all" + arg1 | 209 | print("Invalid suite name " + suite1 + " in Level-A/-B tasks! Exiting...") |
145 | binary2 = dis_inputs[name2] + " | ./dis/" + name2 + "_all" + arg2 | 210 | exit(1) |
146 | proc1 = subprocess.Popen(["sudo numactl --membind=0 " + binary1], shell = True) | ||
147 | proc2 = subprocess.Popen(["sudo numactl --membind=1 " + binary2], shell = True) | ||
148 | #print("sudo numactl --membind=0 " + binary1 + " &") | ||
149 | #print("sudo numactl --membind=1 " + binary2 + " &") | ||
150 | pid1 = proc2.pid + 1 | ||
151 | pid2 = proc2.pid + 3 | ||
152 | |||
153 | run("sudo echo " + str(pid1) + " > sudo /sys/fs/resctrl/level-ab-core-" + core + "/tasks") | ||
154 | run("sudo echo " + str(pid2) + " > sudo /sys/fs/resctrl/level-ab-core-" + core + "/tasks") | ||
155 | addpid(pid1) | ||
156 | addpid(pid2) | ||
157 | 211 | ||
212 | pairID += 1 # Used for sem/shm identification in the pair task | ||
213 | thread = str(int(core) + 16) # How Linux numbers SMT threads on the 3950X | ||
214 | lookupID1 = name1 + str(task1) | ||
215 | lookupID2 = name2 + str(task2) | ||
216 | if ID2PID(lookupID1) or ID2PID(lookupID2): | ||
217 | print("ERROR: Part of the pair containing task IDs {} and {} is already running! Did you end the previous case study?".format(lookupID1, lookupID2)) | ||
218 | exit(1) | ||
219 | # Arg format: <unique name> <infinite loops> <core> <0 other core> <NULL other name> <NULL runID> <no output> <pairID> <period> <crit lvl> | ||
220 | arg1 = " " + lookupID1 + " -1 " + core + " 0 NULL NULL 0 " + str(pairID) + " " + period1 + " " + criticality | ||
221 | arg2 = " " + lookupID2 + " -1 " + thread + " 0 NULL NULL 0 " + str(pairID) + " " + period2 + " " + criticality | ||
222 | bench_tsk1 = subprocess.Popen(input_cmd[name1] + "| numactl --membind=0 " + binary1 + arg1, shell = True) | ||
223 | bench_tsk2 = subprocess.Popen(input_cmd[name2] + "| numactl --membind=1 " + binary2 + arg2, shell = True) | ||
224 | # Find benchmark PID (avoid getting shell or numactl PID) | ||
225 | pid1_str = ID2PID(lookupID1) | ||
226 | pid2_str = ID2PID(lookupID2) | ||
227 | if not pid1_str or not pid2_str: | ||
228 | print("Unable to launch {} and {} in a pair! Exiting...".format(name1, name2)) | ||
229 | exit(1) | ||
230 | # Add this task to the appropriate cache partition (Class of Service in Intel CAT terms) | ||
231 | run("echo " + pid1_str + " > /sys/fs/resctrl/level-ab-core-" + core + "/tasks") | ||
232 | run("echo " + pid2_str + " > /sys/fs/resctrl/level-ab-core-" + core + "/tasks") | ||
233 | addpid(pid1_str) | ||
234 | addpid(pid2_str) | ||
235 | |||
236 | i = 0 | ||
237 | ### Dispatch all the Level-C tasks ### | ||
158 | for task in levelC: | 238 | for task in levelC: |
159 | continue | 239 | if i > 2: |
160 | i+=1 | ||
161 | if(i>8): | ||
162 | break | 240 | break |
163 | tid = int(task[0]) | 241 | i += 1 |
164 | name = all_tasks[tid][2] | ||
165 | period = all_tasks[tid][5] | ||
166 | suite = all_tasks[tid][1] | ||
167 | ccx = task[3] | ||
168 | threaded = task[4] == "t" | ||
169 | arg = "" | ||
170 | 242 | ||
171 | if(name == "rijndael_e"): | 243 | tid = int(task[T_ID]) |
172 | name = "rijndael_enc" | 244 | name = all_tasks[tid][A_BIN] |
173 | if(not threaded): | 245 | period = all_tasks[tid][A_PERIOD] |
174 | arg = " NULL -1 " + ccx + " NULL 0 " + period + " 2" | 246 | suite = all_tasks[tid][A_SUITE] |
175 | else: | 247 | ccx = task[T_CCX] |
176 | pairID += 1 | 248 | |
177 | arg = " NULL -1 " + ccx + " 0 NULL NULL 0 " + str(pairID) + " " + period + " 2" | 249 | if suite == "TACLe": |
178 | if(suite1 == "TACLe"): | 250 | binary = "./baseline/bin/" + name |
179 | binary = "./baseline/bin/" + name1 + arg | 251 | elif suite == "SD-VBS": |
252 | binary = "./SD-VBS/" + name | ||
253 | elif suite == "DIS": | ||
254 | binary = "./dis/" + name | ||
180 | else: | 255 | else: |
181 | binary = dis_inputs[name1] + " | ./dis/" + name1 + "_all" + arg | 256 | print("Invalid suite name " + suite + " in Level-A/-B tasks! Exiting...") |
257 | exit(1) | ||
258 | # XXX XXX XXX: FIXME when LITMUS is fixed | ||
259 | core = str(int(ccx)*4 + 1); | ||
182 | 260 | ||
183 | print(binary + " &") | 261 | lookupID = name + str(tid) |
184 | proc = subprocess.Popen([binary + " &"], shell = True) | 262 | if ID2PID(lookupID): |
185 | pid = proc.pid | 263 | print("ERROR: Task ID {} is already running! Did you end the previous case study?".format(lookupID)) |
186 | run("sudo echo " + str(pid) + " > sudo /sys/fs/resctrl/level-ab-ccx-" + ccx + "/tasks") | 264 | exit(1) |
265 | # Arg format: <unique name> <infinite loops> <core> <NULL runID> <no output> <period> <crit lvl> | ||
266 | arg = " " + lookupID + " -1 " + core + " NULL 0 " + period + " " + str(CRIT_LEVEL_C) | ||
267 | bench_tsk = subprocess.Popen(input_cmd[name] + " | numactl --interleave=all " + binary + arg, shell=True) | ||
268 | # Find benchmark PID (avoid getting shell or numactl PID) | ||
269 | pid_str = ID2PID(lookupID) | ||
270 | if not pid_str: | ||
271 | print("Unable to launch {} as a Level-C thread! Exiting...".format(name)) | ||
272 | exit(1) | ||
273 | # Add this task to the appropriate cache partition (Class of Service in Intel CAT terms) | ||
274 | run("echo " + pid_str + " > /sys/fs/resctrl/level-c-ccx-" + ccx + "/tasks") | ||
275 | addpid(pid_str) | ||
187 | #os.system("/playpen/mc2/liblitmus/release_ts") | 276 | #os.system("/playpen/mc2/liblitmus/release_ts") |
188 | #os.system("ls") | 277 | #os.system("ls") |
189 | time.sleep(3) | 278 | time.sleep(3) |
190 | 279 | ||
191 | if __name__ == "__main__": | 280 | if __name__ == "__main__": |
192 | main() | 281 | if len(sys.argv) < 2: |
282 | print("Usage: " + sys.argv[0] + " <task sets path>") | ||
283 | exit(1) | ||
284 | if os.geteuid() != 0: | ||
285 | print("You must run this script as root to enable cache isolation and access LITMUS-RT.") | ||
286 | exit(1) | ||
287 | pathName = sys.argv[1] | ||
288 | main(pathName) | ||
193 | 289 | ||
194 | 290 | ||