Skip to content

Commit cfc459c

Browse files
committed
Bug 1982882: vendor taskgraph 15.2.1 r=taskgraph-reviewers,mach-reviewers,jcristau
This picks up multiprocess kind processing (taskcluster/taskgraph#765). Differential Revision: https://phabricator.services.mozilla.com/D264588
1 parent 8b3b0f9 commit cfc459c

File tree

9 files changed

+141
-45
lines changed

9 files changed

+141
-45
lines changed

third_party/python/requirements.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,9 +1015,9 @@ taskcluster==75.0.1 \
10151015
--hash=sha256:3100ce68e7a655701cd78290067f0df1b05e0a85c69df29f60ceaad6baf0fc53 \
10161016
--hash=sha256:6b16a0d8ffa3431a66a2ffe428f8e5c7874b9cbeddba7d5ce0e8d8783d4c95a3
10171017
# via mozilla-third-party-python-vendor-dir
1018-
taskcluster-taskgraph==15.1.4 \
1019-
--hash=sha256:12c0b8ce64ec66d0dfbfc35c9effa438fa4b460c907eaf7047043893f1b2e6dd \
1020-
--hash=sha256:ba14600db1dcb1e53a35e30a311f981fad7640d71d07794eddd7b756e7502ed0
1018+
taskcluster-taskgraph==15.2.1 \
1019+
--hash=sha256:31f83af7ae2302ac1e1f9ffcbc46f73728d5ed51dc1fb0917e5f18f678acb3f2 \
1020+
--hash=sha256:66bdca3a95a7706e327cb72665a369249aa91b1a0a24b3804f828f0ff1e0cce1
10211021
# via
10221022
# mozilla-taskgraph
10231023
# mozilla-third-party-python-vendor-dir

third_party/python/taskcluster_taskgraph/taskcluster_taskgraph-15.1.4.dist-info/METADATA renamed to third_party/python/taskcluster_taskgraph/taskcluster_taskgraph-15.2.1.dist-info/METADATA

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Metadata-Version: 2.4
22
Name: taskcluster-taskgraph
3-
Version: 15.1.4
3+
Version: 15.2.1
44
Summary: Build taskcluster taskgraphs
55
Project-URL: Repository, https://github.com/taskcluster/taskgraph
66
Project-URL: Issues, https://github.com/taskcluster/taskgraph/issues

third_party/python/taskcluster_taskgraph/taskcluster_taskgraph-15.1.4.dist-info/RECORD renamed to third_party/python/taskcluster_taskgraph/taskcluster_taskgraph-15.2.1.dist-info/RECORD

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ taskgraph/create.py,sha256=tHz0ErolW8U-mSDnSq8wJICKOxK1aMnIdUWAyhrc-JQ,5299
44
taskgraph/decision.py,sha256=dcl2NnbkKUfKVFDSVkKEHRub0wXcP2P0jxrxlFjrnLY,14091
55
taskgraph/docker.py,sha256=lKMK0CDvsVGKwxKRT5kk7UX9G6bfU0rKGtPtOkSf93E,13586
66
taskgraph/filter_tasks.py,sha256=R7tYXiaVPGIkQ6O1c9-QJrKZ59m9pFXCloUlPraVnZU,866
7-
taskgraph/generator.py,sha256=E-P7e3mDlB_s8updC291njYpayRYPvpePIt0WgOX-AY,16673
7+
taskgraph/generator.py,sha256=_VQ0CZC2y_0Cab042EHhqjyWsmi3wjGHOAsljd_G7hg,20414
88
taskgraph/graph.py,sha256=qvihwxxdc3C55ZJ5FLc2phFV0D7oZNXKXEHBIA_GI1U,4696
99
taskgraph/main.py,sha256=aX3xc07r8SqtwokhXf08y_HOPzeN3t6PsXWNFPzhksY,32895
1010
taskgraph/morph.py,sha256=lK5mBjhnMlL--ucUUeqMg21aXmCfiUmTUo3wDvtxkoQ,9215
@@ -74,8 +74,8 @@ taskgraph/util/vcs.py,sha256=4HeyFK0LKygeLfVi087_EpE7EPkel8PiFBtIvlOpiWI,19810
7474
taskgraph/util/verify.py,sha256=V5MyL5UaxrX9SeLJZU9S1OEvfovvxWXu4oj77swmkxk,9577
7575
taskgraph/util/workertypes.py,sha256=dR5NkwvmcY-no_I4l22mw93EKyvGbe_Xv7N9hzkiG1U,2570
7676
taskgraph/util/yaml.py,sha256=29h6RE7JA4z0U2V3WCu-S39lPMBS9CEZEglv1delDvw,1075
77-
taskcluster_taskgraph-15.1.4.dist-info/METADATA,sha256=WbAxa_Z-wcZ7727-nlhKy5RBMFo-biYKW3PIzIjkYPE,5001
78-
taskcluster_taskgraph-15.1.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
79-
taskcluster_taskgraph-15.1.4.dist-info/entry_points.txt,sha256=2hxDzE3qq_sHh-J3ROqwpxgQgxO-196phWAQREl2-XA,50
80-
taskcluster_taskgraph-15.1.4.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
81-
taskcluster_taskgraph-15.1.4.dist-info/RECORD,,
77+
taskcluster_taskgraph-15.2.1.dist-info/METADATA,sha256=nzWmOD0TJiPp76e1dNoY_cJysMG6oKs-FqmG0tSVy-c,5001
78+
taskcluster_taskgraph-15.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
79+
taskcluster_taskgraph-15.2.1.dist-info/entry_points.txt,sha256=2hxDzE3qq_sHh-J3ROqwpxgQgxO-196phWAQREl2-XA,50
80+
taskcluster_taskgraph-15.2.1.dist-info/licenses/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
81+
taskcluster_taskgraph-15.2.1.dist-info/RECORD,,

third_party/python/taskcluster_taskgraph/taskcluster_taskgraph-15.1.4.dist-info/WHEEL renamed to third_party/python/taskcluster_taskgraph/taskcluster_taskgraph-15.2.1.dist-info/WHEEL

File renamed without changes.

third_party/python/taskcluster_taskgraph/taskcluster_taskgraph-15.1.4.dist-info/entry_points.txt renamed to third_party/python/taskcluster_taskgraph/taskcluster_taskgraph-15.2.1.dist-info/entry_points.txt

File renamed without changes.

third_party/python/taskcluster_taskgraph/taskcluster_taskgraph-15.1.4.dist-info/licenses/LICENSE renamed to third_party/python/taskcluster_taskgraph/taskcluster_taskgraph-15.2.1.dist-info/licenses/LICENSE

File renamed without changes.

third_party/python/taskcluster_taskgraph/taskgraph/generator.py

Lines changed: 127 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,14 @@
44

55
import copy
66
import logging
7+
import multiprocessing
78
import os
9+
import platform
10+
from concurrent.futures import (
11+
FIRST_COMPLETED,
12+
ProcessPoolExecutor,
13+
wait,
14+
)
815
from dataclasses import dataclass
916
from typing import Callable, Dict, Optional, Union
1017

@@ -46,16 +53,20 @@ def _get_loader(self) -> Callable:
4653
assert callable(loader)
4754
return loader
4855

49-
def load_tasks(self, parameters, loaded_tasks, write_artifacts):
56+
def load_tasks(self, parameters, kind_dependencies_tasks, write_artifacts):
57+
logger.debug(f"Loading tasks for kind {self.name}")
58+
59+
parameters = Parameters(**parameters)
5060
loader = self._get_loader()
5161
config = copy.deepcopy(self.config)
5262

53-
kind_dependencies = config.get("kind-dependencies", [])
54-
kind_dependencies_tasks = {
55-
task.label: task for task in loaded_tasks if task.kind in kind_dependencies
56-
}
57-
58-
inputs = loader(self.name, self.path, config, parameters, loaded_tasks)
63+
inputs = loader(
64+
self.name,
65+
self.path,
66+
config,
67+
parameters,
68+
list(kind_dependencies_tasks.values()),
69+
)
5970

6071
transforms = TransformSequence()
6172
for xform_path in config["transforms"]:
@@ -89,6 +100,7 @@ def load_tasks(self, parameters, loaded_tasks, write_artifacts):
89100
)
90101
for task_dict in transforms(trans_config, inputs)
91102
]
103+
logger.info(f"Generated {len(tasks)} tasks for kind {self.name}")
92104
return tasks
93105

