aboutsummaryrefslogtreecommitdiffstats
path: root/run_exps.py
diff options
context:
space:
mode:
Diffstat (limited to 'run_exps.py')
-rwxr-xr-xrun_exps.py218
1 files changed, 128 insertions, 90 deletions
diff --git a/run_exps.py b/run_exps.py
index 6531415..a15018d 100755
--- a/run_exps.py
+++ b/run_exps.py
@@ -2,22 +2,23 @@
2from __future__ import print_function 2from __future__ import print_function
3 3
4import common as com 4import common as com
5import config.config as conf
6import os 5import os
7import re 6import re
8import shutil 7import shutil
9import sys 8import sys
10import run.tracer as trace 9import run.tracer as trace
11 10
11from config.config import PARAMS,DEFAULTS
12from collections import namedtuple 12from collections import namedtuple
13from optparse import OptionParser 13from optparse import OptionParser
14from run.executable.executable import Executable 14from run.executable.executable import Executable
15from run.experiment import Experiment,ExperimentDone,ExperimentFailed,SystemCorrupted 15from run.experiment import Experiment,ExperimentDone,SystemCorrupted
16from run.proc_entry import ProcEntry 16from run.proc_entry import ProcEntry
17 17
18'''Customizable experiment parameters''' 18'''Customizable experiment parameters'''
19ExpParams = namedtuple('ExpParams', ['scheduler', 'duration', 'tracers', 19ExpParams = 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'''
22ConfigResult = namedtuple('ConfigResult', ['param', 'wanted', 'actual']) 23ConfigResult = namedtuple('ConfigResult', ['param', 'wanted', 'actual'])
23 24
@@ -56,12 +57,13 @@ def parse_args():
56 parser.add_option('-d', '--duration', dest='duration', type='int', 57 parser.add_option('-d', '--duration', dest='duration', type='int',
57 help='duration (seconds) of tasks') 58 help='duration (seconds) of tasks')
58 parser.add_option('-o', '--out-dir', dest='out_dir', 59 parser.add_option('-o', '--out-dir', dest='out_dir',
59 help='directory for data output', default=("%s/run-data"%os.getcwd())) 60 help='directory for data output',
61 default=DEFAULTS['out-run'])
60 parser.add_option('-p', '--params', dest='param_file', 62 parser.add_option('-p', '--params', dest='param_file',
61 help='file with experiment parameters') 63 help='file with experiment parameters')
62 parser.add_option('-c', '--schedule-file', dest='sched_file', 64 parser.add_option('-c', '--schedule-file', dest='sched_file',
63 help='name of schedule files within directories', 65 help='name of schedule files within directories',
64 default=conf.DEFAULTS['sched_file']) 66 default=DEFAULTS['sched_file'])
65 parser.add_option('-f', '--force', action='store_true', default=False, 67 parser.add_option('-f', '--force', action='store_true', default=False,
66 dest='force', help='overwrite existing data') 68 dest='force', help='overwrite existing data')
67 parser.add_option('-j', '--jabber', metavar='username@domain', 69 parser.add_option('-j', '--jabber', metavar='username@domain',
@@ -96,7 +98,7 @@ def convert_data(data):
96 proc = (loc, match.group("CONTENT")) 98 proc = (loc, match.group("CONTENT"))
97 procs.append(proc) 99 procs.append(proc)
98 else: 100 else:
99 prog = match.group("PROG") or conf.DEFAULTS['prog'] 101 prog = match.group("PROG") or DEFAULTS['prog']
100 spin = (prog, match.group("ARGS")) 102 spin = (prog, match.group("ARGS"))
101 tasks.append(spin) 103 tasks.append(spin)
102 104
@@ -112,8 +114,8 @@ def fix_paths(schedule, exp_dir, sched_file):
112 args = args.replace(arg, abspath) 114 args = args.replace(arg, abspath)
113 break 115 break
114 elif re.match(r'.*\w+\.[a-zA-Z]\w*', arg): 116 elif re.match(r'.*\w+\.[a-zA-Z]\w*', arg):
115 print("WARNING: non-existent file '%s' may be referenced:\n\t%s" 117 sys.stderr.write("WARNING: non-existent file '%s' " % arg +
116 % (arg, sched_file)) 118 "may be referenced:\n\t%s" % sched_file)
117 119
118 schedule['task'][idx] = (task, args) 120 schedule['task'][idx] = (task, args)
119 121
@@ -181,25 +183,23 @@ def verify_environment(exp_params):
181 raise InvalidConfig(results) 183 raise InvalidConfig(results)
182 184
183 185
184def run_parameter(exp_dir, out_dir, params, param_name): 186def run_script(script_params, exp, exp_dir, out_dir):
185 '''Run an executable (arguments optional) specified as a configurable 187 '''Run an executable (arguments optional)'''
186 @param_name in @params.''' 188 if not script_params:
187 if conf.PARAMS[param_name] not in params:
188 return 189 return
189 190
190 script_params = params[conf.PARAMS[param_name]]
191
192 # Split into arguments and program name 191 # Split into arguments and program name
193 if type(script_params) != type([]): 192 if type(script_params) != type([]):
194 script_params = [script_params] 193 script_params = [script_params]
195 script_name = script_params.pop(0)
196 194
195 exp.log("Running %s" % script_params.join(" "))
196
197 script_name = script_params.pop(0)
197 script = com.get_executable(script_name, cwd=exp_dir) 198 script = com.get_executable(script_name, cwd=exp_dir)
198 199
199 out = open('%s/%s-out.txt' % (out_dir, param_name), 'w') 200 out = open('%s/%s-out.txt' % (out_dir, script_name), 'w')
200 prog = Executable(script, script_params, 201 prog = Executable(script, script_params, cwd=out_dir,
201 stderr_file=out, stdout_file=out) 202 stderr_file=out, stdout_file=out)
202 prog.cwd = out_dir
203 203
204 prog.execute() 204 prog.execute()
205 prog.wait() 205 prog.wait()
@@ -207,28 +207,41 @@ def run_parameter(exp_dir, out_dir, params, param_name):
207 out.close() 207 out.close()
208 208
209 209
210def get_exp_params(cmd_scheduler, cmd_duration, file_params): 210def 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[conf.PARAMS['sched']] 214 # Load parameter file
215 duration = cmd_duration or file_params[conf.PARAMS['dur']] or\ 215 param_file = param_file or "%s/%s" % (sched_dir, DEFAULTS['params_file'])
216 conf.DEFAULTS['duration'] 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\
223 DEFAULTS['duration']
217 224
218 # Experiments can specify required kernel name 225 # Experiments can specify required kernel name
219 if conf.PARAMS['kernel'] in file_params: 226 if PARAMS['kernel'] in fparams:
220 kernel = file_params[conf.PARAMS['kernel']] 227 kernel = fparams[PARAMS['kernel']]
221 228
222 # Or required config options 229 # Or required config options
223 if conf.PARAMS['copts'] in file_params: 230 if PARAMS['copts'] in fparams:
224 copts = file_params[conf.PARAMS['copts']] 231 copts = fparams[PARAMS['copts']]
225 232
226 # Or required tracers 233 # Or required tracers
227 requested = [] 234 requested = []
228 if conf.PARAMS['trace'] in file_params: 235 if PARAMS['trace'] in fparams:
229 requested = file_params[conf.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,61 +249,70 @@ 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,
253 pre_script=pre_script, post_script=post_script)
240 254
241 255def run_experiment(name, sched_file, exp_params, out_dir,
242def load_experiment(sched_file, cmd_scheduler, cmd_duration, 256 start_message, ignore, jabber):
243 param_file, out_dir, 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, conf.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 [(conf.PARAMS['sched'], exp_params.scheduler), 285 [(PARAMS['sched'], exp_params.scheduler),
282 (conf.PARAMS['tasks'], len(execs)), 286 (PARAMS['tasks'], len(execs)),
283 (conf.PARAMS['dur'], exp_params.duration)]) 287 (PARAMS['dur'], exp_params.duration)])
284 288
285 # Feather-trace clock frequency saved for accurate overhead parsing 289 # Feather-trace clock frequency saved for accurate overhead parsing
286 ft_freq = com.ft_freq() 290 ft_freq = com.ft_freq()
287 if ft_freq: 291 if ft_freq:
288 out_params[conf.PARAMS['cycles']] = ft_freq 292 out_params[PARAMS['cycles']] = ft_freq
289 293
290 with open("%s/%s" % (out_dir, conf.DEFAULTS['params_file']), 'w') as f: 294 with open("%s/%s" % (out_dir, DEFAULTS['params_file']), 'w') as f:
291 f.write(str(out_params)) 295 f.write(str(out_params))
292 296
293 297
298def get_exps(opts, args):
299 '''Return list of experiment files or directories'''
300 if args:
301 return args
302
303 # Default to sched_file > generated dirs
304 if os.path.exists(opts.sched_file):
305 sys.stderr.write("Reading schedule from %s.\n" % opts.sched_file)
306 return [opts.sched_file]
307 elif os.path.exists(DEFAULTS['out-gen']):
308 sys.stderr.write("Reading schedules from %s/*.\n" % DEFAULTS['out-gen'])
309 sched_dirs = os.listdir(DEFAULTS['out-gen'])
310 return ['%s/%s' % (DEFAULTS['out-gen'], d) for d in sched_dirs]
311 else:
312 sys.stderr.write("Run with -h to view options.\n");
313 sys.exit(1)
314
315
294def setup_jabber(target): 316def setup_jabber(target):
295 try: 317 try:
296 from run.jabber import Jabber 318 from run.jabber import Jabber
@@ -301,6 +323,7 @@ def setup_jabber(target):
301 "Disabling instant messages.\n") 323 "Disabling instant messages.\n")
302 return None 324 return None
303 325
326
304def setup_email(target): 327def setup_email(target):
305 try: 328 try:
306 from run.emailer import Emailer 329 from run.emailer import Emailer
@@ -314,71 +337,82 @@ def setup_email(target):
314 sys.stderr.write(message + " Disabling email message.\n") 337 sys.stderr.write(message + " Disabling email message.\n")
315 return None 338 return None
316 339
340
341def 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
317def main(): 360def main():
318 opts, args = parse_args() 361 opts, args = parse_args()
319 362
320 scheduler = opts.scheduler 363 exps = get_exps(opts, args)
321 duration = opts.duration
322 param_file = opts.param_file
323 out_base = os.path.abspath(opts.out_dir)
324 364
325 args = args or [opts.sched_file] 365 jabber = setup_jabber(opts.jabber) if opts.jabber else None
366 email = setup_email(opts.email) if opts.email else None
326 367
327 created = False 368 out_base = os.path.abspath(opts.out_dir)
369 created = False
328 if not os.path.exists(out_base): 370 if not os.path.exists(out_base):
329 created = True 371 created = True
330 os.mkdir(out_base) 372 os.mkdir(out_base)
331 373
332 ran = 0 374 ran = done = succ = failed = invalid = 0
333 done = 0
334 succ = 0
335 failed = 0
336 invalid = 0
337
338 jabber = setup_jabber(opts.jabber) if opts.jabber else None
339 email = setup_email(opts.email) if opts.email else None
340
341 for exp in args:
342 path = "%s/%s" % (os.getcwd(), exp)
343 out_dir = "%s/%s" % (out_base, os.path.split(exp.strip('/'))[1])
344 375
345 if not os.path.exists(path): 376 for i, exp in enumerate(exps):
346 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]
347 379
348 if opts.force and os.path.exists(out_dir): 380 try:
349 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)
350 384
351 if os.path.isdir(exp): 385 run_experiment(exp, sched_file, exp_params, out_dir,
352 path = "%s/%s" % (path, opts.sched_file) 386 start_message, opts.ignore, jabber)
353 387
354 try:
355 load_experiment(path, scheduler, duration, param_file,
356 out_dir, opts.ignore, jabber)
357 succ += 1 388 succ += 1
358 except ExperimentDone: 389 except ExperimentDone:
390 sys.stderr.write("Experiment '%s' already completed " % exp +
391 "at '%s'\n" % out_base)
359 done += 1 392 done += 1
360 print("Experiment '%s' already completed at '%s'" % (exp, out_base))
361 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)
362 invalid += 1 396 invalid += 1
363 print("Invalid environment for experiment '%s'" % exp)
364 print(e)
365 except KeyboardInterrupt: 397 except KeyboardInterrupt:
366 print("Keyboard interrupt, quitting") 398 sys.stderr.write("Keyboard interrupt, quitting\n")
367 break 399 break
368 except SystemCorrupted as e: 400 except SystemCorrupted as e:
369 print("System is corrupted! Fix state before continuing.") 401 sys.stderr.write("System is corrupted! Fix state before continuing.\n")
370 print(e) 402 sys.stderr.write("%s\n" % e)
371 break 403 break
372 except ExperimentFailed: 404 except Exception as e:
373 print("Failed experiment %s" % exp) 405 sys.stderr.write("Failed experiment %s\n" % exp)
406 sys.stderr.write("%s\n" % e)
374 failed += 1 407 failed += 1
375 408
376 ran += 1 409 ran += 1
377 410
411 # Clean out directory if it failed immediately
378 if not os.listdir(out_base) and created and not succ: 412 if not os.listdir(out_base) and created and not succ:
379 os.rmdir(out_base) 413 os.rmdir(out_base)
380 414
381 message = "Experiments ran:\t%d of %d" % (ran, len(args)) +\ 415 message = "Experiments ran:\t%d of %d" % (ran, len(exps)) +\
382 "\n Successful:\t\t%d" % succ +\ 416 "\n Successful:\t\t%d" % succ +\
383 "\n Failed:\t\t%d" % failed +\ 417 "\n Failed:\t\t%d" % failed +\
384 "\n Already Done:\t\t%d" % done +\ 418 "\n Already Done:\t\t%d" % done +\
@@ -386,6 +420,10 @@ def main():
386 420
387 print(message) 421 print(message)
388 422
423 if succ:
424 sys.stderr.write("Successful experiment data saved in %s.\n" %
425 opts.out_dir)
426
389 if email: 427 if email:
390 email.send(message) 428 email.send(message)
391 email.close() 429 email.close()