2016-09-22 12:10:02 +00:00
|
|
|
# Copyright 2016 Google Inc.
|
|
|
|
#
|
|
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
|
|
# found in the LICENSE file.
|
|
|
|
|
|
|
|
import time
|
|
|
|
|
|
|
|
class Hardware:
|
2016-09-23 18:36:11 +00:00
|
|
|
"""Locks down and monitors hardware for benchmarking.
|
|
|
|
|
|
|
|
This is a common base for classes that can control the specific hardware
|
|
|
|
we are running on. Its purpose is to lock the hardware into a constant
|
|
|
|
benchmarking mode for the duration of a 'with' block. e.g.:
|
|
|
|
|
|
|
|
with hardware:
|
|
|
|
run_benchmark()
|
|
|
|
|
|
|
|
While benchmarking, the caller must call sanity_check() frequently to verify
|
|
|
|
the hardware state has not changed.
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
2016-09-22 12:10:02 +00:00
|
|
|
def __init__(self):
|
2016-10-12 01:28:54 +00:00
|
|
|
self.warmup_time = 0
|
2016-09-22 12:10:02 +00:00
|
|
|
|
|
|
|
def __enter__(self):
|
|
|
|
return self
|
|
|
|
|
|
|
|
def __exit__(self, exception_type, exception_value, traceback):
|
|
|
|
pass
|
|
|
|
|
2016-11-09 21:25:23 +00:00
|
|
|
def filter_line(self, line):
|
|
|
|
"""Returns False if the provided output line can be suppressed."""
|
|
|
|
return True
|
|
|
|
|
2016-09-22 12:10:02 +00:00
|
|
|
def sanity_check(self):
|
2016-09-23 18:36:11 +00:00
|
|
|
"""Raises a HardwareException if any hardware state is not as expected."""
|
2016-09-22 12:10:02 +00:00
|
|
|
pass
|
|
|
|
|
2016-10-11 19:15:13 +00:00
|
|
|
def print_debug_diagnostics(self):
|
|
|
|
"""Prints any info that may help improve or debug hardware monitoring."""
|
|
|
|
pass
|
|
|
|
|
2016-09-22 12:10:02 +00:00
|
|
|
def sleep(self, sleeptime):
|
2016-09-23 18:36:11 +00:00
|
|
|
"""Puts the hardware into a resting state for a fixed amount of time."""
|
2016-09-22 12:10:02 +00:00
|
|
|
time.sleep(sleeptime)
|
2016-09-23 18:36:11 +00:00
|
|
|
|
|
|
|
|
|
|
|
class HardwareException(Exception):
|
|
|
|
"""Gets thrown when certain hardware state is not what we expect.
|
|
|
|
|
|
|
|
Generally this happens because of thermal conditions or other variables beyond
|
|
|
|
our control, and the appropriate course of action is to take a short nap
|
|
|
|
before resuming the benchmark.
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(self, message, sleeptime=60):
|
|
|
|
Exception.__init__(self, message)
|
|
|
|
self.sleeptime = sleeptime
|
|
|
|
|
|
|
|
|
|
|
|
class Expectation:
|
|
|
|
"""Simple helper for checking the readings on hardware gauges."""
|
|
|
|
def __init__(self, value_type, min_value=None, max_value=None,
|
|
|
|
exact_value=None, name=None, sleeptime=60):
|
|
|
|
self.value_type = value_type
|
|
|
|
self.min_value = min_value
|
|
|
|
self.max_value = max_value
|
|
|
|
self.exact_value = exact_value
|
|
|
|
self.name = name
|
|
|
|
self.sleeptime = sleeptime
|
|
|
|
|
|
|
|
def check(self, stringvalue):
|
|
|
|
typedvalue = self.value_type(stringvalue)
|
|
|
|
if self.min_value is not None and typedvalue < self.min_value:
|
|
|
|
raise HardwareException("%s is too low (%s, min=%s)" %
|
|
|
|
(self.name, stringvalue, str(self.min_value)),
|
|
|
|
sleeptime=self.sleeptime)
|
|
|
|
if self.max_value is not None and typedvalue > self.max_value:
|
|
|
|
raise HardwareException("%s is too high (%s, max=%s)" %
|
|
|
|
(self.name, stringvalue, str(self.max_value)),
|
|
|
|
sleeptime=self.sleeptime)
|
|
|
|
if self.exact_value is not None and typedvalue != self.exact_value:
|
|
|
|
raise HardwareException("unexpected %s (%s, expected=%s)" %
|
|
|
|
(self.name, stringvalue, str(self.exact_value)),
|
|
|
|
sleeptime=self.sleeptime)
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def check_all(expectations, stringvalues):
|
|
|
|
if len(stringvalues) != len(expectations):
|
|
|
|
raise Exception("unexpected reading from hardware gauges "
|
|
|
|
"(expected %i values):\n%s" %
|
|
|
|
(len(expectations), '\n'.join(stringvalues)))
|
|
|
|
|
|
|
|
for value, expected in zip(stringvalues, expectations):
|
|
|
|
expected.check(value)
|