diff options
Diffstat (limited to 'parse')
-rw-r--r-- | parse/ft.py | 2 | ||||
-rw-r--r-- | parse/sched.py | 125 | ||||
-rw-r--r-- | parse/tuple_table.py | 8 |
3 files changed, 81 insertions, 54 deletions
diff --git a/parse/ft.py b/parse/ft.py index 20a430e..127e49f 100644 --- a/parse/ft.py +++ b/parse/ft.py | |||
@@ -12,7 +12,7 @@ def get_ft_output(data_dir, out_dir): | |||
12 | 12 | ||
13 | FT_DATA_NAME = "scheduler=x-ft" | 13 | FT_DATA_NAME = "scheduler=x-ft" |
14 | output_file = "{}/out-ft".format(out_dir) | 14 | output_file = "{}/out-ft".format(out_dir) |
15 | 15 | ||
16 | if os.path.isfile(output_file): | 16 | if os.path.isfile(output_file): |
17 | print("ft-output already exists for %s" % data_dir) | 17 | print("ft-output already exists for %s" % data_dir) |
18 | return output_file | 18 | return output_file |
diff --git a/parse/sched.py b/parse/sched.py index b84e16e..300c569 100644 --- a/parse/sched.py +++ b/parse/sched.py | |||
@@ -34,7 +34,26 @@ COMPLETION_RECORD = r"(?P<RECORD>" +\ | |||
34 | TaskConfig = namedtuple('TaskConfig', ['cpu','wcet','period','type','level']) | 34 | TaskConfig = namedtuple('TaskConfig', ['cpu','wcet','period','type','level']) |
35 | Task = namedtuple('Task', ['pid', 'config']) | 35 | Task = namedtuple('Task', ['pid', 'config']) |
36 | 36 | ||
37 | class LeveledArray(object): | ||
38 | """ | ||
39 | Groups statistics by the level of the task to which they apply | ||
40 | """ | ||
41 | def __init__(self, name): | ||
42 | self.name = name | ||
43 | self.vals = defaultdict(lambda:[]) | ||
44 | |||
45 | def add(self, task, value): | ||
46 | self.vals[task.config.level] += [value] | ||
47 | |||
48 | def write_measurements(self, result): | ||
49 | for level, arr in self.vals.iteritems(): | ||
50 | name = "%s%s" % ("%s-" % level if level else "", self.name) | ||
51 | result[name] = Measurement(name).from_array(arr) | ||
52 | |||
37 | def get_st_output(data_dir, out_dir): | 53 | def get_st_output(data_dir, out_dir): |
54 | """ | ||
55 | Create and return files containing unpacked sched data | ||
56 | """ | ||
38 | bin_files = conf.FILES['sched_data'].format(".*") | 57 | bin_files = conf.FILES['sched_data'].format(".*") |
39 | bins = [f for f in os.listdir(data_dir) if re.match(bin_files, f)] | 58 | bins = [f for f in os.listdir(data_dir) if re.match(bin_files, f)] |
40 | 59 | ||
@@ -70,7 +89,7 @@ def get_tasks(data): | |||
70 | (e, match.groupdict(), match.group('RECORD'))) | 89 | (e, match.groupdict(), match.group('RECORD'))) |
71 | return ret | 90 | return ret |
72 | 91 | ||
73 | def get_tasks_dict(data): | 92 | def get_task_dict(data): |
74 | tasks_list = get_tasks(data) | 93 | tasks_list = get_tasks(data) |
75 | tasks_dict = {} | 94 | tasks_dict = {} |
76 | for t in tasks_list: | 95 | for t in tasks_list: |
@@ -89,17 +108,15 @@ def get_task_exits(data): | |||
89 | except: | 108 | except: |
90 | raise Exception("Invalid exit record, parsed:\n\t%s\n\t%s" % | 109 | raise Exception("Invalid exit record, parsed:\n\t%s\n\t%s" % |
91 | (match.groupdict(), m.group('RECORD'))) | 110 | (match.groupdict(), m.group('RECORD'))) |
92 | 111 | ||
93 | ret += [m] | 112 | ret += [m] |
94 | return ret | 113 | return ret |
95 | |||
96 | 114 | ||
97 | def extract_tardy_vals(data, exp_point): | ||
98 | ratios = [] | ||
99 | avg_tards = [] | ||
100 | max_tards = [] | ||
101 | 115 | ||
102 | tasks = get_tasks_dict(data) | 116 | def extract_tardy_vals(task_dict, data, exp_point): |
117 | ratios = LeveledArray("miss-ratio") | ||
118 | avg_tards = LeveledArray("avg-rel-tardiness") | ||
119 | max_tards = LeveledArray("max-rel-tardiness") | ||
103 | 120 | ||
104 | for match in re.finditer(TARDY_RECORD, data): | 121 | for match in re.finditer(TARDY_RECORD, data): |
105 | try: | 122 | try: |
@@ -114,35 +131,40 @@ def extract_tardy_vals(data, exp_point): | |||
114 | raise Exception("Invalid tardy record:\n\t%s\n\t%s" % | 131 | raise Exception("Invalid tardy record:\n\t%s\n\t%s" % |
115 | (match.groupdict(), match.group("RECORD"))) | 132 | (match.groupdict(), match.group("RECORD"))) |
116 | 133 | ||
117 | if pid not in tasks: | 134 | if pid not in task_dict: |
118 | raise Exception("Invalid pid '%d' in tardy record:\n\t%s" % | 135 | raise Exception("Invalid pid '%d' in tardy record:\n\t%s" % |
119 | match.group("RECORD")) | 136 | match.group("RECORD")) |
120 | 137 | ||
121 | t = tasks[pid] | 138 | t = task_dict[pid] |
122 | avg_tards += [ total_tard / (jobs * t.config.period) ] | 139 | avg_tards.add(t, total_tard / (jobs * t.config.period)) |
123 | max_tards += [ max_tard / t.config.period ] | 140 | max_tards.add(t, max_tard / t.config.period) |
124 | ratios += [ misses / jobs ] | 141 | ratios.add(t, misses / jobs) |
125 | 142 | ||
126 | exp_point["avg-rel-tard"] = Measurement().from_array(avg_tards) | 143 | ratios.write_measurements(exp_point) |
127 | exp_point["max-rel-tard"] = Measurement().from_array(max_tards) | 144 | avg_tards.write_measurements(exp_point) |
128 | exp_point["miss-ratio"] = Measurement().from_array(ratios) | 145 | max_tards.write_measurements(exp_point) |
129 | 146 | ||
130 | def extract_variance(data, exp_point): | 147 | def extract_variance(task_dict, data, exp_point): |
131 | varz = [] | 148 | varz = LeveledArray("exec-variance") |
132 | completions = defaultdict(lambda: []) | 149 | completions = defaultdict(lambda: []) |
150 | missed = defaultdict(lambda: int()) | ||
133 | 151 | ||
134 | for match in re.finditer(COMPLETION_RECORD, data): | 152 | for match in re.finditer(COMPLETION_RECORD, data): |
135 | try: | 153 | try: |
136 | pid = int(match.group("PID")) | 154 | pid = int(match.group("PID")) |
137 | duration = float(match.group("EXEC")) | 155 | duration = float(match.group("EXEC")) |
138 | 156 | ||
139 | if not (duration and pid): raise Exception() | 157 | # Last (exit) record often has exec time of 0 |
158 | missed[pid] += not bool(duration) | ||
159 | |||
160 | if missed[pid] > 1 or not pid: raise Exception() | ||
140 | except: | 161 | except: |
141 | raise Exception("Invalid completion record:\n\t%s\n\t%s" % | 162 | raise Exception("Invalid completion record, missed - %d:" |
142 | (match.groupdict(), match.group("RECORD"))) | 163 | "\n\t%s\n\t%s" % (missed[pid], match.groupdict(), |
164 | match.group("RECORD"))) | ||
143 | completions[pid] += [duration] | 165 | completions[pid] += [duration] |
144 | 166 | ||
145 | for (pid, durations) in completions: | 167 | for pid, durations in completions.iteritems(): |
146 | job_times = np.array(durations) | 168 | job_times = np.array(durations) |
147 | 169 | ||
148 | # Coefficient of variation | 170 | # Coefficient of variation |
@@ -150,32 +172,22 @@ def extract_variance(data, exp_point): | |||
150 | # Correction, assuming normal distributions | 172 | # Correction, assuming normal distributions |
151 | corrected = (1 + 1/(4 * len(job_times))) * cv | 173 | corrected = (1 + 1/(4 * len(job_times))) * cv |
152 | 174 | ||
153 | varz.append(corrected) | 175 | varz.add(task_dict[pid], corrected) |
154 | |||
155 | exp_point['exec-var'] = Measurement().from_array(varz) | ||
156 | |||
157 | def extract_sched_data(data_file, result): | ||
158 | with open(data_file, 'r') as f: | ||
159 | data = f.read() | ||
160 | 176 | ||
161 | extract_tardy_vals(data, result) | 177 | varz.write_measurements(exp_point) |
162 | extract_variance(data, result) | ||
163 | 178 | ||
164 | def config_exit_stats(file): | 179 | def config_exit_stats(task_dict, file): |
165 | with open(file, 'r') as f: | 180 | with open(file, 'r') as f: |
166 | data = f.read() | 181 | data = f.read() |
167 | |||
168 | tasks = get_tasks(data) | ||
169 | 182 | ||
170 | # Dictionary of task exit measurements by pid | 183 | # Dictionary of task exit measurements by pid |
171 | exits = get_task_exits(data) | 184 | exits = get_task_exits(data) |
172 | |||
173 | exit_dict = dict((e.id, e) for e in exits) | 185 | exit_dict = dict((e.id, e) for e in exits) |
174 | 186 | ||
175 | # Dictionary where keys are configurations, values are list | 187 | # Dictionary where keys are configurations, values are list |
176 | # of tasks with those configuratino | 188 | # of tasks with those configuratino |
177 | config_dict = defaultdict(lambda: []) | 189 | config_dict = defaultdict(lambda: []) |
178 | for t in tasks: | 190 | for t in task_dict.itervalues(): |
179 | config_dict[t.config] += [t] | 191 | config_dict[t.config] += [t] |
180 | 192 | ||
181 | for config in config_dict: | 193 | for config in config_dict: |
@@ -185,7 +197,6 @@ def config_exit_stats(file): | |||
185 | if not t.pid in exit_dict: | 197 | if not t.pid in exit_dict: |
186 | raise Exception("Missing exit record for task '%s' in '%s'" % | 198 | raise Exception("Missing exit record for task '%s' in '%s'" % |
187 | (t, file)) | 199 | (t, file)) |
188 | |||
189 | exit_list = [exit_dict[t.pid] for t in task_list] | 200 | exit_list = [exit_dict[t.pid] for t in task_list] |
190 | config_dict[config] = exit_list | 201 | config_dict[config] = exit_list |
191 | 202 | ||
@@ -195,20 +206,22 @@ saved_stats = {} | |||
195 | def get_base_stats(base_file): | 206 | def get_base_stats(base_file): |
196 | if base_file in saved_stats: | 207 | if base_file in saved_stats: |
197 | return saved_stats[base_file] | 208 | return saved_stats[base_file] |
198 | result = config_exit_stats(base_file) | 209 | with open(base_file, 'r') as f: |
210 | data = f.read() | ||
211 | result = config_exit_stats(data) | ||
199 | saved_stats[base_file] = result | 212 | saved_stats[base_file] = result |
200 | return result | 213 | return result |
201 | 214 | ||
202 | def extract_scaling_data(data_file, base_file, result): | 215 | def extract_scaling_data(task_dict, data, result, base_file): |
203 | # Generate trees of tasks with matching configurations | 216 | # Generate trees of tasks with matching configurations |
204 | data_stats = config_exit_stats(data_file) | 217 | data_stats = config_exit_stats(data) |
205 | base_stats = get_base_stats(base_file) | 218 | base_stats = get_base_stats(base_file) |
206 | 219 | ||
207 | # Scaling factors are calculated by matching groups of tasks with the same | 220 | # Scaling factors are calculated by matching groups of tasks with the same |
208 | # config, then comparing task-to-task exec times in order of PID within | 221 | # config, then comparing task-to-task exec times in order of PID within |
209 | # each group | 222 | # each group |
210 | max_scales = [] | 223 | max_scales = LeveledArray("max-scaling") |
211 | avg_scales = [] | 224 | avg_scales = LeveledArray("avg-scaling") |
212 | 225 | ||
213 | for config in data_stats: | 226 | for config in data_stats: |
214 | if len(data_stats[config]) != len(base_stats[config]): | 227 | if len(data_stats[config]) != len(base_stats[config]): |
@@ -220,8 +233,22 @@ def extract_scaling_data(data_file, base_file, result): | |||
220 | avg_scale = float(base_stat[Type.Avg]) / float(base_stat[Type.Avg]) | 233 | avg_scale = float(base_stat[Type.Avg]) / float(base_stat[Type.Avg]) |
221 | max_scale = float(base_stat[Type.Max]) / float(base_stat[Type.Max]) | 234 | max_scale = float(base_stat[Type.Max]) / float(base_stat[Type.Max]) |
222 | 235 | ||
223 | avg_scales += [avg_scale] | 236 | task = task_dict[data_stat.id] |
224 | max_scales += [max_scale] | 237 | |
238 | avg_scales.add(task, avg_scale) | ||
239 | max_scales.add(task, max_scale) | ||
240 | |||
241 | avg_scales.write_measurements(result) | ||
242 | max_scales.write_measurements(result) | ||
243 | |||
244 | def extract_sched_data(data_file, result, base_file): | ||
245 | with open(data_file, 'r') as f: | ||
246 | data = f.read() | ||
247 | |||
248 | task_dict = get_task_dict(data) | ||
249 | |||
250 | extract_tardy_vals(task_dict, data, result) | ||
251 | extract_variance(task_dict, data, result) | ||
225 | 252 | ||
226 | result['max-scale'] = Measurement().from_array(max_scales) | 253 | if (base_file): |
227 | result['avg-scale'] = Measurement().from_array(avg_scales) | 254 | extract_scaling_data(task_dict, data, result, base_file) |
diff --git a/parse/tuple_table.py b/parse/tuple_table.py index 6363b80..e6f0cc5 100644 --- a/parse/tuple_table.py +++ b/parse/tuple_table.py | |||
@@ -13,7 +13,7 @@ class ColMap(object): | |||
13 | def get_key(self, kv): | 13 | def get_key(self, kv): |
14 | key = () | 14 | key = () |
15 | added = 0 | 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,) |
@@ -24,7 +24,7 @@ class ColMap(object): | |||
24 | if added < len(kv): | 24 | if added < len(kv): |
25 | raise Exception("column map '%s' missed field in map '%s'" % | 25 | raise Exception("column map '%s' missed field in map '%s'" % |
26 | (self.col_list, kv)) | 26 | (self.col_list, kv)) |
27 | 27 | ||
28 | return key | 28 | return key |
29 | 29 | ||
30 | def __contains__(self, col): | 30 | def __contains__(self, col): |
@@ -43,7 +43,7 @@ class ColMap(object): | |||
43 | 43 | ||
44 | def __str__(self): | 44 | def __str__(self): |
45 | return "<ColMap>%s" % (self.rev_map) | 45 | return "<ColMap>%s" % (self.rev_map) |
46 | 46 | ||
47 | class TupleTable(object): | 47 | class TupleTable(object): |
48 | def __init__(self, col_map): | 48 | def __init__(self, col_map): |
49 | self.col_map = col_map | 49 | self.col_map = col_map |
@@ -63,7 +63,7 @@ class TupleTable(object): | |||
63 | raise Exception("cannot reduce twice!") | 63 | raise Exception("cannot reduce twice!") |
64 | self.reduced = True | 64 | self.reduced = True |
65 | for key, values in self.table.iteritems(): | 65 | for key, values in self.table.iteritems(): |
66 | self.table[key] = SummaryPoint(key, values) | 66 | self.table[key] = SummaryPoint(str(key), values) |
67 | 67 | ||
68 | def write_result(self, out_dir): | 68 | def write_result(self, out_dir): |
69 | dir_map = DirMap(out_dir) | 69 | dir_map = DirMap(out_dir) |