diff options
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | common.py | 47 | ||||
-rw-r--r-- | config/config.py | 20 | ||||
-rw-r--r-- | run/proc_entry.py | 5 | ||||
-rwxr-xr-x | run_exps.py | 71 |
5 files changed, 69 insertions, 76 deletions
@@ -99,7 +99,7 @@ Schedule files have one of the following two formats: | |||
99 | ..., | 99 | ..., |
100 | ('path/to/proc','proc_value') | 100 | ('path/to/proc','proc_value') |
101 | ], | 101 | ], |
102 | 'spin':[ | 102 | 'task':[ |
103 | ('real_time_task', 'task_arguments'), | 103 | ('real_time_task', 'task_arguments'), |
104 | ... | 104 | ... |
105 | ('real_time_task', 'task_arguments') | 105 | ('real_time_task', 'task_arguments') |
@@ -7,29 +7,34 @@ import sys | |||
7 | from collections import defaultdict | 7 | from collections import defaultdict |
8 | from textwrap import dedent | 8 | from textwrap import dedent |
9 | 9 | ||
10 | def get_executable(prog, hint='unknown', optional=False): | 10 | def get_executable(prog, cwd="."): |
11 | '''Search for @prog in system PATH. Print @hint if no binary is found.''' | 11 | '''Search for @prog in system PATH and @cwd.''' |
12 | 12 | ||
13 | def is_exe(fpath): | 13 | cwd_path = "%s/%s" % (cwd, prog) |
14 | return os.path.isfile(fpath) and os.access(fpath, os.X_OK) | 14 | if is_executable(cwd_path): |
15 | 15 | return cwd_path | |
16 | fpath, fname = os.path.split(prog) | ||
17 | if fpath: | ||
18 | if is_exe(prog): | ||
19 | return prog | ||
20 | else: | 16 | else: |
21 | for path in os.environ["PATH"].split(os.pathsep): | 17 | for path in os.environ["PATH"].split(os.pathsep): |
22 | exe_file = os.path.join(path, prog) | 18 | exe_file = os.path.join(path, prog) |
23 | if is_exe(exe_file): | 19 | if is_executable(exe_file): |
24 | return exe_file | 20 | return exe_file |
25 | 21 | ||
26 | if not optional: | 22 | full_cwd = os.path.abspath(cwd) |
27 | sys.stderr.write("Cannot find executable '%s' in PATH. This is a part " | 23 | raise IOError("Cannot find executable '%s'! (cwd='%s')" % (prog, full_cwd)) |
28 | "of '%s' which should be added to PATH to run.\n" % | 24 | |
29 | (prog, hint)) | 25 | def get_executable_hint(prog, hint, optional=False): |
30 | sys.exit(1) | 26 | '''Search for @prog in system PATH. Print @hint if no binary is found. |
31 | else: | 27 | Die if not @optional.''' |
32 | return None | 28 | try: |
29 | prog = get_executable(prog) | ||
30 | except IOError: | ||
31 | if not optional: | ||
32 | sys.stderr.write(("Cannot find executable '%s' in PATH. This is " +\ | ||
33 | "a part of '%s' which should be added to PATH.\n")\ | ||
34 | % (prog, hint)) | ||
35 | sys.exit(1) | ||
36 | |||
37 | return prog | ||
33 | 38 | ||
34 | def get_config_option(option): | 39 | def get_config_option(option): |
35 | '''Search for @option in installed kernel config (if present). | 40 | '''Search for @option in installed kernel config (if present). |
@@ -174,14 +179,12 @@ def ft_freq(): | |||
174 | return freq | 179 | return freq |
175 | 180 | ||
176 | 181 | ||
177 | def uname_matches(reg): | 182 | def kernel(): |
178 | data = subprocess.check_output(["uname", "-r"]) | 183 | return subprocess.check_output(["uname", "-r"]) |
179 | return bool( re.match(reg, data) ) | ||
180 | 184 | ||
181 | def is_executable(fname): | 185 | def is_executable(fname): |
182 | '''Return whether the file passed in is executable''' | 186 | '''Return whether the file passed in is executable''' |
183 | mode = os.stat(fname)[stat.ST_MODE] | 187 | return os.path.isfile(fname) and os.access(fname, os.X_OK) |
184 | return mode & stat.S_IXUSR and mode & stat.S_IRUSR | ||
185 | 188 | ||
186 | def is_device(dev): | 189 | def is_device(dev): |
187 | if not os.path.exists(dev): | 190 | if not os.path.exists(dev): |
diff --git a/config/config.py b/config/config.py index 3486a40..cbac6b2 100644 --- a/config/config.py +++ b/config/config.py | |||
@@ -1,18 +1,18 @@ | |||
1 | from __future__ import print_function | 1 | from __future__ import print_function |
2 | import itertools | 2 | import itertools |
3 | from common import get_executable,ft_freq | 3 | from common import get_executable_hint,ft_freq |
4 | 4 | ||
5 | '''Paths to binaries.''' | 5 | '''Paths to binaries.''' |
6 | BINS = {'rtspin' : get_executable('rtspin', 'liblitmus'), | 6 | BINS = {'rtspin' : get_executable_hint('rtspin', 'liblitmus'), |
7 | 'release' : get_executable('release_ts', 'liblitmus'), | 7 | 'release' : get_executable_hint('release_ts', 'liblitmus'), |
8 | 'ftcat' : get_executable('ftcat', 'feather-trace-tools'), | 8 | 'ftcat' : get_executable_hint('ftcat', 'feather-trace-tools'), |
9 | 'ftsplit' : get_executable('ft2csv', 'feather-trace-tools'), | 9 | 'ftsplit' : get_executable_hint('ft2csv', 'feather-trace-tools'), |
10 | 'ftsort' : get_executable('ftsort', 'feather-trace-tools'), | 10 | 'ftsort' : get_executable_hint('ftsort', 'feather-trace-tools'), |
11 | 'st_trace' : get_executable('st_trace', 'feather-trace-tools'), | 11 | 'st_trace' : get_executable_hint('st_trace', 'feather-trace-tools'), |
12 | # Option, as not everyone uses kernelshark yet | 12 | # Option, as not everyone uses kernelshark yet |
13 | 'trace-cmd' : get_executable('trace-cmd', 'rt-kernelshark', True), | 13 | 'trace-cmd' : get_executable_hint('trace-cmd', 'rt-kernelshark', True), |
14 | # Optional, as sched_trace is not a publically supported repository | 14 | # Optional, as sched_trace is not a publically supported repository |
15 | 'st_show' : get_executable('st_show', 'sched_trace', True)} | 15 | 'st_show' : get_executable_hint('st_show', 'sched_trace', True)} |
16 | 16 | ||
17 | '''Names of output files.''' | 17 | '''Names of output files.''' |
18 | FILES = {'ft_data' : 'ft.bin', | 18 | FILES = {'ft_data' : 'ft.bin', |
@@ -38,7 +38,7 @@ PARAMS = {'sched' : 'scheduler', # Scheduler used by run_exps | |||
38 | DEFAULTS = {'params_file' : 'params.py', | 38 | DEFAULTS = {'params_file' : 'params.py', |
39 | 'sched_file' : 'sched.py', | 39 | 'sched_file' : 'sched.py', |
40 | 'duration' : 10, | 40 | 'duration' : 10, |
41 | 'spin' : 'rtspin', | 41 | 'prog' : 'rtspin', |
42 | 'cycles' : ft_freq() or 2000} | 42 | 'cycles' : ft_freq() or 2000} |
43 | 43 | ||
44 | '''Default sched_trace events (this is all of them).''' | 44 | '''Default sched_trace events (this is all of them).''' |
diff --git a/run/proc_entry.py b/run/proc_entry.py index 4ac2c51..56f7c24 100644 --- a/run/proc_entry.py +++ b/run/proc_entry.py | |||
@@ -5,9 +5,10 @@ class ProcEntry(object): | |||
5 | self.proc = proc | 5 | self.proc = proc |
6 | self.data = data | 6 | self.data = data |
7 | 7 | ||
8 | def write_proc(self): | ||
9 | if not os.path.exists(self.proc): | 8 | if not os.path.exists(self.proc): |
10 | raise Exception("Invalid proc entry %s" % self.proc) | 9 | raise ValueError("Invalid proc entry %s" % self.proc) |
10 | |||
11 | def write_proc(self): | ||
11 | try: | 12 | try: |
12 | with open(self.proc, 'w') as entry: | 13 | with open(self.proc, 'w') as entry: |
13 | entry.write(self.data) | 14 | entry.write(self.data) |
diff --git a/run_exps.py b/run_exps.py index 6043931..77c9631 100755 --- a/run_exps.py +++ b/run_exps.py | |||
@@ -79,13 +79,13 @@ def convert_data(data): | |||
79 | r"(?P<HEADER>/proc/[\w\-]+?/)?" | 79 | r"(?P<HEADER>/proc/[\w\-]+?/)?" |
80 | r"(?P<ENTRY>[\w\-\/]+)" | 80 | r"(?P<ENTRY>[\w\-\/]+)" |
81 | r"\s*{\s*(?P<CONTENT>.*?)\s*?}$)|" | 81 | r"\s*{\s*(?P<CONTENT>.*?)\s*?}$)|" |
82 | r"(?P<SPIN>^" | 82 | r"(?P<TASK>^" |
83 | r"(?:(?P<TYPE>[^\d\-\s]\w*?) )?\s*" | 83 | r"(?:(?P<PROG>[^\d\-\s][\w\.]*?) )?\s*" |
84 | r"(?P<ARGS>[\w\-_\d\. \=]+)\s*$)", | 84 | r"(?P<ARGS>[\w\-_\d\. \=]+)\s*$)", |
85 | re.S|re.I|re.M) | 85 | re.S|re.I|re.M) |
86 | 86 | ||
87 | procs = [] | 87 | procs = [] |
88 | spins = [] | 88 | tasks = [] |
89 | 89 | ||
90 | for match in regex.finditer(data): | 90 | for match in regex.finditer(data): |
91 | if match.group("PROC"): | 91 | if match.group("PROC"): |
@@ -94,16 +94,16 @@ def convert_data(data): | |||
94 | proc = (loc, match.group("CONTENT")) | 94 | proc = (loc, match.group("CONTENT")) |
95 | procs.append(proc) | 95 | procs.append(proc) |
96 | else: | 96 | else: |
97 | prog = match.group("TYPE") or "rtspin" | 97 | prog = match.group("PROG") or conf.DEFAULTS['prog'] |
98 | spin = (prog, match.group("ARGS")) | 98 | spin = (prog, match.group("ARGS")) |
99 | spins.append(spin) | 99 | tasks.append(spin) |
100 | 100 | ||
101 | return {'proc' : procs, 'spin' : spins} | 101 | return {'proc' : procs, 'task' : tasks} |
102 | 102 | ||
103 | 103 | ||
104 | def fix_paths(schedule, exp_dir, sched_file): | 104 | def fix_paths(schedule, exp_dir, sched_file): |
105 | '''Replace relative paths of command line arguments with absolute ones.''' | 105 | '''Replace relative paths of command line arguments with absolute ones.''' |
106 | for (idx, (spin, args)) in enumerate(schedule['spin']): | 106 | for (idx, (task, args)) in enumerate(schedule['task']): |
107 | for arg in re.split(" +", args): | 107 | for arg in re.split(" +", args): |
108 | abspath = "%s/%s" % (exp_dir, arg) | 108 | abspath = "%s/%s" % (exp_dir, arg) |
109 | if os.path.exists(abspath): | 109 | if os.path.exists(abspath): |
@@ -113,7 +113,7 @@ def fix_paths(schedule, exp_dir, sched_file): | |||
113 | print("WARNING: non-existent file '%s' may be referenced:\n\t%s" | 113 | print("WARNING: non-existent file '%s' may be referenced:\n\t%s" |
114 | % (arg, sched_file)) | 114 | % (arg, sched_file)) |
115 | 115 | ||
116 | schedule['spin'][idx] = (spin, args) | 116 | schedule['task'][idx] = (task, args) |
117 | 117 | ||
118 | 118 | ||
119 | def load_schedule(name, fname, duration): | 119 | def load_schedule(name, fname, duration): |
@@ -126,48 +126,43 @@ def load_schedule(name, fname, duration): | |||
126 | except: | 126 | except: |
127 | schedule = convert_data(data) | 127 | schedule = convert_data(data) |
128 | 128 | ||
129 | sched_dir = os.path.split(fname)[0] | ||
130 | |||
129 | # Make paths relative to the file's directory | 131 | # Make paths relative to the file's directory |
130 | fix_paths(schedule, os.path.split(fname)[0], fname) | 132 | fix_paths(schedule, sched_dir, fname) |
131 | 133 | ||
132 | proc_entries = [] | 134 | proc_entries = [] |
133 | executables = [] | 135 | executables = [] |
134 | 136 | ||
135 | # Create proc entries | 137 | # Create proc entries |
136 | for entry_conf in schedule['proc']: | 138 | for entry_conf in schedule['proc']: |
137 | path = entry_conf[0] | 139 | proc_entries += [ProcEntry(*entry_conf)] |
138 | data = entry_conf[1] | ||
139 | 140 | ||
140 | if not os.path.exists(path): | 141 | # Create executables |
141 | raise IOError("Invalid proc path %s: %s" % (path, name)) | 142 | for task_conf in schedule['task']: |
143 | if len(task_conf) != 2: | ||
144 | raise Exception("Invalid task conf %s: %s" % (task_conf, name)) | ||
142 | 145 | ||
143 | proc_entries += [ProcEntry(path, data)] | 146 | (task, args) = (task_conf[0], task_conf[1]) |
144 | 147 | ||
145 | # Create executables | 148 | real_task = com.get_executable(task, sched_dir) |
146 | for spin_conf in schedule['spin']: | ||
147 | if isinstance(spin_conf, str): | ||
148 | # Just a string defaults to default spin | ||
149 | (spin, args) = (conf.DEFAULTS['spin'], spin_conf) | ||
150 | else: | ||
151 | # Otherwise its a pair, the type and the args | ||
152 | if len(spin_conf) != 2: | ||
153 | raise IOError("Invalid spin conf %s: %s" % (spin_conf, name)) | ||
154 | (spin, args) = (spin_conf[0], spin_conf[1]) | ||
155 | 149 | ||
156 | real_spin = com.get_executable(spin, "") | 150 | # Last argument must always be duration |
157 | real_args = args.split() | 151 | real_args = args.split() + [duration] |
158 | if re.match(".*spin", real_spin): | ||
159 | real_args = ['-w'] + real_args + [duration] | ||
160 | 152 | ||
161 | if not com.is_executable(real_spin): | 153 | # All spins take a -w flag |
162 | raise OSError("Cannot run spin %s: %s" % (real_spin, name)) | 154 | if re.match(".*spin$", real_task) and '-w' not in real_args: |
155 | real_args = ['-w'] + real_args | ||
163 | 156 | ||
164 | executables += [Executable(real_spin, real_args)] | 157 | executables += [Executable(real_task, real_args)] |
165 | 158 | ||
166 | return proc_entries, executables | 159 | return proc_entries, executables |
167 | 160 | ||
168 | 161 | ||
169 | def verify_environment(exp_params): | 162 | def verify_environment(exp_params): |
170 | if exp_params.kernel and not com.uname_matches(exp_params.kernel): | 163 | '''Raise an exception if the current system doesn't match that required |
164 | by @exp_params.''' | ||
165 | if exp_params.kernel and not re.match(exp_params.kernel, com.kernel()): | ||
171 | raise InvalidKernel(exp_params.kernel) | 166 | raise InvalidKernel(exp_params.kernel) |
172 | 167 | ||
173 | if exp_params.config_options: | 168 | if exp_params.config_options: |
@@ -197,15 +192,7 @@ def run_parameter(exp_dir, out_dir, params, param_name): | |||
197 | script_params = [script_params] | 192 | script_params = [script_params] |
198 | script_name = script_params.pop(0) | 193 | script_name = script_params.pop(0) |
199 | 194 | ||
200 | cwd_name = "%s/%s" % (exp_dir, script_name) | 195 | script = com.get_executable(script_name, cwd=exp_dir) |
201 | if os.path.isfile(cwd_name): | ||
202 | script = cwd_name | ||
203 | else: | ||
204 | script = com.get_executable(script_name, optional=True) | ||
205 | |||
206 | if not script: | ||
207 | raise Exception("Cannot find executable %s-script: %s" % | ||
208 | (param_name, script_name)) | ||
209 | 196 | ||
210 | out = open('%s/%s-out.txt' % (out_dir, param_name), 'w') | 197 | out = open('%s/%s-out.txt' % (out_dir, param_name), 'w') |
211 | prog = Executable(script, script_params, | 198 | prog = Executable(script, script_params, |
@@ -219,6 +206,7 @@ def run_parameter(exp_dir, out_dir, params, param_name): | |||
219 | 206 | ||
220 | 207 | ||
221 | def get_exp_params(cmd_scheduler, cmd_duration, file_params): | 208 | def get_exp_params(cmd_scheduler, cmd_duration, file_params): |
209 | '''Return ExpParam with configured values of all hardcoded params.''' | ||
222 | kernel = copts = "" | 210 | kernel = copts = "" |
223 | 211 | ||
224 | scheduler = cmd_scheduler or file_params[conf.PARAMS['sched']] | 212 | scheduler = cmd_scheduler or file_params[conf.PARAMS['sched']] |
@@ -267,6 +255,7 @@ def load_experiment(sched_file, cmd_scheduler, cmd_duration, | |||
267 | else: | 255 | else: |
268 | file_params = {} | 256 | file_params = {} |
269 | 257 | ||
258 | # Create input needed by Experiment | ||
270 | exp_params = get_exp_params(cmd_scheduler, cmd_duration, file_params) | 259 | exp_params = get_exp_params(cmd_scheduler, cmd_duration, file_params) |
271 | procs, execs = load_schedule(exp_name, sched_file, exp_params.duration) | 260 | procs, execs = load_schedule(exp_name, sched_file, exp_params.duration) |
272 | 261 | ||