summaryrefslogtreecommitdiffstats
path: root/testing/raptor/browsertime/support-scripts/browsertime_tp6_bench.py
diff options
context:
space:
mode:
Diffstat (limited to 'testing/raptor/browsertime/support-scripts/browsertime_tp6_bench.py')
-rw-r--r--testing/raptor/browsertime/support-scripts/browsertime_tp6_bench.py217
1 files changed, 217 insertions, 0 deletions
diff --git a/testing/raptor/browsertime/support-scripts/browsertime_tp6_bench.py b/testing/raptor/browsertime/support-scripts/browsertime_tp6_bench.py
new file mode 100644
index 0000000000..f1a514ccd0
--- /dev/null
+++ b/testing/raptor/browsertime/support-scripts/browsertime_tp6_bench.py
@@ -0,0 +1,217 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+import copy
+import re
+
+import filters
+from base_python_support import BasePythonSupport
+from utils import bool_from_str
+
+DOMAIN_MATCHER = re.compile(r"(?:https?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:\/\n]+)")
+VARIANCE_THRESHOLD = 0.2
+
+
+def extract_domain(link):
+ match = DOMAIN_MATCHER.search(link)
+ if match:
+ return match.group(1)
+ raise Exception(f"Could not find domain for {link}")
+
+
+class TP6BenchSupport(BasePythonSupport):
+ def __init__(self, **kwargs):
+ self._load_times = []
+ self._total_times = []
+ self._geomean_load_times = []
+ self._sites_tested = 0
+ self._test_pages = {}
+
+ def setup_test(self, test, args):
+ from cmdline import DESKTOP_APPS
+ from manifest import get_browser_test_list
+ from utils import transform_subtest
+
+ all_tests = get_browser_test_list(args.app, args.run_local)
+
+ manifest_to_find = "browsertime-tp6.toml"
+ if args.app not in DESKTOP_APPS:
+ manifest_to_find = "browsertime-tp6m.toml"
+
+ test_urls = []
+ playback_pageset_manifests = []
+ for parsed_test in all_tests:
+ if manifest_to_find in parsed_test["manifest"]:
+ if not bool_from_str(parsed_test.get("benchmark_page", "false")):
+ continue
+ test_url = parsed_test["test_url"]
+ test_urls.append(test_url)
+ playback_pageset_manifests.append(
+ transform_subtest(
+ parsed_test["playback_pageset_manifest"], parsed_test["name"]
+ )
+ )
+ self._test_pages[test_url] = parsed_test
+
+ if len(playback_pageset_manifests) == 0:
+ raise Exception("Could not find any manifests for testing.")
+
+ test["test_url"] = ",".join(test_urls)
+ test["playback_pageset_manifest"] = ",".join(playback_pageset_manifests)
+
+ def handle_result(self, bt_result, raw_result, last_result=False, **kwargs):
+ measurements = {"totalTime": []}
+
+ # Find new results to add
+ for res in raw_result["extras"]:
+ if "pageload-benchmark" in res:
+ total_time = int(
+ round(res["pageload-benchmark"].get("totalTime", 0), 0)
+ )
+ measurements["totalTime"].append(total_time)
+ self._total_times.append(total_time)
+
+ # Gather the load times of each page/cycle to help with diagnosing issues
+ load_times = []
+ result_name = None
+ for cycle in raw_result["browserScripts"]:
+ if not result_name:
+ # When the test name is unknown, we use the url TLD combined
+ # with the page title to differentiate pages with similar domains, and
+ # limit it to 35 characters
+ page_url = cycle["pageinfo"].get("url", "")
+ if self._test_pages.get(page_url, None) is not None:
+ result_name = self._test_pages[page_url]["name"]
+ else:
+ page_name = extract_domain(page_url)
+ page_title = (
+ cycle["pageinfo"].get("documentTitle", "")[:35].replace(" ", "")
+ )
+ result_name = f"{page_name} - {page_title}"
+
+ load_time = cycle["timings"]["loadEventEnd"]
+ fcp = cycle["timings"]["paintTiming"]["first-contentful-paint"]
+ lcp = (
+ cycle["timings"]
+ .get("largestContentfulPaint", {})
+ .get("renderTime", None)
+ )
+ measurements.setdefault(f"{result_name} - loadTime", []).append(load_time)
+
+ measurements.setdefault(f"{result_name} - fcp", []).append(fcp)
+
+ if lcp is not None:
+ measurements.setdefault(f"{result_name} - lcp", []).append(lcp)
+
+ load_times.append(load_time)
+
+ cur_load_times = self._load_times or [0] * len(load_times)
+ self._load_times = list(map(sum, zip(cur_load_times, load_times)))
+ self._sites_tested += 1
+
+ for measurement, values in measurements.items():
+ bt_result["measurements"].setdefault(measurement, []).extend(values)
+ if last_result:
+ bt_result["measurements"]["totalLoadTime"] = self._load_times
+ bt_result["measurements"]["totalLoadTimePerSite"] = [
+ round(total_load_time / self._sites_tested, 2)
+ for total_load_time in self._load_times
+ ]
+ bt_result["measurements"]["totalTimePerSite"] = [
+ round(total_time / self._sites_tested, 2)
+ for total_time in self._total_times
+ ]
+
+ def _build_subtest(self, measurement_name, replicates, test):
+ unit = test.get("unit", "ms")
+ if test.get("subtest_unit"):
+ unit = test.get("subtest_unit")
+
+ return {
+ "name": measurement_name,
+ "lowerIsBetter": test.get("lower_is_better", True),
+ "alertThreshold": float(test.get("alert_threshold", 2.0)),
+ "unit": unit,
+ "replicates": replicates,
+ "value": round(filters.geometric_mean(replicates), 3),
+ }
+
+ def summarize_test(self, test, suite, **kwargs):
+ suite["type"] = "pageload"
+ if suite["subtests"] == {}:
+ suite["subtests"] = []
+ for measurement_name, replicates in test["measurements"].items():
+ if not replicates:
+ continue
+ suite["subtests"].append(
+ self._build_subtest(measurement_name, replicates, test)
+ )
+ suite["subtests"].sort(key=lambda subtest: subtest["name"])
+
+ def _produce_suite_alts(self, suite_base, subtests, suite_name_prefix):
+ geomean_suite = copy.deepcopy(suite_base)
+ geomean_suite["subtests"] = copy.deepcopy(subtests)
+ median_suite = copy.deepcopy(geomean_suite)
+ median_suite["subtests"] = copy.deepcopy(subtests)
+
+ subtest_values = []
+ for subtest in subtests:
+ subtest_values.extend(subtest["replicates"])
+
+ geomean_suite["name"] = suite_name_prefix + "-geomean"
+ geomean_suite["value"] = filters.geometric_mean(subtest_values)
+ for subtest in geomean_suite["subtests"]:
+ subtest["value"] = filters.geometric_mean(subtest["replicates"])
+
+ median_suite["name"] = suite_name_prefix + "-median"
+ median_suite["value"] = filters.median(subtest_values)
+ for subtest in median_suite["subtests"]:
+ subtest["value"] = filters.median(subtest["replicates"])
+
+ return [
+ geomean_suite,
+ median_suite,
+ ]
+
+ def summarize_suites(self, suites):
+ fcp_subtests = []
+ lcp_subtests = []
+ load_time_subtests = []
+
+ for suite in suites:
+ for subtest in suite["subtests"]:
+ if "- fcp" in subtest["name"]:
+ fcp_subtests.append(subtest)
+ elif "- lcp" in subtest["name"]:
+ lcp_subtests.append(subtest)
+ elif "- loadTime" in subtest["name"]:
+ load_time_subtests.append(subtest)
+
+ fcp_bench_suites = self._produce_suite_alts(
+ suites[0], fcp_subtests, "fcp-bench"
+ )
+
+ lcp_bench_suites = self._produce_suite_alts(
+ suites[0], lcp_subtests, "lcp-bench"
+ )
+
+ load_time_bench_suites = self._produce_suite_alts(
+ suites[0], load_time_subtests, "loadtime-bench"
+ )
+
+ overall_suite = copy.deepcopy(suites[0])
+ new_subtests = [
+ subtest
+ for subtest in suites[0]["subtests"]
+ if subtest["name"].startswith("total")
+ ]
+ overall_suite["subtests"] = new_subtests
+
+ new_suites = [
+ overall_suite,
+ *fcp_bench_suites,
+ *lcp_bench_suites,
+ *load_time_bench_suites,
+ ]
+ suites.pop()
+ suites.extend(new_suites)