diff options
| author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-04-10 14:35:37 -0400 |
|---|---|---|
| committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-04-10 14:35:37 -0400 |
| commit | 4162cc0c57de22566efa6e2dab224909279f2a47 (patch) | |
| tree | a8628096c4161e658c385b07b026371a2ef5e3c4 | |
| parent | 37a410ab7d4ba991a075a3b2f4d24a656f4544ca (diff) | |
run_exps will run any command whose last argument is the duration.
| -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 | ||
