diff options
-rw-r--r-- | common.py | 2 | ||||
-rw-r--r-- | config/config.py | 5 | ||||
-rw-r--r-- | run/experiment.py | 56 | ||||
-rw-r--r-- | run/tracer.py | 52 | ||||
-rwxr-xr-x | run_exps.py | 242 |
5 files changed, 230 insertions, 127 deletions
@@ -7,7 +7,7 @@ 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, optional=False): | 10 | def get_executable(prog, hint='unknown', optional=False): |
11 | '''Search for @prog in system PATH. Print @hint if no binary is found.''' | 11 | '''Search for @prog in system PATH. Print @hint if no binary is found.''' |
12 | 12 | ||
13 | def is_exe(fpath): | 13 | def is_exe(fpath): |
diff --git a/config/config.py b/config/config.py index 49fd234..3486a40 100644 --- a/config/config.py +++ b/config/config.py | |||
@@ -28,7 +28,10 @@ PARAMS = {'sched' : 'scheduler', # Scheduler used by run_exps | |||
28 | 'copts' : 'config-options', # Required kernel configuration options | 28 | 'copts' : 'config-options', # Required kernel configuration options |
29 | 'cycles' : 'clock-frequency', # Frequency run_exps was run with | 29 | 'cycles' : 'clock-frequency', # Frequency run_exps was run with |
30 | 'tasks' : 'tasks', # Number of tasks | 30 | 'tasks' : 'tasks', # Number of tasks |
31 | 'trial' : 'trial' # For multiple exps with same config | 31 | 'trial' : 'trial', # For multiple exps with same config |
32 | 'pre' : 'pre-experiment', # Run before each experiment | ||
33 | 'post' : 'post-experiment', # Run after each experiment | ||
34 | 'trace' : 'tracers' # Tracers to run with an experiment | ||
32 | } | 35 | } |
33 | 36 | ||
34 | '''Default values for program options.''' | 37 | '''Default values for program options.''' |
diff --git a/run/experiment.py b/run/experiment.py index 03d6ab6..3dd4866 100644 --- a/run/experiment.py +++ b/run/experiment.py | |||
@@ -3,7 +3,6 @@ import time | |||
3 | import run.litmus_util as lu | 3 | import run.litmus_util as lu |
4 | import shutil as sh | 4 | import shutil as sh |
5 | from operator import methodcaller | 5 | from operator import methodcaller |
6 | from run.tracer import SchedTracer, LogTracer, PerfTracer, LinuxTracer, OverheadTracer | ||
7 | 6 | ||
8 | class ExperimentException(Exception): | 7 | class ExperimentException(Exception): |
9 | '''Used to indicate when there are problems with an experiment.''' | 8 | '''Used to indicate when there are problems with an experiment.''' |
@@ -32,7 +31,8 @@ class Experiment(object): | |||
32 | '''Execute one task-set and save the results. Experiments have unique IDs.''' | 31 | '''Execute one task-set and save the results. Experiments have unique IDs.''' |
33 | INTERRUPTED_DIR = ".interrupted" | 32 | INTERRUPTED_DIR = ".interrupted" |
34 | 33 | ||
35 | def __init__(self, name, scheduler, working_dir, finished_dir, proc_entries, executables): | 34 | def __init__(self, name, scheduler, working_dir, finished_dir, |
35 | proc_entries, executables, tracer_types): | ||
36 | '''Run an experiment, optionally wrapped in tracing.''' | 36 | '''Run an experiment, optionally wrapped in tracing.''' |
37 | 37 | ||
38 | self.name = name | 38 | self.name = name |
@@ -46,27 +46,17 @@ class Experiment(object): | |||
46 | 46 | ||
47 | self.__make_dirs() | 47 | self.__make_dirs() |
48 | self.__assign_executable_cwds() | 48 | self.__assign_executable_cwds() |
49 | self.__setup_tracers(tracer_types) | ||
49 | 50 | ||
50 | self.tracers = [] | 51 | |
51 | if SchedTracer.enabled(): | 52 | def __setup_tracers(self, tracer_types): |
52 | self.log("Enabling sched_trace") | 53 | tracers = [ t(self.working_dir) for t in tracer_types ] |
53 | self.tracers.append( SchedTracer(working_dir) ) | 54 | |
54 | if LinuxTracer.enabled(): | 55 | self.regular_tracers = [t for t in tracers if not t.is_exact()] |
55 | self.log("Enabling trace-cmd") | 56 | self.exact_tracers = [t for t in tracers if t.is_exact()] |
56 | self.tracers.append( LinuxTracer(working_dir) ) | 57 | |
57 | if LogTracer.enabled(): | 58 | for t in tracers: |
58 | self.log("Enabling logging") | 59 | self.log("Enabling %s" % t.get_name()) |
59 | self.tracers.append( LogTracer(working_dir) ) | ||
60 | if PerfTracer.enabled(): | ||
61 | self.log("Tracking CPU performance counters") | ||
62 | self.tracers.append( PerfTracer(working_dir) ) | ||
63 | |||
64 | # Overhead trace must be handled seperately, see __run_tasks | ||
65 | if OverheadTracer.enabled(): | ||
66 | self.log("Enabling overhead tracing") | ||
67 | self.overhead_trace = OverheadTracer(working_dir) | ||
68 | else: | ||
69 | self.overhead_trace = None | ||
70 | 60 | ||
71 | def __make_dirs(self): | 61 | def __make_dirs(self): |
72 | interrupted = None | 62 | interrupted = None |
@@ -111,11 +101,10 @@ class Experiment(object): | |||
111 | raise Exception("Too much time has passed waiting for tasks!") | 101 | raise Exception("Too much time has passed waiting for tasks!") |
112 | time.sleep(1) | 102 | time.sleep(1) |
113 | 103 | ||
114 | # Overhead tracer must be started right after release or overhead | 104 | # Exact tracers (like overheads) must be started right after release or |
115 | # measurements will be full of irrelevant records | 105 | # measurements will be full of irrelevant records |
116 | if self.overhead_trace: | 106 | self.log("Starting %d released tracers" % len(self.exact_tracers)) |
117 | self.log("Starting overhead trace") | 107 | map(methodcaller('start_tracing'), self.exact_tracers) |
118 | self.overhead_trace.start_tracing() | ||
119 | 108 | ||
120 | self.log("Releasing %d tasks" % len(self.executables)) | 109 | self.log("Releasing %d tasks" % len(self.executables)) |
121 | released = lu.release_tasks() | 110 | released = lu.release_tasks() |
@@ -145,10 +134,9 @@ class Experiment(object): | |||
145 | if not e.wait(): | 134 | if not e.wait(): |
146 | ret = False | 135 | ret = False |
147 | 136 | ||
148 | # And it must be stopped here for the same reason | 137 | # And these must be stopped here for the same reason |
149 | if self.overhead_trace: | 138 | self.log("Stopping exact tracers") |
150 | self.log("Stopping overhead trace") | 139 | map(methodcaller('stop_tracing'), self.exact_tracers) |
151 | self.overhead_trace.stop_tracing() | ||
152 | 140 | ||
153 | if not ret: | 141 | if not ret: |
154 | raise ExperimentFailed(self.name) | 142 | raise ExperimentFailed(self.name) |
@@ -186,8 +174,8 @@ class Experiment(object): | |||
186 | self.log("Switching to %s" % self.scheduler) | 174 | self.log("Switching to %s" % self.scheduler) |
187 | lu.switch_scheduler(self.scheduler) | 175 | lu.switch_scheduler(self.scheduler) |
188 | 176 | ||
189 | self.log("Starting %d tracers" % len(self.tracers)) | 177 | self.log("Starting %d regular tracers" % len(self.regular_tracers)) |
190 | map(methodcaller('start_tracing'), self.tracers) | 178 | map(methodcaller('start_tracing'), self.regular_tracers) |
191 | 179 | ||
192 | self.exec_out = open('%s/exec-out.txt' % self.working_dir, 'w') | 180 | self.exec_out = open('%s/exec-out.txt' % self.working_dir, 'w') |
193 | self.exec_err = open('%s/exec-err.txt' % self.working_dir, 'w') | 181 | self.exec_err = open('%s/exec-err.txt' % self.working_dir, 'w') |
@@ -200,6 +188,6 @@ class Experiment(object): | |||
200 | self.exec_out and self.exec_out.close() | 188 | self.exec_out and self.exec_out.close() |
201 | self.exec_err and self.exec_err.close() | 189 | self.exec_err and self.exec_err.close() |
202 | 190 | ||
203 | self.log("Stopping tracers") | 191 | self.log("Stopping regular tracers") |
204 | map(methodcaller('stop_tracing'), self.tracers) | 192 | map(methodcaller('stop_tracing'), self.regular_tracers) |
205 | 193 | ||
diff --git a/run/tracer.py b/run/tracer.py index 065797c..6e1d05c 100644 --- a/run/tracer.py +++ b/run/tracer.py | |||
@@ -6,10 +6,17 @@ from operator import methodcaller | |||
6 | from run.executable.ftcat import FTcat,Executable | 6 | from run.executable.ftcat import FTcat,Executable |
7 | 7 | ||
8 | class Tracer(object): | 8 | class Tracer(object): |
9 | def __init__(self, name, output_dir): | 9 | def __init__(self, name, output_dir, exact=False): |
10 | self.name = name | 10 | self.name = name |
11 | self.output_dir = output_dir | 11 | self.output_dir = output_dir |
12 | self.bins = [] | 12 | self.bins = [] |
13 | self.exact=exact | ||
14 | |||
15 | def get_name(self): | ||
16 | return self.name | ||
17 | |||
18 | def is_exact(self): | ||
19 | return self.exact | ||
13 | 20 | ||
14 | def start_tracing(self): | 21 | def start_tracing(self): |
15 | map(methodcaller("execute"), self.bins) | 22 | map(methodcaller("execute"), self.bins) |
@@ -23,7 +30,7 @@ class LinuxTracer(Tracer): | |||
23 | LITMUS_EVENTS = "%s/events/litmus" % EVENT_ROOT | 30 | LITMUS_EVENTS = "%s/events/litmus" % EVENT_ROOT |
24 | 31 | ||
25 | def __init__(self, output_dir): | 32 | def __init__(self, output_dir): |
26 | super(LinuxTracer, self).__init__("trace-cmd", output_dir) | 33 | super(LinuxTracer, self).__init__("Trace-cmd / Kernelshark", output_dir) |
27 | 34 | ||
28 | extra_args = ["record", # "-e", "sched:sched_switch", | 35 | extra_args = ["record", # "-e", "sched:sched_switch", |
29 | "-e", "litmus:*", | 36 | "-e", "litmus:*", |
@@ -89,7 +96,7 @@ class OverheadTracer(Tracer): | |||
89 | DEVICE_STR = '/dev/litmus/ft_trace0' | 96 | DEVICE_STR = '/dev/litmus/ft_trace0' |
90 | 97 | ||
91 | def __init__(self, output_dir): | 98 | def __init__(self, output_dir): |
92 | super(OverheadTracer, self).__init__("Overhead Trace", output_dir) | 99 | super(OverheadTracer, self).__init__("Overhead Trace", output_dir, True) |
93 | 100 | ||
94 | stdout_f = open('{0}/{1}'.format(self.output_dir, conf.FILES['ft_data']), 'w') | 101 | stdout_f = open('{0}/{1}'.format(self.output_dir, conf.FILES['ft_data']), 'w') |
95 | stderr_f = open('{0}/{1}.stderr.txt'.format(self.output_dir, conf.FILES['ft_data']), 'w') | 102 | stderr_f = open('{0}/{1}.stderr.txt'.format(self.output_dir, conf.FILES['ft_data']), 'w') |
@@ -109,3 +116,42 @@ class PerfTracer(Tracer): | |||
109 | @staticmethod | 116 | @staticmethod |
110 | def enabled(): | 117 | def enabled(): |
111 | return False | 118 | return False |
119 | |||
120 | |||
121 | tracers = {} | ||
122 | |||
123 | def register_tracer(tracer, name): | ||
124 | tracers[name] = tracer | ||
125 | |||
126 | def get_tracer_types(names): | ||
127 | error = True # Error if name is not present | ||
128 | errors = [] | ||
129 | |||
130 | if not names: | ||
131 | # Just return all enabled tracers if none specified | ||
132 | names = tracers.keys() | ||
133 | error = False | ||
134 | |||
135 | ret = [] | ||
136 | |||
137 | for name in names: | ||
138 | if name not in tracers: | ||
139 | raise ValueError("Invalid tracer '%s', valid names are: %s" % | ||
140 | (name, tracers.keys())) | ||
141 | |||
142 | if tracers[name].enabled(): | ||
143 | ret += [ tracers[name] ] | ||
144 | elif error: | ||
145 | errors += ["Tracer '%s' requested, but not enabled." % name] | ||
146 | |||
147 | if errors: | ||
148 | raise ValueError("Check your kernel compile configuration!\n" + | ||
149 | "\n".join(errors)) | ||
150 | |||
151 | return ret | ||
152 | |||
153 | register_tracer(LinuxTracer, "kernelshark") | ||
154 | register_tracer(LogTracer, "log") | ||
155 | register_tracer(SchedTracer, "sched") | ||
156 | register_tracer(OverheadTracer, "overhead") | ||
157 | |||
diff --git a/run_exps.py b/run_exps.py index c51f4c6..6043931 100755 --- a/run_exps.py +++ b/run_exps.py | |||
@@ -7,6 +7,7 @@ import os | |||
7 | import re | 7 | import re |
8 | import shutil | 8 | import shutil |
9 | import sys | 9 | import sys |
10 | import run.tracer as trace | ||
10 | import traceback | 11 | import traceback |
11 | 12 | ||
12 | from collections import namedtuple | 13 | from collections import namedtuple |
@@ -15,6 +16,12 @@ from run.executable.executable import Executable | |||
15 | from run.experiment import Experiment,ExperimentDone | 16 | from run.experiment import Experiment,ExperimentDone |
16 | from run.proc_entry import ProcEntry | 17 | from run.proc_entry import ProcEntry |
17 | 18 | ||
19 | '''Customizable experiment parameters''' | ||
20 | ExpParams = namedtuple('ExpParams', ['scheduler', 'duration', 'tracers', | ||
21 | 'kernel', 'config_options']) | ||
22 | '''Comparison of requested versus actual kernel compile parameter value''' | ||
23 | ConfigResult = namedtuple('ConfigResult', ['param', 'wanted', 'actual']) | ||
24 | |||
18 | class InvalidKernel(Exception): | 25 | class InvalidKernel(Exception): |
19 | def __init__(self, kernel): | 26 | def __init__(self, kernel): |
20 | self.kernel = kernel | 27 | self.kernel = kernel |
@@ -22,7 +29,7 @@ class InvalidKernel(Exception): | |||
22 | def __str__(self): | 29 | def __str__(self): |
23 | return "Kernel name does not match '%s'." % self.kernel | 30 | return "Kernel name does not match '%s'." % self.kernel |
24 | 31 | ||
25 | ConfigResult = namedtuple('ConfigResult', ['param', 'wanted', 'actual']) | 32 | |
26 | class InvalidConfig(Exception): | 33 | class InvalidConfig(Exception): |
27 | def __init__(self, results): | 34 | def __init__(self, results): |
28 | self.results = results | 35 | self.results = results |
@@ -38,6 +45,7 @@ class InvalidConfig(Exception): | |||
38 | return "Invalid kernel configuration " +\ | 45 | return "Invalid kernel configuration " +\ |
39 | "(ignore configuration with -i option).\n" + "\n".join(messages) | 46 | "(ignore configuration with -i option).\n" + "\n".join(messages) |
40 | 47 | ||
48 | |||
41 | def parse_args(): | 49 | def parse_args(): |
42 | parser = OptionParser("usage: %prog [options] [sched_file]... [exp_dir]...") | 50 | parser = OptionParser("usage: %prog [options] [sched_file]... [exp_dir]...") |
43 | 51 | ||
@@ -92,6 +100,7 @@ def convert_data(data): | |||
92 | 100 | ||
93 | return {'proc' : procs, 'spin' : spins} | 101 | return {'proc' : procs, 'spin' : spins} |
94 | 102 | ||
103 | |||
95 | def fix_paths(schedule, exp_dir, sched_file): | 104 | def fix_paths(schedule, exp_dir, sched_file): |
96 | '''Replace relative paths of command line arguments with absolute ones.''' | 105 | '''Replace relative paths of command line arguments with absolute ones.''' |
97 | for (idx, (spin, args)) in enumerate(schedule['spin']): | 106 | for (idx, (spin, args)) in enumerate(schedule['spin']): |
@@ -106,97 +115,24 @@ def fix_paths(schedule, exp_dir, sched_file): | |||
106 | 115 | ||
107 | schedule['spin'][idx] = (spin, args) | 116 | schedule['spin'][idx] = (spin, args) |
108 | 117 | ||
109 | def verify_environment(kernel, copts): | ||
110 | if kernel and not com.uname_matches(kernel): | ||
111 | raise InvalidKernel(kernel) | ||
112 | |||
113 | if copts: | ||
114 | results = [] | ||
115 | for param, wanted in copts.iteritems(): | ||
116 | try: | ||
117 | actual = com.get_config_option(param) | ||
118 | except IOError: | ||
119 | actual = None | ||
120 | if not str(wanted) == str(actual): | ||
121 | results += [ConfigResult(param, wanted, actual)] | ||
122 | |||
123 | if results: | ||
124 | raise InvalidConfig(results) | ||
125 | |||
126 | def load_experiment(sched_file, scheduler, duration, | ||
127 | param_file, out_dir, ignore, jabber): | ||
128 | if not os.path.isfile(sched_file): | ||
129 | raise IOError("Cannot find schedule file: %s" % sched_file) | ||
130 | |||
131 | dir_name, fname = os.path.split(sched_file) | ||
132 | exp_name = os.path.split(dir_name)[1] + "/" + fname | ||
133 | |||
134 | params = {} | ||
135 | kernel = copts = "" | ||
136 | |||
137 | param_file = param_file or \ | ||
138 | "%s/%s" % (dir_name, conf.DEFAULTS['params_file']) | ||
139 | |||
140 | if os.path.isfile(param_file): | ||
141 | params = com.load_params(param_file) | ||
142 | scheduler = scheduler or params[conf.PARAMS['sched']] | ||
143 | duration = duration or params[conf.PARAMS['dur']] | ||
144 | |||
145 | # Experiments can specify required kernel name | ||
146 | if conf.PARAMS['kernel'] in params: | ||
147 | kernel = params[conf.PARAMS['kernel']] | ||
148 | # Or required config options | ||
149 | if conf.PARAMS['copts'] in params: | ||
150 | copts = params[conf.PARAMS['copts']] | ||
151 | |||
152 | duration = duration or conf.DEFAULTS['duration'] | ||
153 | |||
154 | if not scheduler: | ||
155 | raise IOError("Parameter scheduler not specified in %s" % (param_file)) | ||
156 | |||
157 | # Parse schedule file's intentions | ||
158 | schedule = load_schedule(sched_file) | ||
159 | work_dir = "%s/tmp" % dir_name | ||
160 | |||
161 | fix_paths(schedule, os.path.split(sched_file)[0], sched_file) | ||
162 | |||
163 | if not ignore: | ||
164 | verify_environment(kernel, copts) | ||
165 | |||
166 | run_exp(exp_name, schedule, scheduler, kernel, duration, work_dir, out_dir) | ||
167 | |||
168 | if jabber: | ||
169 | jabber.send("Completed '%s'" % exp_name) | ||
170 | |||
171 | # Save parameters used to run experiment in out_dir | ||
172 | out_params = dict(params.items() + | ||
173 | [(conf.PARAMS['sched'], scheduler), | ||
174 | (conf.PARAMS['tasks'], len(schedule['spin'])), | ||
175 | (conf.PARAMS['dur'], duration)]) | ||
176 | 118 | ||
177 | # Feather-trace clock frequency saved for accurate overhead parsing | 119 | def load_schedule(name, fname, duration): |
178 | ft_freq = com.ft_freq() | 120 | '''Turn schedule file @fname into ProcEntry's and Executable's which execute |
179 | if ft_freq: | 121 | for @duration time.''' |
180 | out_params[conf.PARAMS['cycles']] = ft_freq | ||
181 | |||
182 | with open("%s/%s" % (out_dir, conf.DEFAULTS['params_file']), 'w') as f: | ||
183 | f.write(str(out_params)) | ||
184 | |||
185 | def load_schedule(fname): | ||
186 | with open(fname, 'r') as f: | 122 | with open(fname, 'r') as f: |
187 | data = f.read().strip() | 123 | data = f.read().strip() |
188 | try: | 124 | try: |
189 | schedule = eval(data) | 125 | schedule = eval(data) |
190 | except: | 126 | except: |
191 | schedule = convert_data(data) | 127 | schedule = convert_data(data) |
192 | return schedule | ||
193 | 128 | ||
129 | # Make paths relative to the file's directory | ||
130 | fix_paths(schedule, os.path.split(fname)[0], fname) | ||
194 | 131 | ||
195 | def run_exp(name, schedule, scheduler, kernel, duration, work_dir, out_dir): | ||
196 | proc_entries = [] | 132 | proc_entries = [] |
197 | executables = [] | 133 | executables = [] |
198 | 134 | ||
199 | # Parse values for proc entries | 135 | # Create proc entries |
200 | for entry_conf in schedule['proc']: | 136 | for entry_conf in schedule['proc']: |
201 | path = entry_conf[0] | 137 | path = entry_conf[0] |
202 | data = entry_conf[1] | 138 | data = entry_conf[1] |
@@ -206,7 +142,7 @@ def run_exp(name, schedule, scheduler, kernel, duration, work_dir, out_dir): | |||
206 | 142 | ||
207 | proc_entries += [ProcEntry(path, data)] | 143 | proc_entries += [ProcEntry(path, data)] |
208 | 144 | ||
209 | # Parse spinners | 145 | # Create executables |
210 | for spin_conf in schedule['spin']: | 146 | for spin_conf in schedule['spin']: |
211 | if isinstance(spin_conf, str): | 147 | if isinstance(spin_conf, str): |
212 | # Just a string defaults to default spin | 148 | # Just a string defaults to default spin |
@@ -217,9 +153,6 @@ def run_exp(name, schedule, scheduler, kernel, duration, work_dir, out_dir): | |||
217 | raise IOError("Invalid spin conf %s: %s" % (spin_conf, name)) | 153 | raise IOError("Invalid spin conf %s: %s" % (spin_conf, name)) |
218 | (spin, args) = (spin_conf[0], spin_conf[1]) | 154 | (spin, args) = (spin_conf[0], spin_conf[1]) |
219 | 155 | ||
220 | # if not conf.BINS[spin]: | ||
221 | # raise IndexError("No knowledge of program %s: %s" % (spin, name)) | ||
222 | |||
223 | real_spin = com.get_executable(spin, "") | 156 | real_spin = com.get_executable(spin, "") |
224 | real_args = args.split() | 157 | real_args = args.split() |
225 | if re.match(".*spin", real_spin): | 158 | if re.match(".*spin", real_spin): |
@@ -230,21 +163,154 @@ def run_exp(name, schedule, scheduler, kernel, duration, work_dir, out_dir): | |||
230 | 163 | ||
231 | executables += [Executable(real_spin, real_args)] | 164 | executables += [Executable(real_spin, real_args)] |
232 | 165 | ||
233 | exp = Experiment(name, scheduler, work_dir, out_dir, | 166 | return proc_entries, executables |
234 | proc_entries, executables) | 167 | |
168 | |||
169 | def verify_environment(exp_params): | ||
170 | if exp_params.kernel and not com.uname_matches(exp_params.kernel): | ||
171 | raise InvalidKernel(exp_params.kernel) | ||
172 | |||
173 | if exp_params.config_options: | ||
174 | results = [] | ||
175 | for param, wanted in exp_params.config_options.iteritems(): | ||
176 | try: | ||
177 | actual = com.get_config_option(param) | ||
178 | except IOError: | ||
179 | actual = None | ||
180 | if not str(wanted) == str(actual): | ||
181 | results += [ConfigResult(param, wanted, actual)] | ||
182 | |||
183 | if results: | ||
184 | raise InvalidConfig(results) | ||
185 | |||
186 | |||
187 | def run_parameter(exp_dir, out_dir, params, param_name): | ||
188 | '''Run an executable (arguments optional) specified as a configurable | ||
189 | @param_name in @params.''' | ||
190 | if conf.PARAMS[param_name] not in params: | ||
191 | return | ||
192 | |||
193 | script_params = params[conf.PARAMS[param_name]] | ||
194 | |||
195 | # Split into arguments and program name | ||
196 | if type(script_params) != type([]): | ||
197 | script_params = [script_params] | ||
198 | script_name = script_params.pop(0) | ||
199 | |||
200 | cwd_name = "%s/%s" % (exp_dir, script_name) | ||
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 | |||
210 | out = open('%s/%s-out.txt' % (out_dir, param_name), 'w') | ||
211 | prog = Executable(script, script_params, | ||
212 | stderr_file=out, stdout_file=out) | ||
213 | prog.cwd = out_dir | ||
214 | |||
215 | prog.execute() | ||
216 | prog.wait() | ||
217 | |||
218 | out.close() | ||
219 | |||
220 | |||
221 | def get_exp_params(cmd_scheduler, cmd_duration, file_params): | ||
222 | kernel = copts = "" | ||
223 | |||
224 | scheduler = cmd_scheduler or file_params[conf.PARAMS['sched']] | ||
225 | duration = cmd_duration or file_params[conf.PARAMS['dur']] or\ | ||
226 | conf.DEFAULTS['duration'] | ||
227 | |||
228 | # Experiments can specify required kernel name | ||
229 | if conf.PARAMS['kernel'] in file_params: | ||
230 | kernel = file_params[conf.PARAMS['kernel']] | ||
231 | |||
232 | # Or required config options | ||
233 | if conf.PARAMS['copts'] in file_params: | ||
234 | copts = file_params[conf.PARAMS['copts']] | ||
235 | |||
236 | # Or required tracers | ||
237 | requested = [] | ||
238 | if conf.PARAMS['trace'] in file_params: | ||
239 | requested = file_params[conf.PARAMS['trace']] | ||
240 | tracers = trace.get_tracer_types(requested) | ||
241 | |||
242 | # But only these two are mandatory | ||
243 | if not scheduler: | ||
244 | raise IOError("No scheduler found in param file!") | ||
245 | if not duration: | ||
246 | raise IOError("No duration found in param file!") | ||
247 | |||
248 | return ExpParams(scheduler=scheduler, kernel=kernel, duration=duration, | ||
249 | config_options=copts, tracers=tracers) | ||
250 | |||
251 | |||
252 | def load_experiment(sched_file, cmd_scheduler, cmd_duration, | ||
253 | param_file, out_dir, ignore, jabber): | ||
254 | '''Load and parse data from files and run result.''' | ||
255 | if not os.path.isfile(sched_file): | ||
256 | raise IOError("Cannot find schedule file: %s" % sched_file) | ||
257 | |||
258 | dir_name, fname = os.path.split(sched_file) | ||
259 | exp_name = os.path.split(dir_name)[1] + "/" + fname | ||
260 | work_dir = "%s/tmp" % dir_name | ||
261 | |||
262 | # Load parameter file | ||
263 | param_file = param_file or \ | ||
264 | "%s/%s" % (dir_name, conf.DEFAULTS['params_file']) | ||
265 | if os.path.isfile(param_file): | ||
266 | file_params = com.load_params(param_file) | ||
267 | else: | ||
268 | file_params = {} | ||
269 | |||
270 | exp_params = get_exp_params(cmd_scheduler, cmd_duration, file_params) | ||
271 | procs, execs = load_schedule(exp_name, sched_file, exp_params.duration) | ||
272 | |||
273 | exp = Experiment(exp_name, exp_params.scheduler, work_dir, out_dir, | ||
274 | procs, execs, exp_params.tracers) | ||
275 | |||
276 | if not ignore: | ||
277 | verify_environment(exp_params) | ||
278 | |||
279 | run_parameter(dir_name, work_dir, file_params, 'pre') | ||
235 | 280 | ||
236 | exp.run_exp() | 281 | exp.run_exp() |
237 | 282 | ||
283 | run_parameter(dir_name, out_dir, file_params, 'post') | ||
284 | |||
285 | if jabber: | ||
286 | jabber.send("Completed '%s'" % exp_name) | ||
287 | |||
288 | # Save parameters used to run experiment in out_dir | ||
289 | out_params = dict(file_params.items() + | ||
290 | [(conf.PARAMS['sched'], exp_params.scheduler), | ||
291 | (conf.PARAMS['tasks'], len(execs)), | ||
292 | (conf.PARAMS['dur'], exp_params.duration)]) | ||
293 | |||
294 | # Feather-trace clock frequency saved for accurate overhead parsing | ||
295 | ft_freq = com.ft_freq() | ||
296 | if ft_freq: | ||
297 | out_params[conf.PARAMS['cycles']] = ft_freq | ||
298 | |||
299 | with open("%s/%s" % (out_dir, conf.DEFAULTS['params_file']), 'w') as f: | ||
300 | f.write(str(out_params)) | ||
301 | |||
302 | |||
238 | def setup_jabber(target): | 303 | def setup_jabber(target): |
239 | try: | 304 | try: |
240 | from run.jabber import Jabber | 305 | from run.jabber import Jabber |
241 | 306 | ||
242 | return Jabber(target) | 307 | return Jabber(target) |
243 | except ImportError: | 308 | except ImportError: |
244 | sys.stderr.write("Failed to import jabber. Is python-xmpppy "+\ | 309 | sys.stderr.write("Failed to import jabber, disabling messages. " + |
245 | "installed?\nDisabling Jabber messaging.\n") | 310 | "Is python-xmpp installed?") |
246 | return None | 311 | return None |
247 | 312 | ||
313 | |||
248 | def main(): | 314 | def main(): |
249 | opts, args = parse_args() | 315 | opts, args = parse_args() |
250 | 316 | ||