diff options
author | Victor Stinner <vstinner@python.org> | 2019-10-03 14:15:16 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-10-03 14:15:16 (GMT) |
commit | 098e25672f1c3578855d5ded4f5147795c9ed956 (patch) | |
tree | 80a8a09e94f5ec3c1a5dcc0538db23ff63754674 /Lib/test/libregrtest/win_utils.py | |
parent | c65119d5bfded03f80a9805889391b66fa7bf551 (diff) | |
download | cpython-098e25672f1c3578855d5ded4f5147795c9ed956.zip cpython-098e25672f1c3578855d5ded4f5147795c9ed956.tar.gz cpython-098e25672f1c3578855d5ded4f5147795c9ed956.tar.bz2 |
bpo-36670: Enhance regrtest (GH-16556)
* Add log() method: add timestamp and load average prefixes
to main messages.
* WindowsLoadTracker:
* LOAD_FACTOR_1 is now computed using SAMPLING_INTERVAL
* Initialize the load to the arithmetic mean of the first 5 values
of the Processor Queue Length value (so over 5 seconds), rather
than 0.0.
* Handle BrokenPipeError and when typeperf exit.
* format_duration(1.5) now returns '1.5 sec', rather than
'1 sec 500 ms'
Diffstat (limited to 'Lib/test/libregrtest/win_utils.py')
-rw-r--r-- | Lib/test/libregrtest/win_utils.py | 66 |
1 files changed, 47 insertions, 19 deletions
diff --git a/Lib/test/libregrtest/win_utils.py b/Lib/test/libregrtest/win_utils.py index 0b73a94..028c011 100644 --- a/Lib/test/libregrtest/win_utils.py +++ b/Lib/test/libregrtest/win_utils.py @@ -1,4 +1,5 @@ import _winapi +import math import msvcrt import os import subprocess @@ -10,11 +11,14 @@ from test.libregrtest.utils import print_warning # Max size of asynchronous reads BUFSIZE = 8192 -# Exponential damping factor (see below) -LOAD_FACTOR_1 = 0.9200444146293232478931553241 - # 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 # Windows registry subkey of HKEY_LOCAL_MACHINE where the counter names # of typeperf are registered COUNTER_REGISTRY_KEY = (r"SOFTWARE\Microsoft\Windows NT\CurrentVersion" @@ -30,10 +34,10 @@ class WindowsLoadTracker(): """ def __init__(self): - self.load = 0.0 - self.counter_name = '' + self._values = [] + self._load = None self._buffer = '' - self.popen = None + self._popen = None self.start() def start(self): @@ -65,7 +69,7 @@ class WindowsLoadTracker(): # Spawn off the load monitor counter_name = self._get_counter_name() command = ['typeperf', counter_name, '-si', str(SAMPLING_INTERVAL)] - self.popen = subprocess.Popen(' '.join(command), stdout=command_stdout, cwd=support.SAVEDCWD) + self._popen = subprocess.Popen(' '.join(command), stdout=command_stdout, cwd=support.SAVEDCWD) # Close our copy of the write end of the pipe os.close(command_stdout) @@ -85,12 +89,16 @@ class WindowsLoadTracker(): process_queue_length = counters_dict['44'] return f'"\\{system}\\{process_queue_length}"' - def close(self): - if self.popen is None: + def close(self, kill=True): + if self._popen is None: return - self.popen.kill() - self.popen.wait() - self.popen = None + + self._load = None + + if kill: + self._popen.kill() + self._popen.wait() + self._popen = None def __del__(self): self.close() @@ -109,7 +117,7 @@ class WindowsLoadTracker(): value = value[1:-1] return float(value) - def read_lines(self): + def _read_lines(self): overlapped, _ = _winapi.ReadFile(self.pipe, BUFSIZE, True) bytes_read, res = overlapped.GetOverlappedResult(False) if res != 0: @@ -135,7 +143,21 @@ class WindowsLoadTracker(): return lines def getloadavg(self): - for line in self.read_lines(): + if self._popen is None: + return None + + returncode = self._popen.poll() + if returncode is not None: + self.close(kill=False) + return None + + try: + lines = self._read_lines() + except BrokenPipeError: + self.close() + return None + + for line in lines: line = line.rstrip() # Ignore the initial header: @@ -148,7 +170,7 @@ class WindowsLoadTracker(): continue try: - load = self._parse_line(line) + processor_queue_length = self._parse_line(line) except ValueError: print_warning("Failed to parse typeperf output: %a" % line) continue @@ -156,7 +178,13 @@ class WindowsLoadTracker(): # 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 - new_load = self.load * LOAD_FACTOR_1 + load * (1.0 - LOAD_FACTOR_1) - self.load = new_load - - return self.load + # 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) + + return self._load |