experiment.py revision e5bc63bbed4e001b080c4ce0b18c5c78900d4786
1#!/usr/bin/python
2
3# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7"""The experiment setting module."""
8
9import os
10import time
11
12import afe_lock_machine
13
14from utils import logger
15from utils import misc
16
17from benchmark_run import BenchmarkRun
18from machine_manager import MachineManager
19from machine_manager import MockMachineManager
20import test_flag
21
22
23class Experiment(object):
24  """Class representing an Experiment to be run."""
25
26  def __init__(self, name, remote, working_directory,
27               chromeos_root, cache_conditions, labels, benchmarks,
28               experiment_file, email_to, acquire_timeout, log_dir,
29               log_level, share_cache, results_directory, locks_directory):
30    self.name = name
31    self.working_directory = working_directory
32    self.remote = remote
33    self.chromeos_root = chromeos_root
34    self.cache_conditions = cache_conditions
35    self.experiment_file = experiment_file
36    self.email_to = email_to
37    if not results_directory:
38      self.results_directory = os.path.join(self.working_directory,
39                                            self.name + "_results")
40    else:
41      self.results_directory = misc.CanonicalizePath(results_directory)
42    self.log_dir = log_dir
43    self.log_level = log_level
44    self.labels = labels
45    self.benchmarks = benchmarks
46    self.num_complete = 0
47    self.num_run_complete = 0
48    self.share_cache = share_cache
49
50    # We need one chromeos_root to run the benchmarks in, but it doesn't
51    # matter where it is, unless the ABIs are different.
52    if not chromeos_root:
53      for label in self.labels:
54        if label.chromeos_root:
55          chromeos_root = label.chromeos_root
56    if not chromeos_root:
57      raise Exception("No chromeos_root given and could not determine one from "
58                      "the image path.")
59
60    # This is a local directory, where the machine manager will keep track of
61    # which machines are available for which benchmark run.   The assumption is
62    # that all of the machines have been globally locked for this experiment,
63    # to keep other people/experiments from accessing them, but we still need the
64    # local locks directory to keep two or more benchmark runs within the same
65    # experiment from trying to use the same machine at the same time.
66    local_locks_directory = os.path.join(self.working_directory,
67                                         "local_locks")
68    if test_flag.GetTestMode():
69      self.machine_manager = MockMachineManager(chromeos_root, acquire_timeout,
70                                                log_level, locks_directory)
71    else:
72      self.machine_manager = MachineManager(chromeos_root, acquire_timeout,
73                                            log_level, local_locks_directory)
74    self.l = logger.GetLogger(log_dir)
75
76    for machine in remote:
77      self.machine_manager.AddMachine(machine)
78    for label in labels:
79      self.machine_manager.ComputeCommonCheckSum(label)
80      self.machine_manager.ComputeCommonCheckSumString(label)
81
82    self.start_time = None
83    self.benchmark_runs = self._GenerateBenchmarkRuns()
84
85  def _GenerateBenchmarkRuns(self):
86    """Generate benchmark runs from labels and benchmark defintions."""
87    benchmark_runs = []
88    for label in self.labels:
89      for benchmark in self.benchmarks:
90        for iteration in range(1, benchmark.iterations + 1):
91
92          benchmark_run_name = "%s: %s (%s)" % (label.name, benchmark.name,
93                                                iteration)
94          full_name = "%s_%s_%s" % (label.name, benchmark.name, iteration)
95          logger_to_use = logger.Logger(self.log_dir,
96                                        "run.%s" % (full_name),
97                                        True)
98          benchmark_run = BenchmarkRun(benchmark_run_name,
99                                       benchmark,
100                                       label,
101                                       iteration,
102                                       self.cache_conditions,
103                                       self.machine_manager,
104                                       logger_to_use,
105                                       self.log_level,
106                                       self.share_cache)
107
108          benchmark_runs.append(benchmark_run)
109    return benchmark_runs
110
111  def Build(self):
112    pass
113
114  def Terminate(self):
115    for t in self.benchmark_runs:
116      if t.isAlive():
117        self.l.LogError("Terminating run: '%s'." % t.name)
118        t.Terminate()
119
120  def IsComplete(self):
121    if self.active_threads:
122      for t in self.active_threads:
123        if t.isAlive():
124          t.join(0)
125        if not t.isAlive():
126          self.num_complete += 1
127          if not t.cache_hit:
128            self.num_run_complete += 1
129          self.active_threads.remove(t)
130      return False
131    return True
132
133  def Run(self):
134    self.start_time = time.time()
135    self.active_threads = []
136    for benchmark_run in self.benchmark_runs:
137      # Set threads to daemon so program exits when ctrl-c is pressed.
138      benchmark_run.daemon = True
139      benchmark_run.start()
140      self.active_threads.append(benchmark_run)
141
142  def SetCacheConditions(self, cache_conditions):
143    for benchmark_run in self.benchmark_runs:
144      benchmark_run.SetCacheConditions(cache_conditions)
145
146  def Cleanup(self):
147    """Make sure all machines are unlocked."""
148    all_machines = self.remote
149    for l in self.labels:
150      all_machines += l.remote
151    lock_mgr = afe_lock_machine.AFELockManager(all_machines, "",
152                                               self.labels[0].chromeos_root, None)
153    machine_states = lock_mgr.GetMachineStates("unlock")
154    for k, state in machine_states.iteritems():
155      if state["locked"]:
156        lock_mgr.UpdateLockInAFE(False, k)
157