From 020b4ec1ab959e96e9f630aa182c1c5042b660ba Mon Sep 17 00:00:00 2001 From: Patrick Meenan Date: Wed, 8 Nov 2023 15:49:32 -0500 Subject: [PATCH] Improve stability of benchmark-based CPU throttle scaling --- internal/webpagetest.py | 24 +++++++++++++++++++++++- wptagent.py | 2 ++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/internal/webpagetest.py b/internal/webpagetest.py index 801c5b972..fdc7342f8 100644 --- a/internal/webpagetest.py +++ b/internal/webpagetest.py @@ -234,10 +234,32 @@ def benchmark_cpu(self): hash_val.update(hash_data) iteration += 1 elapsed = monotonic() - start - self.cpu_scale_multiplier = 1.0 / elapsed + self.cpu_scale_multiplier = min(1.0 / elapsed, float(self.options.maxcpuscale)) logging.debug('CPU Benchmark elapsed time: %0.3f, multiplier: %0.3f', elapsed, self.cpu_scale_multiplier) + # Get the median scale value from the last 9 benchmarks on this machine + try: + cpu_scale = [] + scale_file = os.path.join(self.persistent_dir, 'cpu_scale.json') + if os.path.isfile(scale_file): + with open(scale_file, 'r') as f_in: + cpu_scale = json.load(f_in) + if type(cpu_scale) is list: + if len(cpu_scale) >= 9: + cpu_scale.pop(0) + cpu_scale.append(self.cpu_scale_multiplier) + if not os.path.isdir(self.persistent_dir): + os.makedirs(self.persistent_dir) + with open(scale_file, 'w') as f_out: + json.dump(cpu_scale, f_out) + cpu_scale.sort() + median_index = int((len(cpu_scale) - 1) / 2) + self.cpu_scale_multiplier = cpu_scale[median_index] + logging.debug('CPU Benchmark selected multiplier: %0.3f at index %d of %d values', self.cpu_scale_multiplier, median_index, len(cpu_scale)) + except Exception: + logging.exception('Error processing benchmark history') + def get_persistent_dir(self): """Return the path to the persistent cache directory""" return self.persistent_dir diff --git a/wptagent.py b/wptagent.py index 99886f800..7829321f5 100644 --- a/wptagent.py +++ b/wptagent.py @@ -1152,6 +1152,8 @@ def main(): parser.add_argument('--healthcheckport', type=int, default=8889, help='Run a HTTP health check server on the given port.') parser.add_argument('--har', action='store_true', default=False, help="Generate a per-run HAR file as part of the test result (defaults to False).") + parser.add_argument('--maxcpuscale', type=int, default=2, + help='Maximum scaling to apply to CPU throttle based on host benchmark (defaults to 2).') # Video capture/display settings parser.add_argument('--xvfb', action='store_true', default=False,