diff --git a/automation/taskcluster/decision_task.py b/automation/taskcluster/decision_task.py index 48f771c0c..9a3133353 100644 --- a/automation/taskcluster/decision_task.py +++ b/automation/taskcluster/decision_task.py @@ -61,23 +61,8 @@ def raptor(builder, is_staging): build_task = builder.craft_assemble_raptor_task(variant) signing_task = builder.craft_raptor_signing_task(build_task['label'], variant, is_staging) - tasks = [build_task, signing_task] - - for abi in ('armeabi-v7a', 'arm64-v8a'): - variant_apk = variant.get_apk(abi) - all_raptor_craft_functions = [ - builder.craft_raptor_tp6m_cold_task(for_suite=i) - for i in range(1, 28) - ] + [ - builder.craft_raptor_youtube_playback_task, - ] - for craft_function in all_raptor_craft_functions: - raptor_task = craft_function( - signing_task['label'], mozharness_task_id, variant_apk, gecko_revision, is_staging - ) - tasks.append(raptor_task) - - return tasks + # Raptor tests are generated in taskgraph + return [build_task, signing_task] def release(builder, channel, engine, is_staging, version_name): diff --git a/automation/taskcluster/lib/tasks.py b/automation/taskcluster/lib/tasks.py index 3c9987ba4..ec941bdeb 100644 --- a/automation/taskcluster/lib/tasks.py +++ b/automation/taskcluster/lib/tasks.py @@ -123,6 +123,7 @@ class TaskBuilder(object): 'symbol': 'A', 'tier': 1, }, + attributes={'build-type': 'raptor'}, ) def craft_assemble_pr_task(self, variant): @@ -316,7 +317,7 @@ class TaskBuilder(object): def _craft_build_ish_task( self, name, description, command, dependencies=None, artifacts=None, - routes=None, treeherder=None, env_vars=None, scopes=None + routes=None, treeherder=None, env_vars=None, scopes=None, attributes=None ): artifacts = {} if artifacts is None else artifacts scopes = [] if scopes is None else scopes @@ -361,9 +362,10 @@ class TaskBuilder(object): routes=routes, scopes=scopes, treeherder=treeherder, + attributes=attributes, ) - def _craft_signing_task(self, name, description, signing_type, assemble_task_label, apk_paths, routes, treeherder): + def _craft_signing_task(self, name, description, signing_type, assemble_task_label, apk_paths, routes, treeherder, attributes=None): signing_format = "autograph_apk" payload = { 'upstreamArtifacts': [{ @@ -387,6 +389,7 @@ class TaskBuilder(object): description=description, payload=payload, treeherder=treeherder, + attributes=attributes, ) def _craft_default_task_definition( @@ -401,11 +404,13 @@ class TaskBuilder(object): scopes=None, treeherder=None, notify=None, + attributes=None ): dependencies = {} if dependencies is None else dependencies scopes = [] if scopes is None else scopes routes = [] if routes is None else routes treeherder = {} if treeherder is None else treeherder + attributes = {} if attributes is None else attributes created = datetime.datetime.now() deadline = taskcluster.fromNow('1 day') @@ -422,7 +427,7 @@ class TaskBuilder(object): extra['notify'] = notify return { - "attributes": {}, + "attributes": attributes, "dependencies": dependencies, "label": name, "task": { @@ -477,9 +482,16 @@ class TaskBuilder(object): 'machine': { 'platform': 'android-all', }, + 'collection': { + 'opt': True, + }, 'symbol': 'As', 'tier': 1, }, + attributes={ + 'build-type': 'raptor', + 'apks': variant.upstream_artifacts_per_abi, + }, ) def craft_release_signing_task( @@ -559,158 +571,6 @@ class TaskBuilder(object): }, ) - def craft_raptor_tp6m_cold_task(self, for_suite): - - def craft_function(signing_task_label, mozharness_task_id, variant_apk, gecko_revision, is_staging, force_run_on_64_bit_device=False): - return self._craft_raptor_task( - signing_task_label, - mozharness_task_id, - variant_apk, - gecko_revision, - is_staging, - name_prefix='raptor tp6m-cold-{}'.format(for_suite), - description='Raptor tp6m cold on Fenix', - test_name='raptor-tp6m-cold-{}'.format(for_suite), - job_symbol='tp6m-c-{}'.format(for_suite), - force_run_on_64_bit_device=force_run_on_64_bit_device, - ) - return craft_function - - def craft_raptor_youtube_playback_task(self, signing_task_label, mozharness_task_id, variant_apk, gecko_revision, - is_staging, force_run_on_64_bit_device=False): - return self._craft_raptor_task( - signing_task_label, - mozharness_task_id, - variant_apk, - gecko_revision, - is_staging, - name_prefix='raptor youtube playback', - description='Raptor YouTube Playback on Fenix', - test_name='raptor-youtube-playback', - job_symbol='ytp', - group_symbol='Rap', - force_run_on_64_bit_device=force_run_on_64_bit_device, - ) - - def _craft_raptor_task( - self, - signing_task_label, - mozharness_task_id, - variant_apk, - gecko_revision, - is_staging, - name_prefix, - description, - test_name, - job_symbol, - group_symbol=None, - force_run_on_64_bit_device=False, - ): - worker_type = 'gecko-t-bitbar-gw-perf-p2' if force_run_on_64_bit_device or variant_apk.abi == 'arm64-v8a' else 'gecko-t-bitbar-gw-perf-g5' - - if force_run_on_64_bit_device: - treeherder_platform = 'android-hw-p2-8-0-arm7-api-16' - elif variant_apk.abi == 'armeabi-v7a': - treeherder_platform = 'android-hw-g5-7-0-arm7-api-16' - elif variant_apk.abi == 'arm64-v8a': - treeherder_platform = 'android-hw-p2-8-0-android-aarch64' - else: - raise ValueError('Unsupported architecture "{}"'.format(variant_apk.abi)) - - task_name = '{} {}: forPerformanceTest {}'.format( - name_prefix, variant_apk.abi, '(on 64-bit-device)' if force_run_on_64_bit_device else '' - ) - - apk_url = '{}//artifacts/{}'.format(_DEFAULT_TASK_URL, variant_apk.taskcluster_path) - command = [[ - "/builds/taskcluster/script.py", - "bash", - "./test-linux.sh", - "--cfg=mozharness/configs/raptor/android_hw_config.py", - "--test={}".format(test_name), - "--app=fenix", - "--binary=org.mozilla.fenix.performancetest", - "--activity=org.mozilla.fenix.browser.BrowserPerformanceTestActivity", - "--download-symbols=ondemand", - ]] - # Bug 1558456 - Stop tracking youtube-playback-test on motoG5 for >1080p cases - if variant_apk.abi == 'armeabi-v7a' and test_name == 'raptor-youtube-playback': - params_query = '&'.join(ARM_RAPTOR_URL_PARAMS) - add_extra_params_option = "--test-url-params={}".format(params_query) - command[0].append(add_extra_params_option) - - return self._craft_default_task_definition( - worker_type=worker_type, - provisioner_id='proj-autophone', - dependencies={'signing': signing_task_label}, - name=task_name, - description=description, - routes=['notify.email.perftest-alerts@mozilla.com.on-failed'] if not is_staging else [], - payload={ - "maxRunTime": 2700, - "artifacts": [{ - 'path': '{}'.format(worker_path), - 'expires': taskcluster.stringDate(taskcluster.fromNow(DEFAULT_EXPIRES_IN)), - 'type': 'directory', - 'name': 'public/{}/'.format(public_folder) - } for worker_path, public_folder in ( - ('artifacts/public', 'test'), - ('workspace/logs', 'logs'), - ('workspace/build/blobber_upload_dir', 'test_info'), - )], - "command": command, - "env": { - "EXTRA_MOZHARNESS_CONFIG": {'task-reference': json.dumps({ - "test_packages_url": "{}/{}/artifacts/public/build/en-US/target.test_packages.json".format(_DEFAULT_TASK_URL, mozharness_task_id), - "installer_url": apk_url, - })}, - "GECKO_HEAD_REPOSITORY": "https://hg.mozilla.org/mozilla-central", - "GECKO_HEAD_REV": gecko_revision, - "MOZ_AUTOMATION": "1", - "MOZ_HIDE_RESULTS_TABLE": "1", - "MOZ_NO_REMOTE": "1", - "MOZ_NODE_PATH": "/usr/local/bin/node", - "MOZHARNESS_CONFIG": "raptor/android_hw_config.py", - "MOZHARNESS_SCRIPT": "raptor_script.py", - "MOZHARNESS_URL": "{}/{}/artifacts/public/build/en-US/mozharness.zip".format(_DEFAULT_TASK_URL, mozharness_task_id), - "MOZILLA_BUILD_URL": {'task-reference': apk_url}, - "NEED_XVFB": "false", - "NO_FAIL_ON_TEST_ERRORS": "1", - "SCCACHE_DISABLE": "1", - "TASKCLUSTER_WORKER_TYPE": worker_type[len('gecko-'):], - "TRY_COMMIT_MSG": "", - "TRY_SELECTOR": "fuzzy", - "XPCOM_DEBUG_BREAK": "warn", - }, - "mounts": [{ - "content": { - "url": "https://hg.mozilla.org/mozilla-central/raw-file/{}/taskcluster/scripts/tester/test-linux.sh".format(gecko_revision), - }, - "file": "test-linux.sh", - }] - }, - treeherder={ - 'jobKind': 'test', - 'groupSymbol': 'Rap' if group_symbol is None else group_symbol, - 'machine': { - 'platform': treeherder_platform, - }, - 'symbol': job_symbol, - 'tier': 2, - }, - notify={ - 'email': { - 'link': { - 'text': "Treeherder Job", - 'href': "https://treeherder.mozilla.org/#/jobs?repo=fenix&revision={}".format(self.commit), - }, - 'subject': '[fenix] Raptor job "{}" failed'.format(task_name), - 'content': "This calls for an action of the Performance team. Use the link to view it on Treeherder.", - }, - }, - ) - - def schedule_task(queue, taskId, task): print("TASK", taskId) print(json.dumps(task, indent=4, separators=(',', ': '))) diff --git a/automation/taskcluster/lib/variant.py b/automation/taskcluster/lib/variant.py index 4812ae6c9..b3392c500 100644 --- a/automation/taskcluster/lib/variant.py +++ b/automation/taskcluster/lib/variant.py @@ -28,3 +28,7 @@ class Variant: def upstream_artifacts(self): return [apk.taskcluster_path for apk in self._apks] + + @property + def upstream_artifacts_per_abi(self): + return {apk.abi: apk.taskcluster_path for apk in self._apks} diff --git a/taskcluster/ci/geckoview/kind.yml b/taskcluster/ci/geckoview/kind.yml new file mode 100644 index 000000000..262e8192b --- /dev/null +++ b/taskcluster/ci/geckoview/kind.yml @@ -0,0 +1,11 @@ +--- +loader: taskgraph.loader.transform:loader +transforms: + - taskgraph.transforms.index_search:transforms + - taskgraph.transforms.task:transforms + +jobs: + nightly: + description: "upstream nightly job" + index-search: + - gecko.v2.mozilla-central.nightly.latest.mobile.android-x86_64-opt diff --git a/taskcluster/ci/raptor/kind.yml b/taskcluster/ci/raptor/kind.yml new file mode 100644 index 000000000..289fe2bf1 --- /dev/null +++ b/taskcluster/ci/raptor/kind.yml @@ -0,0 +1,207 @@ +--- +loader: taskgraph.loader.transform:loader +transforms: + - fenix_taskgraph.raptor:transforms + - taskgraph.transforms.job:transforms + - taskgraph.transforms.task:transforms + +kind-dependencies: + - old-decision +only-for-build-types: + - raptor +only-for-abis: + - armeabi-v7a + - arm64-v8a + +job-defaults: + worker-type: + by-abi: + armeabi-v7a: t-bitbar-gw-perf-g5 + arm64-v8a: t-bitbar-gw-perf-p2 + run-on-tasks-for: [] + treeherder: + kind: test + tier: 2 + platform: + by-abi: + arm64-v8a: android-hw-p2-8-0-android-aarch64/opt + armeabi-v7a: android-hw-g5-7-0-arm7-api-16/opt + dependencies: + geckoview-nightly: geckoview-nightly + signing: 'sign: forPerformanceTest' # comes from the old-decision task + worker: + max-run-time: 3600 + env: + GECKO_HEAD_REPOSITORY: "https://hg.mozilla.org/mozilla-central" + MOZ_AUTOMATION: "1" + MOZ_HIDE_RESULTS_TABLE: "1" + MOZ_NO_REMOTE: "1" + MOZ_NODE_PATH: "/usr/local/bin/node" + MOZHARNESS_CONFIG: "raptor/android_hw_config.py" + MOZHARNESS_SCRIPT: "raptor_script.py" + NEED_XVFB: "false" + NO_FAIL_ON_TEST_ERRORS: "1" + XPCOM_DEBUG_BREAK: "warn" + artifacts: + - name: public/logs/ + path: workspace/logs + type: directory + + - name: public/test_info/ + path: workspace/build/blobber_upload_dir + type: directory + + + run: + using: run-task + checkout: false + run-as-root: true + command: + - 'bash' + - './test-linux.sh' + - '--cfg=mozharness/configs/raptor/android_hw_config.py' + - '--app=fenix' + - '--binary=org.mozilla.fenix.performancetest' + - '--activity=org.mozilla.fenix.browser.BrowserPerformanceTestActivity' + - '--download-symbols=ondemand' + +jobs: + tp6m-cold-1: + test-name: raptor-tp6m-cold-1 + treeherder: + symbol: 'Rap(tp6m-c-1)' + + tp6m-cold-2: + test-name: raptor-tp6m-cold-2 + treeherder: + symbol: 'Rap(tp6m-c-2)' + + tp6m-cold-3: + test-name: raptor-tp6m-cold-3 + treeherder: + symbol: 'Rap(tp6m-c-3)' + + tp6m-cold-4: + test-name: raptor-tp6m-cold-4 + treeherder: + symbol: 'Rap(tp6m-c-4)' + + tp6m-cold-5: + test-name: raptor-tp6m-cold-5 + treeherder: + symbol: 'Rap(tp6m-c-5)' + + tp6m-cold-6: + test-name: raptor-tp6m-cold-6 + treeherder: + symbol: 'Rap(tp6m-c-6)' + + tp6m-cold-7: + test-name: raptor-tp6m-cold-7 + treeherder: + symbol: 'Rap(tp6m-c-7)' + + tp6m-cold-8: + test-name: raptor-tp6m-cold-8 + treeherder: + symbol: 'Rap(tp6m-c-8)' + + tp6m-cold-9: + test-name: raptor-tp6m-cold-9 + treeherder: + symbol: 'Rap(tp6m-c-9)' + + tp6m-cold-10: + test-name: raptor-tp6m-cold-10 + treeherder: + symbol: 'Rap(tp6m-c-10)' + + tp6m-cold-11: + test-name: raptor-tp6m-cold-11 + treeherder: + symbol: 'Rap(tp6m-c-11)' + + tp6m-cold-12: + test-name: raptor-tp6m-cold-12 + treeherder: + symbol: 'Rap(tp6m-c-12)' + + tp6m-cold-13: + test-name: raptor-tp6m-cold-13 + treeherder: + symbol: 'Rap(tp6m-c-13)' + + tp6m-cold-14: + test-name: raptor-tp6m-cold-14 + treeherder: + symbol: 'Rap(tp6m-c-14)' + + tp6m-cold-15: + test-name: raptor-tp6m-cold-15 + treeherder: + symbol: 'Rap(tp6m-c-15)' + + tp6m-cold-16: + test-name: raptor-tp6m-cold-16 + treeherder: + symbol: 'Rap(tp6m-c-16)' + + tp6m-cold-17: + test-name: raptor-tp6m-cold-17 + treeherder: + symbol: 'Rap(tp6m-c-17)' + + tp6m-cold-18: + test-name: raptor-tp6m-cold-18 + treeherder: + symbol: 'Rap(tp6m-c-18)' + + tp6m-cold-19: + test-name: raptor-tp6m-cold-19 + treeherder: + symbol: 'Rap(tp6m-c-19)' + + tp6m-cold-20: + test-name: raptor-tp6m-cold-20 + treeherder: + symbol: 'Rap(tp6m-c-20)' + + tp6m-cold-21: + test-name: raptor-tp6m-cold-21 + treeherder: + symbol: 'Rap(tp6m-c-21)' + + tp6m-cold-22: + test-name: raptor-tp6m-cold-22 + treeherder: + symbol: 'Rap(tp6m-c-22)' + + tp6m-cold-23: + test-name: raptor-tp6m-cold-23 + treeherder: + symbol: 'Rap(tp6m-c-23)' + + tp6m-cold-24: + test-name: raptor-tp6m-cold-24 + treeherder: + symbol: 'Rap(tp6m-c-24)' + + tp6m-cold-25: + test-name: raptor-tp6m-cold-25 + treeherder: + symbol: 'Rap(tp6m-c-25)' + + tp6m-cold-26: + test-name: raptor-tp6m-cold-26 + treeherder: + symbol: 'Rap(tp6m-c-26)' + + tp6m-cold-27: + test-name: raptor-tp6m-cold-27 + treeherder: + symbol: 'Rap(tp6m-c-27)' + + youtube-playback: + test-name: raptor-youtube-playback + treeherder: + symbol: 'Rap(ytp)' diff --git a/taskcluster/fenix_taskgraph/raptor.py b/taskcluster/fenix_taskgraph/raptor.py new file mode 100644 index 000000000..4ebb86cb3 --- /dev/null +++ b/taskcluster/fenix_taskgraph/raptor.py @@ -0,0 +1,96 @@ +# 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/. +""" +Apply some defaults and minor modifications to the jobs defined in the build +kind. +""" + +from __future__ import absolute_import, print_function, unicode_literals + +import copy +import json + +from taskgraph.transforms.base import TransformSequence +from taskgraph.util.treeherder import inherit_treeherder_from_dep +from taskgraph.util.schema import resolve_keyed_by + +transforms = TransformSequence() + + +@transforms.add +def add_variants(config, tasks): + only_types = config.config["only-for-build-types"] + only_abis = config.config["only-for-abis"] + + tests = list(tasks) + + for dep_task in config.kind_dependencies_tasks: + build_type = dep_task.attributes.get("build-type", '') + if build_type not in only_types: + continue + + # TODO remove this if statement once signing tasks are fully created in taskgraph + if not dep_task.label.startswith('sign: '): + continue + + for abi, apk_path in dep_task.attributes["apks"].items(): + if abi not in only_abis: + continue + for test in tests: + test = copy.deepcopy(test) + attributes = copy.deepcopy(dep_task.attributes) + attributes.update(test.get("attributes", {})) + attributes["abi"] = abi + attributes["apk"] = apk_path + test["attributes"] = attributes + test["primary-dependency"] = dep_task + yield test + + +@transforms.add +def build_raptor_task(config, tasks): + for task in tasks: + signing = task.pop("primary-dependency") + build_type = task["attributes"]["build-type"] + abi = task["attributes"]["abi"] + apk = task["attributes"]["apk"] + + test_name = task.pop("test-name") + + task["name"] = "{}-{}-{}".format(task["name"], build_type, abi) + task["description"] = "{}-{}".format(build_type, abi) + + for key in ("worker-type", "treeherder.platform"): + resolve_keyed_by(task, key, item_name=task["name"], **{"abi": abi}) + + task["treeherder"] = inherit_treeherder_from_dep(task, signing) + + extra_config = { + "installer_url": "".format(apk), + "test_packages_url": "", + } + env = task["worker"]["env"] + env["EXTRA_MOZHARNESS_CONFIG"] = { + "artifact-reference": json.dumps(extra_config, sort_keys=True) + } + env["GECKO_HEAD_REV"] = "default" + env["MOZILLA_BUILD_URL"] = {"artifact-reference": "".format(apk)} + env["MOZHARNESS_URL"] = { + "artifact-reference": "" + } + env["TASKCLUSTER_WORKER_TYPE"] = task["worker-type"] + + worker = task["worker"] + worker.setdefault("mounts", []).append( + { + "content": { + "url": "https://hg.mozilla.org/mozilla-central/raw-file/default/taskcluster/scripts/tester/test-linux.sh" + }, + "file": "./test-linux.sh", + } + ) + task["run"]["command"].append("--test={}".format(test_name)) + task["run"]["command"].extend(task.pop("args", [])) + + yield task diff --git a/taskcluster/fenix_taskgraph/target_tasks.py b/taskcluster/fenix_taskgraph/target_tasks.py index 765f0995d..0e9de3ec9 100644 --- a/taskcluster/fenix_taskgraph/target_tasks.py +++ b/taskcluster/fenix_taskgraph/target_tasks.py @@ -6,18 +6,20 @@ from __future__ import absolute_import, print_function, unicode_literals from taskgraph.target_tasks import _target_task, standard_filter + # XXX We're overwritting the default target_task while all tasks are ported to taskgraph @_target_task('default') def target_tasks_default(full_task_graph, parameters, graph_config): """Target the tasks which have indicated they should be run on this project via the `run_on_projects` attributes.""" - def filter(t, params): - if t.kind == 'old-decision': - return True + return [l for l, t in full_task_graph.tasks.iteritems() if _old_decision_filter(t, parameters)] - return standard_filter(t, params) - return [l for l, t in full_task_graph.tasks.iteritems() if filter(t, parameters)] +def _old_decision_filter(task, parameters): + if task.kind == 'old-decision': + return True + + return standard_filter(task, parameters) @_target_task('nightly') @@ -28,5 +30,10 @@ def target_tasks_raptor(full_task_graph, parameters, graph_config): @_target_task('raptor') def target_tasks_raptor(full_task_graph, parameters, graph_config): - # TODO Change this target task method once old-decision loader is no more - return target_tasks_default(full_task_graph, parameters, graph_config) + def filter(t, params): + if t.kind == 'raptor': + return True + + return _old_decision_filter(t, params) + + return [l for l, t in full_task_graph.tasks.iteritems() if filter(t, parameters)]