diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2012-10-23 15:07:27 -0400 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2012-10-23 15:07:27 -0400 |
commit | f1e90e1a5f7b148cf8113fe463615bd95d5bf26d (patch) | |
tree | 90c38ab2e6397c7a3129cb67238a3748520e9bd3 | |
parent | 6d830d55ccae53dca6f0338dfee1274312c93161 (diff) |
Added parsing for load / flush operations in MC.
-rw-r--r-- | parse/dir_map.py | 15 | ||||
-rw-r--r-- | parse/ft.py | 1 | ||||
-rw-r--r-- | parse/sched.py | 65 | ||||
-rw-r--r-- | parse/tuple_table.py | 24 | ||||
-rwxr-xr-x | parse_exps.py | 9 |
5 files changed, 65 insertions, 49 deletions
diff --git a/parse/dir_map.py b/parse/dir_map.py index 6e959f2..319a5de 100644 --- a/parse/dir_map.py +++ b/parse/dir_map.py | |||
@@ -15,7 +15,7 @@ class DirMap(object): | |||
15 | for key in sorted(vals.keys()): | 15 | for key in sorted(vals.keys()): |
16 | val_strs += ["%s=%s" % (key, vals[key])] | 16 | val_strs += ["%s=%s" % (key, vals[key])] |
17 | return "%s.csv" % ("_".join(val_strs)) | 17 | return "%s.csv" % ("_".join(val_strs)) |
18 | 18 | ||
19 | def __init__(self, out_dir): | 19 | def __init__(self, out_dir): |
20 | self.root = TreeNode(None) | 20 | self.root = TreeNode(None) |
21 | self.out_dir = out_dir | 21 | self.out_dir = out_dir |
@@ -49,8 +49,6 @@ class DirMap(object): | |||
49 | 49 | ||
50 | self.__update_node(path, keys, (vary_value, result)) | 50 | self.__update_node(path, keys, (vary_value, result)) |
51 | 51 | ||
52 | |||
53 | |||
54 | def reduce(self): | 52 | def reduce(self): |
55 | def reduce2(node): | 53 | def reduce2(node): |
56 | for key in node.children.keys(): | 54 | for key in node.children.keys(): |
@@ -64,7 +62,7 @@ class DirMap(object): | |||
64 | 62 | ||
65 | reduce2(self.root) | 63 | reduce2(self.root) |
66 | 64 | ||
67 | def write(self): | 65 | def write(self): |
68 | def write2(path, node): | 66 | def write2(path, node): |
69 | out_path = "/".join(path) | 67 | out_path = "/".join(path) |
70 | if node.values: | 68 | if node.values: |
@@ -73,7 +71,7 @@ class DirMap(object): | |||
73 | arr = [",".join([str(b) for b in n]) for n in node.values] | 71 | arr = [",".join([str(b) for b in n]) for n in node.values] |
74 | f.write("\n".join(arr) + "\n") | 72 | f.write("\n".join(arr) + "\n") |
75 | elif not os.path.isdir(out_path): | 73 | elif not os.path.isdir(out_path): |
76 | os.mkdir(out_path) | 74 | os.mkdir(out_path) |
77 | 75 | ||
78 | for (key, child) in node.children.iteritems(): | 76 | for (key, child) in node.children.iteritems(): |
79 | path.append(key) | 77 | path.append(key) |
@@ -94,11 +92,4 @@ class DirMap(object): | |||
94 | ret += "%s/%s\n" % (header, key) | 92 | ret += "%s/%s\n" % (header, key) |
95 | ret += str2(child, level + 1) | 93 | ret += str2(child, level + 1) |
96 | return ret | 94 | return ret |
97 | |||
98 | return "%s\n%s" % (self.out_dir, str2(self.root, 1)) | 95 | return "%s\n%s" % (self.out_dir, str2(self.root, 1)) |
99 | |||
100 | |||
101 | |||
102 | |||
103 | |||
104 | |||
diff --git a/parse/ft.py b/parse/ft.py index c915978..2c2b597 100644 --- a/parse/ft.py +++ b/parse/ft.py | |||
@@ -39,6 +39,7 @@ def get_ft_output(data_dir, out_dir, force=False): | |||
39 | bins = [f for f in bins if os.stat("%s/%s"%(out_dir, f)).st_size] | 39 | bins = [f for f in bins if os.stat("%s/%s"%(out_dir, f)).st_size] |
40 | 40 | ||
41 | # Analyze will summarize those | 41 | # Analyze will summarize those |
42 | # todo pass in f | ||
42 | cmd_arr = [conf.BINS['analyze']] | 43 | cmd_arr = [conf.BINS['analyze']] |
43 | cmd_arr.extend(bins) | 44 | cmd_arr.extend(bins) |
44 | with open(output_file, "w") as f: | 45 | with open(output_file, "w") as f: |
diff --git a/parse/sched.py b/parse/sched.py index a65f001..7dd80e0 100644 --- a/parse/sched.py +++ b/parse/sched.py | |||
@@ -13,7 +13,7 @@ from point import Measurement,Type | |||
13 | 13 | ||
14 | PARAM_RECORD = r"(?P<RECORD>" +\ | 14 | PARAM_RECORD = r"(?P<RECORD>" +\ |
15 | r"PARAM *?(?P<PID>\d+)\/.*?" +\ | 15 | r"PARAM *?(?P<PID>\d+)\/.*?" +\ |
16 | r"cost:\s+(?P<WCET>[\d\.]+)ms.*?" +\ | 16 | r"cost.*?(?P<WCET>[\d\.]+)ms.*?" +\ |
17 | r"period.*?(?P<PERIOD>[\d.]+)ms.*?" +\ | 17 | r"period.*?(?P<PERIOD>[\d.]+)ms.*?" +\ |
18 | r"part.*?(?P<CPU>\d+)[, ]*" +\ | 18 | r"part.*?(?P<CPU>\d+)[, ]*" +\ |
19 | r"(?:class=(?P<CLASS>\w+))?[, ]*" +\ | 19 | r"(?:class=(?P<CLASS>\w+))?[, ]*" +\ |
@@ -23,13 +23,15 @@ EXIT_RECORD = r"(?P<RECORD>" +\ | |||
23 | r"Avg.*?(?P<AVG>\d+).*?" +\ | 23 | r"Avg.*?(?P<AVG>\d+).*?" +\ |
24 | r"Max.*?(?P<MAX>\d+))" | 24 | r"Max.*?(?P<MAX>\d+))" |
25 | TARDY_RECORD = r"(?P<RECORD>" +\ | 25 | TARDY_RECORD = r"(?P<RECORD>" +\ |
26 | r"TARDY.*?(?P<PID>\d+)/(?P<JOB>\d+).*?" +\ | 26 | r"TASK_TARDY.*?(?P<PID>\d+)/(?P<JOB>\d+).*?" +\ |
27 | r"Tot.*?(?P<TOTAL>[\d\.]+).*?ms.*?" +\ | 27 | r"Tot.*?(?P<TOTAL>[\d\.]+).*?ms.*?" +\ |
28 | r"(?P<MAX>[\d\.]+).*?ms.*?" +\ | 28 | r"(?P<MAX>[\d\.]+).*?ms.*?" +\ |
29 | r"(?P<MISSES>[\d\.]+))" | 29 | r"(?P<MISSES>[\d\.]+))" |
30 | COMPLETION_RECORD = r"(?P<RECORD>" +\ | 30 | COMPLETION_RECORD = r"(?P<RECORD>" +\ |
31 | r"COMPLETION.*?(?P<PID>\d+)/.*?" +\ | 31 | r"COMPLETION.*?(?P<PID>\d+)/.*?" +\ |
32 | r"(?P<EXEC>[\d\.]+)ms)" | 32 | r"exec.*?(?P<EXEC>[\d\.]+)ms.*?" +\ |
33 | r"flush.*?(?P<FLUSH>[\d\.]+)ms.*?" +\ | ||
34 | r"load.*?(?P<LOAD>[\d\.]+)ms)" | ||
33 | 35 | ||
34 | TaskConfig = namedtuple('TaskConfig', ['cpu','wcet','period','type','level']) | 36 | TaskConfig = namedtuple('TaskConfig', ['cpu','wcet','period','type','level']) |
35 | Task = namedtuple('Task', ['pid', 'config']) | 37 | Task = namedtuple('Task', ['pid', 'config']) |
@@ -107,11 +109,9 @@ def get_task_exits(data): | |||
107 | m = Measurement( int(match.group('PID')), | 109 | m = Measurement( int(match.group('PID')), |
108 | {Type.Max : float(match.group('MAX')), | 110 | {Type.Max : float(match.group('MAX')), |
109 | Type.Avg : float(match.group('AVG'))}) | 111 | Type.Avg : float(match.group('AVG'))}) |
110 | for (type, value) in m: | ||
111 | if not value: raise Exception() | ||
112 | except: | 112 | except: |
113 | raise Exception("Invalid exit record, parsed:\n\t%s\n\t%s" % | 113 | raise Exception("Invalid exit record, parsed:\n\t%s\n\t%s" % |
114 | (match.groupdict(), m.group('RECORD'))) | 114 | (match.groupdict(), match.group('RECORD'))) |
115 | 115 | ||
116 | ret += [m] | 116 | ret += [m] |
117 | return ret | 117 | return ret |
@@ -137,7 +137,7 @@ def extract_tardy_vals(task_dict, data, exp_point): | |||
137 | 137 | ||
138 | if pid not in task_dict: | 138 | if pid not in task_dict: |
139 | raise Exception("Invalid pid '%d' in tardy record:\n\t%s" % | 139 | raise Exception("Invalid pid '%d' in tardy record:\n\t%s" % |
140 | match.group("RECORD")) | 140 | (pid, match.group("RECORD"))) |
141 | 141 | ||
142 | t = task_dict[pid] | 142 | t = task_dict[pid] |
143 | avg_tards.add(t, total_tard / (jobs * t.config.period)) | 143 | avg_tards.add(t, total_tard / (jobs * t.config.period)) |
@@ -148,8 +148,12 @@ def extract_tardy_vals(task_dict, data, exp_point): | |||
148 | avg_tards.write_measurements(exp_point) | 148 | avg_tards.write_measurements(exp_point) |
149 | max_tards.write_measurements(exp_point) | 149 | max_tards.write_measurements(exp_point) |
150 | 150 | ||
151 | # TODO: rename | ||
151 | def extract_variance(task_dict, data, exp_point): | 152 | def extract_variance(task_dict, data, exp_point): |
152 | varz = LeveledArray("exec-variance") | 153 | varz = LeveledArray("exec-variance") |
154 | flushes = LeveledArray("cache-flush") | ||
155 | loads = LeveledArray("cache-load") | ||
156 | |||
153 | completions = defaultdict(lambda: []) | 157 | completions = defaultdict(lambda: []) |
154 | missed = defaultdict(lambda: int()) | 158 | missed = defaultdict(lambda: int()) |
155 | 159 | ||
@@ -157,19 +161,31 @@ def extract_variance(task_dict, data, exp_point): | |||
157 | try: | 161 | try: |
158 | pid = int(match.group("PID")) | 162 | pid = int(match.group("PID")) |
159 | duration = float(match.group("EXEC")) | 163 | duration = float(match.group("EXEC")) |
164 | load = float(match.group("LOAD")) | ||
165 | flush = float(match.group("FLUSH")) | ||
166 | |||
167 | if load: | ||
168 | loads.add(task_dict[pid], load) | ||
169 | if flush: | ||
170 | flushes.add(task_dict[pid], flush) | ||
160 | 171 | ||
161 | # Last (exit) record often has exec time of 0 | 172 | # Last (exit) record often has exec time of 0 |
162 | missed[pid] += not bool(duration) | 173 | missed[pid] += not bool(duration) |
163 | 174 | ||
164 | if missed[pid] > 1 or not pid: raise Exception() | 175 | if missed[pid] > 1 or not pid: #TODO: fix, raise Exception() |
176 | continue | ||
165 | except: | 177 | except: |
166 | raise Exception("Invalid completion record, missed - %d:" | 178 | raise Exception("Invalid completion record, missed: %d:" |
167 | "\n\t%s\n\t%s" % (missed[pid], match.groupdict(), | 179 | "\n\t%s\n\t%s" % (missed[pid], match.groupdict(), |
168 | match.group("RECORD"))) | 180 | match.group("RECORD"))) |
169 | completions[pid] += [duration] | 181 | completions[pid] += [duration] |
170 | 182 | ||
171 | for pid, durations in completions.iteritems(): | 183 | for pid, durations in completions.iteritems(): |
172 | job_times = np.array(durations) | 184 | job_times = np.array(durations) |
185 | mean = job_times.mean() | ||
186 | |||
187 | if not mean or not durations: | ||
188 | continue | ||
173 | 189 | ||
174 | # Coefficient of variation | 190 | # Coefficient of variation |
175 | cv = job_times.std() / job_times.mean() | 191 | cv = job_times.std() / job_times.mean() |
@@ -179,11 +195,10 @@ def extract_variance(task_dict, data, exp_point): | |||
179 | varz.add(task_dict[pid], corrected) | 195 | varz.add(task_dict[pid], corrected) |
180 | 196 | ||
181 | varz.write_measurements(exp_point) | 197 | varz.write_measurements(exp_point) |
198 | flushes.write_measurements(exp_point) | ||
199 | loads.write_measurements(exp_point) | ||
182 | 200 | ||
183 | def config_exit_stats(task_dict, file): | 201 | def config_exit_stats(task_dict, data): |
184 | with open(file, 'r') as f: | ||
185 | data = f.read() | ||
186 | |||
187 | # Dictionary of task exit measurements by pid | 202 | # Dictionary of task exit measurements by pid |
188 | exits = get_task_exits(data) | 203 | exits = get_task_exits(data) |
189 | exit_dict = dict((e.id, e) for e in exits) | 204 | exit_dict = dict((e.id, e) for e in exits) |
@@ -200,7 +215,7 @@ def config_exit_stats(task_dict, file): | |||
200 | # Replace tasks with corresponding exit stats | 215 | # Replace tasks with corresponding exit stats |
201 | if not t.pid in exit_dict: | 216 | if not t.pid in exit_dict: |
202 | raise Exception("Missing exit record for task '%s' in '%s'" % | 217 | raise Exception("Missing exit record for task '%s' in '%s'" % |
203 | (t, file)) | 218 | (t, file.name)) |
204 | exit_list = [exit_dict[t.pid] for t in task_list] | 219 | exit_list = [exit_dict[t.pid] for t in task_list] |
205 | config_dict[config] = exit_list | 220 | config_dict[config] = exit_list |
206 | 221 | ||
@@ -212,13 +227,14 @@ def get_base_stats(base_file): | |||
212 | return saved_stats[base_file] | 227 | return saved_stats[base_file] |
213 | with open(base_file, 'r') as f: | 228 | with open(base_file, 'r') as f: |
214 | data = f.read() | 229 | data = f.read() |
215 | result = config_exit_stats(data) | 230 | task_dict = get_task_dict(data) |
231 | result = config_exit_stats(task_dict, data) | ||
216 | saved_stats[base_file] = result | 232 | saved_stats[base_file] = result |
217 | return result | 233 | return result |
218 | 234 | ||
219 | def extract_scaling_data(task_dict, data, result, base_file): | 235 | def extract_scaling_data(task_dict, data, result, base_file): |
220 | # Generate trees of tasks with matching configurations | 236 | # Generate trees of tasks with matching configurations |
221 | data_stats = config_exit_stats(data) | 237 | data_stats = config_exit_stats(task_dict, data) |
222 | base_stats = get_base_stats(base_file) | 238 | base_stats = get_base_stats(base_file) |
223 | 239 | ||
224 | # Scaling factors are calculated by matching groups of tasks with the same | 240 | # Scaling factors are calculated by matching groups of tasks with the same |
@@ -233,9 +249,12 @@ def extract_scaling_data(task_dict, data, result, base_file): | |||
233 | # a task-to-task comparison | 249 | # a task-to-task comparison |
234 | continue | 250 | continue |
235 | for data_stat, base_stat in zip(data_stats[config],base_stats[config]): | 251 | for data_stat, base_stat in zip(data_stats[config],base_stats[config]): |
252 | if not base_stat[Type.Avg] or not base_stat[Type.Max] or \ | ||
253 | not data_stat[Type.Avg] or not data_stat[Type.Max]: | ||
254 | continue | ||
236 | # How much larger is their exec stat than ours? | 255 | # How much larger is their exec stat than ours? |
237 | avg_scale = float(base_stat[Type.Avg]) / float(base_stat[Type.Avg]) | 256 | avg_scale = float(base_stat[Type.Avg]) / float(data_stat[Type.Avg]) |
238 | max_scale = float(base_stat[Type.Max]) / float(base_stat[Type.Max]) | 257 | max_scale = float(base_stat[Type.Max]) / float(data_stat[Type.Max]) |
239 | 258 | ||
240 | task = task_dict[data_stat.id] | 259 | task = task_dict[data_stat.id] |
241 | 260 | ||
@@ -251,8 +270,12 @@ def extract_sched_data(data_file, result, base_file): | |||
251 | 270 | ||
252 | task_dict = get_task_dict(data) | 271 | task_dict = get_task_dict(data) |
253 | 272 | ||
254 | extract_tardy_vals(task_dict, data, result) | 273 | try: |
255 | extract_variance(task_dict, data, result) | 274 | extract_tardy_vals(task_dict, data, result) |
275 | extract_variance(task_dict, data, result) | ||
276 | except Exception as e: | ||
277 | print("Error in %s" % data_file) | ||
278 | raise e | ||
256 | 279 | ||
257 | if (base_file): | 280 | if (base_file): |
258 | extract_scaling_data(task_dict, data, result, base_file) | 281 | extract_scaling_data(task_dict, data, result, base_file) |
diff --git a/parse/tuple_table.py b/parse/tuple_table.py index 5e98d87..cb5a72a 100644 --- a/parse/tuple_table.py +++ b/parse/tuple_table.py | |||
@@ -5,6 +5,7 @@ from dir_map import DirMap | |||
5 | class ColMap(object): | 5 | class ColMap(object): |
6 | def __init__(self): | 6 | def __init__(self): |
7 | self.rev_map = {} | 7 | self.rev_map = {} |
8 | self.value_map = {} | ||
8 | self.col_list = [] | 9 | self.col_list = [] |
9 | 10 | ||
10 | def columns(self): | 11 | def columns(self): |
@@ -12,19 +13,13 @@ class ColMap(object): | |||
12 | 13 | ||
13 | def get_key(self, kv): | 14 | def get_key(self, kv): |
14 | key = () | 15 | key = () |
15 | added = 0 | ||
16 | 16 | ||
17 | for col in self.col_list: | 17 | for col in self.col_list: |
18 | if col not in kv: | 18 | if col not in kv: |
19 | key += (None,) | 19 | key += (None,) |
20 | else: | 20 | else: |
21 | added += 1 | ||
22 | key += (kv[col],) | 21 | key += (kv[col],) |
23 | 22 | ||
24 | if added < len(kv): | ||
25 | raise Exception("column map '%s' missed field in map '%s'" % | ||
26 | (self.col_list, kv)) | ||
27 | |||
28 | return key | 23 | return key |
29 | 24 | ||
30 | def __contains__(self, col): | 25 | def __contains__(self, col): |
@@ -36,10 +31,13 @@ class ColMap(object): | |||
36 | map[self.col_list[i]] = tuple[i] | 31 | map[self.col_list[i]] = tuple[i] |
37 | return map | 32 | return map |
38 | 33 | ||
39 | def try_add(self, column): | 34 | def try_add(self, column, value): |
40 | if column not in self.rev_map: | 35 | if column not in self.rev_map: |
41 | self.rev_map[column] = len(self.col_list) | 36 | if column not in self.value_map: |
42 | self.col_list += [column] | 37 | self.value_map[column] = value |
38 | elif value != self.value_map[column]: | ||
39 | self.rev_map[column] = len(self.col_list) | ||
40 | self.col_list += [column] | ||
43 | 41 | ||
44 | def __str__(self): | 42 | def __str__(self): |
45 | return "<ColMap>%s" % (self.rev_map) | 43 | return "<ColMap>%s" % (self.rev_map) |
@@ -67,6 +65,7 @@ class TupleTable(object): | |||
67 | 65 | ||
68 | def write_result(self, out_dir): | 66 | def write_result(self, out_dir): |
69 | dir_map = DirMap(out_dir) | 67 | dir_map = DirMap(out_dir) |
68 | |||
70 | for key, point in self.table.iteritems(): | 69 | for key, point in self.table.iteritems(): |
71 | kv = self.col_map.get_map(key) | 70 | kv = self.col_map.get_map(key) |
72 | 71 | ||
@@ -75,12 +74,13 @@ class TupleTable(object): | |||
75 | 74 | ||
76 | try: | 75 | try: |
77 | float(val) | 76 | float(val) |
78 | kv.pop(col) | ||
79 | dir_map.add_point(col, val, kv, point) | ||
80 | kv[col] = val | ||
81 | except: | 77 | except: |
82 | # Only vary numbers. Otherwise, just have seperate lines | 78 | # Only vary numbers. Otherwise, just have seperate lines |
83 | continue | 79 | continue |
84 | 80 | ||
81 | kv.pop(col) | ||
82 | dir_map.add_point(col, val, kv, point) | ||
83 | kv[col] = val | ||
84 | |||
85 | dir_map.reduce() | 85 | dir_map.reduce() |
86 | dir_map.write() | 86 | dir_map.write() |
diff --git a/parse_exps.py b/parse_exps.py index 1f36bab..aa203d3 100755 --- a/parse_exps.py +++ b/parse_exps.py | |||
@@ -20,6 +20,7 @@ def parse_args(): | |||
20 | 20 | ||
21 | parser.add_option('-o', '--out-dir', dest='out_dir', | 21 | parser.add_option('-o', '--out-dir', dest='out_dir', |
22 | help='directory for data output', default='parse-data') | 22 | help='directory for data output', default='parse-data') |
23 | # TODO: this means nothing | ||
23 | parser.add_option('-c', '--clean', action='store_true', default=False, | 24 | parser.add_option('-c', '--clean', action='store_true', default=False, |
24 | dest='clean', help='do not output single-point csvs') | 25 | dest='clean', help='do not output single-point csvs') |
25 | parser.add_option('-s', '--scale-against', dest='scale_against', | 26 | parser.add_option('-s', '--scale-against', dest='scale_against', |
@@ -47,8 +48,8 @@ def get_exp_params(data_dir, col_map): | |||
47 | params.pop(ignored) | 48 | params.pop(ignored) |
48 | 49 | ||
49 | # Track all changed params | 50 | # Track all changed params |
50 | for key in params.keys(): | 51 | for key, value in params.iteritems(): |
51 | col_map.try_add(key) | 52 | col_map.try_add(key, value) |
52 | 53 | ||
53 | return params | 54 | return params |
54 | 55 | ||
@@ -122,6 +123,7 @@ def main(): | |||
122 | base_params = copy.deepcopy(exp.params) | 123 | base_params = copy.deepcopy(exp.params) |
123 | base_params.pop(base_conf.keys()[0]) | 124 | base_params.pop(base_conf.keys()[0]) |
124 | base = base_table.get_exps(base_params)[0] | 125 | base = base_table.get_exps(base_params)[0] |
126 | |||
125 | # Write deadline misses / tardiness into result | 127 | # Write deadline misses / tardiness into result |
126 | st.extract_sched_data(exp.data_files.st, result, | 128 | st.extract_sched_data(exp.data_files.st, result, |
127 | base.data_files.st if base else None) | 129 | base.data_files.st if base else None) |
@@ -135,8 +137,7 @@ def main(): | |||
135 | sh.rmtree(opts.out_dir) | 137 | sh.rmtree(opts.out_dir) |
136 | 138 | ||
137 | # Remove un-plottable values | 139 | # Remove un-plottable values |
138 | if opts.clean: | 140 | result_table.reduce() |
139 | result_table.reduce() | ||
140 | 141 | ||
141 | result_table.write_result(opts.out_dir) | 142 | result_table.write_result(opts.out_dir) |
142 | 143 | ||