aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--experiment/experiment.py3
-rw-r--r--experiment/litmus_util.py13
-rw-r--r--parse/ft.py132
-rwxr-xr-xparse_exps.py9
-rwxr-xr-xrun_exps.py6
5 files changed, 125 insertions, 38 deletions
diff --git a/experiment/experiment.py b/experiment/experiment.py
index 8c88799..deb4ff2 100644
--- a/experiment/experiment.py
+++ b/experiment/experiment.py
@@ -178,7 +178,8 @@ class Experiment(object):
178 self.log("Writing %d proc entries" % len(self.proc_entries)) 178 self.log("Writing %d proc entries" % len(self.proc_entries))
179 map(methodcaller('write_proc'), self.proc_entries) 179 map(methodcaller('write_proc'), self.proc_entries)
180 180
181 time.sleep(5) 181 if len(self.proc_entries):
182 time.sleep(2)
182 183
183 self.log("Switching to %s" % self.scheduler) 184 self.log("Switching to %s" % self.scheduler)
184 litmus_util.switch_scheduler(self.scheduler) 185 litmus_util.switch_scheduler(self.scheduler)
diff --git a/experiment/litmus_util.py b/experiment/litmus_util.py
index cde0bca..42d3e5f 100644
--- a/experiment/litmus_util.py
+++ b/experiment/litmus_util.py
@@ -17,6 +17,19 @@ def num_cpus():
17 cpus += 1 17 cpus += 1
18 return cpus 18 return cpus
19 19
20def cpu_freq():
21 """
22 The frequency (in MHz) of the CPU.
23 """
24 reg = re.compile(r'^cpu MHz\s*:\s*(\d+)', re.M)
25 with open('/proc/cpuinfo', 'r') as f:
26 data = f.read()
27
28 match = re.search(reg, data)
29 if not match:
30 raise Exception("Cannot parse CPU frequency!")
31 return int(match.group(1))
32
20def switch_scheduler(switch_to_in): 33def switch_scheduler(switch_to_in):
21 """Switch the scheduler to whatever is passed in. 34 """Switch the scheduler to whatever is passed in.
22 35
diff --git a/parse/ft.py b/parse/ft.py
index 4e310b0..cbf75f2 100644
--- a/parse/ft.py
+++ b/parse/ft.py
@@ -1,4 +1,5 @@
1import config.config as conf 1import config.config as conf
2import numpy as np
2import os 3import os
3import re 4import re
4import shutil as sh 5import shutil as sh
@@ -6,14 +7,17 @@ import subprocess
6 7
7from point import Measurement,Type 8from point import Measurement,Type
8 9
9def get_ft_output(data_dir, out_dir, force=False): 10SPLIT_DATA_NAME = "overhead={}.bin"
11FT_DATA_NAME = "sorted-ft.bin"
12FIELDS = ["Overhead", "samples", "max", "avg", "min", "med", "std", "var"]
13
14def get_ft_output(data_dir, cycles, out_dir, force=False):
10 """ 15 """
11 Create and return files containing sorted and analyzed overhead data 16 Create and return file containing analyzed overhead data
12 """ 17 """
13 bin_file = conf.FILES['ft_data'] + "$" 18 freg = conf.FILES['ft_data'] + "$"
14 bins = [f for f in os.listdir(data_dir) if re.match(bin_file, f)] 19 bins = [f for f in os.listdir(data_dir) if re.match(freg, f)]
15 20
16 FT_DATA_NAME = "scheduler=x-ft"
17 output_file = "{}/out-ft".format(out_dir) 21 output_file = "{}/out-ft".format(out_dir)
18 22
19 if os.path.isfile(output_file): 23 if os.path.isfile(output_file):
@@ -23,44 +27,106 @@ def get_ft_output(data_dir, out_dir, force=False):
23 return output_file 27 return output_file
24 28
25 if len(bins) != 0: 29 if len(bins) != 0:
30 bin_file = "{}/{}".format(data_dir, bins[0])
26 err_file = open("%s/err-ft" % out_dir, 'w') 31 err_file = open("%s/err-ft" % out_dir, 'w')
27 # Need to make a copy of the original data file so scripts can change it 32
28 sh.copyfile("{}/{}".format(data_dir, bins[0]), 33 sorted_bin = sort_ft(bin_file, err_file, out_dir)
29 "{}/{}".format(out_dir, FT_DATA_NAME)) 34 make_data_file(sorted_bin, cycles, output_file, err_file, out_dir)
30 35
31 subprocess.call([conf.BINS['sort'], FT_DATA_NAME], 36 os.remove(sorted_bin)
32 cwd=out_dir, stderr=err_file, stdout=err_file) 37
33 subprocess.call([conf.BINS['split'], FT_DATA_NAME], 38 return output_file
34 cwd=out_dir, stderr=err_file, stdout=err_file)
35
36 # Previous subprocesses just spit out all these intermediate files
37 bins = [f for f in os.listdir(out_dir) if re.match(".*overhead=.*bin", f)]
38 bins = [f for f in bins if os.stat("%s/%s"%(out_dir, f)).st_size]
39
40 # Analyze will summarize those
41 # todo pass in f
42 cmd_arr = [conf.BINS['analyze']]
43 cmd_arr.extend(bins)
44 with open(output_file, "w") as f:
45 subprocess.call(cmd_arr, cwd=out_dir, stdout=f, stderr=err_file)
46 else: 39 else:
47 return None 40 return None
48 return output_file 41 return output_file
49 42
50def extract_ft_data(data_file, result, overheads): 43def fmt_cell(x):
51 rstr = r",(?:\s+[^\s]+){3}.*?([\d\.]+).*?([\d\.]+),(?:\s+[^\s]+){3}.*?([\d\.]+)" 44 if type(x) == str:
45 return "%15s" % x
46 if type(x) == int:
47 return "%15d" % x
48 else:
49 return "%15.3f" % x
50
51def make_data_file(sorted_bin, cycles, out_fname, err_file, out_dir):
52 """
53 Create file containing all overhead information.
54 """
55 base_name = "{}/{}".format(out_dir, SPLIT_DATA_NAME)
56
57 with open(out_fname, "w") as f:
58 f.write("#%s" % ", ".join(fmt_cell(x) for x in FIELDS))
59 f.write("\n")
60
61 for event in conf.BASE_EVENTS:
62 ovh_fname = base_name.format(event.replace("_", "-"))
63
64 if os.path.exists(ovh_fname):
65 os.remove(ovh_fname)
66 ovh_file = open(ovh_fname, 'w')
67
68 # Extract matching overhead events into a seperate file
69 cmd = [conf.BINS["split"], "-r", "-b", event, sorted_bin]
70 ret = subprocess.call(cmd, cwd=out_dir,
71 stderr=err_file, stdout=ovh_file)
72 size = os.stat(ovh_fname).st_size
73
74 if ret:
75 err_file.write("Failed with command: %s" % " ".join(cmd))
76 if not size:
77 os.remove(ovh_fname)
78 if not size or ret:
79 continue
80
81 # Map and sort file for stats
82 data = np.memmap(ovh_fname, dtype="float32", mode='c')
83 data /= float(cycles) # Scale for processor speed
84 data.sort()
52 85
86 stats = [event, len(data), data[-1], np.mean(data), data[0],
87 np.median(data), np.std(data, ddof=1), np.var(data)]
88 f.write(", ".join([fmt_cell(x) for x in stats]))
89 f.write("\n")
90
91 os.remove(ovh_fname)
92
93def sort_ft(ft_file, err_file, out_dir):
94 """
95 Create and return file with sorted overheads from @ft_file.
96 """
97 out_fname = "{}/{}".format(out_dir, FT_DATA_NAME)
98
99 # Sort happens in-place
100 sh.copyfile(ft_file, out_fname)
101 cmd = [conf.BINS['ftsort'], out_fname]
102 ret = subprocess.call(cmd, cwd=out_dir, stderr=err_file, stdout=err_file)
103
104 if ret:
105 raise Exception("Sort failed with command: %s" % " ".join(cmd))
106
107 return out_fname
108
109def extract_ft_data(data_file, result, overheads):
110 """
111 Return exp point with overhead measurements from data_file
112 """
53 with open(data_file) as f: 113 with open(data_file) as f:
54 data = f.read() 114 data = f.read()
55 115
56 for ovh in overheads: 116 for ovh in overheads:
117 regex = r"({}[^\n]*)".format(ovh)
118 line = re.search(regex, data)
119
120 if not line:
121 continue
122
123 vals = re.split(r"[,\s]+", line.groups(1)[0])
124
57 measure = Measurement("%s-%s" % (data_file, ovh)) 125 measure = Measurement("%s-%s" % (data_file, ovh))
58 vals = re.findall(r"\s+{}".format(ovh.replace('_','-')) + rstr, data); 126 measure[Type.Max] = float(vals[FIELDS.index("max")])
59 if len(vals) != 0: 127 measure[Type.Avg] = float(vals[FIELDS.index("avg")])
60 vals = vals[0] 128 measure[Type.Var] = float(vals[FIELDS.index("var")])
61 measure[Type.Max] = float(vals[0]) 129
62 measure[Type.Avg] = float(vals[1]) 130 result[ovh] = measure
63 measure[Type.Var] = float(vals[2])
64 result[ovh] = measure
65 131
66 return result 132 return result
diff --git a/parse_exps.py b/parse_exps.py
index 87d0783..24bdb85 100755
--- a/parse_exps.py
+++ b/parse_exps.py
@@ -52,13 +52,17 @@ def get_exp_params(data_dir, col_map):
52 # Keep only params that uniquely identify the experiment 52 # Keep only params that uniquely identify the experiment
53 params = load_params(param_file) 53 params = load_params(param_file)
54 for ignored in conf.PARAMS.itervalues(): 54 for ignored in conf.PARAMS.itervalues():
55 if ignored in params: 55 # Always include cycles or overhead parsing fails
56 if ignored in params and ignored != conf.PARAMS['cycles']:
56 params.pop(ignored) 57 params.pop(ignored)
57 58
58 # Track all changed params 59 # Track all changed params
59 for key, value in params.iteritems(): 60 for key, value in params.iteritems():
60 col_map.try_add(key, value) 61 col_map.try_add(key, value)
61 62
63 if conf.PARAMS['cycles'] not in params:
64 params[conf.PARAMS['cycles']] = conf.DEFAULTS['cycles']
65
62 return params 66 return params
63 67
64 68
@@ -78,8 +82,9 @@ def gen_exp_data(exp_dirs, base_conf, col_map, force):
78 82
79 # Read and translate exp output files 83 # Read and translate exp output files
80 params = get_exp_params(data_dir, col_map) 84 params = get_exp_params(data_dir, col_map)
85 cycles = int(params[conf.PARAMS['cycles']])
81 st_output = st.get_st_output(data_dir, tmp_dir, force) 86 st_output = st.get_st_output(data_dir, tmp_dir, force)
82 ft_output = ft.get_ft_output(data_dir, tmp_dir, force) 87 ft_output = ft.get_ft_output(data_dir, cycles, tmp_dir, force)
83 88
84 89
85 if base_conf and base_conf.viewitems() & params.viewitems(): 90 if base_conf and base_conf.viewitems() & params.viewitems():
diff --git a/run_exps.py b/run_exps.py
index 8812bc6..3efb09d 100755
--- a/run_exps.py
+++ b/run_exps.py
@@ -114,9 +114,11 @@ def load_experiment(sched_file, scheduler, duration, param_file, out_dir):
114 run_exp(sched_file, schedule, scheduler, kernel, duration, work_dir, out_dir) 114 run_exp(sched_file, schedule, scheduler, kernel, duration, work_dir, out_dir)
115 115
116 # Save parameters used to run experiment in out_dir 116 # Save parameters used to run experiment in out_dir
117 # Cycles is saved here for accurate overhead calculations later
117 out_params = dict(params.items() + 118 out_params = dict(params.items() +
118 [(conf.PARAMS['sched'], scheduler), 119 [(conf.PARAMS['sched'], scheduler),
119 (conf.PARAMS['dur'], duration)]) 120 (conf.PARAMS['dur'], duration),
121 (conf.PARAMS['cycles'], lu.cpu_freq())])
120 with open("%s/%s" % (out_dir, conf.DEFAULTS['params_file']), 'w') as f: 122 with open("%s/%s" % (out_dir, conf.DEFAULTS['params_file']), 'w') as f:
121 f.write(str(out_params)) 123 f.write(str(out_params))
122 124