blob: f7c37c3f701fcd65c7ab5932db55b5b4be23e7a0 [file] [log] [blame]
#!/usr/bin/python
# Copyright 2011 Google Inc. All Rights Reserved.
import datetime
import os
import re
import threading
import time
import traceback
from results_cache import Result
from utils import logger
from utils import command_executer
from autotest_runner import AutotestRunner
from perf_processor import PerfProcessor
from results_cache import ResultsCache
STATUS_FAILED = "FAILED"
STATUS_SUCCEEDED = "SUCCEEDED"
STATUS_IMAGING = "IMAGING"
STATUS_RUNNING = "RUNNING"
STATUS_WAITING = "WAITING"
STATUS_PENDING = "PENDING"
class BenchmarkRun(threading.Thread):
def __init__(self, name, benchmark_name, autotest_name, autotest_args,
label_name, chromeos_root, chromeos_image, board, iteration,
cache_conditions, outlier_range, profile_counters, profile_type,
machine_manager,
logger_to_use):
threading.Thread.__init__(self)
self.name = name
self._logger = logger_to_use
self.benchmark_name = benchmark_name
self.autotest_name = autotest_name
self.autotest_args = autotest_args
self.label_name = label_name
self.chromeos_root = chromeos_root
self.chromeos_image = os.path.expanduser(chromeos_image)
self.board = board
self.iteration = iteration
self.result = None
self.results = {}
self.terminated = False
self.retval = None
self.status = STATUS_PENDING
self.run_completed = False
self.outlier_range = outlier_range
self.profile_counters = profile_counters
self.profile_type = profile_type
self.machine_manager = machine_manager
self.cache = ResultsCache()
self.autotest_runner = AutotestRunner(self._logger)
self.perf_processor = None
self.machine = None
self.full_name = self.autotest_name
self.cache_conditions = cache_conditions
self.runs_complete = 0
self.cache_hit = False
self.perf_results = None
self.failure_reason = ""
self._ce = command_executer.GetCommandExecuter(self._logger)
def ProcessResults(self):
# Generate results from the output file.
self.full_name = os.path.basename(self.results_dir)
self.results = self.result.keyvals
# Store the autotest output in the cache also.
if not self.cache_hit:
self.cache.StoreResult(self.result)
self.cache.StoreAutotestOutput(self.results_dir)
self.perf_processor = PerfProcessor(self.results_dir,
self.chromeos_root,
self.board,
self._logger)
# Generate a perf report and cache it.
if self.profile_type:
if self.cache_hit:
self.perf_results = self.cache.ReadPerfResults()
else:
self.perf_results = self.perf_processor.GeneratePerfResults()
self.cache.StorePerfResults(self.perf_results)
# If there are valid results from perf stat, combine them with the
# autotest results.
if self.perf_results:
stat_results = self.perf_processor.ParseStatResults(self.perf_results)
self.results = dict(self.results.items() + stat_results.items())
def _GetResultsDir(self, output):
mo = re.search("Results placed in (\S+)", output)
if mo:
result = mo.group(1)
return result
raise Exception("Could not find results directory.")
def run(self):
try:
# Just use the first machine for running the cached version,
# without locking it.
self.cache.Init(self.chromeos_image,
self.chromeos_root,
self.autotest_name,
self.iteration,
self.autotest_args,
self.machine_manager.GetMachines()[0].name,
self.board,
self.cache_conditions,
self._logger)
self.result = self.cache.ReadResult()
self.cache_hit = (self.result is not None)
if self.result:
self._logger.LogOutput("%s: Cache hit." % self.name)
self._logger.LogOutput(self.result.out + "\n" + self.result.err)
self.results_dir = self._GetResultsDir(self.result.out)
else:
self._logger.LogOutput("%s: No cache hit." % self.name)
self.status = STATUS_WAITING
# Try to acquire a machine now.
self.machine = self.AcquireMachine()
self.cache.remote = self.machine.name
self.result = self.RunTest(self.machine)
if self.terminated:
return
if not self.result.retval:
self.status = STATUS_SUCCEEDED
else:
if self.status != STATUS_FAILED:
self.status = STATUS_FAILED
self.failure_reason = "Return value of autotest was non-zero."
self.ProcessResults()
except Exception, e:
self._logger.LogError("Benchmark run: '%s' failed: %s" % (self.name, e))
traceback.print_exc()
if self.status != STATUS_FAILED:
self.status = STATUS_FAILED
self.failure_reason = str(e)
finally:
if self.machine:
self._logger.LogOutput("Releasing machine: %s" % self.machine.name)
self.machine_manager.ReleaseMachine(self.machine)
self._logger.LogOutput("Released machine: %s" % self.machine.name)
def Terminate(self):
self.terminated = True
self.autotest_runner.Terminate()
if self.status != STATUS_FAILED:
self.status = STATUS_FAILED
self.failure_reason = "Thread terminated."
def AcquireMachine(self):
while True:
if self.terminated:
raise Exception("Thread terminated while trying to acquire machine.")
machine = self.machine_manager.AcquireMachine(self.chromeos_image)
if machine:
self._logger.LogOutput("%s: Machine %s acquired at %s" %
(self.name,
machine.name,
datetime.datetime.now()))
break
else:
sleep_duration = 10
time.sleep(sleep_duration)
return machine
def RunTest(self, machine):
self.status = STATUS_IMAGING
self.machine_manager.ImageMachine(machine,
self.chromeos_image,
self.board)
self.status = "%s %s" % (STATUS_RUNNING, self.autotest_name)
[retval, out, err] = self.autotest_runner.Run(machine.name,
self.chromeos_root,
self.board,
self.autotest_name,
self.autotest_args,
self.profile_counters,
self.profile_type)
self.run_completed = True
# Include the keyvals in the result.
self.results_dir = self._GetResultsDir(out)
keyvals = self._GetKeyvals()
keyvals["retval"] = retval
result = Result(out, err, retval, keyvals)
return result
def _GetKeyvals(self):
full_results_dir = os.path.join(self.chromeos_root,
"chroot",
self.results_dir.lstrip("/"))
command = "find %s -regex .*results/keyval$" % full_results_dir
[ret, out, err] = self._ce.RunCommand(command, return_output=True)
keyvals_dict = {}
for f in out.splitlines():
keyvals = open(f, "r").read()
keyvals_dict.update(self._ParseKeyvals(keyvals))
return keyvals_dict
def _ParseKeyvals(self, keyvals):
keyval_dict = {}
for l in keyvals.splitlines():
l = l.strip()
if l:
key, val = l.split("=")
keyval_dict[key] = val
return keyval_dict
def SetCacheConditions(self, cache_conditions):
self.cache_conditions = cache_conditions