94106
@classmethod
@@ -253,6 +265,103 @@ def _load_kinds(self, graph_config, target_kinds=None):
253265
except KindNotFound:
254266
continue
255267

268+
def _load_tasks_serial(self, kinds, kind_graph, parameters):
269+
all_tasks = {}
270+
for kind_name in kind_graph.visit_postorder():
271+
logger.debug(f"Loading tasks for kind {kind_name}")
272+
273+
kind = kinds.get(kind_name)
274+
if not kind:
275+
message = f'Could not find the kind "{kind_name}"\nAvailable kinds:\n'
276+
for k in sorted(kinds):
277+
message += f' - "{k}"\n'
278+
raise Exception(message)
279+
280+
try:
281+
new_tasks = kind.load_tasks(
282+
parameters,
283+
{
284+
k: t
285+
for k, t in all_tasks.items()
286+
if t.kind in kind.config.get("kind-dependencies", [])
287+
},
288+
self._write_artifacts,
289+
)
290+
except Exception:
291+
logger.exception(f"Error loading tasks for kind {kind_name}:")
292+
raise
293+
for task in new_tasks:
294+
if task.label in all_tasks:
295+
raise Exception("duplicate tasks with label " + task.label)
296+
all_tasks[task.label] = task
297+
298+
return all_tasks
299+
300+
def _load_tasks_parallel(self, kinds, kind_graph, parameters):
301+
all_tasks = {}
302+
futures_to_kind = {}
303+
futures = set()
304+
edges = set(kind_graph.edges)
305+
306+
with ProcessPoolExecutor(
307+
mp_context=multiprocessing.get_context("fork")
308+
) as executor:
309+
310+
def submit_ready_kinds():
311+
"""Create the next batch of tasks for kinds without dependencies."""
312+
nonlocal kinds, edges, futures
313+
loaded_tasks = all_tasks.copy()
314+
kinds_with_deps = {edge[0] for edge in edges}
315+
ready_kinds = (
316+
set(kinds) - kinds_with_deps - set(futures_to_kind.values())
317+
)
318+
for name in ready_kinds:
319+
kind = kinds.get(name)
320+
if not kind:
321+
message = (
322+
f'Could not find the kind "{name}"\nAvailable kinds:\n'
323+
)
324+
for k in sorted(kinds):
325+
message += f' - "{k}"\n'
326+
raise Exception(message)
327+
328+
future = executor.submit(
329+
kind.load_tasks,
330+
dict(parameters),
331+
{
332+
k: t
333+
for k, t in loaded_tasks.items()
334+
if t.kind in kind.config.get("kind-dependencies", [])
335+
},
336+
self._write_artifacts,
337+
)
338+
futures.add(future)
339+
futures_to_kind[future] = name
340+
341+
submit_ready_kinds()
342+
while futures:
343+
done, _ = wait(futures, return_when=FIRST_COMPLETED)
344+
for future in done:
345+
if exc := future.exception():
346+
executor.shutdown(wait=False, cancel_futures=True)
347+
raise exc
348+
kind = futures_to_kind.pop(future)
349+
futures.remove(future)
350+
351+
for task in future.result():
352+
if task.label in all_tasks:
353+
raise Exception("duplicate tasks with label " + task.label)
354+
all_tasks[task.label] = task
355+
356+
# Update state for next batch of futures.
357+
del kinds[kind]
358+
edges = {e for e in edges if e[1] != kind}
359+
360+
# Submit any newly unblocked kinds
361+
submit_ready_kinds()
362+
363+
return all_tasks
364+
256365
def _run(self):
257366
logger.info("Loading graph configuration.")
258367
graph_config = load_graph_config(self.root_dir)
@@ -307,31 +416,18 @@ def _run(self):
307416
)
308417

