Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion .github/scripts/tests/therock_matrix_test.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import copy
from pathlib import Path
import os
import sys
Expand All @@ -13,6 +14,11 @@ def test_collect_projects_to_run_without_additional_option(self):

project_to_run = therock_matrix.collect_projects_to_run(subtrees)
self.assertEqual(len(project_to_run), 1)
blas_entry = project_to_run[0]
self.assertIn(
"hipsparselt",
blas_entry["projects_to_test"].split(","),
)
Comment thread
davidd-amd marked this conversation as resolved.

def test_collect_projects_to_run(self):
subtrees = ["projects/rocsparse", "projects/hipblaslt"]
Expand All @@ -36,7 +42,31 @@ def test_collect_projects_to_run_dependency_graph_diff_projects(self):
subtrees = ["projects/miopen", "projects/rocwmma"]

project_to_run = therock_matrix.collect_projects_to_run(subtrees)
self.assertEqual(len(project_to_run), 2)
# rocwmma only contributes via blas under additional_options; miopen absorbs blas.
self.assertEqual(len(project_to_run), 1)
combined = project_to_run[0]
self.assertIn("rocwmma", combined["projects_to_test"].split(","))
self.assertIn("miopen", combined["projects_to_test"].split(","))

def test_collect_projects_to_run_does_not_mutate_module_state(self):
# Snapshot module-level dicts, run a series of representative calls, and
# confirm the originals are untouched. This guards against the
# mutate-globals regression that previously required importlib.reload
# between tests.
project_map_before = copy.deepcopy(therock_matrix.project_map)
additional_options_before = copy.deepcopy(therock_matrix.additional_options)

therock_matrix.collect_projects_to_run(["projects/hipblaslt"])
therock_matrix.collect_projects_to_run(
["projects/rocsparse", "projects/hipblaslt"]
)
therock_matrix.collect_projects_to_run(
["projects/miopen", "projects/hipblaslt"]
)
therock_matrix.collect_projects_to_run(["projects/miopen", "projects/rocwmma"])

self.assertEqual(therock_matrix.project_map, project_map_before)
self.assertEqual(therock_matrix.additional_options, additional_options_before)


if __name__ == "__main__":
Expand Down
48 changes: 33 additions & 15 deletions .github/scripts/therock_matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
This dictionary is used to map specific file directory changes to the corresponding build flag and tests
"""

import copy
import os

subtree_to_project_map = {
Expand Down Expand Up @@ -152,36 +153,53 @@
"miopen": ["blas", "rand", "fusilli-provider"],
}

# When these subtrees change, also activate the given optional matrix project so
# its additional_options merge into the parent job (e.g. hipSPARSELt depends on hipBLASLt).
SUBTREE_EXTRA_MATRIX_PROJECTS = {
"projects/hipblaslt": "sparselt",
Comment thread
tony-davis marked this conversation as resolved.
}


def collect_projects_to_run(subtrees):
platform = os.getenv("PLATFORM")
projects = set()
# Work on per-call deep copies so module-level state stays immutable across calls.
# Without this, the function would extend lists, replace values, and delete keys
# in `project_map` / `additional_options`, breaking any second call in the same
# process (and forcing tests to `importlib.reload` between cases).
local_project_map = copy.deepcopy(project_map)
local_additional_options = copy.deepcopy(additional_options)

# collect the associated subtree to project
for subtree in subtrees:
if subtree in subtree_to_project_map:
projects.add(subtree_to_project_map.get(subtree))

extra_matrix = SUBTREE_EXTRA_MATRIX_PROJECTS.get(subtree)
if extra_matrix:
projects.add(extra_matrix)

for project in list(projects):
# Check if an optional math component was included.
if project in additional_options:
project_options_to_add = additional_options[project]
if project in local_additional_options:
project_options_to_add = local_additional_options[project]

project_to_add = project_options_to_add["project_to_add"]
# If `project_to_add` is in included, add options to the existing `project_map` entry
if project_to_add in projects:
project_map[project_to_add]["cmake_options"].extend(
local_project_map[project_to_add]["cmake_options"].extend(
project_options_to_add["cmake_options"]
)
project_map[project_to_add]["projects_to_test"].extend(
local_project_map[project_to_add]["projects_to_test"].extend(
project_options_to_add["projects_to_test"]
)
# If `project_to_add` is not included, only run build and tests for the optional project
else:
projects.add(project_to_add)
project_map[project_to_add]["cmake_options"] = project_options_to_add[
"cmake_options"
]
project_map[project_to_add]["projects_to_test"] = (
local_project_map[project_to_add]["cmake_options"] = (
project_options_to_add["cmake_options"]
)
local_project_map[project_to_add]["projects_to_test"] = (
project_options_to_add["projects_to_test"]
)

Expand All @@ -193,24 +211,24 @@ def collect_projects_to_run(subtrees):
for dependency in dependency_graph[project]:
# If the dependency is also included, let's combine to avoid overlap
if dependency in projects:
project_map[project]["cmake_options"].extend(
project_map[dependency]["cmake_options"]
local_project_map[project]["cmake_options"].extend(
local_project_map[dependency]["cmake_options"]
)
project_map[project]["projects_to_test"].extend(
project_map[dependency]["projects_to_test"]
local_project_map[project]["projects_to_test"].extend(
local_project_map[dependency]["projects_to_test"]
)
to_remove_from_project_map.append(dependency)

# if dependency is included in projects and parent is found, we delete the dependency as the parent will build and test
for to_remove_item in to_remove_from_project_map:
projects.remove(to_remove_item)
del project_map[to_remove_item]
del local_project_map[to_remove_item]

# retrieve the subtrees to checkout, cmake options to build, and projects to test
project_to_run = []
for project in projects:
if project in project_map:
project_map_data = project_map.get(project)
if project in local_project_map:
project_map_data = local_project_map.get(project)

# Check if platform-based additional flags are needed
if (
Expand Down
Loading