1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
|
# 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/.
"""
The objective of optimization is to remove as many tasks from the graph as
possible, as efficiently as possible, thereby delivering useful results as
quickly as possible. For example, ideally if only a test script is modified in
a push, then the resulting graph contains only the corresponding test suite
task.
See ``taskcluster/docs/optimization.rst`` for more information.
"""
from taskgraph.optimize.base import Alias, All, Any, Not, register_strategy
from taskgraph.util.python_path import import_sibling_modules
# Trigger registration in sibling modules.
import_sibling_modules()
def split_bugbug_arg(arg, substrategies):
"""Split args for bugbug based strategies.
Many bugbug based optimizations require passing an empty dict by reference
to communicate to downstream strategies. This function passes the provided
arg to the first (non bugbug) strategies and a shared empty dict to the
bugbug strategy and all substrategies after it.
"""
from gecko_taskgraph.optimize.bugbug import BugBugPushSchedules
index = [
i
for i, strategy in enumerate(substrategies)
if isinstance(strategy, BugBugPushSchedules)
][0]
return [arg] * index + [{}] * (len(substrategies) - index)
# Register composite strategies.
register_strategy("build", args=("skip-unless-schedules",))(Alias)
register_strategy("test", args=("skip-unless-schedules",))(Alias)
register_strategy("test-inclusive", args=("skip-unless-schedules",))(Alias)
register_strategy("test-verify", args=("skip-unless-schedules",))(Alias)
register_strategy("upload-symbols", args=("never",))(Alias)
register_strategy("reprocess-symbols", args=("never",))(Alias)
register_strategy(
"skip-unless-missing-or-changed",
args=("skip-unless-missing", "skip-unless-changed"),
kwargs={"split_args": lambda args, _: (args[0], args[1])},
)(All)
# Strategy overrides used to tweak the default strategies. These are referenced
# by the `optimize_strategies` parameter.
class project:
"""Strategies that should be applied per-project."""
autoland = {
"test": Any(
# This `Any` strategy implements bi-modal behaviour. It allows different
# strategies on expanded pushes vs regular pushes.
# This first `All` handles "expanded" pushes.
All(
# There are three substrategies in this `All`, the first two act as barriers
# that help determine when to apply the third:
# 1. On backstop pushes, `skip-unless-backstop` returns False. Therefore
# the overall composite strategy is False and we don't optimize.
# 2. On regular pushes, `Not('skip-unless-expanded')` returns False. Therefore
# the overall composite strategy is False and we don't optimize.
# 3. On expanded pushes, the third strategy will determine whether or
# not to optimize each individual task.
# The barrier strategies.
"skip-unless-backstop",
Not("skip-unless-expanded"),
# The actual test strategy applied to "expanded" pushes.
Any(
"skip-unless-schedules",
"bugbug-reduced-manifests-fallback-last-10-pushes",
"platform-disperse",
split_args=split_bugbug_arg,
),
),
# This second `All` handles regular (aka not expanded or backstop)
# pushes.
All(
# There are two substrategies in this `All`, the first acts as a barrier
# that determines when to apply the second:
# 1. On expanded pushes (which includes backstops), `skip-unless-expanded`
# returns False. Therefore the overall composite strategy is False and we
# don't optimize.
# 2. On regular pushes, the second strategy will determine whether or
# not to optimize each individual task.
# The barrier strategy.
"skip-unless-expanded",
# The actual test strategy applied to regular pushes.
Any(
"skip-unless-schedules",
"bugbug-reduced-manifests-fallback-low",
"platform-disperse",
split_args=split_bugbug_arg,
),
),
),
"build": All(
"skip-unless-expanded",
Any(
"skip-unless-schedules",
"bugbug-reduced-fallback",
split_args=split_bugbug_arg,
),
),
}
"""Strategy overrides that apply to autoland."""
class experimental:
"""Experimental strategies either under development or used as benchmarks.
These run as "shadow-schedulers" on each autoland push (tier 3) and/or can be used
with `./mach try auto`. E.g:
./mach try auto --strategy relevant_tests
"""
bugbug_tasks_medium = {
"test": Any(
"skip-unless-schedules", "bugbug-tasks-medium", split_args=split_bugbug_arg
),
}
"""Doesn't limit platforms, medium confidence threshold."""
bugbug_tasks_high = {
"test": Any(
"skip-unless-schedules", "bugbug-tasks-high", split_args=split_bugbug_arg
),
}
"""Doesn't limit platforms, high confidence threshold."""
bugbug_debug_disperse = {
"test": Any(
"skip-unless-schedules",
"bugbug-low",
"platform-debug",
"platform-disperse",
split_args=split_bugbug_arg,
),
}
"""Restricts tests to debug platforms."""
bugbug_disperse_low = {
"test": Any(
"skip-unless-schedules",
"bugbug-low",
"platform-disperse",
split_args=split_bugbug_arg,
),
}
"""Disperse tests across platforms, low confidence threshold."""
bugbug_disperse_medium = {
"test": Any(
"skip-unless-schedules",
"bugbug-medium",
"platform-disperse",
split_args=split_bugbug_arg,
),
}
"""Disperse tests across platforms, medium confidence threshold."""
bugbug_disperse_reduced_medium = {
"test": Any(
"skip-unless-schedules",
"bugbug-reduced-manifests",
"platform-disperse",
split_args=split_bugbug_arg,
),
}
"""Disperse tests across platforms, medium confidence threshold with reduced tasks."""
bugbug_reduced_manifests_config_selection_low = {
"test": Any(
"skip-unless-schedules",
"bugbug-reduced-manifests-config-selection-low",
split_args=split_bugbug_arg,
),
}
"""Choose configs selected by bugbug, low confidence threshold with reduced tasks."""
bugbug_reduced_manifests_config_selection_medium = {
"test": Any(
"skip-unless-schedules",
"bugbug-reduced-manifests-config-selection",
split_args=split_bugbug_arg,
),
}
"""Choose configs selected by bugbug, medium confidence threshold with reduced tasks."""
bugbug_disperse_medium_no_unseen = {
"test": Any(
"skip-unless-schedules",
"bugbug-medium",
"platform-disperse-no-unseen",
split_args=split_bugbug_arg,
),
}
"""Disperse tests across platforms (no modified for unseen configurations), medium confidence
threshold."""
bugbug_disperse_medium_only_one = {
"test": Any(
"skip-unless-schedules",
"bugbug-medium",
"platform-disperse-only-one",
split_args=split_bugbug_arg,
),
}
"""Disperse tests across platforms (one platform per group), medium confidence threshold."""
bugbug_disperse_high = {
"test": Any(
"skip-unless-schedules",
"bugbug-high",
"platform-disperse",
split_args=split_bugbug_arg,
),
}
"""Disperse tests across platforms, high confidence threshold."""
bugbug_reduced = {
"test": Any(
"skip-unless-schedules", "bugbug-reduced", split_args=split_bugbug_arg
),
}
"""Use the reduced set of tasks (and no groups) chosen by bugbug."""
bugbug_reduced_high = {
"test": Any(
"skip-unless-schedules", "bugbug-reduced-high", split_args=split_bugbug_arg
),
}
"""Use the reduced set of tasks (and no groups) chosen by bugbug, high
confidence threshold."""
relevant_tests = {
"test": Any("skip-unless-schedules", "skip-unless-has-relevant-tests"),
}
"""Runs task containing tests in the same directories as modified files."""
class ExperimentalOverride:
"""Overrides dictionaries that are stored in a container with new values.
This can be used to modify all strategies in a collection the same way,
presumably with strategies affecting kinds of tasks tangential to the
current context.
Args:
base (object): A container class supporting attribute access.
overrides (dict): Values to update any accessed dictionaries with.
"""
def __init__(self, base, overrides):
self.base = base
self.overrides = overrides
def __getattr__(self, name):
val = getattr(self.base, name).copy()
for name, strategy in self.overrides.items():
if isinstance(strategy, str) and strategy.startswith("base:"):
strategy = val[strategy[len("base:") :]]
val[name] = strategy
return val
tryselect = ExperimentalOverride(
experimental,
{
"build": Any(
"skip-unless-schedules", "bugbug-reduced", split_args=split_bugbug_arg
),
"test-verify": "base:test",
"upload-symbols": Alias("always"),
"reprocess-symbols": Alias("always"),
},
)
|