aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2012-09-28 16:55:30 -0400
committerJonathan Herman <hermanjl@cs.unc.edu>2012-09-28 16:55:30 -0400
commit2844e3887b4ff635dfa85e9b2ec773b06fe9af4f (patch)
tree2308fd16cd7def6d4fce28239524e28f1ce3ed67
parente9c71d9c11628b24fd7661d7473841fbda43cdda (diff)
Added option to parse scaling factors against a base task set.
-rw-r--r--experiment/experiment.py2
-rw-r--r--parse/ft.py2
-rw-r--r--parse/sched.py123
-rw-r--r--parse/tuple_table.py8
-rwxr-xr-xparse_exps.py67
-rwxr-xr-xrun_exps.py2
6 files changed, 165 insertions, 39 deletions
diff --git a/experiment/experiment.py b/experiment/experiment.py
index 5ed6480..a95ca42 100644
--- a/experiment/experiment.py
+++ b/experiment/experiment.py
@@ -161,7 +161,7 @@ class Experiment(object):
161 161
162 self.log("Starting %d tracers" % len(self.tracers)) 162 self.log("Starting %d tracers" % len(self.tracers))
163 map(methodcaller('start_tracing'), self.tracers) 163 map(methodcaller('start_tracing'), self.tracers)
164 time.sleep(2) 164 time.sleep(4)
165 165
166 def teardown(self): 166 def teardown(self):
167 sleep_time = 5 167 sleep_time = 5
diff --git a/parse/ft.py b/parse/ft.py
index 9837898..868c8ca 100644
--- a/parse/ft.py
+++ b/parse/ft.py
@@ -41,7 +41,7 @@ def get_ft_output(data_dir, out_dir):
41 return None 41 return None
42 return output_file 42 return output_file
43 43
44def get_ft_data(data_file, result, overheads): 44def extract_ft_data(data_file, result, overheads):
45 rstr = r",(?:\s+[^\s]+){3}.*?([\d\.]+).*?([\d\.]+),(?:\s+[^\s]+){3}.*?([\d\.]+)" 45 rstr = r",(?:\s+[^\s]+){3}.*?([\d\.]+).*?([\d\.]+),(?:\s+[^\s]+){3}.*?([\d\.]+)"
46 46
47 with open(data_file) as f: 47 with open(data_file) as f:
diff --git a/parse/sched.py b/parse/sched.py
index a84aece..94ab000 100644
--- a/parse/sched.py
+++ b/parse/sched.py
@@ -1,5 +1,6 @@
1""" 1"""
2TODO: make regexes indexable by name 2TODO: make regexes indexable by name
3
3""" 4"""
4 5
5import config.config as conf 6import config.config as conf
@@ -8,10 +9,11 @@ import re
8import numpy as np 9import numpy as np
9import subprocess 10import subprocess
10 11
11from collections import namedtuple 12from collections import namedtuple,defaultdict
12from point import Measurement 13from point import Measurement,Type
13 14
14Task = namedtuple('Task', ['pid', 'period']) 15TaskConfig = namedtuple('TaskConfig', ['cpu','wcet','period'])
16Task = namedtuple('Task', ['pid', 'config'])
15 17
16def get_st_output(data_dir, out_dir): 18def get_st_output(data_dir, out_dir):
17 bin_files = conf.FILES['sched_data'].format(".*") 19 bin_files = conf.FILES['sched_data'].format(".*")
@@ -32,32 +34,54 @@ def get_st_output(data_dir, out_dir):
32 return output_file 34 return output_file
33 35
34def get_tasks(data): 36def get_tasks(data):
35 reg = r"PARAM.*?(\d+).*?cost:\s+[\d\.]+ms.*?period.*?([\d.]+)" 37 reg = r"PARAM *?(\d+)\/.*?cost:\s+([\d\.]+)ms.*?period.*?([\d.]+)ms.*?part.*?(\d+)"
36 return [Task(x[0], x[1]) for x in re.findall(reg, data)] 38 ret = []
39 for match in re.findall(reg, data):
40 t = Task(match[0], TaskConfig(match[3],match[1],match[2]))
41 ret += [t]
42 return ret
43
44def get_task_exits(data):
45 reg = r"TASK_EXIT *?(\d+)/.*?Avg.*?(\d+).*?Max.*?(\d+)"
46 ret = []
47 for match in re.findall(reg, data):
48 m = Measurement(match[0], {Type.Max : match[2], Type.Avg : match[1]})
49 ret += [m]
50 return ret
51
37 52
38def extract_tardy_vals(data, exp_point): 53def extract_tardy_vals(data, exp_point):
39 ratios = [] 54 ratios = []
40 tards = [] 55 avg_tards = []
56 max_tards = []
41 57
42 for t in get_tasks(data): 58 for t in get_tasks(data):
43 reg = r"TARDY.*?" + t.pid + "/(\d+).*?Tot.*?([\d.]+).*?ms.*([\d.]+).*?ms.*?([\d.]+)" 59 reg = r"TARDY.*?" + t.pid + "/(\d+).*?Tot.*?([\d\.]+).*?ms.*([\d\.]+).*?ms.*?([\d\.]+)"
44 matches = re.findall(reg, data) 60 matches = re.findall(reg, data)
45 if len(matches) != 0: 61 if len(matches) != 0:
46 jobs = float(matches[0][0]) 62 jobs = float(matches[0][0])
63
47 total_tard = float(matches[0][1]) 64 total_tard = float(matches[0][1])
48 # max_tard = float(matches[0][2]) 65 print("total tard: %s" % total_tard)
66 avg_tard = (total_tard / jobs) / float(t.config.period)
67 max_tard = float(matches[0][2]) / float(t.config.period)
68
69 print("avg tard: %s" % avg_tard)
70
49 misses = float(matches[0][3]) 71 misses = float(matches[0][3])
50 rel_tard = (total_tard / jobs) / float(t.period)
51 if misses != 0: 72 if misses != 0:
52 miss_ratio = (misses / jobs) 73 miss_ratio = (misses / jobs)
74 print("misses is %d, jobs is %d" % (misses, jobs))
53 else: 75 else:
54 miss_ratio = 0 76 miss_ratio = 0
55 77
56 ratios.append(miss_ratio) 78 ratios += [miss_ratio]
57 tards.append(rel_tard) 79 avg_tards += [avg_tard]
80 max_tards += [max_tard]
58 81
59 for (array, name) in ((tards, "rel-tard"), (ratios, "miss-ratio")): 82 exp_point["avg-rel-tard"] = Measurement().from_array(avg_tards)
60 exp_point[name] = Measurement().from_array(array) 83 exp_point["max-rel-tard"] = Measurement().from_array(max_tards)
84 exp_point["miss-ratio"] = Measurement().from_array(ratios)
61 85
62def extract_variance(data, exp_point): 86def extract_variance(data, exp_point):
63 varz = [] 87 varz = []
@@ -77,17 +101,70 @@ def extract_variance(data, exp_point):
77 101
78 varz.append(corrected) 102 varz.append(corrected)
79 103
80 exp_point['var'] = Measurement().from_array(varz) 104 exp_point['exec-var'] = Measurement().from_array(varz)
81 105
82def get_sched_data(data_file, result): 106def extract_sched_data(data_file, result):
83 with open(data_file, 'r') as f: 107 with open(data_file, 'r') as f:
84 data = f.read() 108 data = f.read()
85 109
86 # if conf != BASE: 110 extract_tardy_vals(data, result)
87 # (our_values, their_values) = extract_exec_vals(our_data, their_data) 111 extract_variance(data, result)
88 # conf_result = get_stats(our_values, their_values)
89 # for key in conf_result.keys():
90 # result[key][conf] = conf_result[key]
91 112
92 extract_tardy_vals(data, result) 113def config_exit_stats(file):
93 extract_variance(data, result) 114 with open(file, 'r') as f:
115 data = f.read()
116
117 tasks = get_tasks(data)
118
119 # Dictionary of task exit measurements by pid
120 exits = get_task_exits(data)
121 exit_dict = dict((e.id, e) for e in exits)
122
123 # Dictionary where keys are configurations, values are list
124 # of tasks with those configuratino
125 config_dict = defaultdict(lambda: [])
126 for t in tasks:
127 config_dict[t.config] += [t]
128
129 for config in config_dict:
130 task_list = sorted(config_dict[config])
131
132 # Replace tasks with corresponding exit stats
133 exit_list = [exit_dict[t.pid] for t in task_list]
134 config_dict[config] = exit_list
135
136 return config_dict
137
138saved_stats = {}
139def get_base_stats(base_file):
140 if base_file in saved_stats:
141 return saved_stats[base_file]
142 result = config_exit_stats(base_file)
143 saved_stats[base_file] = result
144 return result
145
146def extract_scaling_data(data_file, base_file, result):
147 # Generate trees of tasks with matching configurations
148 data_stats = config_exit_stats(data_file)
149 base_stats = get_base_stats(base_file)
150
151 # Scaling factors are calculated by matching groups of tasks with the same
152 # config, then comparing task-to-task exec times in order of PID within
153 # each group
154 max_scales = []
155 avg_scales = []
156 for config in data_stats:
157 if len(data_stats[config]) != len(base_stats[config]):
158 # Quit, we are missing a record and can't guarantee
159 # a task-to-task comparison
160 continue
161 for data_stat, base_stat in zip(data_stats[config],base_stats[config]):
162 # How much larger is their exec stat than ours?
163 avg_scale = float(base_stat[Type.Avg]) / float(base_stat[Type.Avg])
164 max_scale = float(base_stat[Type.Max]) / float(base_stat[Type.Max])
165
166 avg_scales += [avg_scale]
167 max_scales += [max_scale]
168
169 result['max-scale'] = Measurement().from_array(max_scales)
170 result['avg-scale'] = Measurement().from_array(avg_scales)
diff --git a/parse/tuple_table.py b/parse/tuple_table.py
index 0cf6bec..b56fa6c 100644
--- a/parse/tuple_table.py
+++ b/parse/tuple_table.py
@@ -21,8 +21,8 @@ class ColMap(object):
21 added += 1 21 added += 1
22 key += (kv[col],) 22 key += (kv[col],)
23 23
24 if added != len(kv): 24 if added < len(kv):
25 raise Exception("column map '%s' missed field in map\n%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
@@ -51,6 +51,10 @@ class TupleTable(object):
51 key = self.col_map.get_key(kv) 51 key = self.col_map.get_key(kv)
52 self.table[key] += [point] 52 self.table[key] += [point]
53 53
54 def get_exps(self, kv):
55 key = self.col_map.get_key(kv)
56 return self.table[key]
57
54 def __reduce(self): 58 def __reduce(self):
55 if self.reduced: 59 if self.reduced:
56 raise Exception("cannot reduce twice!") 60 raise Exception("cannot reduce twice!")
diff --git a/parse_exps.py b/parse_exps.py
index ecb1cac..3a1d1b9 100755
--- a/parse_exps.py
+++ b/parse_exps.py
@@ -2,9 +2,11 @@
2from __future__ import print_function 2from __future__ import print_function
3 3
4import config.config as conf 4import config.config as conf
5import copy
5import os 6import os
6import parse.ft as ft 7import parse.ft as ft
7import parse.sched as st 8import parse.sched as st
9import re
8 10
9from collections import namedtuple 11from collections import namedtuple
10from common import load_params 12from common import load_params
@@ -17,6 +19,9 @@ def parse_args():
17 19
18 parser.add_option('-o', '--out-dir', dest='out_dir', 20 parser.add_option('-o', '--out-dir', dest='out_dir',
19 help='directory for data output', default=os.getcwd()) 21 help='directory for data output', default=os.getcwd())
22 parser.add_option('-s', '--scale-against', dest='scale_against',
23 metavar='PARAM=VALUE', default="",
24 help='calculate task scaling factors against these configs')
20 25
21 return parser.parse_args() 26 return parser.parse_args()
22 27
@@ -41,8 +46,10 @@ def get_exp_params(data_dir, col_map):
41 return params 46 return params
42 47
43 48
44def gen_exp_data(exp_dirs, col_map): 49def gen_exp_data(exp_dirs, base_conf, col_map):
45 exps = [] 50 plain_exps = []
51 scaling_bases = []
52
46 for data_dir in exp_dirs: 53 for data_dir in exp_dirs:
47 if not os.path.isdir(data_dir): 54 if not os.path.isdir(data_dir):
48 raise IOError("Invalid experiment '%s'" % os.path.abspath(data_dir)) 55 raise IOError("Invalid experiment '%s'" % os.path.abspath(data_dir))
@@ -51,34 +58,72 @@ def gen_exp_data(exp_dirs, col_map):
51 if not os.path.exists(tmp_dir): 58 if not os.path.exists(tmp_dir):
52 os.mkdir(tmp_dir) 59 os.mkdir(tmp_dir)
53 60
61 # Read and translate exp output files
54 params = get_exp_params(data_dir, col_map) 62 params = get_exp_params(data_dir, col_map)
55 st_output = st.get_st_output(data_dir, tmp_dir) 63 st_output = st.get_st_output(data_dir, tmp_dir)
56 ft_output = ft.get_ft_output(data_dir, tmp_dir) 64 ft_output = ft.get_ft_output(data_dir, tmp_dir)
57 65
66 # Create experiment named after the data dir
58 exp_data = ExpData(data_dir, params, DataFiles(ft_output, st_output)) 67 exp_data = ExpData(data_dir, params, DataFiles(ft_output, st_output))
59 exps += [exp_data]
60 68
61 return exps 69 if base_conf and base_conf.viewitems() & params.viewitems():
70 if not st_output:
71 raise Exception("Scaling base '%s' useless without sched data!"
72 % data_dir)
73 params.pop(base_conf.keys()[0])
74 scaling_bases += [exp_data]
75 else:
76 plain_exps += [exp_data]
77
78 return (plain_exps, scaling_bases)
62 79
63def main(): 80def main():
64 opts, args = parse_args() 81 opts, args = parse_args()
65 82
66 args = args or [os.getcwd()] 83 args = args or [os.getcwd()]
84
85 # Configuration key for task systems used to calculate task
86 # execution scaling factors
87 base_conf = dict(re.findall("(.*)=(.*)", opts.scale_against))
88
67 col_map = ColMap() 89 col_map = ColMap()
68 exps = gen_exp_data(args, col_map)
69 90
70 table = TupleTable(col_map) 91 (plain_exps, scaling_bases) = gen_exp_data(args, base_conf, col_map)
92
93 base_table = TupleTable(col_map)
94 result_table = TupleTable(col_map)
71 95
72 for exp in exps: 96 # Used to find matching scaling_base for each experiment
97 for base in scaling_bases:
98 base_table.add_exp(base.params, base)
99
100 for exp in plain_exps:
73 result = ExpPoint(exp.name) 101 result = ExpPoint(exp.name)
102
74 if exp.data_files.ft: 103 if exp.data_files.ft:
75 ft.get_ft_data(exp.data_files.ft, result, conf.BASE_EVENTS) 104 # Write overheads into result
105 ft.extract_ft_data(exp.data_files.ft, result, conf.BASE_EVENTS)
106
76 if exp.data_files.st: 107 if exp.data_files.st:
77 st.get_sched_data(exp.data_files.st, result) 108 if base_conf:
109 # Try to find a scaling base
110 base_params = copy.deepcopy(exp.params)
111 base_params.pop(base_conf.keys()[0])
112 base = base_table.get_exps(base_params)[0]
113 if base:
114 # Write scaling factor (vs base) into result
115 st.extract_scaling_data(exp.data_files.st,
116 base.data_files.st,
117 result)
118 # Write deadline misses / tardiness into result
119 st.extract_sched_data(exp.data_files.st, result)
120
121 result_table.add_exp(exp.params, result)
122
123 print(result)
78 124
79 table.add_exp(exp.params, result)
80 125
81 table.write_result(opts.out_dir) 126 result_table.write_result(opts.out_dir)
82 127
83if __name__ == '__main__': 128if __name__ == '__main__':
84 main() 129 main()
diff --git a/run_exps.py b/run_exps.py
index bda0e40..4484952 100755
--- a/run_exps.py
+++ b/run_exps.py
@@ -218,7 +218,7 @@ def main():
218 print(" Successful:\t\t%d" % succ) 218 print(" Successful:\t\t%d" % succ)
219 print(" Failed:\t\t%d" % failed) 219 print(" Failed:\t\t%d" % failed)
220 print(" Already Done:\t\t%d" % done) 220 print(" Already Done:\t\t%d" % done)
221 print(" Invalid Kernel:\t\t%d" % invalid) 221 print(" Wrong Kernel:\t\t%d" % invalid)
222 222
223 223
224if __name__ == '__main__': 224if __name__ == '__main__':