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