#!/usr/bin/env vpython3
# Copyright 2016 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# pylint: disable=too-many-lines
# pylint: disable=line-too-long
"""Generates chromium.perf{,.fyi}.json from a set of condensed configs.
This file contains condensed configurations for the perf bots along with
logic to inflate those into the full (unwieldy) configurations in
//testing/buildbot that are consumed by the chromium recipe code.
"""
from __future__ import print_function
import argparse
import collections
import copy
import csv
import filecmp
import json
import os
import re
import shutil
import sys
import tempfile
import textwrap
from chrome_telemetry_build import android_browser_types
from core import benchmark_finders
from core import benchmark_utils
from core import bot_platforms
from core import path_util
from core import undocumented_benchmarks as ub_module
path_util.AddTelemetryToPath()
from telemetry import decorators
# The condensed configurations below get inflated into the perf builder
# configurations in //testing/buildbot. The expected format of these is:
#
# {
# 'builder_name1': {
# # Targets that the builder should compile in addition to those
# # required for tests, as a list of strings.
# 'additional_compile_targets': ['target1', 'target2', ...],
#
# 'tests': [
# {
# # Arguments to pass to the test suite as a list of strings.
# 'extra_args': ['--arg1', '--arg2', ...],
#
# # Name of the isolate to run as a string.
# 'isolate': 'isolate_name',
#
# # Name of the test suite as a string.
# # If not present, will default to `isolate`.
# 'name': 'presentation_name',
#
# # The number of shards for this test as an int.
# # This is only required for GTEST tests since this is defined
# # in bot_platforms.py for Telemetry tests.
# 'num_shards': 2,
#
# # What kind of test this is; for options, see TEST_TYPES
# # below. Defaults to TELEMETRY.
# 'type': TEST_TYPES.TELEMETRY,
# },
# ...
# ],
#
# # Testing platform, as a string. Used in determining the browser
# # argument to pass to telemetry.
# 'platform': 'platform_name',
#
# # Dimensions to pass to swarming, as a dict of string keys & values.
# 'dimension': {
# 'dimension1_name': 'dimension1_value',
# ...
# },
# },
# ...
# }
class TEST_TYPES(object):
GENERIC = 0
GTEST = 1
TELEMETRY = 2
ALL = (GENERIC, GTEST, TELEMETRY)
# This is an opt-in list for tester which will skip the perf data handling.
# The perf data will be handled on a separated 'processor' VM.
# This list will be removed or replace by an opt-out list.
LIGHTWEIGHT_TESTERS = [
'linux-perf',
'win-10-perf',
'win-10_laptop_low_end-perf',
'win-11-perf',
'mac-laptop_high_end-perf',
'mac-laptop_low_end-perf',
]
# This is an opt-in list for builders which uses dynamic sharding.
DYNAMIC_SHARDING_TESTERS = ['linux-perf-calibration']
CALIBRATION_BUILDERS = {
'linux-perf-calibration': {
'tests': [
{
'isolate': 'performance_test_suite',
'extra_args': [
'--assert-gpu-compositing',
],
},
],
'platform':
'linux',
'dimension': {
'gpu': '10de:1cb3-440.100',
'os': 'Ubuntu-18.04',
'pool': 'chrome.tests.perf',
'synthetic_product_name': 'PowerEdge R230 (Dell Inc.)'
},
},
}
FYI_BUILDERS = {
'android-cfi-builder-perf-fyi': {
'additional_compile_targets': [
'android_tools',
'chrome_public_apk',
'chromium_builder_perf',
'push_apps_to_background_apk',
'system_webview_apk',
'system_webview_shell_apk',
],
},
'android_arm64-cfi-builder-perf-fyi': {
'additional_compile_targets': [
'android_tools',
'chrome_public_apk',
'chromium_builder_perf',
'push_apps_to_background_apk',
'system_webview_apk',
'system_webview_shell_apk',
],
},
'linux-perf-fyi': {
'tests': [{
'isolate':
'performance_test_suite',
'extra_args': [
'--output-format=histograms',
'--experimental-tbmv3-metrics',
],
}],
'platform':
'linux',
'dimension': {
'gpu': '10de',
'os': 'Ubuntu',
'pool': 'chrome.tests.perf-fyi',
},
},
'fuchsia-perf-nsn': {
'tests': [{
'isolate':
'performance_web_engine_test_suite',
'extra_args': [
'--output-format=histograms', '--experimental-tbmv3-metrics',
'--extra-path=/b/s/w/ir/bin/'
] + bot_platforms.FUCHSIA_EXEC_ARGS['nelson'],
'type':
TEST_TYPES.TELEMETRY,
}],
'platform':
'fuchsia-wes',
# TODO(crbug.com/40272046): Replace with long-term solution for ssh in Fuchsia img,
# or codify as long-term solution.
'cipd': {
"cipd_package": "fuchsia/third_party/openssh-portable/${platform}",
"location": ".",
"revision": "build_id:8787350426829126785"
},
'dimension': {
'cpu': None,
'device_type': 'Nelson',
'os': 'Fuchsia',
'pool': 'chrome.tests',
},
},
'fuchsia-perf-shk': {
'tests': [{
'isolate':
'performance_web_engine_test_suite',
'extra_args': [
'--output-format=histograms', '--experimental-tbmv3-metrics',
'--extra-path=/b/s/w/ir/bin/'
] + bot_platforms.FUCHSIA_EXEC_ARGS['sherlock'],
'type':
TEST_TYPES.TELEMETRY,
}],
'platform':
'fuchsia-wes',
# TODO(crbug.com/40272046): Replace with long-term solution for ssh in Fuchsia img,
# or codify as long-term solution.
'cipd': {
"cipd_package": "fuchsia/third_party/openssh-portable/${platform}",
"location": ".",
"revision": "build_id:8787350426829126785"
},
'dimension': {
'cpu': None,
'device_type': 'Sherlock',
'os': 'Fuchsia',
'pool': 'chrome.tests',
},
},
'win-10_laptop_low_end-perf_HP-Candidate': {
'tests': [
{
'isolate':
'performance_test_suite',
'extra_args': [
'--output-format=histograms',
'--experimental-tbmv3-metrics',
],
},
],
'platform':
'win',
'target_bits':
64,
'dimension': {
'pool':
'chrome.tests.perf-fyi',
# TODO(crbug.com/41463380): Explicitly set the gpu to None to make
# chromium_swarming recipe_module ignore this dimension.
'gpu':
None,
'os':
'Windows-10',
'synthetic_product_name':
'HP Laptop 15-bs1xx [Type1ProductConfigId] (HP)'
},
},
'chromeos-kevin-builder-perf-fyi': {
'additional_compile_targets': ['chromium_builder_perf'],
},
'chromeos-kevin-perf-fyi': {
'tests': [
{
'isolate':
'performance_test_suite',
'extra_args': [
# The magic hostname that resolves to a CrOS device in the test lab
'--remote=variable_chromeos_device_hostname',
],
},
],
'platform':
'chromeos',
'target_bits':
32,
'dimension': {
'pool': 'chrome.tests',
# TODO(crbug.com/41463380): Explicitly set the gpu to None to make
# chromium_swarming recipe_module ignore this dimension.
'gpu': None,
'os': 'ChromeOS',
'device_type': 'kevin',
},
},
'fuchsia-builder-perf-arm64': {
'additional_compile_targets': [
'web_engine_shell_pkg', 'cast_runner_pkg', 'chromium_builder_perf',
'base_perftests'
],
},
}
# These configurations are taken from chromium_perf.py in
# build/scripts/slave/recipe_modules/chromium_tests and must be kept in sync
# to generate the correct json for each tester
#
# The dimensions in pinpoint configs, excluding the dimension "pool",
# must be kept in sync with the dimensions here.
# This is to make sure the same type of machines are used between waterfall
# tests and pinpoint jobs
#
# On desktop builders, chromedriver is added as an additional compile target.
# The perf waterfall builds this target for each commit, and the resulting
# ChromeDriver is archived together with Chrome for use in bisecting.
# This can be used by Chrome test team, as well as by google3 teams for
# bisecting Chrome builds with their web tests. For questions or to report
# issues, please contact [email protected].
BUILDERS = {
'android-builder-perf': {
'tests': [
{
'name': 'resource_sizes_monochrome_minimal_apks',
'isolate': 'resource_sizes_monochrome_minimal_apks',
'type': TEST_TYPES.GENERIC,
'resultdb': {
'has_native_resultdb_integration': True,
},
},
{
'name': 'resource_sizes_trichrome_google',
'isolate': 'resource_sizes_trichrome_google',
'type': TEST_TYPES.GENERIC,
'resultdb': {
'has_native_resultdb_integration': True,
},
},
{
'name': 'resource_sizes_system_webview_google_bundle',
'isolate': 'resource_sizes_system_webview_google_bundle',
'type': TEST_TYPES.GENERIC,
'resultdb': {
'has_native_resultdb_integration': True,
},
},
],
'dimension': {
'cpu': 'x86',
'os': 'Ubuntu-22.04',
'pool': 'chrome.tests',
},
'perf_trigger':
False,
},
'android-builder-perf-pgo': {
'dimension': {
'cpu': 'x86',
'os': 'Ubuntu-22.04',
'pool': 'chrome.tests',
},
'perf_trigger': False,
},
'android_arm64-builder-perf': {
'tests': [
{
'name': 'resource_sizes_monochrome_minimal_apks',
'isolate': 'resource_sizes_monochrome_minimal_apks',
'type': TEST_TYPES.GENERIC,
'resultdb': {
'has_native_resultdb_integration': True,
},
},
{
'name': 'resource_sizes_trichrome_google',
'isolate': 'resource_sizes_trichrome_google',
'type': TEST_TYPES.GENERIC,
'resultdb': {
'has_native_resultdb_integration': True,
},
},
{
'name': 'resource_sizes_system_webview_google_bundle',
'isolate': 'resource_sizes_system_webview_google_bundle',
'type': TEST_TYPES.GENERIC,
'resultdb': {
'has_native_resultdb_integration': True,
},
},
],
'dimension': {
'cpu': 'x86',
'os': 'Ubuntu-22.04',
'pool': 'chrome.tests',
},
'perf_trigger':
False,
},
'android_arm64-builder-perf-pgo': {
'dimension': {
'cpu': 'x86',
'os': 'Ubuntu-22.04',
'pool': 'chrome.tests',
},
'perf_trigger': False,
},
'android_arm64_high_end-builder-perf': {
'additional_compile_targets': ['trichrome_google_64_32_minimal_apks'],
'pinpoint_additional_compile_targets': [],
},
'linux-builder-perf': {
'additional_compile_targets': [
'chromedriver_group',
'chrome/installer/linux',
],
'pinpoint_additional_compile_targets': [],
'tests': [{
'name': 'chrome_sizes',
'isolate': 'chrome_sizes',
'type': TEST_TYPES.GENERIC,
'resultdb': {
'has_native_resultdb_integration': True,
},
}],
'dimension': {
'cpu': 'x86-64',
'os': 'Ubuntu-22.04',
'pool': 'chrome.tests',
},
'perf_trigger':
False,
},
'linux-builder-perf-pgo': {
'dimension': {
'cpu': 'x86-64',
'os': 'Ubuntu-22.04',
'pool': 'chrome.tests',
},
'perf_trigger': False,
},
'linux-builder-perf-rel': {},
'mac-builder-perf': {
'additional_compile_targets': ['chromedriver'],
'pinpoint_additional_compile_targets': [],
'tests': [{
'name': 'chrome_sizes',
'isolate': 'chrome_sizes',
'type': TEST_TYPES.GENERIC,
'resultdb': {
'has_native_resultdb_integration': True,
},
}],
'dimension': {
'cpu': 'x86-64',
'os': 'Mac',
'pool': 'chrome.tests',
},
'perf_trigger':
False,
},
'mac-builder-perf-pgo': {
'dimension': {
'cpu': 'x86-64',
'os': 'Mac',
'pool': 'chrome.tests',
},
'perf_trigger': False,
},
'mac-arm-builder-perf': {
'additional_compile_targets': ['chromedriver'],
'pinpoint_additional_compile_targets': [],
'tests': [{
'name': 'chrome_sizes',
'isolate': 'chrome_sizes',
'type': TEST_TYPES.GENERIC,
'resultdb': {
'has_native_resultdb_integration': True,
},
}],
'dimension': {
'cpu': 'x86',
'os': 'Mac',
'pool': 'chrome.tests',
},
'perf_trigger':
False,
},
'mac-arm-builder-perf-pgo': {
'dimension': {
'cpu': 'x86',
'os': 'Mac',
'pool': 'chrome.tests',
},
'perf_trigger': False,
},
'win64-builder-perf': {
'additional_compile_targets': ['chromedriver'],
'pinpoint_additional_compile_targets': [],
'tests': [{
'name': 'chrome_sizes',
'isolate': 'chrome_sizes',
'type': TEST_TYPES.GENERIC,
'resultdb': {
'has_native_resultdb_integration': True,
},
}],
'dimension': {
'cpu': 'x86-64',
'os': 'Windows-10',
'pool': 'chrome.tests',
},
'perf_trigger':
False,
},
'win64-builder-perf-pgo': {
'dimension': {
'cpu': 'x86-64',
'os': 'Windows-10',
'pool': 'chrome.tests',
},
'perf_trigger': False,
},
'android-pixel4_webview-perf': {
'tests': [{
'isolate': 'performance_webview_test_suite',
}],
'platform': 'android-webview-trichrome-google-bundle',
'dimension': {
'pool': 'chrome.tests.perf-webview',
'os': 'Android',
'device_type': 'flame',
'device_os': 'RP1A.201105.002',
'device_os_flavor': 'google',
},
},
'android-pixel4-perf': {
'tests': [{
'isolate':
'performance_test_suite_android_clank_trichrome_chrome_google_64_32_bundle',
}],
'platform':
'android-trichrome-chrome-google-64-32-bundle',
'dimension': {
'pool': 'chrome.tests.perf',
'os': 'Android',
'device_type': 'flame',
'device_os': 'RP1A.201105.002',
'device_os_flavor': 'google',
},
},
'android-pixel4-perf-pgo': {
'tests': [{
'isolate':
'performance_test_suite_android_clank_trichrome_chrome_google_64_32_bundle',
}],
'platform':
'android-trichrome-chrome-google-64-32-bundle',
'dimension': {
'pool': 'chrome.tests.perf',
'os': 'Android',
'device_type': 'flame',
'device_os': 'RP1A.201105.002',
'device_os_flavor': 'google',
},
},
'android-pixel6-perf': {
'tests': [{
'isolate':
'performance_test_suite_android_clank_trichrome_chrome_google_64_32_bundle',
}],
'platform':
'android-trichrome-chrome-google-64-32-bundle',
'dimension': {
'pool': 'chrome.tests.perf',
'os': 'Android',
'device_type': 'oriole',
'device_os': 'AP1A.240405.002',
'device_os_flavor': 'google',
},
},
'android-pixel6-perf-pgo': {
'tests': [{
'isolate':
'performance_test_suite_android_clank_trichrome_chrome_google_64_32_bundle',
}],
'platform':
'android-trichrome-chrome-google-64-32-bundle',
'dimension': {
'pool': 'chrome.tests.perf-pgo',
'os': 'Android',
'device_type': 'oriole',
'device_os': 'AP1A.240405.002',
'device_os_flavor': 'google',
},
},
'android-pixel-fold-perf': {
'tests': [{
'isolate':
'performance_test_suite_android_clank_trichrome_chrome_google_64_32_bundle',
}],
'platform':
'android-trichrome-chrome-google-64-32-bundle',
'dimension': {
'pool': 'chrome.tests.perf',
'os': 'Android',
'device_type': 'felix',
# 'device_os': 'UQ1A.240205.002', # relax before all pixel folds are reimaged
'device_os_flavor': 'google',
},
},
'android-pixel-tangor-perf': {
'tests': [{
'isolate':
'performance_test_suite_android_clank_trichrome_chrome_google_64_32_bundle',
}],
'platform':
'android-trichrome-chrome-google-64-32-bundle',
'dimension': {
'pool': 'chrome.tests.perf',
'os': 'Android',
'device_type': 'tangorpro',
'device_os_flavor': 'google',
},
},
'android-pixel6-pro-perf': {
'tests': [{
'isolate':
'performance_test_suite_android_clank_trichrome_chrome_google_64_32_bundle',
}],
'platform':
'android-trichrome-chrome-google-64-32-bundle',
'dimension': {
'pool': 'chrome.tests.perf',
'os': 'Android',
'device_type': 'raven',
'device_os': 'AP1A.240405.002',
'device_os_flavor': 'google',
},
},
'android-pixel6-pro-perf-pgo': {
'tests': [{
'isolate':
'performance_test_suite_android_clank_trichrome_chrome_google_64_32_bundle',
}],
'platform':
'android-trichrome-chrome-google-64-32-bundle',
'dimension': {
'pool': 'chrome.tests.perf',
'os': 'Android',
'device_type': 'raven',
'device_os': 'AP1A.240405.002',
'device_os_flavor': 'google',
},
},
'android-go-wembley-perf': {
'tests': [{
'isolate':
'performance_test_suite_android_clank_trichrome_bundle',
}],
'platform':
'android-trichrome-bundle',
'dimension': {
'pool': 'chrome.tests.perf',
'os': 'Android',
'device_type': 'wembley_2GB',
'device_os_flavor': 'google',
},
},
'android-go-wembley_webview-perf': {
'tests': [{
'isolate': 'performance_webview_test_suite',
}],
'platform': 'android-webview-google',
'dimension': {
'pool': 'chrome.tests.perf-webview',
'os': 'Android',
'device_type': 'wembley_2GB',
'device_os_flavor': 'google',
},
},
'android-new-pixel-perf': {
'tests': [{
'isolate':
'performance_test_suite_android_clank_trichrome_chrome_google_64_32_bundle',
}],
'platform':
'android-trichrome-chrome-google-64-32-bundle',
'dimension': {},
},
'android-new-pixel-perf-pgo': {
'tests': [{
'isolate':
'performance_test_suite_android_clank_trichrome_chrome_google_64_32_bundle',
}],
'platform':
'android-trichrome-chrome-google-64-32-bundle',
'dimension': {},
},
'android-new-pixel-pro-perf': {
'tests': [{
'isolate':
'performance_test_suite_android_clank_trichrome_chrome_google_64_32_bundle',
}],
'platform':
'android-trichrome-chrome-google-64-32-bundle',
'dimension': {},
},
'android-new-pixel-pro-perf-pgo': {
'tests': [{
'isolate':
'performance_test_suite_android_clank_trichrome_chrome_google_64_32_bundle',
}],
'platform':
'android-trichrome-chrome-google-64-32-bundle',
'dimension': {},
},
'win-10_laptop_low_end-perf': {
'tests': [
{
'isolate': 'performance_test_suite',
'extra_args': [
'--assert-gpu-compositing',
],
},
],
'platform':
'win',
'target_bits':
64,
'dimension': {
'pool':
'chrome.tests.perf',
# Explicitly set GPU driver version and Windows OS version such
# that we can be informed if this
# version ever changes or becomes inconsistent. It is important
# that bots are homogeneous. See crbug.com/988045 for history.
'os':
'Windows-10-19045',
'gpu':
'8086:1616-20.19.15.5171',
'synthetic_product_name':
'HP Laptop 15-bs1xx [Type1ProductConfigId] (HP)'
},
},
'win-10_laptop_low_end-perf-pgo': {
'tests': [
{
'isolate': 'performance_test_suite',
'extra_args': [
'--assert-gpu-compositing',
],
},
],
'platform':
'win',
'target_bits':
64,
'dimension': {
'pool': 'chrome.tests.perf',
'os': 'Windows-10',
'gpu': '8086:1616',
},
},
'win-10-perf': {
'tests': [
{
'isolate': 'performance_test_suite',
'extra_args': [
'--assert-gpu-compositing',
],
},
],
'platform':
'win',
'target_bits':
64,
'dimension': {
'pool': 'chrome.tests.perf',
'os': 'Windows-10',
'synthetic_product_name': 'OptiPlex 7050 (Dell Inc.)'
},
},
'win-10-perf-pgo': {
'tests': [
{
'isolate': 'performance_test_suite',
'extra_args': [
'--assert-gpu-compositing',
],
},
],
'platform':
'win',
'target_bits':
64,
'dimension': {
'pool': 'chrome.tests.perf',
'os': 'Windows-10',
'synthetic_product_name': 'OptiPlex 7050 (Dell Inc.)'
},
},
'win-10_amd_laptop-perf': {
'tests': [
{
'isolate': 'performance_test_suite',
'extra_args': [
'--assert-gpu-compositing',
],
},
],
'platform':
'win',
'target_bits':
64,
'dimension': {
'pool': 'chrome.tests.perf',
# Explicitly set GPU driver version and Windows OS version such
# that we can be informed if this
# version ever changes or becomes inconsistent. It is important
# that bots are homogeneous. See crbug.com/988045 for history.
'os': 'Windows-10',
'gpu': '1002:1638',
'synthetic_product_name': 'OMEN by HP Laptop 16-c0xxx [ ] (HP)',
},
},
'win-10_amd_laptop-perf-pgo': {
'tests': [
{
'isolate': 'performance_test_suite',
'extra_args': [
'--assert-gpu-compositing',
],
},
],
'platform':
'win',
'target_bits':
64,
'dimension': {
'pool': 'chrome.tests.perf',
# Explicitly set GPU driver version and Windows OS version such
# that we can be informed if this
# version ever changes or becomes inconsistent. It is important
# that bots are homogeneous. See crbug.com/988045 for history.
'os': 'Windows-10',
'gpu': '1002:1638',
'synthetic_product_name': 'OMEN by HP Laptop 16-c0xxx [ ] (HP)',
},
},
'win-11-perf': {
'tests': [
{
'isolate': 'performance_test_suite',
'extra_args': [
'--assert-gpu-compositing',
],
},
],
'platform':
'win',
'target_bits':
64,
'dimension': {
'pool': 'chrome.tests.perf',
# Explicitly set GPU driver version and Windows OS version such
# that we can be informed if this
# version ever changes or becomes inconsistent. It is important
# that bots are homogeneous. See crbug.com/988045 for history.
'os': 'Windows-11-22631.2428',
'gpu': '102b:0536-4.5.0.5',
'synthetic_product_name': 'PowerEdge R350 (Dell Inc.)'
},
},
'win-11-perf-pgo': {
'tests': [
{
'isolate': 'performance_test_suite',
'extra_args': [
'--assert-gpu-compositing',
],
},
],
'platform':
'win',
'target_bits':
64,
'dimension': {
'pool': 'chrome.tests.perf',
# Explicitly set GPU driver version and Windows OS version such
# that we can be informed if this
# version ever changes or becomes inconsistent. It is important
# that bots are homogeneous. See crbug.com/988045 for history.
'os': 'Windows-11-22631.2428',
'gpu': '102b:0536-4.5.0.5',
'synthetic_product_name': 'PowerEdge R350 (Dell Inc.)'
},
},
'mac-laptop_low_end-perf': {
'tests': [
{
'isolate': 'performance_test_suite',
'extra_args': [
'--assert-gpu-compositing',
],
},
],
'platform':
'mac',
'dimension': {
'cpu':
'x86-64',
'gpu':
'8086:1626',
'os':
'Mac-12',
'pool':
'chrome.tests.perf',
'synthetic_product_name':
'MacBookAir7,2_x86-64-i5-5350U_Intel Broadwell HD Graphics 6000_8192_APPLE SSD SM0128G'
},
},
'mac-laptop_low_end-perf-pgo': {
'tests': [
{
'isolate': 'performance_test_suite',
'extra_args': [
'--assert-gpu-compositing',
],
},
],
'platform':
'mac',
'dimension': {
'cpu':
'x86-64',
'gpu':
'8086:1626',
'os':
'Mac-12',
'pool':
'chrome.tests.perf',
'synthetic_product_name':
'MacBookAir7,2_x86-64-i5-5350U_Intel Broadwell HD Graphics 6000_8192_APPLE SSD SM0128G'
},
},
'mac-m1_mini_2020-perf': {
'tests': [
{
'isolate': 'performance_test_suite',
'extra_args': [
'--assert-gpu-compositing',
],
},
],
'platform':
'mac',
'dimension': {
'cpu': 'arm',
'mac_model': 'Macmini9,1',
'os': 'Mac',
'pool': 'chrome.tests.perf',
},
},
'mac-m1_mini_2020-perf-pgo': {
'tests': [
{
'isolate': 'performance_test_suite',
'extra_args': [
'--assert-gpu-compositing',
],
},
],
'platform':
'mac',
'dimension': {
'cpu': 'arm',
'mac_model': 'Macmini9,1',
'os': 'Mac',
'pool': 'chrome.tests.perf-pgo',
},
},
'mac-m1_mini_2020-no-brp-perf': {
'tests': [
{
'isolate': 'performance_test_suite',
'extra_args': [
'--assert-gpu-compositing',
],
},
],
'platform':
'mac',
'dimension': {
'cpu': 'arm',
'mac_model': 'Macmini9,1',
'os': 'Mac',
'pool': 'chrome.tests.perf',
},
},
'mac-m1-pro-perf': {
'tests': [
{
'isolate': 'performance_test_suite',
'extra_args': [
'--assert-gpu-compositing',
],
},
],
'platform':
'mac',
'dimension': {
'cpu': 'arm',
'mac_model': 'MacBookPro18,3',
'os': 'Mac',
'pool': 'chrome.tests.perf',
},
},
'mac-m2-pro-perf': {
'tests': [
{
'isolate': 'performance_test_suite',
'extra_args': [
'--assert-gpu-compositing',
],
},
],
'platform':
'mac',
'dimension': {
'cpu': 'arm',
'mac_model': 'Mac14,7',
'os': 'Mac',
'pool': 'chrome.tests.perf',
},
},
'linux-perf': {
'tests': [
{
'isolate': 'performance_test_suite',
'extra_args': [
'--assert-gpu-compositing',
],
},
],
'platform':
'linux',
'dimension': {
'gpu': '10de:1cb3-440.100',
'os': 'Ubuntu-18.04',
'pool': 'chrome.tests.perf',
'synthetic_product_name': 'PowerEdge R230 (Dell Inc.)'
},
},
'linux-perf-pgo': {
'tests': [
{
'isolate': 'performance_test_suite',
'extra_args': [
'--assert-gpu-compositing',
],
},
],
'platform':
'linux',
'dimension': {
'gpu': '10de:1cb3-440.100',
'os': 'Ubuntu-18.04',
'pool': 'chrome.tests.perf',
'synthetic_product_name': 'PowerEdge R230 (Dell Inc.)'
},
},
'linux-perf-rel': {
'tests': [
{
'isolate': 'performance_test_suite',
'extra_args': [
'--assert-gpu-compositing',
],
},
],
'platform':
'linux',
'dimension': {
'gpu': '10de:1cb3-440.100',
'os': 'Ubuntu-18.04',
'pool': 'chrome.tests.perf',
'synthetic_product_name': 'PowerEdge R230 (Dell Inc.)'
},
},
'linux-r350-perf': {
'tests': [
{
'isolate': 'performance_test_suite',
'extra_args': [
'--assert-gpu-compositing',
],
},
],
'platform':
'linux',
'dimension': {
'os': 'Ubuntu-22',
'pool': 'chrome.tests.perf',
'synthetic_product_name': 'PowerEdge R350 (Dell Inc.)'
},
},
'mac-laptop_high_end-perf': {
'tests': [
{
'isolate': 'performance_test_suite',
'extra_args': [
'--assert-gpu-compositing',
],
},
],
'platform':
'mac',
'dimension': {
'cpu':
'x86-64',
'gpu':
'1002:6821-4.0.20-3.2.8',
'os':
'Mac-12',
'pool':
'chrome.tests.perf',
'synthetic_product_name':
'MacBookPro11,5_x86-64-i7-4870HQ_AMD Radeon R8 M370X 4.0.20 [3.2.8]_Intel Haswell Iris Pro Graphics 5200 4.0.20 [3.2.8]_16384_APPLE SSD SM0512G',
},
},
'mac-laptop_high_end-perf-pgo': {
'tests': [
{
'isolate': 'performance_test_suite',
'extra_args': [
'--assert-gpu-compositing',
],
},
],
'platform':
'mac',
'dimension': {
'cpu':
'x86-64',
'gpu':
'1002:6821-4.0.20-3.2.8',
'os':
'Mac-12',
'pool':
'chrome.tests.perf',
'synthetic_product_name':
'MacBookPro11,5_x86-64-i7-4870HQ_AMD Radeon R8 M370X 4.0.20 [3.2.8]_Intel Haswell Iris Pro Graphics 5200 4.0.20 [3.2.8]_16384_APPLE SSD SM0512G',
},
},
'linux-processor-perf': {
'platform': 'linux',
'perf_processor': True,
},
'android-go-processor-perf': {
'platform': 'linux',
'perf_processor': True,
},
'win-10-processor-perf': {
'platform': 'linux',
'perf_processor': True,
},
'win-10_laptop_low_end-processor-perf': {
'platform': 'linux',
'perf_processor': True,
},
'win-11-processor-perf': {
'platform': 'linux',
'perf_processor': True,
},
'mac-laptop_low_end-processor-perf': {
'platform': 'linux',
'perf_processor': True,
},
'mac-laptop_high_end-processor-perf': {
'platform': 'linux',
'perf_processor': True,
},
'chromecast-linux-builder-perf': {
'additional_compile_targets': ['cast_shell'],
'tests': [
{
'name': 'resource_sizes_chromecast',
'isolate': 'resource_sizes_chromecast',
'type': TEST_TYPES.GENERIC,
'resultdb': {
'has_native_resultdb_integration': True,
},
},
],
'dimension': {
'cpu': 'x86-64',
'os': 'Ubuntu-22.04',
'pool': 'chrome.tests',
},
'perf_trigger':
False,
},
'chromeos-amd64-generic-lacros-builder-perf': {
'additional_compile_targets': ['chrome'],
'tests': [
{
'name': 'resource_sizes_lacros_chrome',
'isolate': 'resource_sizes_lacros_chrome',
'type': TEST_TYPES.GENERIC,
'resultdb': {
'has_native_resultdb_integration': True,
},
'extra_args': [
'--arch=amd64',
],
},
],
'dimension': {
'cpu': 'x86-64',
'os': 'Ubuntu-22.04',
'pool': 'chrome.tests',
},
'perf_trigger':
False,
},
'chromeos-arm-generic-lacros-builder-perf': {
'additional_compile_targets': ['chrome'],
'tests': [
{
'name': 'resource_sizes_lacros_chrome',
'isolate': 'resource_sizes_lacros_chrome',
'type': TEST_TYPES.GENERIC,
'resultdb': {
'has_native_resultdb_integration': True,
},
'extra_args': [
'--arch=arm32',
],
},
],
'dimension': {
'cpu': 'x86-64',
'os': 'Ubuntu-22.04',
'pool': 'chrome.tests',
},
'perf_trigger':
False,
},
'chromeos-arm64-generic-lacros-builder-perf': {
'additional_compile_targets': ['chrome'],
'tests': [
{
'name': 'resource_sizes_lacros_chrome',
'isolate': 'resource_sizes_lacros_chrome',
'type': TEST_TYPES.GENERIC,
'resultdb': {
'has_native_resultdb_integration': True,
},
'extra_args': [
'--arch=arm64',
],
},
],
'dimension': {
'cpu': 'x86-64',
'os': 'Ubuntu-22.04',
'pool': 'chrome.tests',
},
'perf_trigger':
False,
},
'lacros-eve-perf': {
'tests': [
{
'isolate':
'performance_test_suite_eve',
'extra_args': [
# The magic hostname that resolves to a CrOS device in the test lab
'--remote=variable_chromeos_device_hostname',
],
'timeout':
12 * 60 * 60, # 12 hours, due to small number of devices
},
],
'platform':
'lacros',
'target_bits':
64,
'dimension': {
'pool': 'chrome.tests.perf',
# TODO(crbug.com/41463380): Explicitly set the gpu to None to make
# chromium_swarming recipe_module ignore this dimension.
'gpu': None,
'os': 'ChromeOS',
'device_status': 'available',
'device_type': 'eve',
},
},
'lacros-x86-perf': {
'tests': [
{
'isolate':
'performance_test_suite_octopus',
'extra_args': [
# The magic hostname that resolves to a CrOS device in the test lab
'--remote=variable_chromeos_device_hostname',
],
},
],
'platform':
'lacros',
'target_bits':
64,
'dimension': {
'pool': 'chrome.tests.perf',
# TODO(crbug.com/41463380): Explicitly set the gpu to None to make
# chromium_swarming recipe_module ignore this dimension.
'gpu': None,
'os': 'ChromeOS',
'device_status': 'available',
'device_type': 'octopus',
},
},
}
# pylint: enable=line-too-long
_TESTER_SERVICE_ACCOUNT = (
'[email protected]')
def _generate_pinpoint_builders_dict(builder):
result = {}
for key in builder:
content = copy.deepcopy(builder[key])
if 'pinpoint_additional_compile_targets' in content:
additional_compile_targets = content.pop(
'pinpoint_additional_compile_targets')
else:
additional_compile_targets = content.pop('additional_compile_targets',
None)
if additional_compile_targets:
content['additional_compile_targets'] = additional_compile_targets
elif 'additional_compile_targets' in content:
del content['additional_compile_targets']
tests = content.get('tests', [])
tests = list(
filter(
lambda x: not (x.get('name') == 'chrome_sizes' or x.get('name', '').
startswith('resource_sizes')), tests))
if tests:
content['tests'] = tests
elif 'tests' in content:
del content['tests']
if content:
result[key] = content
return result
def update_all_builders(file_path):
return (_update_builders(BUILDERS, file_path)
and is_perf_benchmarks_scheduling_valid(file_path, sys.stderr))
def update_all_pinpoint_builders(file_path):
return (_update_builders(_generate_pinpoint_builders_dict(BUILDERS),
file_path) and is_perf_benchmarks_scheduling_valid(
file_path, sys.stderr, is_waterfall=False))
def update_all_fyi_builders(file_path):
return _update_builders(FYI_BUILDERS, file_path)
def update_all_calibration_builders(file_path):
return _update_builders(CALIBRATION_BUILDERS, file_path)
def _update_builders(builders_dict, file_path):
tests = {}
tests['AAAAA1 AUTOGENERATED FILE DO NOT EDIT'] = {}
tests['AAAAA2 See //tools/perf/generate_perf_data to make changes'] = {}
for name, config in builders_dict.items():
tests[name] = generate_builder_config(config, name)
with open(file_path, 'w',
newline='') if sys.version_info.major == 3 else open(
file_path, 'wb') as fp:
json.dump(tests, fp, indent=2, separators=(',', ': '), sort_keys=True)
fp.write('\n')
return True
def merge_dicts(*dict_args):
result = {}
for dictionary in dict_args:
result.update(dictionary)
return result
class BenchmarkMetadata(object):
def __init__(self, emails, component='', documentation_url='', stories=None):
"""An object to hold information about a benchmark.
Args:
emails: A string with a comma separated list of owner emails.
component: An optional string with a component for filing bugs about this
benchmark.
documentation_url: An optional string with a URL where documentation
about the benchmark can be found.
stories: An optional list of benchmark_utils.StoryInfo tuples with
information about stories contained in this benchmark.
"""
self.emails = emails
self.component = component
self.documentation_url = documentation_url
if stories is not None:
assert isinstance(stories, list)
self.stories = stories
else:
self.stories = []
@property
def tags(self):
"""Return a comma separated list of all tags used by benchmark stories."""
return ','.join(sorted(set().union(*(s.tags for s in self.stories))))
GTEST_BENCHMARKS = {
'base_perftests':
BenchmarkMetadata(
'[email protected], [email protected]', 'Internals>SequenceManager',
('https://chromium.googlesource.com/chromium/src/+/HEAD/base/' +
'README.md#performance-testing')),
'tracing_perftests':
BenchmarkMetadata(
'[email protected], [email protected], [email protected]',
'Speed>Tracing'),
'load_library_perf_tests':
BenchmarkMetadata('[email protected], [email protected]',
'Internals>Media>Encrypted'),
'views_perftests':
BenchmarkMetadata('[email protected]', 'Internals>Views'),
'components_perftests':
BenchmarkMetadata('[email protected]'),
'dawn_perf_tests':
BenchmarkMetadata(
'[email protected]', 'Dawn',
'https://dawn.googlesource.com/dawn/+/HEAD/src/tests/perf_tests/README.md'
),
'tint_benchmark':
BenchmarkMetadata(
'[email protected], [email protected]', 'Dawn>Tint',
'https://dawn.googlesource.com/dawn/+/HEAD/docs/tint/benchmark.md'),
}
RESOURCE_SIZES_METADATA = BenchmarkMetadata(
'[email protected]', 'Build>Android',
('https://chromium.googlesource.com/chromium/src/+/HEAD/'
'tools/binary_size/README.md#resource_sizes_py'))
OTHER_BENCHMARKS = {
'resource_sizes_monochrome_minimal_apks': RESOURCE_SIZES_METADATA,
'resource_sizes_trichrome_google': RESOURCE_SIZES_METADATA,
'resource_sizes_system_webview_google_bundle': RESOURCE_SIZES_METADATA,
}
OTHER_BENCHMARKS.update({
'chrome_sizes':
BenchmarkMetadata(
emails='[email protected]',
component='Build',
documentation_url=(
'https://chromium.googlesource.com/chromium/'
'src/+/HEAD/tools/binary_size/README.md#resource_sizes_py'),
),
})
OTHER_BENCHMARKS.update({
'resource_sizes_chromecast':
BenchmarkMetadata(
emails='[email protected]',
component='Chromecast',
documentation_url=(
'https://chromium.googlesource.com/chromium/'
'src/+/HEAD/tools/binary_size/README.md#resource_sizes_py'),
),
})
OTHER_BENCHMARKS.update({
'resource_sizes_lacros_chrome':
BenchmarkMetadata(
emails='[email protected], [email protected]',
component='OS>LaCrOS',
documentation_url=(
'https://chromium.googlesource.com/chromium/'
'src/+/HEAD/tools/binary_size/README.md#resource_sizes_py'),
),
})
SYSTEM_HEALTH_BENCHMARKS = set([
'system_health.common_desktop',
'system_health.common_mobile',
'system_health.memory_desktop',
'system_health.memory_mobile',
])
# Valid test suite (benchmark) names should match this regex.
RE_VALID_TEST_SUITE_NAME = r'^[\w._-]+$'
def _get_telemetry_perf_benchmarks_metadata():
metadata = {}
for benchmark in benchmark_finders.GetOfficialBenchmarks():
benchmark_name = benchmark.Name()
emails = decorators.GetEmails(benchmark)
if emails:
emails = ', '.join(emails)
metadata[benchmark_name] = BenchmarkMetadata(
emails=emails,
component=decorators.GetComponent(benchmark),
documentation_url=decorators.GetDocumentationLink(benchmark),
stories=benchmark_utils.GetBenchmarkStoryInfo(benchmark()))
return metadata
TELEMETRY_PERF_BENCHMARKS = _get_telemetry_perf_benchmarks_metadata()
PERFORMANCE_TEST_SUITES = [
'performance_test_suite',
'performance_test_suite_eve',
'performance_test_suite_octopus',
'performance_webview_test_suite',
'performance_web_engine_test_suite',
]
for suffix in android_browser_types.TELEMETRY_ANDROID_BROWSER_TARGET_SUFFIXES:
PERFORMANCE_TEST_SUITES.append('performance_test_suite' + suffix)
def get_scheduled_non_telemetry_benchmarks(perf_waterfall_file):
test_names = set()
with open(perf_waterfall_file) as f:
tests_by_builder = json.load(f)
script_tests = []
for tests in tests_by_builder.values():
if 'isolated_scripts' in tests:
script_tests += tests['isolated_scripts']
if 'scripts' in tests:
script_tests += tests['scripts']
for s in script_tests:
name = s['name']
# TODO(eyaich): Determine new way to generate ownership based
# on the benchmark bot map instead of on the generated tests
# for new perf recipe.
if not name in PERFORMANCE_TEST_SUITES:
test_names.add(name)
for platform in bot_platforms.ALL_PLATFORMS:
for executable in platform.executables:
test_names.add(executable.name)
return test_names
def is_perf_benchmarks_scheduling_valid(perf_waterfall_file,
outstream,
is_waterfall=True):
"""Validates that all existing benchmarks are properly scheduled.
Return: True if all benchmarks are properly scheduled, False otherwise.
"""
scheduled_non_telemetry_tests = get_scheduled_non_telemetry_benchmarks(
perf_waterfall_file)
all_perf_gtests = set(GTEST_BENCHMARKS)
all_perf_other_tests = set(OTHER_BENCHMARKS)
error_messages = []
for test_name in all_perf_gtests - scheduled_non_telemetry_tests:
error_messages.append(
'Benchmark %s is tracked but not scheduled on any perf waterfall '
'builders. Either schedule or remove it from GTEST_BENCHMARKS.' %
test_name)
if is_waterfall:
for test_name in all_perf_other_tests - scheduled_non_telemetry_tests:
error_messages.append(
'Benchmark %s is tracked but not scheduled on any perf waterfall '
'builders. Either schedule or remove it from OTHER_BENCHMARKS.' %
test_name)
for test_name in scheduled_non_telemetry_tests.difference(
all_perf_gtests, all_perf_other_tests):
error_messages.append(
'Benchmark %s is scheduled on perf waterfall but not tracked. Please '
'add an entry for it in GTEST_BENCHMARKS or OTHER_BENCHMARKS in'
'//tools/perf/core/perf_data_generator.py.' % test_name)
for message in error_messages:
print('*', textwrap.fill(message, 70), '\n', file=outstream)
return not error_messages
# Verify that all benchmarks have owners except those on the whitelist.
def _verify_benchmark_owners(benchmark_metadatas):
unowned_benchmarks = set()
for benchmark_name in benchmark_metadatas:
if benchmark_metadatas[benchmark_name].emails is None:
unowned_benchmarks.add(benchmark_name)
assert not unowned_benchmarks, (
'All benchmarks must have owners. Please add owners for the following '
'benchmarks:\n%s' % '\n'.join(unowned_benchmarks))
# Open a CSV file for writing, handling the differences between Python 2 and 3.
def _create_csv(file_path):
if sys.version_info.major == 2:
return open(file_path, 'wb')
return open(file_path, 'w', newline='')
def update_benchmark_csv(file_path):
"""Updates go/chrome-benchmarks.
Updates telemetry/perf/benchmark.csv containing the current benchmark names,
owners, and components. Requires that all benchmarks have owners.
"""
header_data = [
['AUTOGENERATED FILE DO NOT EDIT'],
[
'See the following link for directions for making changes ' +
'to this data:', 'https://bit.ly/update-benchmarks-info'
],
[
'Googlers can view additional information about internal perf ' +
'infrastructure at',
'https://goto.google.com/chrome-benchmarking-sheet'
],
[
'Benchmark name', 'Individual owners', 'Component', 'Documentation',
'Tags'
]
]
csv_data = []
benchmark_metadatas = merge_dicts(
GTEST_BENCHMARKS, OTHER_BENCHMARKS, TELEMETRY_PERF_BENCHMARKS)
_verify_benchmark_owners(benchmark_metadatas)
undocumented_benchmarks = set()
for benchmark_name in benchmark_metadatas:
if not re.match(RE_VALID_TEST_SUITE_NAME, benchmark_name):
raise ValueError('Invalid benchmark name: %s' % benchmark_name)
if not benchmark_metadatas[benchmark_name].documentation_url:
undocumented_benchmarks.add(benchmark_name)
csv_data.append([
benchmark_name,
benchmark_metadatas[benchmark_name].emails,
benchmark_metadatas[benchmark_name].component,
benchmark_metadatas[benchmark_name].documentation_url,
benchmark_metadatas[benchmark_name].tags,
])
if undocumented_benchmarks != ub_module.UNDOCUMENTED_BENCHMARKS:
error_message = (
'The list of known undocumented benchmarks does not reflect the actual '
'ones.\n')
if undocumented_benchmarks - ub_module.UNDOCUMENTED_BENCHMARKS:
error_message += (
'New undocumented benchmarks found. Please document them before '
'enabling on perf waterfall: %s' %
(','.join(b for b in undocumented_benchmarks -
ub_module.UNDOCUMENTED_BENCHMARKS)))
if ub_module.UNDOCUMENTED_BENCHMARKS - undocumented_benchmarks:
error_message += (
'These benchmarks are already documented. Please remove them from '
'the UNDOCUMENTED_BENCHMARKS list in undocumented_benchmarks.py: %s' %
(','.join(b for b in ub_module.UNDOCUMENTED_BENCHMARKS -
undocumented_benchmarks)))
raise ValueError(error_message)
csv_data = sorted(csv_data, key=lambda b: b[0])
csv_data = header_data + csv_data
with _create_csv(file_path) as f:
writer = csv.writer(f, lineterminator='\n')
writer.writerows(csv_data)
return True
def update_system_health_stories(filepath):
"""Updates bit.ly/csh-stories.
Updates tools/perf/system_health_stories.csv containing the current set
of system health stories.
"""
header_data = [[
'AUTOGENERATED FILE DO NOT EDIT'
], ['See //tools/perf/core/perf_data_generator.py to make changes'],
['Story', 'Description', 'Platforms', 'Tags']]
stories = {}
for benchmark_name in sorted(SYSTEM_HEALTH_BENCHMARKS):
platform = benchmark_name.rsplit('_', 1)[-1]
for story in TELEMETRY_PERF_BENCHMARKS[benchmark_name].stories:
if story.name not in stories:
stories[story.name] = {
'description': story.description,
'platforms': set([platform]),
'tags': set(story.tags)
}
else:
stories[story.name]['platforms'].add(platform)
stories[story.name]['tags'].update(story.tags)
with _create_csv(filepath) as f:
writer = csv.writer(f, lineterminator='\n')
for row in header_data:
writer.writerow(row)
for story_name, info in sorted(stories.items()):
platforms = ','.join(sorted(info['platforms']))
tags = ','.join(sorted(info['tags']))
writer.writerow([story_name, info['description'], platforms, tags])
return True
def update_labs_docs_md(filepath):
primary_configs = collections.defaultdict(list)
pinpoint_configs = collections.defaultdict(list)
fyi_configs = collections.defaultdict(list)
for tester in bot_platforms.ALL_PLATFORMS:
if tester.pinpoint_only:
pinpoint_configs[tester.platform].append(tester)
elif tester.is_fyi:
fyi_configs[tester.platform].append(tester)
else:
primary_configs[tester.platform].append(tester)
with open(filepath, 'w', newline='') as f:
f.write("""
[comment]: # (AUTOGENERATED FILE DO NOT EDIT)
[comment]: # (See //tools/perf/generate_perf_data to make changes)
# Platforms tested in the Performance Lab
""")
config_groups = (
('Primary', primary_configs),
('Pinpoint-Only', pinpoint_configs),
('FYI', fyi_configs),
)
for group, configs in config_groups:
f.write('## %s Platforms\n\n' % group)
for platform, testers in sorted(configs.items()):
f.write('### %s\n\n' % platform.title())
testers.sort()
for tester in testers:
f.write(' * ')
if tester.builder_url:
f.write('[{0.name}]({0.builder_url})'.format(tester))
else:
f.write(tester.name)
if tester.description:
f.write(': {0.description}.\n'.format(tester))
else:
f.write('.\n')
f.write('\n')
return True
def generate_telemetry_args(tester_config, platform):
# First determine the browser that you need based on the tester
browser_name = ''
# For trybot testing we always use the reference build
if tester_config.get('testing', False):
browser_name = 'reference'
elif 'browser' in tester_config:
browser_name = 'exact'
elif tester_config['platform'] == 'android':
browser_name = 'android-chromium'
elif tester_config['platform'].startswith('android-'):
browser_name = tester_config['platform']
elif tester_config['platform'] == 'chromeos':
browser_name = 'cros-chrome'
elif tester_config['platform'] == 'lacros':
browser_name = 'lacros-chrome'
elif (tester_config['platform'] == 'win'
and tester_config['target_bits'] == 64):
browser_name = 'release_x64'
elif tester_config['platform'] == 'fuchsia-wes':
browser_name = 'web-engine-shell'
elif tester_config['platform'] == 'fuchsia-chrome':
browser_name = 'fuchsia-chrome'
else:
browser_name = 'release'
test_args = [
'-v',
'--browser=%s' % browser_name,
'--upload-results',
'--test-shard-map-filename=%s' % platform.shards_map_file_name,
'--ignore-benchmark-exit-code',
]
if platform.run_reference_build:
test_args.append('--run-ref-build')
if 'browser' in tester_config:
test_args.append('--browser-executable=../../out/Release/%s' %
tester_config['browser'])
if tester_config['platform'].startswith('android'):
test_args.append('--device=android')
return test_args
def generate_gtest_args(test_name):
# --gtest-benchmark-name so the benchmark name is consistent with the test
# step's name. This is not always the same as the test binary's name (see
# crbug.com/870692).
return [
'--gtest-benchmark-name',
test_name,
]
def generate_performance_test(tester_config, test, builder_name):
isolate_name = test['isolate']
test_name = test.get('name', isolate_name)
test_type = test.get('type', TEST_TYPES.TELEMETRY)
assert test_type in TEST_TYPES.ALL
shards = test.get('num_shards', None)
test_args = []
if test_type == TEST_TYPES.TELEMETRY:
platform = bot_platforms.PLATFORMS_BY_NAME[builder_name]
test_args += generate_telemetry_args(tester_config, platform)
assert shards is None
shards = platform.num_shards
elif test_type == TEST_TYPES.GTEST:
test_args += generate_gtest_args(test_name=test_name)
assert shards
# Append any additional args specific to an isolate
test_args += test.get('extra_args', [])
result = {
'args': test_args,
'test': isolate_name,
'name': test_name,
}
if test.get('resultdb'):
result['resultdb'] = test['resultdb'].copy()
elif 'builder-perf' not in builder_name:
# Enable Result DB on all perf test bots. Builders with names including
# "builder-perf" are used for compiling only, and do not run perf tests.
# TODO(crbug.com/40151981): Replace the following line by specifying either
# "result_format" for GTests, or "has_native_resultdb_integration" for all
# other tests.
result['resultdb'] = {'enable': True}
# For now we either get shards from the number of devices specified
# or a test entry needs to specify the num shards if it supports
# soft device affinity.
if tester_config.get('perf_trigger', True):
result['trigger_script'] = {
'requires_simultaneous_shard_dispatch': True,
'script': '//testing/trigger_scripts/perf_device_trigger.py',
'args': [
'--multiple-dimension-script-verbose',
'True'
],
}
if builder_name in DYNAMIC_SHARDING_TESTERS:
result['trigger_script']['args'].append('--use-dynamic-shards')
result['merge'] = {
'script': '//tools/perf/process_perf_results.py',
}
if builder_name in LIGHTWEIGHT_TESTERS:
result['merge']['args'] = ['--lightweight', '--skip-perf']
result['swarming'] = {
# Always say this is true regardless of whether the tester
# supports swarming. It doesn't hurt.
'can_use_on_swarming_builders': True,
'expiration': 2 * 60 * 60, # 2 hours pending max
# TODO(crbug.com/40585750): once we have plenty of windows hardwares,
# to shards perf benchmarks on Win builders, reduce this hard timeout
# limit to ~2 hrs.
# Note that the builder seems to time out after 7 hours
# (crbug.com/1036447), so we must timeout the shards within ~6 hours to
# allow for other overhead. If the overall builder times out then we
# don't get data even from the passing shards.
'hard_timeout': test.get('timeout', 6 * 60 * 60), # default 6 hours
# This is effectively the timeout for a
# benchmarking subprocess to run since we intentionally do not stream
# subprocess output to the task stdout.
# TODO(crbug.com/40585750): Reduce this once we can reduce hard_timeout.
'io_timeout': test.get('timeout', 6 * 60 * 60),
'dimensions': tester_config['dimension'],
'service_account': _TESTER_SERVICE_ACCOUNT,
}
if shards:
result['swarming']['shards'] = shards
if tester_config.get('cipd'):
result['swarming']['cipd_packages'] = [tester_config['cipd']]
return result
def generate_builder_config(condensed_config, builder_name):
config = {}
if 'additional_compile_targets' in condensed_config:
config['additional_compile_targets'] = (
condensed_config['additional_compile_targets'])
# TODO(crbug.com/40129604): remove this setting
if 'perf_processor' in condensed_config:
config['merge'] = {
'script': '//tools/perf/process_perf_results.py',
}
config['merge']['args'] = ['--lightweight']
condensed_tests = condensed_config.get('tests')
if condensed_tests:
gtest_tests = []
telemetry_tests = []
other_tests = []
for test in condensed_tests:
generated_script = generate_performance_test(
condensed_config, test, builder_name)
test_type = test.get('type', TEST_TYPES.TELEMETRY)
if test_type == TEST_TYPES.GTEST:
gtest_tests.append(generated_script)
elif test_type == TEST_TYPES.TELEMETRY:
telemetry_tests.append(generated_script)
elif test_type == TEST_TYPES.GENERIC:
other_tests.append(generated_script)
else:
raise ValueError(
'perf_data_generator.py does not understand test type %s.' %
test_type)
gtest_tests.sort(key=lambda x: x['name'])
telemetry_tests.sort(key=lambda x: x['name'])
other_tests.sort(key=lambda x: x['name'])
# Put Telemetry tests as the end since they tend to run longer to avoid
# starving gtests (see crbug.com/873389).
config['isolated_scripts'] = gtest_tests + telemetry_tests + other_tests
return config
# List of all updater functions and the file they generate. The updater
# functions must return True on success and False otherwise. File paths are
# relative to chromium src and should use posix path separators (i.e. '/').
ALL_UPDATERS_AND_FILES = [
(update_all_builders, 'testing/buildbot/chromium.perf.json'),
(update_all_pinpoint_builders,
'testing/buildbot/chromium.perf.pinpoint.json'),
(update_all_fyi_builders, 'testing/buildbot/chromium.perf.fyi.json'),
(update_all_calibration_builders,
'testing/buildbot/chromium.perf.calibration.json'),
(update_benchmark_csv, 'tools/perf/benchmark.csv'),
(update_system_health_stories, 'tools/perf/system_health_stories.csv'),
(update_labs_docs_md, 'docs/speed/perf_lab_platforms.md'),
]
def _source_filepath(posix_path):
return os.path.join(path_util.GetChromiumSrcDir(), *posix_path.split('/'))
def validate_all_files():
"""Validate all generated files."""
tempdir = tempfile.mkdtemp()
try:
for run_updater, src_file in ALL_UPDATERS_AND_FILES:
real_filepath = _source_filepath(src_file)
temp_filepath = os.path.join(tempdir, os.path.basename(real_filepath))
if not (os.path.exists(real_filepath) and
run_updater(temp_filepath) and
filecmp.cmp(temp_filepath, real_filepath)):
return False
finally:
shutil.rmtree(tempdir)
return True
def update_all_files():
"""Update all generated files."""
for run_updater, src_file in ALL_UPDATERS_AND_FILES:
if not run_updater(_source_filepath(src_file)):
print('Failed updating:', src_file)
return False
print('Updated:', src_file)
return True
def main(args):
parser = argparse.ArgumentParser(
description=('Generate perf test\' json config and benchmark.csv. '
'This needs to be done anytime you add/remove any existing'
'benchmarks in tools/perf/benchmarks.'))
parser.add_argument(
'--validate-only', action='store_true', default=False,
help=('Validate whether the perf json generated will be the same as the '
'existing configs. This does not change the contain of existing '
'configs'))
options = parser.parse_args(args)
if options.validate_only:
if validate_all_files():
print('All the perf config files are up-to-date. \\o/')
return 0
print('Not all perf config files are up-to-date. Please run %s '
'to update them.' % sys.argv[0])
return 1
return 0 if update_all_files() else 1