From 8dd40ed2bd4411d73ca1661803635345c2d9c3c1 Mon Sep 17 00:00:00 2001 From: Samson <16504129+sagudev@users.noreply.github.com> Date: Thu, 29 Aug 2024 17:58:57 +0200 Subject: [PATCH] mach: Add `test-speedometer` command and `--bmf-output` to speedometer and dromaeo (#33247) * Allow exporting Dromaeo results as BMF JSON Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * Add speedometer runner Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> --------- Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> --- python/servo/testing_commands.py | 49 +++++++++++++++++++++++++++++--- tests/dromaeo/run_dromaeo.py | 13 +++++++-- 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/python/servo/testing_commands.py b/python/servo/testing_commands.py index fb7f1e22931..0e08f84c3ea 100644 --- a/python/servo/testing_commands.py +++ b/python/servo/testing_commands.py @@ -16,6 +16,7 @@ import os.path as path import shutil import subprocess import textwrap +import json from python.servo.post_build_commands import PostBuildCommands import wpt @@ -402,9 +403,16 @@ class MachCommands(CommandBase): @Command('test-dromaeo', description='Run the Dromaeo test suite', category='testing') @CommandArgument('tests', default=["recommended"], nargs="...", help="Specific tests to run") + @CommandArgument('--bmf-output', default=None, help="Specify BMF JSON output file") @CommandBase.common_command_arguments(binary_selection=True) - def test_dromaeo(self, tests, servo_binary: str): - return self.dromaeo_test_runner(tests, servo_binary) + def test_dromaeo(self, tests, servo_binary: str, bmf_output: str | None = None): + return self.dromaeo_test_runner(tests, servo_binary, bmf_output) + + @Command('test-speedometer', description="Run servo's speedometer", category='testing') + @CommandArgument('--bmf-output', default=None, help="Specify BMF JSON output file") + @CommandBase.common_command_arguments(binary_selection=True) + def test_speedometer(self, servo_binary: str, bmf_output: str | None = None): + return self.speedometer_runner(servo_binary, bmf_output) @Command('update-jquery', description='Update the jQuery test suite expected results', @@ -488,10 +496,14 @@ class MachCommands(CommandBase): return call([run_file, cmd, bin_path, base_dir]) - def dromaeo_test_runner(self, tests, binary: str): + def dromaeo_test_runner(self, tests, binary: str, bmf_output: str | None): base_dir = path.abspath(path.join("tests", "dromaeo")) dromaeo_dir = path.join(base_dir, "dromaeo") run_file = path.join(base_dir, "run_dromaeo.py") + if bmf_output: + bmf_output = path.abspath(bmf_output) + else: + bmf_output = "" # Clone the Dromaeo repository if it doesn't exist if not os.path.isdir(dromaeo_dir): @@ -510,7 +522,36 @@ class MachCommands(CommandBase): bin_path = path.abspath(binary) return check_call( - [run_file, "|".join(tests), bin_path, base_dir]) + [run_file, "|".join(tests), bin_path, base_dir, bmf_output]) + + def speedometer_runner(self, binary: str, bmf_output: str | None): + speedometer = json.loads(subprocess.check_output([ + binary, + "https://servospeedometer.netlify.app?headless=1", + "--pref", "dom.allow_scripts_to_close_windows", + "--resolution=1100x900", + "--headless"], timeout=60).decode()) + + print(f"Score: {speedometer['Score']['mean']} ± {speedometer['Score']['delta']}") + + if bmf_output: + output = dict() + + def parse_speedometer_result(result): + output[f"Speedometer/{result['name']}"] = { + 'latency': { # speedometer has ms we need to convert to ns + 'value': float(result['mean']) * 1000.0, + 'lower_value': float(result['min']) * 1000.0, + 'upper_value': float(result['max']) * 1000.0, + } + } + for child in result['children']: + parse_speedometer_result(child) + + for v in speedometer.values(): + parse_speedometer_result(v) + with open(bmf_output, 'w', encoding='utf-8') as f: + json.dump(output, f, indent=4) def create_parser_create(): diff --git a/tests/dromaeo/run_dromaeo.py b/tests/dromaeo/run_dromaeo.py index 5e9d2c54228..b9ece34588a 100755 --- a/tests/dromaeo/run_dromaeo.py +++ b/tests/dromaeo/run_dromaeo.py @@ -26,7 +26,7 @@ def run_servo(servo_exe, tests): # Print usage if command line args are incorrect def print_usage(): - print("USAGE: {0} tests servo_binary dromaeo_base_dir".format(sys.argv[0])) + print("USAGE: {0} tests servo_binary dromaeo_base_dir [BMF JSON output]".format(sys.argv[0])) post_data = None @@ -48,10 +48,13 @@ class RequestHandler(SimpleHTTPRequestHandler): if __name__ == '__main__': - if len(sys.argv) == 4: + if len(sys.argv) == 4 or len(sys.argv) == 5: tests = sys.argv[1] servo_exe = sys.argv[2] base_dir = sys.argv[3] + bmf_output = "" + if len(sys.argv) == 5: + bmf_output = sys.argv[4] os.chdir(base_dir) # Ensure servo binary can be found @@ -76,6 +79,12 @@ if __name__ == '__main__': print("-{0}-|-{1}-".format("-" * length, "-" * number)) for test in data: print(" {0}{1} | {2}".format(test, " " * (length - len(test)), data[test])) + if bmf_output: + output = dict() + for (k, v) in data.items(): + output[f"Dromaeo/{k}"] = {'throughput': {'value': float(v)}} + with open(bmf_output, 'w', encoding='utf-8') as f: + json.dump(output, f, indent=4) proc.kill() else: print_usage()