diff options
-rw-r--r-- | common.py | 2 | ||||
-rw-r--r-- | gen/generators.py | 22 | ||||
-rw-r--r-- | parse/dir_map.py | 2 | ||||
-rw-r--r-- | parse/ft.py | 14 | ||||
-rw-r--r-- | parse/sched.py | 8 | ||||
-rw-r--r-- | parse/tuple_table.py | 3 | ||||
-rwxr-xr-x | parse_exps.py | 58 | ||||
-rw-r--r-- | plot/style.py | 3 | ||||
-rwxr-xr-x | plot_exps.py | 29 | ||||
-rw-r--r-- | run/executable/executable.py | 9 | ||||
-rw-r--r-- | run/executable/ftcat.py | 21 | ||||
-rw-r--r-- | run/experiment.py | 9 | ||||
-rw-r--r-- | run/litmus_util.py | 10 | ||||
-rw-r--r-- | run/tracer.py | 19 | ||||
-rwxr-xr-x | run_exps.py | 2 |
15 files changed, 138 insertions, 73 deletions
@@ -105,7 +105,7 @@ def recordtype(typename, field_names, default=0): | |||
105 | namespace = {} | 105 | namespace = {} |
106 | try: | 106 | try: |
107 | exec template in namespace | 107 | exec template in namespace |
108 | except SyntaxError, e: | 108 | except SyntaxError as e: |
109 | raise SyntaxError(e.message + ':\n' + template) | 109 | raise SyntaxError(e.message + ':\n' + template) |
110 | cls = namespace[typename] | 110 | cls = namespace[typename] |
111 | 111 | ||
diff --git a/gen/generators.py b/gen/generators.py index 09ae979..dd6f1cc 100644 --- a/gen/generators.py +++ b/gen/generators.py | |||
@@ -53,7 +53,7 @@ GenOption = namedtuple('GenOption', ['name', 'types', 'default', 'help']) | |||
53 | class BaseGenerator(object): | 53 | class BaseGenerator(object): |
54 | '''Creates sporadic task sets with the most common Litmus options.''' | 54 | '''Creates sporadic task sets with the most common Litmus options.''' |
55 | def __init__(self, name, templates, options, params): | 55 | def __init__(self, name, templates, options, params): |
56 | self.options = self.__make_options() + options | 56 | self.options = self.__make_options(params) + options |
57 | 57 | ||
58 | self.__setup_params(params) | 58 | self.__setup_params(params) |
59 | 59 | ||
@@ -61,11 +61,14 @@ class BaseGenerator(object): | |||
61 | self.template = "\n".join([TP_RM] + templates) | 61 | self.template = "\n".join([TP_RM] + templates) |
62 | self.name = name | 62 | self.name = name |
63 | 63 | ||
64 | def __make_options(self): | 64 | def __make_options(self, params): |
65 | '''Return generic Litmus options.''' | 65 | '''Return generic Litmus options.''' |
66 | 66 | ||
67 | # Guess defaults using the properties of this computer | 67 | # Guess defaults using the properties of this computer |
68 | cpus = lu.num_cpus() | 68 | if 'cpus' in params: |
69 | cpus = min(map(int, params['cpus'])) | ||
70 | else: | ||
71 | cpus = lu.num_cpus() | ||
69 | try: | 72 | try: |
70 | config = get_config_option("RELEASE_MASTER") and True | 73 | config = get_config_option("RELEASE_MASTER") and True |
71 | except: | 74 | except: |
@@ -127,9 +130,10 @@ class BaseGenerator(object): | |||
127 | f.write(str(Template(self.template, searchList=[exp_params]))) | 130 | f.write(str(Template(self.template, searchList=[exp_params]))) |
128 | 131 | ||
129 | del exp_params['task_set'] | 132 | del exp_params['task_set'] |
133 | del exp_params['num_tasks'] | ||
130 | exp_params_file = out_dir + "/" + DEFAULTS['params_file'] | 134 | exp_params_file = out_dir + "/" + DEFAULTS['params_file'] |
131 | with open(exp_params_file, 'wa') as f: | 135 | with open(exp_params_file, 'wa') as f: |
132 | exp_params['scheduler'] = 'CEDF' | 136 | exp_params['scheduler'] = self.name |
133 | f.write(str(exp_params)) | 137 | f.write(str(exp_params)) |
134 | 138 | ||
135 | def __setup_params(self, params): | 139 | def __setup_params(self, params): |
@@ -195,7 +199,7 @@ class BaseGenerator(object): | |||
195 | col_map = builder.build() | 199 | col_map = builder.build() |
196 | 200 | ||
197 | for dp in DesignPointGenerator(self.params): | 201 | for dp in DesignPointGenerator(self.params): |
198 | dir_leaf = "sched=%s_%s" % (self.name, col_map.get_encoding(dp)) | 202 | dir_leaf = "sched=%s_%s" % (self.name, col_map.encode(dp)) |
199 | dir_path = "%s/%s" % (out_dir, dir_leaf.strip('_')) | 203 | dir_path = "%s/%s" % (out_dir, dir_leaf.strip('_')) |
200 | 204 | ||
201 | if os.path.exists(dir_path): | 205 | if os.path.exists(dir_path): |
@@ -225,10 +229,10 @@ class BaseGenerator(object): | |||
225 | i+= len(word) | 229 | i+= len(word) |
226 | res += [word] | 230 | res += [word] |
227 | if i > 80: | 231 | if i > 80: |
228 | print ", ".join(res[:-1]) | 232 | print(", ".join(res[:-1])) |
229 | res = ["\t\t "+res[-1]] | 233 | res = ["\t\t "+res[-1]] |
230 | i = line.index("'") | 234 | i = line.index("'") |
231 | print ", ".join(res) | 235 | print(", ".join(res)) |
232 | 236 | ||
233 | class PartitionedGenerator(BaseGenerator): | 237 | class PartitionedGenerator(BaseGenerator): |
234 | def __init__(self, name, templates, options, params): | 238 | def __init__(self, name, templates, options, params): |
@@ -243,7 +247,7 @@ class PartitionedGenerator(BaseGenerator): | |||
243 | 247 | ||
244 | class PedfGenerator(PartitionedGenerator): | 248 | class PedfGenerator(PartitionedGenerator): |
245 | def __init__(self, params={}): | 249 | def __init__(self, params={}): |
246 | super(PedfGenerator, self).__init__("P-EDF", [], [], params) | 250 | super(PedfGenerator, self).__init__("PSN-EDF", [], [], params) |
247 | 251 | ||
248 | class CedfGenerator(PartitionedGenerator): | 252 | class CedfGenerator(PartitionedGenerator): |
249 | LEVEL_OPTION = GenOption('level', ['L2', 'L3', 'All'], ['L2'], | 253 | LEVEL_OPTION = GenOption('level', ['L2', 'L3', 'All'], ['L2'], |
@@ -255,4 +259,4 @@ class CedfGenerator(PartitionedGenerator): | |||
255 | 259 | ||
256 | class GedfGenerator(BaseGenerator): | 260 | class GedfGenerator(BaseGenerator): |
257 | def __init__(self, params={}): | 261 | def __init__(self, params={}): |
258 | super(GedfGenerator, self).__init__("G-EDF", [TP_GLOB_TASK], [], params) | 262 | super(GedfGenerator, self).__init__("GSN-EDF", [TP_GLOB_TASK], [], params) |
diff --git a/parse/dir_map.py b/parse/dir_map.py index 1c17f40..601dd3b 100644 --- a/parse/dir_map.py +++ b/parse/dir_map.py | |||
@@ -46,7 +46,7 @@ class DirMap(object): | |||
46 | 46 | ||
47 | def remove_childless(self): | 47 | def remove_childless(self): |
48 | def remove_childless2(node): | 48 | def remove_childless2(node): |
49 | for key, child in node: | 49 | for key, child in node.children.items(): |
50 | remove_childless2(child) | 50 | remove_childless2(child) |
51 | if not (child.children or child.values): | 51 | if not (child.children or child.values): |
52 | node.children.pop(key) | 52 | node.children.pop(key) |
diff --git a/parse/ft.py b/parse/ft.py index 5293b00..19453d1 100644 --- a/parse/ft.py +++ b/parse/ft.py | |||
@@ -3,6 +3,7 @@ import numpy as np | |||
3 | import os | 3 | import os |
4 | import re | 4 | import re |
5 | import shutil as sh | 5 | import shutil as sh |
6 | import sys | ||
6 | import subprocess | 7 | import subprocess |
7 | 8 | ||
8 | from point import Measurement,Type | 9 | from point import Measurement,Type |
@@ -28,7 +29,6 @@ def parse_overhead(result, overhead_bin, overhead, cycles, out_dir, err_file): | |||
28 | raise Exception("Failed (%d) with command: %s" % (ret, " ".join(cmd))) | 29 | raise Exception("Failed (%d) with command: %s" % (ret, " ".join(cmd))) |
29 | if not size: | 30 | if not size: |
30 | os.remove(ovh_fname) | 31 | os.remove(ovh_fname) |
31 | |||
32 | if size and not ret: | 32 | if size and not ret: |
33 | # Map and sort file for stats | 33 | # Map and sort file for stats |
34 | data = np.memmap(ovh_fname, dtype="float32", mode='c') | 34 | data = np.memmap(ovh_fname, dtype="float32", mode='c') |
@@ -47,19 +47,22 @@ def parse_overhead(result, overhead_bin, overhead, cycles, out_dir, err_file): | |||
47 | 47 | ||
48 | def sort_ft(ft_file, err_file, out_dir): | 48 | def sort_ft(ft_file, err_file, out_dir): |
49 | '''Create and return file with sorted overheads from @ft_file.''' | 49 | '''Create and return file with sorted overheads from @ft_file.''' |
50 | out_fname = "{}/{}".format("%s/%s" % (os.getcwd(), out_dir), FT_SORTED_NAME) | 50 | out_fname = "{}/{}".format(out_dir, FT_SORTED_NAME) |
51 | 51 | ||
52 | # Sort happens in-place | 52 | # Sort happens in-place |
53 | sh.copyfile(ft_file, out_fname) | 53 | sh.copyfile(ft_file, out_fname) |
54 | cmd = [conf.BINS['ftsort'], out_fname] | 54 | cmd = [conf.BINS['ftsort'], out_fname] |
55 | ret = subprocess.call(cmd, cwd="%s/%s" % (os.getcwd(), out_dir), stderr=err_file, stdout=err_file) | ||
56 | 55 | ||
56 | ret = subprocess.call(cmd, cwd=out_dir, stderr=err_file, stdout=err_file) | ||
57 | if ret: | 57 | if ret: |
58 | raise Exception("Sort failed with command: %s" % " ".join(cmd)) | 58 | raise Exception("Sort failed (%d) with command: %s" % (ret, " ".join(cmd))) |
59 | 59 | ||
60 | return out_fname | 60 | return out_fname |
61 | 61 | ||
62 | def extract_ft_data(result, data_dir, work_dir, cycles): | 62 | def extract_ft_data(result, data_dir, work_dir, cycles): |
63 | data_dir = os.path.abspath(data_dir) | ||
64 | work_dir = os.path.abspath(work_dir) | ||
65 | |||
63 | freg = conf.FILES['ft_data'] + "$" | 66 | freg = conf.FILES['ft_data'] + "$" |
64 | bins = [f for f in os.listdir(data_dir) if re.match(freg, f)] | 67 | bins = [f for f in os.listdir(data_dir) if re.match(freg, f)] |
65 | 68 | ||
@@ -67,6 +70,9 @@ def extract_ft_data(result, data_dir, work_dir, cycles): | |||
67 | return False | 70 | return False |
68 | 71 | ||
69 | bin_file = "{}/{}".format(data_dir, bins[0]) | 72 | bin_file = "{}/{}".format(data_dir, bins[0]) |
73 | if not os.path.getsize(bin_file): | ||
74 | sys.stderr.write("Empty feather trace file %s!" % bin_file) | ||
75 | return False | ||
70 | 76 | ||
71 | with open("%s/%s" % (work_dir, FT_ERR_NAME), 'w') as err_file: | 77 | with open("%s/%s" % (work_dir, FT_ERR_NAME), 'w') as err_file: |
72 | sorted_bin = sort_ft(bin_file, err_file, work_dir) | 78 | sorted_bin = sort_ft(bin_file, err_file, work_dir) |
diff --git a/parse/sched.py b/parse/sched.py index ba0df5e..2da0149 100644 --- a/parse/sched.py +++ b/parse/sched.py | |||
@@ -2,6 +2,7 @@ import config.config as conf | |||
2 | import os | 2 | import os |
3 | import re | 3 | import re |
4 | import struct | 4 | import struct |
5 | import sys | ||
5 | import subprocess | 6 | import subprocess |
6 | 7 | ||
7 | from collections import defaultdict,namedtuple | 8 | from collections import defaultdict,namedtuple |
@@ -66,6 +67,10 @@ def register_record(name, id, method, fmt, fields): | |||
66 | def make_iterator(fname): | 67 | def make_iterator(fname): |
67 | '''Iterate over (parsed record, processing method) in a | 68 | '''Iterate over (parsed record, processing method) in a |
68 | sched-trace file.''' | 69 | sched-trace file.''' |
70 | if not os.path.getsize(fname): | ||
71 | sys.stderr.write("Empty sched_trace file %s!" % fname) | ||
72 | return | ||
73 | |||
69 | f = open(fname, 'rb') | 74 | f = open(fname, 'rb') |
70 | max_type = len(record_map) | 75 | max_type = len(record_map) |
71 | 76 | ||
@@ -182,4 +187,7 @@ def extract_sched_data(result, data_dir, work_dir): | |||
182 | 187 | ||
183 | # Summarize value groups | 188 | # Summarize value groups |
184 | for name, data in stat_data.iteritems(): | 189 | for name, data in stat_data.iteritems(): |
190 | if not data: | ||
191 | continue | ||
185 | result[name] = Measurement(str(name)).from_array(data) | 192 | result[name] = Measurement(str(name)).from_array(data) |
193 | |||
diff --git a/parse/tuple_table.py b/parse/tuple_table.py index 86baa08..ee94772 100644 --- a/parse/tuple_table.py +++ b/parse/tuple_table.py | |||
@@ -3,8 +3,6 @@ from collections import defaultdict,namedtuple | |||
3 | from point import SummaryPoint,Type | 3 | from point import SummaryPoint,Type |
4 | from dir_map import DirMap | 4 | from dir_map import DirMap |
5 | from col_map import ColMap,ColMapBuilder | 5 | from col_map import ColMap,ColMapBuilder |
6 | |||
7 | |||
8 | from pprint import pprint | 6 | from pprint import pprint |
9 | 7 | ||
10 | class TupleTable(object): | 8 | class TupleTable(object): |
@@ -88,7 +86,6 @@ class ReducedTupleTable(TupleTable): | |||
88 | self.__add_to_dirmap(dir_map, col, kv, point) | 86 | self.__add_to_dirmap(dir_map, col, kv, point) |
89 | 87 | ||
90 | dir_map.remove_childless() | 88 | dir_map.remove_childless() |
91 | print("wrote: %s" % self) | ||
92 | return dir_map | 89 | return dir_map |
93 | 90 | ||
94 | @staticmethod | 91 | @staticmethod |
diff --git a/parse_exps.py b/parse_exps.py index f27021a..4cdc0a1 100755 --- a/parse_exps.py +++ b/parse_exps.py | |||
@@ -8,13 +8,13 @@ import parse.sched as st | |||
8 | import pickle | 8 | import pickle |
9 | import shutil as sh | 9 | import shutil as sh |
10 | import sys | 10 | import sys |
11 | import traceback | ||
11 | 12 | ||
12 | from collections import namedtuple | 13 | from collections import namedtuple |
13 | from common import load_params | 14 | from common import load_params |
14 | from optparse import OptionParser | 15 | from optparse import OptionParser |
15 | from parse.dir_map import DirMap | ||
16 | from parse.point import ExpPoint | 16 | from parse.point import ExpPoint |
17 | from parse.tuple_table import TupleTable,ReducedTupleTable | 17 | from parse.tuple_table import TupleTable |
18 | from parse.col_map import ColMapBuilder | 18 | from parse.col_map import ColMapBuilder |
19 | from multiprocessing import Pool, cpu_count | 19 | from multiprocessing import Pool, cpu_count |
20 | 20 | ||
@@ -23,7 +23,6 @@ def parse_args(): | |||
23 | parser = OptionParser("usage: %prog [options] [data_dir]...") | 23 | parser = OptionParser("usage: %prog [options] [data_dir]...") |
24 | 24 | ||
25 | print("default to no params.py") | 25 | print("default to no params.py") |
26 | print("save measurements in temp directory for faster reloading") | ||
27 | 26 | ||
28 | parser.add_option('-o', '--out', dest='out', | 27 | parser.add_option('-o', '--out', dest='out', |
29 | help='file or directory for data output', default='parse-data') | 28 | help='file or directory for data output', default='parse-data') |
@@ -85,16 +84,24 @@ def load_exps(exp_dirs, cm_builder, clean): | |||
85 | 84 | ||
86 | return exps | 85 | return exps |
87 | 86 | ||
88 | def parse_exp(exp, force): | 87 | def parse_exp(exp_force): |
88 | # Tupled for multiprocessing | ||
89 | exp, force = exp_force | ||
90 | |||
89 | result_file = exp.work_dir + "/exp_point.pkl" | 91 | result_file = exp.work_dir + "/exp_point.pkl" |
90 | should_load = not force and os.path.exists(result_file) | 92 | should_load = not force and os.path.exists(result_file) |
91 | mode = 'r' if should_load else 'w' | ||
92 | 93 | ||
93 | with open(result_file, mode + 'b') as f: | 94 | result = None |
94 | if should_load: | 95 | if should_load: |
95 | # No need to go through this work twice | 96 | with open(result_file, 'rb') as f: |
96 | result = pickle.load(f) | 97 | try: |
97 | else: | 98 | # No need to go through this work twice |
99 | result = pickle.load(f) | ||
100 | except: | ||
101 | pass | ||
102 | |||
103 | if not result: | ||
104 | try: | ||
98 | result = ExpPoint(exp.path) | 105 | result = ExpPoint(exp.path) |
99 | cycles = exp.params[conf.PARAMS['cycles']] | 106 | cycles = exp.params[conf.PARAMS['cycles']] |
100 | 107 | ||
@@ -104,7 +111,10 @@ def parse_exp(exp, force): | |||
104 | # Write scheduling statistics into result | 111 | # Write scheduling statistics into result |
105 | st.extract_sched_data(result, exp.path, exp.work_dir) | 112 | st.extract_sched_data(result, exp.path, exp.work_dir) |
106 | 113 | ||
107 | pickle.dump(result, f) | 114 | with open(result_file, 'wb') as f: |
115 | pickle.dump(result, f) | ||
116 | except: | ||
117 | traceback.print_exc() | ||
108 | 118 | ||
109 | return (exp, result) | 119 | return (exp, result) |
110 | 120 | ||
@@ -128,14 +138,24 @@ def main(): | |||
128 | sys.stderr.write("Parsing data...\n") | 138 | sys.stderr.write("Parsing data...\n") |
129 | 139 | ||
130 | procs = min(len(exps), cpu_count()/2) | 140 | procs = min(len(exps), cpu_count()/2) |
131 | pool = Pool(processes=procs) | 141 | pool = Pool(processes=procs) |
132 | enum = pool.imap_unordered(parse_exp, exps, [opts.force]*len(exps)) | 142 | pool_args = zip(exps, [opts.force]*len(exps)) |
133 | for i, (exp, result) in enumerate(enum): | 143 | enum = pool.imap_unordered(parse_exp, pool_args, 1) |
134 | if opts.verbose: | 144 | |
135 | print(result) | 145 | try: |
136 | else: | 146 | for i, (exp, result) in enumerate(enum): |
137 | sys.stderr.write('\r {0:.2%}'.format(float(i)/len(exps))) | 147 | if opts.verbose: |
138 | result_table[exp.params] += [result] | 148 | print(result) |
149 | else: | ||
150 | sys.stderr.write('\r {0:.2%}'.format(float(i)/len(exps))) | ||
151 | result_table[exp.params] += [result] | ||
152 | pool.close() | ||
153 | except: | ||
154 | pool.terminate() | ||
155 | traceback.print_exc() | ||
156 | raise Exception("Failed parsing!") | ||
157 | finally: | ||
158 | pool.join() | ||
139 | 159 | ||
140 | sys.stderr.write('\n') | 160 | sys.stderr.write('\n') |
141 | 161 | ||
diff --git a/plot/style.py b/plot/style.py index ca7a112..fd1fa97 100644 --- a/plot/style.py +++ b/plot/style.py | |||
@@ -16,6 +16,9 @@ class StyleMap(object): | |||
16 | self.field_map = {} | 16 | self.field_map = {} |
17 | 17 | ||
18 | for field, values in self.__get_all()._asdict().iteritems(): | 18 | for field, values in self.__get_all()._asdict().iteritems(): |
19 | if not col_list: | ||
20 | break | ||
21 | |||
19 | next_column = col_list.pop(0) | 22 | next_column = col_list.pop(0) |
20 | value_dict = {} | 23 | value_dict = {} |
21 | 24 | ||
diff --git a/plot_exps.py b/plot_exps.py index 8fbef99..49cc729 100755 --- a/plot_exps.py +++ b/plot_exps.py | |||
@@ -5,6 +5,7 @@ import matplotlib.pyplot as plot | |||
5 | import os | 5 | import os |
6 | import shutil as sh | 6 | import shutil as sh |
7 | import sys | 7 | import sys |
8 | import traceback | ||
8 | from collections import namedtuple | 9 | from collections import namedtuple |
9 | from optparse import OptionParser | 10 | from optparse import OptionParser |
10 | from parse.col_map import ColMap,ColMapBuilder | 11 | from parse.col_map import ColMap,ColMapBuilder |
@@ -83,6 +84,15 @@ def plot_by_variable(details): | |||
83 | 84 | ||
84 | plot.savefig(details.out, format=OUT_FORMAT) | 85 | plot.savefig(details.out, format=OUT_FORMAT) |
85 | 86 | ||
87 | return True | ||
88 | |||
89 | def plot_wrapper(details): | ||
90 | '''Wrap exceptions in named method for printing in multiprocessing pool.''' | ||
91 | try: | ||
92 | return plot_by_variable(details) | ||
93 | except: | ||
94 | traceback.print_exc() | ||
95 | |||
86 | def plot_dir(data_dir, out_dir, force): | 96 | def plot_dir(data_dir, out_dir, force): |
87 | sys.stderr.write("Reading data...\n") | 97 | sys.stderr.write("Reading data...\n") |
88 | dir_map = DirMap.read(data_dir) | 98 | dir_map = DirMap.read(data_dir) |
@@ -102,11 +112,24 @@ def plot_dir(data_dir, out_dir, force): | |||
102 | if force or not os.path.exists(details.out): | 112 | if force or not os.path.exists(details.out): |
103 | plot_details += [details] | 113 | plot_details += [details] |
104 | 114 | ||
115 | if not plot_details: | ||
116 | return | ||
117 | |||
105 | procs = min(len(plot_details), cpu_count()/2) | 118 | procs = min(len(plot_details), cpu_count()/2) |
106 | pool = Pool(processes=procs) | 119 | pool = Pool(processes=procs) |
107 | enum = pool.imap_unordered(plot_by_variable, plot_details) | 120 | enum = pool.imap_unordered(plot_wrapper, plot_details) |
108 | for i, _ in enumerate(enum): | 121 | |
109 | sys.stderr.write('\r {0:.2%}'.format(float(i)/num_plots)) | 122 | try: |
123 | for i, _ in enumerate(enum): | ||
124 | sys.stderr.write('\r {0:.2%}'.format(float(i)/num_plots)) | ||
125 | pool.close() | ||
126 | except: | ||
127 | pool.terminate() | ||
128 | traceback.print_exc() | ||
129 | raise Exception("Failed plotting!") | ||
130 | finally: | ||
131 | pool.join() | ||
132 | |||
110 | sys.stderr.write('\n') | 133 | sys.stderr.write('\n') |
111 | 134 | ||
112 | def main(): | 135 | def main(): |
diff --git a/run/executable/executable.py b/run/executable/executable.py index bc8edd7..0a408b7 100644 --- a/run/executable/executable.py +++ b/run/executable/executable.py | |||
@@ -44,7 +44,6 @@ class Executable(object): | |||
44 | return full_command | 44 | return full_command |
45 | 45 | ||
46 | def __str__(self): | 46 | def __str__(self): |
47 | print("Full command: %s" % self.__get_full_command()) | ||
48 | return " ".join(self.__get_full_command()) | 47 | return " ".join(self.__get_full_command()) |
49 | 48 | ||
50 | def execute(self): | 49 | def execute(self): |
@@ -63,7 +62,7 @@ class Executable(object): | |||
63 | '''Send the terminate signal to the binary.''' | 62 | '''Send the terminate signal to the binary.''' |
64 | self.sp.terminate() | 63 | self.sp.terminate() |
65 | 64 | ||
66 | def wait(self): | 65 | def wait(self, error=True): |
67 | '''Wait until the executable is finished, checking return code. | 66 | '''Wait until the executable is finished, checking return code. |
68 | 67 | ||
69 | If the exit status is non-zero, raise an exception. | 68 | If the exit status is non-zero, raise an exception. |
@@ -71,8 +70,10 @@ class Executable(object): | |||
71 | ''' | 70 | ''' |
72 | 71 | ||
73 | self.sp.wait() | 72 | self.sp.wait() |
74 | if self.sp.returncode != 0: | 73 | if self.sp.returncode != 0 and error: |
75 | print >>sys.stderr, "Non-zero return: %s %s" % (self.exec_file, " ".join(self.extra_args)) | 74 | print >>sys.stderr, "Non-zero return %d: %s %s" % (self.sp.returncode, |
75 | self.exec_file, | ||
76 | " ".join(self.extra_args)) | ||
76 | return 0 | 77 | return 0 |
77 | else: | 78 | else: |
78 | return 1 | 79 | return 1 |
diff --git a/run/executable/ftcat.py b/run/executable/ftcat.py index 5da8fa7..1f0420b 100644 --- a/run/executable/ftcat.py +++ b/run/executable/ftcat.py | |||
@@ -1,18 +1,15 @@ | |||
1 | import os | 1 | import os |
2 | import stat | 2 | import stat |
3 | 3 | ||
4 | from executable import Executable | 4 | from .executable import Executable |
5 | 5 | ||
6 | class FTcat(Executable): | 6 | class FTcat(Executable): |
7 | '''Used to wrap the ftcat binary in the Experiment object.''' | 7 | '''Used to wrap the ftcat binary in the Experiment object.''' |
8 | 8 | ||
9 | def __init__(self, ft_cat_bin, stdout_file, stderr_file, dev, events, cpu=None): | 9 | def __init__(self, ft_cat_bin, stdout_file, stderr_file, dev, events, cpu=None): |
10 | '''Extends the Executable initializer method with ftcat attributes.''' | 10 | '''Extends the Executable initializer method with ftcat attributes.''' |
11 | super(FTcat, self).__init__('/usr/bin/taskset') | ||
11 | 12 | ||
12 | # hack to run FTCat at higher priority | ||
13 | chrt_bin = '/usr/bin/chrt' | ||
14 | |||
15 | super(FTcat, self).__init__(chrt_bin) | ||
16 | self.stdout_file = stdout_file | 13 | self.stdout_file = stdout_file |
17 | self.stderr_file = stderr_file | 14 | self.stderr_file = stderr_file |
18 | 15 | ||
@@ -23,11 +20,15 @@ class FTcat(Executable): | |||
23 | if events is None: | 20 | if events is None: |
24 | raise Exception('No events!') | 21 | raise Exception('No events!') |
25 | 22 | ||
26 | # hack to run FTCat at higher priority | ||
27 | self.extra_args = ['-f', '40'] | ||
28 | if cpu is not None: | 23 | if cpu is not None: |
29 | # and bind it to a CPU | 24 | # Execute only on the given CPU |
30 | self.extra_args.extend(['/usr/bin/taskset', '-c', str(cpu)]) | 25 | self.extra_args = ['-c', str(cpu)] |
26 | else: | ||
27 | # Execute on any cpu | ||
28 | self.extra_args = ['0xFFFFFFFF'] | ||
29 | |||
31 | events_str_arr = map(str, events) | 30 | events_str_arr = map(str, events) |
32 | self.extra_args.extend([ft_cat_bin, dev] + events_str_arr) | 31 | ft_cat_cmd = [ft_cat_bin, dev] + list(events_str_arr) |
32 | |||
33 | self.extra_args.extend(ft_cat_cmd) | ||
33 | 34 | ||
diff --git a/run/experiment.py b/run/experiment.py index c8fc228..ecb0241 100644 --- a/run/experiment.py +++ b/run/experiment.py | |||
@@ -1,8 +1,9 @@ | |||
1 | import os | 1 | import os |
2 | import time | 2 | import time |
3 | import litmus_util as lu | 3 | import run.litmus_util as lu |
4 | import shutil as sh | ||
4 | from operator import methodcaller | 5 | from operator import methodcaller |
5 | from tracer import SchedTracer, LogTracer, PerfTracer, LinuxTracer, OverheadTracer | 6 | from run.tracer import SchedTracer, LogTracer, PerfTracer, LinuxTracer, OverheadTracer |
6 | 7 | ||
7 | class ExperimentException(Exception): | 8 | class ExperimentException(Exception): |
8 | '''Used to indicate when there are problems with an experiment.''' | 9 | '''Used to indicate when there are problems with an experiment.''' |
@@ -78,6 +79,8 @@ class Experiment(object): | |||
78 | Experiment.INTERRUPTED_DIR) | 79 | Experiment.INTERRUPTED_DIR) |
79 | interrupted = "%s/%s" % (os.path.split(self.working_dir)[0], | 80 | interrupted = "%s/%s" % (os.path.split(self.working_dir)[0], |
80 | Experiment.INTERRUPTED_DIR) | 81 | Experiment.INTERRUPTED_DIR) |
82 | if os.path.exists(interrupted): | ||
83 | sh.rmtree(interrupted) | ||
81 | os.rename(self.working_dir, interrupted) | 84 | os.rename(self.working_dir, interrupted) |
82 | 85 | ||
83 | os.mkdir(self.working_dir) | 86 | os.mkdir(self.working_dir) |
@@ -154,7 +157,7 @@ class Experiment(object): | |||
154 | os.rename(self.working_dir, self.finished_dir) | 157 | os.rename(self.working_dir, self.finished_dir) |
155 | 158 | ||
156 | def log(self, msg): | 159 | def log(self, msg): |
157 | print "[Exp %s]: %s" % (self.name, msg) | 160 | print("[Exp %s]: %s" % (self.name, msg)) |
158 | 161 | ||
159 | def run_exp(self): | 162 | def run_exp(self): |
160 | succ = False | 163 | succ = False |
diff --git a/run/litmus_util.py b/run/litmus_util.py index ec1700e..8a7f87d 100644 --- a/run/litmus_util.py +++ b/run/litmus_util.py | |||
@@ -4,7 +4,6 @@ import subprocess | |||
4 | import os | 4 | import os |
5 | import stat | 5 | import stat |
6 | import config.config as conf | 6 | import config.config as conf |
7 | from common import get_config_option | ||
8 | 7 | ||
9 | def num_cpus(): | 8 | def num_cpus(): |
10 | '''Return the number of CPUs in the system.''' | 9 | '''Return the number of CPUs in the system.''' |
@@ -19,11 +18,12 @@ def num_cpus(): | |||
19 | return cpus | 18 | return cpus |
20 | 19 | ||
21 | def ft_freq(): | 20 | def ft_freq(): |
22 | '''The frequency (in MHz) of the clock used by feather trace.''' | 21 | umachine = subprocess.check_output(["uname", "-m"]) |
23 | if get_config_option('CPU_V7') == 'y': | 22 | |
23 | if re.match("armv7", umachine): | ||
24 | # Arm V7s use a millisecond timer | 24 | # Arm V7s use a millisecond timer |
25 | freq = 1000.0 | 25 | freq = 1000.0 |
26 | elif get_config_option('X86') == 'y': | 26 | elif re.match("x86", umachine): |
27 | # X86 timer is equal to processor clock | 27 | # X86 timer is equal to processor clock |
28 | reg = re.compile(r'^cpu MHz\s*:\s*(?P<FREQ>\d+)', re.M) | 28 | reg = re.compile(r'^cpu MHz\s*:\s*(?P<FREQ>\d+)', re.M) |
29 | with open('/proc/cpuinfo', 'r') as f: | 29 | with open('/proc/cpuinfo', 'r') as f: |
@@ -76,7 +76,7 @@ def is_device(dev): | |||
76 | return not (not mode & stat.S_IFCHR) | 76 | return not (not mode & stat.S_IFCHR) |
77 | 77 | ||
78 | def waiting_tasks(): | 78 | def waiting_tasks(): |
79 | reg = re.compile(r'^ready.*(?P<READY>\d+)$', re.M) | 79 | reg = re.compile(r'^ready.*?(?P<READY>\d+)$', re.M) |
80 | with open('/proc/litmus/stats', 'r') as f: | 80 | with open('/proc/litmus/stats', 'r') as f: |
81 | data = f.read() | 81 | data = f.read() |
82 | 82 | ||
diff --git a/run/tracer.py b/run/tracer.py index 5d00e86..723bcad 100644 --- a/run/tracer.py +++ b/run/tracer.py | |||
@@ -1,10 +1,9 @@ | |||
1 | import litmus_util | 1 | from . import litmus_util |
2 | import os | 2 | import os |
3 | import config.config as conf | 3 | import config.config as conf |
4 | 4 | ||
5 | from operator import methodcaller | 5 | from operator import methodcaller |
6 | from executable.ftcat import FTcat,Executable | 6 | from run.executable.ftcat import FTcat,Executable |
7 | |||
8 | 7 | ||
9 | class Tracer(object): | 8 | class Tracer(object): |
10 | def __init__(self, name, output_dir): | 9 | def __init__(self, name, output_dir): |
@@ -19,7 +18,6 @@ class Tracer(object): | |||
19 | map(methodcaller('terminate'), self.bins) | 18 | map(methodcaller('terminate'), self.bins) |
20 | map(methodcaller('wait'), self.bins) | 19 | map(methodcaller('wait'), self.bins) |
21 | 20 | ||
22 | |||
23 | class LinuxTracer(Tracer): | 21 | class LinuxTracer(Tracer): |
24 | EVENT_ROOT = "/sys/kernel/debug/tracing" | 22 | EVENT_ROOT = "/sys/kernel/debug/tracing" |
25 | LITMUS_EVENTS = "%s/events/litmus" % EVENT_ROOT | 23 | LITMUS_EVENTS = "%s/events/litmus" % EVENT_ROOT |
@@ -45,7 +43,6 @@ class LinuxTracer(Tracer): | |||
45 | map(methodcaller('interrupt'), self.bins) | 43 | map(methodcaller('interrupt'), self.bins) |
46 | map(methodcaller('wait'), self.bins) | 44 | map(methodcaller('wait'), self.bins) |
47 | 45 | ||
48 | |||
49 | class LogTracer(Tracer): | 46 | class LogTracer(Tracer): |
50 | DEVICE_STR = '/dev/litmus/log' | 47 | DEVICE_STR = '/dev/litmus/log' |
51 | 48 | ||
@@ -63,6 +60,9 @@ class LogTracer(Tracer): | |||
63 | def enabled(): | 60 | def enabled(): |
64 | return litmus_util.is_device(LogTracer.DEVICE_STR) | 61 | return litmus_util.is_device(LogTracer.DEVICE_STR) |
65 | 62 | ||
63 | def stop_tracing(self): | ||
64 | map(methodcaller('interrupt'), self.bins) | ||
65 | map(methodcaller('wait', False), self.bins) | ||
66 | 66 | ||
67 | class SchedTracer(Tracer): | 67 | class SchedTracer(Tracer): |
68 | DEVICE_STR = '/dev/litmus/sched_trace' | 68 | DEVICE_STR = '/dev/litmus/sched_trace' |
@@ -76,14 +76,14 @@ class SchedTracer(Tracer): | |||
76 | stdout_f = open('%s/st-%d.bin' % (self.output_dir, cpu), 'w') | 76 | stdout_f = open('%s/st-%d.bin' % (self.output_dir, cpu), 'w') |
77 | stderr_f = open('%s/st-%d-stderr.txt' % (self.output_dir, cpu), 'w') | 77 | stderr_f = open('%s/st-%d-stderr.txt' % (self.output_dir, cpu), 'w') |
78 | dev = '{0}{1}'.format(SchedTracer.DEVICE_STR, cpu) | 78 | dev = '{0}{1}'.format(SchedTracer.DEVICE_STR, cpu) |
79 | ftc = FTcat(conf.BINS['ftcat'], stdout_f, stderr_f, dev, conf.SCHED_EVENTS, cpu=cpu) | 79 | ftc = FTcat(conf.BINS['ftcat'], stdout_f, stderr_f, dev, |
80 | conf.SCHED_EVENTS, cpu=cpu) | ||
80 | 81 | ||
81 | self.bins.append(ftc) | 82 | self.bins.append(ftc) |
82 | 83 | ||
83 | @staticmethod | 84 | @staticmethod |
84 | def enabled(): | 85 | def enabled(): |
85 | return litmus_util.is_device("%s%d" % (SchedTracer.DEVICE_STR, 0)) | 86 | return litmus_util.is_device("%s%d" % (SchedTracer.DEVICE_STR, 0)) |
86 | |||
87 | 87 | ||
88 | class OverheadTracer(Tracer): | 88 | class OverheadTracer(Tracer): |
89 | DEVICE_STR = '/dev/litmus/ft_trace0' | 89 | DEVICE_STR = '/dev/litmus/ft_trace0' |
@@ -100,8 +100,7 @@ class OverheadTracer(Tracer): | |||
100 | 100 | ||
101 | @staticmethod | 101 | @staticmethod |
102 | def enabled(): | 102 | def enabled(): |
103 | return litmus_util.is_device(OverheadTracer.DEVICE_STR) | 103 | return litmus_util.is_device(OverheadTracer.DEVICE_STR) |
104 | |||
105 | 104 | ||
106 | class PerfTracer(Tracer): | 105 | class PerfTracer(Tracer): |
107 | def __init__(self, output_dir): | 106 | def __init__(self, output_dir): |
diff --git a/run_exps.py b/run_exps.py index 84e2b4c..195d3f8 100755 --- a/run_exps.py +++ b/run_exps.py | |||
@@ -50,7 +50,7 @@ def convert_data(data): | |||
50 | r"(?P<ENTRY>[\w\-\/]+)" | 50 | r"(?P<ENTRY>[\w\-\/]+)" |
51 | r"\s*{\s*(?P<CONTENT>.*?)\s*?}$)|" | 51 | r"\s*{\s*(?P<CONTENT>.*?)\s*?}$)|" |
52 | r"(?P<SPIN>^" | 52 | r"(?P<SPIN>^" |
53 | r"(?:(?P<TYPE>\w+) )?\s*" | 53 | r"(?:(?P<TYPE>[^\d\-]\w*?) )?\s*" |
54 | r"(?P<ARGS>[\w\-_\d\. \=]+)\s*$)", | 54 | r"(?P<ARGS>[\w\-_\d\. \=]+)\s*$)", |
55 | re.S|re.I|re.M) | 55 | re.S|re.I|re.M) |
56 | 56 | ||