309418
logger.info("Generating full task set")
310-
all_tasks = {}
311-
for kind_name in kind_graph.visit_postorder():
312-
logger.debug(f"Loading tasks for kind {kind_name}")
313-
314-
kind = kinds.get(kind_name)
315-
if not kind:
316-
message = f'Could not find the kind "{kind_name}"\nAvailable kinds:\n'
317-
for k in sorted(kinds):
318-
message += f' - "{k}"\n'
319-
raise Exception(message)
419+
# Current parallel generation relies on multiprocessing, and forking.
420+
# This causes problems on Windows and macOS due to how new processes
421+
# are created there, and how doing so reinitializes global variables
422+
# that are modified earlier in graph generation, that doesn't get
423+
# redone in the new processes. Ideally this would be fixed, or we
424+
# would take another approach to parallel kind generation. In the
425+
# meantime, it's not supported outside of Linux.
426+
if platform.system() != "Linux" or os.environ.get("TASKGRAPH_SERIAL"):
427+
all_tasks = self._load_tasks_serial(kinds, kind_graph, parameters)
428+
else:
429+
all_tasks = self._load_tasks_parallel(kinds, kind_graph, parameters)
320430

321-
try:
322-
new_tasks = kind.load_tasks(
323-
parameters,
324-
list(all_tasks.values()),
325-
self._write_artifacts,
326-
)
327-
except Exception:
328-
logger.exception(f"Error loading tasks for kind {kind_name}:")
329-
raise
330-
for task in new_tasks:
331-
if task.label in all_tasks:
332-
raise Exception("duplicate tasks with label " + task.label)
333-
all_tasks[task.label] = task
334-
logger.info(f"Generated {len(new_tasks)} tasks for kind {kind_name}")
335431
full_task_set = TaskGraph(all_tasks, Graph(frozenset(all_tasks), frozenset()))
336432
yield self.verify("full_task_set", full_task_set, graph_config, parameters)
337433

third_party/python/uv.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

third_party/python/uv.lock.hash

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)