1cb93a386Sopenharmony_ci# Copyright 2016 Google Inc.
2cb93a386Sopenharmony_ci#
3cb93a386Sopenharmony_ci# Use of this source code is governed by a BSD-style license that can be
4cb93a386Sopenharmony_ci# found in the LICENSE file.
5cb93a386Sopenharmony_ci
6cb93a386Sopenharmony_ciimport time
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ciclass Hardware:
9cb93a386Sopenharmony_ci  """Locks down and monitors hardware for benchmarking.
10cb93a386Sopenharmony_ci
11cb93a386Sopenharmony_ci  This is a common base for classes that can control the specific hardware
12cb93a386Sopenharmony_ci  we are running on. Its purpose is to lock the hardware into a constant
13cb93a386Sopenharmony_ci  benchmarking mode for the duration of a 'with' block. e.g.:
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_ci    with hardware:
16cb93a386Sopenharmony_ci      run_benchmark()
17cb93a386Sopenharmony_ci
18cb93a386Sopenharmony_ci  While benchmarking, the caller must call sanity_check() frequently to verify
19cb93a386Sopenharmony_ci  the hardware state has not changed.
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_ci  """
22cb93a386Sopenharmony_ci
23cb93a386Sopenharmony_ci  def __init__(self):
24cb93a386Sopenharmony_ci    self.warmup_time = 0
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_ci  def __enter__(self):
27cb93a386Sopenharmony_ci    return self
28cb93a386Sopenharmony_ci
29cb93a386Sopenharmony_ci  def __exit__(self, exception_type, exception_value, traceback):
30cb93a386Sopenharmony_ci    pass
31cb93a386Sopenharmony_ci
32cb93a386Sopenharmony_ci  def filter_line(self, line):
33cb93a386Sopenharmony_ci    """Returns False if the provided output line can be suppressed."""
34cb93a386Sopenharmony_ci    return True
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_ci  def sanity_check(self):
37cb93a386Sopenharmony_ci    """Raises a HardwareException if any hardware state is not as expected."""
38cb93a386Sopenharmony_ci    pass
39cb93a386Sopenharmony_ci
40cb93a386Sopenharmony_ci  def print_debug_diagnostics(self):
41cb93a386Sopenharmony_ci    """Prints any info that may help improve or debug hardware monitoring."""
42cb93a386Sopenharmony_ci    pass
43cb93a386Sopenharmony_ci
44cb93a386Sopenharmony_ci
45cb93a386Sopenharmony_ciclass HardwareException(Exception):
46cb93a386Sopenharmony_ci  """Gets thrown when certain hardware state is not what we expect.
47cb93a386Sopenharmony_ci
48cb93a386Sopenharmony_ci  Generally this happens because of thermal conditions or other variables beyond
49cb93a386Sopenharmony_ci  our control, and the appropriate course of action is to take a short nap
50cb93a386Sopenharmony_ci  before resuming the benchmark.
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_ci  """
53cb93a386Sopenharmony_ci
54cb93a386Sopenharmony_ci  def __init__(self, message, sleeptime=60):
55cb93a386Sopenharmony_ci    Exception.__init__(self, message)
56cb93a386Sopenharmony_ci    self.sleeptime = sleeptime
57cb93a386Sopenharmony_ci
58cb93a386Sopenharmony_ci
59cb93a386Sopenharmony_ciclass Expectation:
60cb93a386Sopenharmony_ci  """Simple helper for checking the readings on hardware gauges."""
61cb93a386Sopenharmony_ci  def __init__(self, value_type, min_value=None, max_value=None,
62cb93a386Sopenharmony_ci               exact_value=None, name=None, sleeptime=60):
63cb93a386Sopenharmony_ci    self.value_type = value_type
64cb93a386Sopenharmony_ci    self.min_value = min_value
65cb93a386Sopenharmony_ci    self.max_value = max_value
66cb93a386Sopenharmony_ci    self.exact_value = exact_value
67cb93a386Sopenharmony_ci    self.name = name
68cb93a386Sopenharmony_ci    self.sleeptime = sleeptime
69cb93a386Sopenharmony_ci
70cb93a386Sopenharmony_ci  def check(self, stringvalue):
71cb93a386Sopenharmony_ci    typedvalue = self.value_type(stringvalue)
72cb93a386Sopenharmony_ci    if self.min_value is not None and typedvalue < self.min_value:
73cb93a386Sopenharmony_ci       raise HardwareException("%s is too low (%s, min=%s)" %
74cb93a386Sopenharmony_ci                               (self.name, stringvalue, str(self.min_value)),
75cb93a386Sopenharmony_ci                               sleeptime=self.sleeptime)
76cb93a386Sopenharmony_ci    if self.max_value is not None and typedvalue > self.max_value:
77cb93a386Sopenharmony_ci       raise HardwareException("%s is too high (%s, max=%s)" %
78cb93a386Sopenharmony_ci                               (self.name, stringvalue, str(self.max_value)),
79cb93a386Sopenharmony_ci                               sleeptime=self.sleeptime)
80cb93a386Sopenharmony_ci    if self.exact_value is not None and typedvalue != self.exact_value:
81cb93a386Sopenharmony_ci       raise HardwareException("unexpected %s (%s, expected=%s)" %
82cb93a386Sopenharmony_ci                               (self.name, stringvalue, str(self.exact_value)),
83cb93a386Sopenharmony_ci                               sleeptime=self.sleeptime)
84cb93a386Sopenharmony_ci
85cb93a386Sopenharmony_ci  @staticmethod
86cb93a386Sopenharmony_ci  def check_all(expectations, stringvalues):
87cb93a386Sopenharmony_ci    if len(stringvalues) != len(expectations):
88cb93a386Sopenharmony_ci      raise Exception("unexpected reading from hardware gauges "
89cb93a386Sopenharmony_ci                      "(expected %i values):\n%s" %
90cb93a386Sopenharmony_ci                      (len(expectations), '\n'.join(stringvalues)))
91cb93a386Sopenharmony_ci
92cb93a386Sopenharmony_ci    for value, expected in zip(stringvalues, expectations):
93cb93a386Sopenharmony_ci      expected.check(value)
94