|  | import _overlapped | 
|  | import _thread | 
|  | import _winapi | 
|  | import math | 
|  | import struct | 
|  | import winreg | 
|  |  | 
|  |  | 
|  | # Seconds per measurement | 
|  | SAMPLING_INTERVAL = 1 | 
|  | # Exponential damping factor to compute exponentially weighted moving average | 
|  | # on 1 minute (60 seconds) | 
|  | LOAD_FACTOR_1 = 1 / math.exp(SAMPLING_INTERVAL / 60) | 
|  | # Initialize the load using the arithmetic mean of the first NVALUE values | 
|  | # of the Processor Queue Length | 
|  | NVALUE = 5 | 
|  |  | 
|  |  | 
|  | class WindowsLoadTracker(): | 
|  | """ | 
|  | This class asynchronously reads the performance counters to calculate | 
|  | the system load on Windows.  A "raw" thread is used here to prevent | 
|  | interference with the test suite's cases for the threading module. | 
|  | """ | 
|  |  | 
|  | def __init__(self): | 
|  | # Pre-flight test for access to the performance data; | 
|  | # `PermissionError` will be raised if not allowed | 
|  | winreg.QueryInfoKey(winreg.HKEY_PERFORMANCE_DATA) | 
|  |  | 
|  | self._values = [] | 
|  | self._load = None | 
|  | self._running = _overlapped.CreateEvent(None, True, False, None) | 
|  | self._stopped = _overlapped.CreateEvent(None, True, False, None) | 
|  |  | 
|  | _thread.start_new_thread(self._update_load, (), {}) | 
|  |  | 
|  | def _update_load(self, | 
|  | # localize module access to prevent shutdown errors | 
|  | _wait=_winapi.WaitForSingleObject, | 
|  | _signal=_overlapped.SetEvent): | 
|  | # run until signaled to stop | 
|  | while _wait(self._running, 1000): | 
|  | self._calculate_load() | 
|  | # notify stopped | 
|  | _signal(self._stopped) | 
|  |  | 
|  | def _calculate_load(self, | 
|  | # localize module access to prevent shutdown errors | 
|  | _query=winreg.QueryValueEx, | 
|  | _hkey=winreg.HKEY_PERFORMANCE_DATA, | 
|  | _unpack=struct.unpack_from): | 
|  | # get the 'System' object | 
|  | data, _ = _query(_hkey, '2') | 
|  | # PERF_DATA_BLOCK { | 
|  | #   WCHAR Signature[4]      8 + | 
|  | #   DWOWD LittleEndian      4 + | 
|  | #   DWORD Version           4 + | 
|  | #   DWORD Revision          4 + | 
|  | #   DWORD TotalByteLength   4 + | 
|  | #   DWORD HeaderLength      = 24 byte offset | 
|  | #   ... | 
|  | # } | 
|  | obj_start, = _unpack('L', data, 24) | 
|  | # PERF_OBJECT_TYPE { | 
|  | #   DWORD TotalByteLength | 
|  | #   DWORD DefinitionLength | 
|  | #   DWORD HeaderLength | 
|  | #   ... | 
|  | # } | 
|  | data_start, defn_start = _unpack('4xLL', data, obj_start) | 
|  | data_base = obj_start + data_start | 
|  | defn_base = obj_start + defn_start | 
|  | # find the 'Processor Queue Length' counter (index=44) | 
|  | while defn_base < data_base: | 
|  | # PERF_COUNTER_DEFINITION { | 
|  | #   DWORD ByteLength | 
|  | #   DWORD CounterNameTitleIndex | 
|  | #   ... [7 DWORDs/28 bytes] | 
|  | #   DWORD CounterOffset | 
|  | # } | 
|  | size, idx, offset = _unpack('LL28xL', data, defn_base) | 
|  | defn_base += size | 
|  | if idx == 44: | 
|  | counter_offset = data_base + offset | 
|  | # the counter is known to be PERF_COUNTER_RAWCOUNT (DWORD) | 
|  | processor_queue_length, = _unpack('L', data, counter_offset) | 
|  | break | 
|  | else: | 
|  | return | 
|  |  | 
|  | # We use an exponentially weighted moving average, imitating the | 
|  | # load calculation on Unix systems. | 
|  | # https://en.wikipedia.org/wiki/Load_(computing)#Unix-style_load_calculation | 
|  | # https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average | 
|  | if self._load is not None: | 
|  | self._load = (self._load * LOAD_FACTOR_1 | 
|  | + processor_queue_length  * (1.0 - LOAD_FACTOR_1)) | 
|  | elif len(self._values) < NVALUE: | 
|  | self._values.append(processor_queue_length) | 
|  | else: | 
|  | self._load = sum(self._values) / len(self._values) | 
|  |  | 
|  | def close(self, kill=True): | 
|  | self.__del__() | 
|  | return | 
|  |  | 
|  | def __del__(self, | 
|  | # localize module access to prevent shutdown errors | 
|  | _wait=_winapi.WaitForSingleObject, | 
|  | _close=_winapi.CloseHandle, | 
|  | _signal=_overlapped.SetEvent): | 
|  | if self._running is not None: | 
|  | # tell the update thread to quit | 
|  | _signal(self._running) | 
|  | # wait for the update thread to signal done | 
|  | _wait(self._stopped, -1) | 
|  | # cleanup events | 
|  | _close(self._running) | 
|  | _close(self._stopped) | 
|  | self._running = self._stopped = None | 
|  |  | 
|  | def getloadavg(self): | 
|  | return self._load |