diff options
| author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-04-29 16:50:23 -0400 |
|---|---|---|
| committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-04-29 16:50:23 -0400 |
| commit | 7e32c3915e7ea27d2533d99a22fa53ef923198f5 (patch) | |
| tree | 5bd8d8a3ed6861e039a683f47a953d2f7a22d8b1 | |
| parent | 7545402506aa76261e18d85af585ff0ac1cf05c1 (diff) | |
Added run_exps.py option to --retry failed experiments.
If the retry flag is specified, failed experiments will be re-run after all
other experiments have run. They can be re-run at most 5 times.
This commit required a refactoring of run_exps.py to clean up the main
experiment running loop.
| -rw-r--r-- | gen/edf_generators.py | 1 | ||||
| -rwxr-xr-x | gen_exps.py | 15 | ||||
| -rw-r--r-- | run/experiment.py | 50 | ||||
| -rwxr-xr-x | run_exps.py | 246 |
4 files changed, 194 insertions, 118 deletions
diff --git a/gen/edf_generators.py b/gen/edf_generators.py index a722c21..8e4b8df 100644 --- a/gen/edf_generators.py +++ b/gen/edf_generators.py | |||
| @@ -28,6 +28,7 @@ class EdfGenerator(gen.Generator): | |||
| 28 | pdist = self._create_dist('period', | 28 | pdist = self._create_dist('period', |
| 29 | exp_params['periods'], | 29 | exp_params['periods'], |
| 30 | gen.NAMED_PERIODS) | 30 | gen.NAMED_PERIODS) |
| 31 | |||
| 31 | udist = self._create_dist('utilization', | 32 | udist = self._create_dist('utilization', |
| 32 | exp_params['utils'], | 33 | exp_params['utils'], |
| 33 | gen.NAMED_UTILIZATIONS) | 34 | gen.NAMED_UTILIZATIONS) |
diff --git a/gen_exps.py b/gen_exps.py index b847661..00ce27b 100755 --- a/gen_exps.py +++ b/gen_exps.py | |||
| @@ -43,6 +43,14 @@ def load_file(fname): | |||
| 43 | except: | 43 | except: |
| 44 | raise IOError("Invalid generation file: %s" % fname) | 44 | raise IOError("Invalid generation file: %s" % fname) |
| 45 | 45 | ||
| 46 | def print_descriptions(described): | ||
| 47 | for generator in described.split(','): | ||
| 48 | if generator not in gen.get_generators(): | ||
| 49 | sys.stderr.write("No generator '%s'\n" % generator) | ||
| 50 | else: | ||
| 51 | print("Generator '%s', " % generator) | ||
| 52 | gen.get_generators()[generator]().print_help() | ||
| 53 | |||
| 46 | def main(): | 54 | def main(): |
| 47 | opts, args = parse_args() | 55 | opts, args = parse_args() |
| 48 | 56 | ||
| @@ -50,12 +58,7 @@ def main(): | |||
| 50 | if opts.list_gens: | 58 | if opts.list_gens: |
| 51 | print(", ".join(gen.get_generators())) | 59 | print(", ".join(gen.get_generators())) |
| 52 | if opts.described != None: | 60 | if opts.described != None: |
| 53 | for generator in opts.described.split(','): | 61 | print_descriptions(opts.described) |
| 54 | if generator not in gen.get_generators(): | ||
| 55 | sys.stderr.write("No generator '%s'\n" % generator) | ||
| 56 | else: | ||
| 57 | print("Generator '%s', " % generator) | ||
| 58 | gen.get_generators()[generator]().print_help() | ||
| 59 | if opts.list_gens or opts.described: | 62 | if opts.list_gens or opts.described: |
| 60 | return 0 | 63 | return 0 |
| 61 | 64 | ||
diff --git a/run/experiment.py b/run/experiment.py index b0e46b6..9a70414 100644 --- a/run/experiment.py +++ b/run/experiment.py | |||
| @@ -2,6 +2,7 @@ import os | |||
| 2 | import time | 2 | 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 | |||
| 5 | from operator import methodcaller | 6 | from operator import methodcaller |
| 6 | 7 | ||
| 7 | class ExperimentException(Exception): | 8 | class ExperimentException(Exception): |
| @@ -69,21 +70,24 @@ class Experiment(object): | |||
| 69 | executable.cwd = self.working_dir | 70 | executable.cwd = self.working_dir |
| 70 | map(assign_cwd, self.executables) | 71 | map(assign_cwd, self.executables) |
| 71 | 72 | ||
| 72 | def __kill_all(self): | 73 | def __try_kill_all(self): |
| 73 | if lu.waiting_tasks(): | 74 | try: |
| 74 | released = lu.release_tasks() | 75 | if lu.waiting_tasks(): |
| 75 | self.log("Re-released %d tasks" % released) | 76 | released = lu.release_tasks() |
| 77 | self.log("Re-released %d tasks" % released) | ||
| 76 | 78 | ||
| 77 | time.sleep(1) | 79 | time.sleep(1) |
| 78 | 80 | ||
| 79 | self.log("Killing all tasks") | 81 | self.log("Killing all tasks") |
| 80 | for e in self.executables: | 82 | for e in self.executables: |
| 81 | try: | 83 | try: |
| 82 | e.kill() | 84 | e.kill() |
| 83 | except: | 85 | except: |
| 84 | pass | 86 | pass |
| 85 | 87 | ||
| 86 | time.sleep(1) | 88 | time.sleep(1) |
| 89 | except: | ||
| 90 | self.log("Failed to kill all tasks.") | ||
| 87 | 91 | ||
| 88 | def __strip_path(self, path): | 92 | def __strip_path(self, path): |
| 89 | '''Shorten path to something more readable.''' | 93 | '''Shorten path to something more readable.''' |
| @@ -138,7 +142,7 @@ class Experiment(object): | |||
| 138 | now_ready = lu.waiting_tasks() | 142 | now_ready = lu.waiting_tasks() |
| 139 | if now_ready != num_ready: | 143 | if now_ready != num_ready: |
| 140 | wait_start = time.time() | 144 | wait_start = time.time() |
| 141 | num_ready = lu.now_ready | 145 | num_ready = now_ready |
| 142 | 146 | ||
| 143 | def __run_tasks(self): | 147 | def __run_tasks(self): |
| 144 | self.log("Starting %d tasks" % len(self.executables)) | 148 | self.log("Starting %d tasks" % len(self.executables)) |
| @@ -185,6 +189,7 @@ class Experiment(object): | |||
| 185 | 189 | ||
| 186 | sched = lu.scheduler() | 190 | sched = lu.scheduler() |
| 187 | if sched != "Linux": | 191 | if sched != "Linux": |
| 192 | self.log("Switching back to Linux scheduler") | ||
| 188 | try: | 193 | try: |
| 189 | lu.switch_scheduler("Linux") | 194 | lu.switch_scheduler("Linux") |
| 190 | except: | 195 | except: |
| @@ -229,6 +234,8 @@ class Experiment(object): | |||
| 229 | self.log("Stopping regular tracers") | 234 | self.log("Stopping regular tracers") |
| 230 | map(methodcaller('stop_tracing'), self.regular_tracers) | 235 | map(methodcaller('stop_tracing'), self.regular_tracers) |
| 231 | 236 | ||
| 237 | os.system('sync') | ||
| 238 | |||
| 232 | def log(self, msg): | 239 | def log(self, msg): |
| 233 | print("[Exp %s]: %s" % (self.name, msg)) | 240 | print("[Exp %s]: %s" % (self.name, msg)) |
| 234 | 241 | ||
| @@ -236,6 +243,7 @@ class Experiment(object): | |||
| 236 | self.__to_linux() | 243 | self.__to_linux() |
| 237 | 244 | ||
| 238 | succ = False | 245 | succ = False |
| 246 | exception = None | ||
| 239 | try: | 247 | try: |
| 240 | self.__setup() | 248 | self.__setup() |
| 241 | 249 | ||
| @@ -244,16 +252,20 @@ class Experiment(object): | |||
| 244 | self.log("Saving results in %s" % self.finished_dir) | 252 | self.log("Saving results in %s" % self.finished_dir) |
| 245 | succ = True | 253 | succ = True |
| 246 | except Exception as e: | 254 | except Exception as e: |
| 255 | exception = e | ||
| 256 | |||
| 247 | # Give time for whatever failed to finish failing | 257 | # Give time for whatever failed to finish failing |
| 248 | time.sleep(2) | 258 | time.sleep(2) |
| 249 | self.__kill_all() | ||
| 250 | 259 | ||
| 251 | raise e | 260 | self.__try_kill_all() |
| 252 | finally: | ||
| 253 | self.__teardown() | ||
| 254 | finally: | 261 | finally: |
| 255 | self.log("Switching back to Linux scheduler") | 262 | try: |
| 256 | self.__to_linux() | 263 | self.__teardown() |
| 264 | self.__to_linux() | ||
| 265 | except Exception as e: | ||
| 266 | exception = exception or e | ||
| 267 | finally: | ||
| 268 | if exception: raise exception | ||
| 257 | 269 | ||
| 258 | if succ: | 270 | if succ: |
| 259 | self.__save_results() | 271 | self.__save_results() |
diff --git a/run_exps.py b/run_exps.py index a15018d..1d46b45 100755 --- a/run_exps.py +++ b/run_exps.py | |||
| @@ -3,6 +3,7 @@ from __future__ import print_function | |||
| 3 | 3 | ||
| 4 | import common as com | 4 | import common as com |
| 5 | import os | 5 | import os |
| 6 | import pprint | ||
| 6 | import re | 7 | import re |
| 7 | import shutil | 8 | import shutil |
| 8 | import sys | 9 | import sys |
| @@ -11,17 +12,26 @@ import run.tracer as trace | |||
| 11 | from config.config import PARAMS,DEFAULTS | 12 | from config.config import PARAMS,DEFAULTS |
| 12 | from collections import namedtuple | 13 | from collections import namedtuple |
| 13 | from optparse import OptionParser | 14 | from optparse import OptionParser |
| 15 | from parse.enum import Enum | ||
| 14 | from run.executable.executable import Executable | 16 | from run.executable.executable import Executable |
| 15 | from run.experiment import Experiment,ExperimentDone,SystemCorrupted | 17 | from run.experiment import Experiment,ExperimentDone,SystemCorrupted |
| 16 | from run.proc_entry import ProcEntry | 18 | from run.proc_entry import ProcEntry |
| 17 | 19 | ||
| 20 | '''Maximum times an experiment will be retried''' | ||
| 21 | MAX_RETRY = 5 | ||
| 22 | |||
| 18 | '''Customizable experiment parameters''' | 23 | '''Customizable experiment parameters''' |
| 19 | ExpParams = namedtuple('ExpParams', ['scheduler', 'duration', 'tracers', | 24 | ExpParams = namedtuple('ExpParams', ['scheduler', 'duration', 'tracers', |
| 20 | 'kernel', 'config_options', 'file_params', | 25 | 'kernel', 'config_options', 'file_params', |
| 21 | 'pre_script', 'post_script']) | 26 | 'pre_script', 'post_script']) |
| 27 | '''Tracked with each experiment''' | ||
| 28 | ExpState = Enum(['Failed', 'Succeeded', 'Invalid', 'Done', 'None']) | ||
| 29 | ExpData = com.recordtype('ExpData', ['name', 'params', 'sched_file', 'out_dir', | ||
| 30 | 'retries', 'state']) | ||
| 22 | '''Comparison of requested versus actual kernel compile parameter value''' | 31 | '''Comparison of requested versus actual kernel compile parameter value''' |
| 23 | ConfigResult = namedtuple('ConfigResult', ['param', 'wanted', 'actual']) | 32 | ConfigResult = namedtuple('ConfigResult', ['param', 'wanted', 'actual']) |
| 24 | 33 | ||
