experiment_runner.py revision 42709763f709b0e08d4ed041e4374cb9dd5d6570
1#!/usr/bin/python
2
3# Copyright 2011 Google Inc. All Rights Reserved.
4
5"""The experiment runner module."""
6import getpass
7import os
8import time
9
10from utils import command_executer
11from utils import logger
12from utils.email_sender import EmailSender
13from utils.file_utils import FileUtils
14
15import config
16from experiment_status import ExperimentStatus
17from results_report import HTMLResultsReport
18from results_report import TextResultsReport
19
20
21class ExperimentRunner(object):
22  """ExperimentRunner Class."""
23
24  STATUS_TIME_DELAY = 30
25  THREAD_MONITOR_DELAY = 2
26
27  def __init__(self, experiment, logger=None, cmd_exec=None):
28    self._experiment = experiment
29    self.l = logger or logger.GetLogger(experiment.log_dir)
30    self._ce = cmd_exec or command_executer.GetCommandExecuter(self.l)
31    self._terminated = False
32    if experiment.log_level != "verbose":
33      self.STATUS_TIME_DELAY = 10
34
35  def _Run(self, experiment):
36    status = ExperimentStatus(experiment)
37    experiment.Run()
38    last_status_time = 0
39    last_status_string = ""
40    try:
41      if experiment.log_level != "verbose":
42        self.l.LogStartDots()
43      while not experiment.IsComplete():
44        if last_status_time + self.STATUS_TIME_DELAY < time.time():
45          last_status_time = time.time()
46          border = "=============================="
47          if experiment.log_level == "verbose":
48            self.l.LogOutput(border)
49            self.l.LogOutput(status.GetProgressString())
50            self.l.LogOutput(status.GetStatusString())
51            self.l.LogOutput(border)
52          else:
53            current_status_string = status.GetStatusString()
54            if (current_status_string != last_status_string):
55              self.l.LogEndDots()
56              self.l.LogOutput(border)
57              self.l.LogOutput(current_status_string)
58              self.l.LogOutput(border)
59              last_status_string = current_status_string
60            else:
61              self.l.LogAppendDot()
62        time.sleep(self.THREAD_MONITOR_DELAY)
63    except KeyboardInterrupt:
64      self._terminated = True
65      self.l.LogError("Ctrl-c pressed. Cleaning up...")
66      experiment.Terminate()
67
68  def _PrintTable(self, experiment):
69    self.l.LogOutput(TextResultsReport(experiment).GetReport())
70
71  def _Email(self, experiment):
72    # Only email by default if a new run was completed.
73    send_mail = False
74    for benchmark_run in experiment.benchmark_runs:
75      if not benchmark_run.cache_hit:
76        send_mail = True
77        break
78    if (not send_mail and not experiment.email_to
79        or config.GetConfig("no_email")):
80      return
81
82    label_names = []
83    for label in experiment.labels:
84      label_names.append(label.name)
85    subject = "%s: %s" % (experiment.name, " vs. ".join(label_names))
86
87    text_report = TextResultsReport(experiment, True).GetReport()
88    text_report = "<pre style='font-size: 13px'>%s</pre>" % text_report
89    html_report = HTMLResultsReport(experiment).GetReport()
90    attachment = EmailSender.Attachment("report.html", html_report)
91    email_to = [getpass.getuser()] + experiment.email_to
92    EmailSender().SendEmail(email_to,
93                            subject,
94                            text_report,
95                            attachments=[attachment],
96                            msg_type="html")
97
98  def _StoreResults (self, experiment):
99    if self._terminated:
100      return
101    results_directory = experiment.results_directory
102    FileUtils().RmDir(results_directory)
103    FileUtils().MkDirP(results_directory)
104    self.l.LogOutput("Storing experiment file in %s." % results_directory)
105    experiment_file_path = os.path.join(results_directory,
106                                        "experiment.exp")
107    FileUtils().WriteFile(experiment_file_path, experiment.experiment_file)
108
109    self.l.LogOutput("Storing results report in %s." % results_directory)
110    results_table_path = os.path.join(results_directory, "results.html")
111    report = HTMLResultsReport(experiment).GetReport()
112    FileUtils().WriteFile(results_table_path, report)
113
114    self.l.LogOutput("Storing results of each benchmark run.")
115    for benchmark_run in experiment.benchmark_runs:
116      if benchmark_run.result:
117        benchmark_run_name = filter(str.isalnum, benchmark_run.name)
118        benchmark_run_path = os.path.join(results_directory,
119                                          benchmark_run_name)
120        benchmark_run.result.CopyResultsTo(benchmark_run_path)
121        benchmark_run.result.CleanUp(benchmark_run.benchmark.rm_chroot_tmp)
122
123  def Run(self):
124    self._Run(self._experiment)
125    self._PrintTable(self._experiment)
126    if not self._terminated:
127      self._StoreResults(self._experiment)
128      self._Email(self._experiment)
129
130
131class MockExperimentRunner(ExperimentRunner):
132  """Mocked ExperimentRunner for testing."""
133
134  def __init__(self, experiment):
135    super(MockExperimentRunner, self).__init__(experiment)
136
137  def _Run(self, experiment):
138    self.l.LogOutput("Would run the following experiment: '%s'." %
139                     experiment.name)
140
141  def _PrintTable(self, experiment):
142    self.l.LogOutput("Would print the experiment table.")
143
144  def _Email(self, experiment):
145    self.l.LogOutput("Would send result email.")
146
147  def _StoreResults(self, experiment):
148    self.l.LogOutput("Would store the results.")
149