diff options
Diffstat (limited to 'run_exps.py')
-rwxr-xr-x | run_exps.py | 170 |
1 files changed, 92 insertions, 78 deletions
diff --git a/run_exps.py b/run_exps.py index d7a06b5..a15018d 100755 --- a/run_exps.py +++ b/run_exps.py | |||
@@ -12,12 +12,13 @@ from config.config import PARAMS,DEFAULTS | |||
12 | from collections import namedtuple | 12 | from collections import namedtuple |
13 | from optparse import OptionParser | 13 | from optparse import OptionParser |
14 | from run.executable.executable import Executable | 14 | from run.executable.executable import Executable |
15 | from run.experiment import Experiment,ExperimentDone,ExperimentFailed,SystemCorrupted | 15 | from run.experiment import Experiment,ExperimentDone,SystemCorrupted |
16 | from run.proc_entry import ProcEntry | 16 | from run.proc_entry import ProcEntry |
17 | 17 | ||
18 | '''Customizable experiment parameters''' | 18 | '''Customizable experiment parameters''' |
19 | ExpParams = namedtuple('ExpParams', ['scheduler', 'duration', 'tracers', | 19 | ExpParams = namedtuple('ExpParams', ['scheduler', 'duration', 'tracers', |
20 | 'kernel', 'config_options']) | 20 | 'kernel', 'config_options', 'file_params', |
21 | 'pre_script', 'post_script']) | ||
21 | '''Comparison of requested versus actual kernel compile parameter value''' | 22 | '''Comparison of requested versus actual kernel compile parameter value''' |
22 | ConfigResult = namedtuple('ConfigResult', ['param', 'wanted', 'actual']) | 23 | ConfigResult = namedtuple('ConfigResult', ['param', 'wanted', 'actual']) |
23 | 24 | ||
@@ -113,8 +114,8 @@ def fix_paths(schedule, exp_dir, sched_file): | |||
113 | args = args.replace(arg, abspath) | 114 | args = args.replace(arg, abspath) |
114 | break | 115 | break |
115 | elif re.match(r'.*\w+\.[a-zA-Z]\w*', arg): | 116 | elif re.match(r'.*\w+\.[a-zA-Z]\w*', arg): |
116 | print("WARNING: non-existent file '%s' may be referenced:\n\t%s" | 117 | sys.stderr.write("WARNING: non-existent file '%s' " % arg + |
117 | % (arg, sched_file)) | 118 | "may be referenced:\n\t%s" % sched_file) |
118 | 119 | ||
119 | schedule['task'][idx] = (task, args) | 120 | schedule['task'][idx] = (task, args) |
120 | 121 | ||
@@ -182,22 +183,21 @@ def verify_environment(exp_params): | |||
182 | raise InvalidConfig(results) | 183 | raise InvalidConfig(results) |
183 | 184 | ||
184 | 185 | ||
185 | def run_parameter(exp_dir, out_dir, params, param_name): | 186 | def run_script(script_params, exp, exp_dir, out_dir): |
186 | '''Run an executable (arguments optional) specified as a configurable | 187 | '''Run an executable (arguments optional)''' |
187 | @param_name in @params.''' | 188 | if not script_params: |
188 | if PARAMS[param_name] not in params: | ||
189 | return | 189 | return |
190 | 190 | ||
191 | script_params = params[PARAMS[param_name]] | ||
192 | |||
193 | # Split into arguments and program name | 191 | # Split into arguments and program name |
194 | if type(script_params) != type([]): | 192 | if type(script_params) != type([]): |
195 | script_params = [script_params] | 193 | script_params = [script_params] |
196 | script_name = script_params.pop(0) | ||
197 | 194 | ||
195 | exp.log("Running %s" % script_params.join(" ")) | ||
196 | |||
197 | script_name = script_params.pop(0) | ||
198 | script = com.get_executable(script_name, cwd=exp_dir) | 198 | script = com.get_executable(script_name, cwd=exp_dir) |
199 | 199 | ||
200 | out = open('%s/%s-out.txt' % (out_dir, param_name), 'w') | 200 | out = open('%s/%s-out.txt' % (out_dir, script_name), 'w') |
201 | prog = Executable(script, script_params, cwd=out_dir, | 201 | prog = Executable(script, script_params, cwd=out_dir, |
202 | stderr_file=out, stdout_file=out) | 202 | stderr_file=out, stdout_file=out) |
203 | 203 | ||
@@ -207,28 +207,41 @@ def run_parameter(exp_dir, out_dir, params, param_name): | |||
207 | out.close() | 207 | out.close() |
208 | 208 | ||
209 | 209 | ||
210 | def get_exp_params(cmd_scheduler, cmd_duration, file_params): | 210 | def make_exp_params(cmd_scheduler, cmd_duration, sched_dir, param_file): |
211 | '''Return ExpParam with configured values of all hardcoded params.''' | 211 | '''Return ExpParam with configured values of all hardcoded params.''' |
212 | kernel = copts = "" | 212 | kernel = copts = "" |
213 | 213 | ||
214 | scheduler = cmd_scheduler or file_params[PARAMS['sched']] | 214 | # Load parameter file |
215 | duration = cmd_duration or file_params[PARAMS['dur']] or\ | 215 | param_file = param_file or "%s/%s" % (sched_dir, DEFAULTS['params_file']) |
216 | if os.path.isfile(param_file): | ||
217 | fparams = com.load_params(param_file) | ||
218 | else: | ||
219 | fparams = {} | ||
220 | |||
221 | scheduler = cmd_scheduler or fparams[PARAMS['sched']] | ||
222 | duration = cmd_duration or fparams[PARAMS['dur']] or\ | ||
216 | DEFAULTS['duration'] | 223 | DEFAULTS['duration'] |
217 | 224 | ||
218 | # Experiments can specify required kernel name | 225 | # Experiments can specify required kernel name |
219 | if PARAMS['kernel'] in file_params: | 226 | if PARAMS['kernel'] in fparams: |
220 | kernel = file_params[PARAMS['kernel']] | 227 | kernel = fparams[PARAMS['kernel']] |
221 | 228 | ||
222 | # Or required config options | 229 | # Or required config options |
223 | if PARAMS['copts'] in file_params: | 230 | if PARAMS['copts'] in fparams: |
224 | copts = file_params[PARAMS['copts']] | 231 | copts = fparams[PARAMS['copts']] |
225 | 232 | ||
226 | # Or required tracers | 233 | # Or required tracers |
227 | requested = [] | 234 | requested = [] |
228 | if PARAMS['trace'] in file_params: | 235 | if PARAMS['trace'] in fparams: |
229 | requested = file_params[PARAMS['trace']] | 236 | requested = fparams[PARAMS['trace']] |
230 | tracers = trace.get_tracer_types(requested) | 237 | tracers = trace.get_tracer_types(requested) |
231 | 238 | ||
239 | # Or scripts to run before and after experiments | ||
240 | def get_script(name): | ||
241 | return fparams[name] if name in fparams else None | ||
242 | pre_script = get_script('pre') | ||
243 | post_script = get_script('post') | ||
244 | |||
232 | # But only these two are mandatory | 245 | # But only these two are mandatory |
233 | if not scheduler: | 246 | if not scheduler: |
234 | raise IOError("No scheduler found in param file!") | 247 | raise IOError("No scheduler found in param file!") |
@@ -236,48 +249,39 @@ def get_exp_params(cmd_scheduler, cmd_duration, file_params): | |||
236 | raise IOError("No duration found in param file!") | 249 | raise IOError("No duration found in param file!") |
237 | 250 | ||
238 | return ExpParams(scheduler=scheduler, kernel=kernel, duration=duration, | 251 | return ExpParams(scheduler=scheduler, kernel=kernel, duration=duration, |
239 | config_options=copts, tracers=tracers) | 252 | config_options=copts, tracers=tracers, file_params=fparams, |
240 | 253 | pre_script=pre_script, post_script=post_script) | |
241 | 254 | ||
242 | def load_experiment(sched_file, cmd_scheduler, cmd_duration, | 255 | def run_experiment(name, sched_file, exp_params, out_dir, |
243 | param_file, out_dir, ignore, jabber): | 256 | start_message, ignore, jabber): |
244 | '''Load and parse data from files and run result.''' | 257 | '''Load and parse data from files and run result.''' |
245 | if not os.path.isfile(sched_file): | 258 | if not os.path.isfile(sched_file): |
246 | raise IOError("Cannot find schedule file: %s" % sched_file) | 259 | raise IOError("Cannot find schedule file: %s" % sched_file) |
247 | 260 | ||
248 | dir_name, fname = os.path.split(sched_file) | 261 | dir_name, fname = os.path.split(sched_file) |
249 | exp_name = os.path.split(dir_name)[1] + "/" + fname | ||
250 | work_dir = "%s/tmp" % dir_name | 262 | work_dir = "%s/tmp" % dir_name |
251 | 263 | ||
252 | # Load parameter file | 264 | procs, execs = load_schedule(name, sched_file, exp_params.duration) |
253 | param_file = param_file or \ | ||
254 | "%s/%s" % (dir_name, DEFAULTS['params_file']) | ||
255 | if os.path.isfile(param_file): | ||
256 | file_params = com.load_params(param_file) | ||
257 | else: | ||
258 | file_params = {} | ||
259 | |||
260 | # Create input needed by Experiment | ||
261 | exp_params = get_exp_params(cmd_scheduler, cmd_duration, file_params) | ||
262 | procs, execs = load_schedule(exp_name, sched_file, exp_params.duration) | ||
263 | 265 | ||
264 | exp = Experiment(exp_name, exp_params.scheduler, work_dir, out_dir, | 266 | exp = Experiment(name, exp_params.scheduler, work_dir, out_dir, |
265 | procs, execs, exp_params.tracers) | 267 | procs, execs, exp_params.tracers) |
266 | 268 | ||
269 | exp.log(start_message) | ||
270 | |||
267 | if not ignore: | 271 | if not ignore: |
268 | verify_environment(exp_params) | 272 | verify_environment(exp_params) |
269 | 273 | ||
270 | run_parameter(dir_name, work_dir, file_params, 'pre') | 274 | run_script(exp_params.pre_script, exp, dir_name, work_dir) |
271 | 275 | ||
272 | exp.run_exp() | 276 | exp.run_exp() |
273 | 277 | ||
274 | run_parameter(dir_name, out_dir, file_params, 'post') | 278 | run_script(exp_params.post_script, exp, dir_name, out_dir) |
275 | 279 | ||
276 | if jabber: | 280 | if jabber: |
277 | jabber.send("Completed '%s'" % exp_name) | 281 | jabber.send("Completed '%s'" % name) |
278 | 282 | ||
279 | # Save parameters used to run experiment in out_dir | 283 | # Save parameters used to run experiment in out_dir |
280 | out_params = dict(file_params.items() + | 284 | out_params = dict(exp_params.file_params.items() + |
281 | [(PARAMS['sched'], exp_params.scheduler), | 285 | [(PARAMS['sched'], exp_params.scheduler), |
282 | (PARAMS['tasks'], len(execs)), | 286 | (PARAMS['tasks'], len(execs)), |
283 | (PARAMS['dur'], exp_params.duration)]) | 287 | (PARAMS['dur'], exp_params.duration)]) |
@@ -292,6 +296,7 @@ def load_experiment(sched_file, cmd_scheduler, cmd_duration, | |||
292 | 296 | ||
293 | 297 | ||
294 | def get_exps(opts, args): | 298 | def get_exps(opts, args): |
299 | '''Return list of experiment files or directories''' | ||
295 | if args: | 300 | if args: |
296 | return args | 301 | return args |
297 | 302 | ||
@@ -333,63 +338,72 @@ def setup_email(target): | |||
333 | return None | 338 | return None |
334 | 339 | ||
335 | 340 | ||
341 | def make_paths(exp, out_base_dir, opts): | ||
342 | '''Translate experiment name to (schedule file, output directory) paths''' | ||
343 | path = "%s/%s" % (os.getcwd(), exp) | ||
344 | out_dir = "%s/%s" % (out_base_dir, os.path.split(exp.strip('/'))[1]) | ||
345 | |||
346 | if not os.path.exists(path): | ||
347 | raise IOError("Invalid experiment: %s" % path) | ||
348 | |||
349 | if opts.force and os.path.exists(out_dir): | ||
350 | shutil.rmtree(out_dir) | ||
351 | |||
352 | if os.path.isdir(path): | ||
353 | sched_file = "%s/%s" % (path, opts.sched_file) | ||
354 | else: | ||
355 | sched_file = path | ||
356 | |||
357 | return sched_file, out_dir | ||
358 | |||
359 | |||
336 | def main(): | 360 | def main(): |
337 | opts, args = parse_args() | 361 | opts, args = parse_args() |
338 | 362 | ||
339 | scheduler = opts.scheduler | ||
340 | duration = opts.duration | ||
341 | param_file = opts.param_file | ||
342 | out_base = os.path.abspath(opts.out_dir) | ||
343 | |||
344 | exps = get_exps(opts, args) | 363 | exps = get_exps(opts, args) |
345 | 364 | ||
346 | created = False | 365 | jabber = setup_jabber(opts.jabber) if opts.jabber else None |
366 | email = setup_email(opts.email) if opts.email else None | ||
367 | |||
368 | out_base = os.path.abspath(opts.out_dir) | ||
369 | created = False | ||
347 | if not os.path.exists(out_base): | 370 | if not os.path.exists(out_base): |
348 | created = True | 371 | created = True |
349 | os.mkdir(out_base) | 372 | os.mkdir(out_base) |
350 | 373 | ||
351 | ran = 0 | 374 | ran = done = succ = failed = invalid = 0 |
352 | done = 0 | ||
353 | succ = 0 | ||
354 | failed = 0 | ||
355 | invalid = 0 | ||
356 | |||
357 | jabber = setup_jabber(opts.jabber) if opts.jabber else None | ||
358 | email = setup_email(opts.email) if opts.email else None | ||
359 | |||
360 | for exp in exps: | ||
361 | path = "%s/%s" % (os.getcwd(), exp) | ||
362 | out_dir = "%s/%s" % (out_base, os.path.split(exp.strip('/'))[1]) | ||
363 | 375 | ||
364 | if not os.path.exists(path): | 376 | for i, exp in enumerate(exps): |
365 | raise IOError("Invalid experiment: %s" % path) | 377 | sched_file, out_dir = make_paths(exp, out_base, opts) |
378 | sched_dir = os.path.split(sched_file)[0] | ||
366 | 379 | ||
367 | if opts.force and os.path.exists(out_dir): | 380 | try: |
368 | shutil.rmtree(out_dir) | 381 | start_message = "Loading experiment %d of %d." % (i+1, len(exps)) |
382 | exp_params = make_exp_params(opts.scheduler, opts.duration, | ||
383 | sched_dir, opts.param_file) | ||
369 | 384 | ||
370 | if os.path.isdir(exp): | 385 | run_experiment(exp, sched_file, exp_params, out_dir, |
371 | path = "%s/%s" % (path, opts.sched_file) | 386 | start_message, opts.ignore, jabber) |
372 | 387 | ||
373 | try: | ||
374 | load_experiment(path, scheduler, duration, param_file, | ||
375 | out_dir, opts.ignore, jabber) | ||
376 | succ += 1 | 388 | succ += 1 |
377 | except ExperimentDone: | 389 | except ExperimentDone: |
390 | sys.stderr.write("Experiment '%s' already completed " % exp + | ||
391 | "at '%s'\n" % out_base) | ||
378 | done += 1 | 392 | done += 1 |
379 | print("Experiment '%s' already completed at '%s'" % (exp, out_base)) | ||
380 | except (InvalidKernel, InvalidConfig) as e: | 393 | except (InvalidKernel, InvalidConfig) as e: |
394 | sys.stderr.write("Invalid environment for experiment '%s'\n" % exp) | ||
395 | sys.stderr.write("%s\n" % e) | ||
381 | invalid += 1 | 396 | invalid += 1 |
382 | print("Invalid environment for experiment '%s'" % exp) | ||
383 | print(e) | ||
384 | except KeyboardInterrupt: | 397 | except KeyboardInterrupt: |
385 | print("Keyboard interrupt, quitting") | 398 | sys.stderr.write("Keyboard interrupt, quitting\n") |
386 | break | 399 | break |
387 | except SystemCorrupted as e: | 400 | except SystemCorrupted as e: |
388 | print("System is corrupted! Fix state before continuing.") | 401 | sys.stderr.write("System is corrupted! Fix state before continuing.\n") |
389 | print(e) | 402 | sys.stderr.write("%s\n" % e) |
390 | break | 403 | break |
391 | except ExperimentFailed: | 404 | except Exception as e: |
392 | print("Failed experiment %s" % exp) | 405 | sys.stderr.write("Failed experiment %s\n" % exp) |
406 | sys.stderr.write("%s\n" % e) | ||
393 | failed += 1 | 407 | failed += 1 |
394 | 408 | ||
395 | ran += 1 | 409 | ran += 1 |
@@ -398,7 +412,7 @@ def main(): | |||
398 | if not os.listdir(out_base) and created and not succ: | 412 | if not os.listdir(out_base) and created and not succ: |
399 | os.rmdir(out_base) | 413 | os.rmdir(out_base) |
400 | 414 | ||
401 | message = "Experiments ran:\t%d of %d" % (ran, len(args)) +\ | 415 | message = "Experiments ran:\t%d of %d" % (ran, len(exps)) +\ |
402 | "\n Successful:\t\t%d" % succ +\ | 416 | "\n Successful:\t\t%d" % succ +\ |
403 | "\n Failed:\t\t%d" % failed +\ | 417 | "\n Failed:\t\t%d" % failed +\ |
404 | "\n Already Done:\t\t%d" % done +\ | 418 | "\n Already Done:\t\t%d" % done +\ |