diff --git a/.github/workflows/multi_arch_ci.yml b/.github/workflows/multi_arch_ci.yml index defdc47ab34..0693a973430 100644 --- a/.github/workflows/multi_arch_ci.yml +++ b/.github/workflows/multi_arch_ci.yml @@ -46,6 +46,10 @@ on: type: string default: "" description: "Comma-separated list of changed projects to filter tests (empty = run all tests)" + build_pytorch: + type: boolean + default: true + description: "Build PyTorch wheels" pull_request: types: - labeled @@ -78,6 +82,7 @@ jobs: windows_test_labels: ${{ inputs.windows_test_labels || '' }} prebuilt_stages: ${{ inputs.prebuilt_stages || '' }} baseline_run_id: ${{ inputs.baseline_run_id || '' }} + build_pytorch: ${{ github.event_name != 'workflow_dispatch' || inputs.build_pytorch }} linux_build_and_test: name: Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} diff --git a/.github/workflows/multi_arch_ci_asan.yml b/.github/workflows/multi_arch_ci_asan.yml index dab0030c3cb..e293959f4fe 100644 --- a/.github/workflows/multi_arch_ci_asan.yml +++ b/.github/workflows/multi_arch_ci_asan.yml @@ -58,6 +58,7 @@ jobs: linux_test_labels: ${{ inputs.linux_test_labels || '' }} prebuilt_stages: ${{ inputs.prebuilt_stages || '' }} baseline_run_id: ${{ inputs.baseline_run_id || '' }} + build_pytorch: false linux_build_and_test: name: Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} diff --git a/.github/workflows/multi_arch_ci_linux.yml b/.github/workflows/multi_arch_ci_linux.yml index 5415cf36c7c..edbfa149e08 100644 --- a/.github/workflows/multi_arch_ci_linux.yml +++ b/.github/workflows/multi_arch_ci_linux.yml @@ -14,6 +14,7 @@ on: build_variant_label, build_variant_cmake_preset, build_variant_suffix, build_pytorch, build_native_linux, test_python_packages_matrix, + pytorch_build_matrix, prebuilt_stages, baseline_run_id. test_labels: type: string @@ -289,20 +290,26 @@ jobs: # inputs.kpack_split. build_pytorch_wheel_fat: needs: [build_python_packages] - name: Build PyTorch (fat + split) | ${{ matrix.pytorch_git_ref }} - if: ${{ !failure() && !cancelled() && fromJSON(inputs.build_config).build_pytorch == true }} + name: Build PyTorch (fat + split) + if: >- + ${{ + !failure() && + !cancelled() && + fromJSON(inputs.build_config).build_pytorch == true && + toJSON(fromJSON(inputs.build_config).pytorch_build_matrix) != '[]' + }} strategy: fail-fast: false matrix: - pytorch_git_ref: ["release/2.10", "release/2.11", "release/2.12"] + include: ${{ fromJSON(inputs.build_config).pytorch_build_matrix }} uses: ./.github/workflows/multi_arch_build_portable_linux_pytorch_wheels_ci.yml with: artifact_group: ${{ fromJSON(inputs.build_config).artifact_group }} - python_version: "3.12" + python_version: ${{ matrix.python_version }} pytorch_git_ref: ${{ matrix.pytorch_git_ref }} # The reusable workflow expands this to gfx targets via # cmake/therock_amdgpu_targets.cmake. - amdgpu_families: ${{ fromJSON(inputs.build_config).dist_amdgpu_families }} + amdgpu_families: ${{ matrix.amdgpu_families }} kpack_split: ${{ needs.build_python_packages.outputs.kpack_split }} rocm_package_find_links_url: ${{ needs.build_python_packages.outputs.package_find_links_url }} rocm_version: ${{ inputs.rocm_package_version }} diff --git a/.github/workflows/multi_arch_ci_windows.yml b/.github/workflows/multi_arch_ci_windows.yml index 53948afa83a..5982401b271 100644 --- a/.github/workflows/multi_arch_ci_windows.yml +++ b/.github/workflows/multi_arch_ci_windows.yml @@ -14,6 +14,7 @@ on: build_variant_label, build_variant_cmake_preset, build_variant_suffix, build_pytorch, build_native_linux, test_python_packages_matrix, + pytorch_build_matrix, prebuilt_stages, baseline_run_id. test_labels: type: string @@ -206,15 +207,25 @@ jobs: build_pytorch_wheel_fat: needs: [build_python_packages] name: Build PyTorch (fat + split) - if: ${{ !failure() && !cancelled() && fromJSON(inputs.build_config).build_pytorch == true }} + if: >- + ${{ + !failure() && + !cancelled() && + fromJSON(inputs.build_config).build_pytorch == true && + toJSON(fromJSON(inputs.build_config).pytorch_build_matrix) != '[]' + }} + strategy: + fail-fast: false + matrix: + include: ${{ fromJSON(inputs.build_config).pytorch_build_matrix }} uses: ./.github/workflows/multi_arch_build_windows_pytorch_wheels_ci.yml with: artifact_group: ${{ fromJSON(inputs.build_config).artifact_group }} - python_version: "3.12" - pytorch_git_ref: "release/2.10" + python_version: ${{ matrix.python_version }} + pytorch_git_ref: ${{ matrix.pytorch_git_ref }} # The reusable workflow expands this to gfx targets via # cmake/therock_amdgpu_targets.cmake. - amdgpu_families: ${{ fromJSON(inputs.build_config).dist_amdgpu_families }} + amdgpu_families: ${{ matrix.amdgpu_families }} kpack_split: ${{ needs.build_python_packages.outputs.kpack_split }} rocm_package_find_links_url: ${{ needs.build_python_packages.outputs.package_find_links_url }} rocm_version: ${{ inputs.rocm_package_version }} diff --git a/.github/workflows/multi_arch_release.yml b/.github/workflows/multi_arch_release.yml index 5612ec64812..1b02d78ce20 100644 --- a/.github/workflows/multi_arch_release.yml +++ b/.github/workflows/multi_arch_release.yml @@ -105,6 +105,8 @@ jobs: build_variant: "release" release_type: ${{ inputs.release_type }} prerelease_version: ${{ inputs.prerelease_version }} + build_pytorch: ${{ inputs.build_pytorch }} + python_version: ${{ inputs.python_version }} linux_amdgpu_families: ${{ inputs.linux_amdgpu_families }} windows_amdgpu_families: ${{ inputs.windows_amdgpu_families }} repository: ${{ inputs.repository || github.repository }} diff --git a/.github/workflows/multi_arch_release_asan.yml b/.github/workflows/multi_arch_release_asan.yml index a6f3ff5c9b4..746540460d9 100644 --- a/.github/workflows/multi_arch_release_asan.yml +++ b/.github/workflows/multi_arch_release_asan.yml @@ -86,6 +86,8 @@ jobs: prerelease_version: ${{ inputs.prerelease_version }} linux_amdgpu_families: ${{ inputs.linux_amdgpu_families || 'all' }} windows_amdgpu_families: "none" + build_pytorch: false + python_version: ${{ inputs.python_version }} repository: ${{ inputs.repository || github.repository }} ref: ${{ inputs.ref }} diff --git a/.github/workflows/multi_arch_release_linux.yml b/.github/workflows/multi_arch_release_linux.yml index de8d1b0e31c..f459651a460 100644 --- a/.github/workflows/multi_arch_release_linux.yml +++ b/.github/workflows/multi_arch_release_linux.yml @@ -231,7 +231,7 @@ jobs: trigger_release_pytorch_wheels: needs: [build_artifacts, build_python_packages] name: Trigger Release PyTorch Wheels - if: ${{ inputs.build_pytorch != false }} + if: ${{ inputs.build_pytorch != false && fromJSON(inputs.build_config).build_pytorch == true }} runs-on: ubuntu-24.04 permissions: actions: write diff --git a/.github/workflows/multi_arch_release_linux_pytorch_wheels.yml b/.github/workflows/multi_arch_release_linux_pytorch_wheels.yml index 11eddc62c62..3f94fa0d101 100644 --- a/.github/workflows/multi_arch_release_linux_pytorch_wheels.yml +++ b/.github/workflows/multi_arch_release_linux_pytorch_wheels.yml @@ -131,11 +131,13 @@ jobs: python ./build_tools/github_actions/configure_pytorch_release_matrix.py \ --python-versions="${{ inputs.python_version }}" \ --platform=linux \ + --release-type="${{ inputs.release_type }}" \ --amdgpu-families="${{ inputs.amdgpu_families }}" build_pytorch_wheels: needs: setup_matrix name: Build | py ${{ matrix.python_version }} | torch ${{ matrix.pytorch_git_ref }} + if: ${{ needs.setup_matrix.outputs.pytorch_matrix != '[]' }} strategy: fail-fast: false matrix: diff --git a/.github/workflows/multi_arch_release_windows.yml b/.github/workflows/multi_arch_release_windows.yml index 0942c08562f..4e6b18d7595 100644 --- a/.github/workflows/multi_arch_release_windows.yml +++ b/.github/workflows/multi_arch_release_windows.yml @@ -156,7 +156,7 @@ jobs: trigger_release_pytorch_wheels: needs: [build_artifacts, build_python_packages] name: Trigger Release PyTorch Wheels - if: ${{ inputs.build_pytorch != false }} + if: ${{ inputs.build_pytorch != false && fromJSON(inputs.build_config).build_pytorch == true }} runs-on: ubuntu-24.04 permissions: actions: write diff --git a/.github/workflows/multi_arch_release_windows_pytorch_wheels.yml b/.github/workflows/multi_arch_release_windows_pytorch_wheels.yml index 1ffd8195ecb..1ad75293eeb 100644 --- a/.github/workflows/multi_arch_release_windows_pytorch_wheels.yml +++ b/.github/workflows/multi_arch_release_windows_pytorch_wheels.yml @@ -123,11 +123,13 @@ jobs: python ./build_tools/github_actions/configure_pytorch_release_matrix.py \ --python-versions="${{ inputs.python_version }}" \ --platform=windows \ + --release-type="${{ inputs.release_type }}" \ --amdgpu-families="${{ inputs.amdgpu_families }}" build_pytorch_wheels: needs: setup_matrix name: Build | py ${{ matrix.python_version }} | torch ${{ matrix.pytorch_git_ref }} + if: ${{ needs.setup_matrix.outputs.pytorch_matrix != '[]' }} strategy: fail-fast: false matrix: diff --git a/.github/workflows/setup_multi_arch.yml b/.github/workflows/setup_multi_arch.yml index a0aec0483d5..b2acb6bcbfc 100644 --- a/.github/workflows/setup_multi_arch.yml +++ b/.github/workflows/setup_multi_arch.yml @@ -43,6 +43,14 @@ on: description: "Workflow run ID to copy prebuilt stage artifacts from." type: string default: "" + build_pytorch: + description: "Build PyTorch wheels." + type: boolean + default: true + python_version: + description: "Single Python version for wheel builds; empty uses the default matrix." + type: string + default: "" repository: description: "Repository to checkout. Defaults to github.repository." type: string @@ -138,6 +146,8 @@ jobs: env: BUILD_VARIANT: ${{ inputs.build_variant }} RELEASE_TYPE: ${{ inputs.release_type }} + BUILD_PYTORCH: ${{ inputs.build_pytorch }} + PYTHON_VERSION: ${{ inputs.python_version }} LINUX_AMDGPU_FAMILIES: ${{ inputs.linux_amdgpu_families }} WINDOWS_AMDGPU_FAMILIES: ${{ inputs.windows_amdgpu_families }} LINUX_TEST_LABELS: ${{ inputs.linux_test_labels }} diff --git a/build_tools/github_actions/configure_multi_arch_ci.py b/build_tools/github_actions/configure_multi_arch_ci.py index 0166cd47439..5d8e7af4284 100755 --- a/build_tools/github_actions/configure_multi_arch_ci.py +++ b/build_tools/github_actions/configure_multi_arch_ci.py @@ -65,6 +65,7 @@ get_git_submodule_paths, is_ci_run_required, ) +from configure_pytorch_release_matrix import generate_pytorch_matrix_for_release_type from configure_rocm_python_test_matrix import build_rocm_python_test_matrix from github_actions_api import ( gha_append_step_summary, @@ -130,6 +131,8 @@ class CIInputs: base_ref: str # Git ref for the workflow run (PR base or HEAD^1, used for diffing) build_variant: str # Build variant label, e.g. "release", "asan", "tsan" release_type: str = "ci" # "ci", or "dev", "nightly", "prerelease" for releases + build_pytorch: bool = True + python_versions: list[str] = field(default_factory=list) # PR labels (from event payload for pull_request events) pr_labels: list[str] = field(default_factory=list) @@ -181,6 +184,8 @@ def from_environ() -> "CIInputs": # push before-commit) comes from the event payload. build_variant = os.environ.get("BUILD_VARIANT", "release") release_type = os.environ.get("RELEASE_TYPE", "ci") + build_pytorch = os.environ.get("BUILD_PYTORCH", "true").lower() != "false" + python_version = os.environ.get("PYTHON_VERSION", "").strip() pr_labels: list[str] = [] base_ref = "HEAD^1" @@ -215,6 +220,8 @@ def from_environ() -> "CIInputs": base_ref=base_ref, build_variant=build_variant, release_type=release_type, + build_pytorch=build_pytorch, + python_versions=[python_version] if python_version else [], pr_labels=pr_labels, linux_amdgpu_families=_parse_comma_list( os.environ.get("LINUX_AMDGPU_FAMILIES", "") @@ -429,6 +436,7 @@ class BuildConfig: build_native_linux: bool build_pytorch: bool test_python_packages_matrix: list[dict[str, str]] = field(default_factory=list) + pytorch_build_matrix: list[dict[str, str]] = field(default_factory=list) # Build runner label for this platform/variant combination build_runs_on: str = "" # Prebuilt stage configuration — set by configure() from JobDecisions. @@ -663,6 +671,8 @@ def decide_jobs( test_type_reason="ASAN tests skipped due to non-nightly trigger", ) + build_pytorch_action = JobAction.RUN if ci_inputs.build_pytorch else JobAction.SKIP + # Other jobs run unconditionally with no configuration. # TODO: job pruning: skip pytorch if only JAX has been edited, etc. @@ -670,8 +680,8 @@ def decide_jobs( build_rocm=build_rocm, test_rocm=test_rocm, build_rocm_python=JobGroupDecision(action=JobAction.RUN), - build_pytorch=JobGroupDecision(action=JobAction.RUN), - test_pytorch=JobGroupDecision(action=JobAction.RUN), + build_pytorch=JobGroupDecision(action=build_pytorch_action), + test_pytorch=JobGroupDecision(action=build_pytorch_action), ) @@ -952,11 +962,24 @@ def _expand_build_config_for_platform( return None family_names = [f["amdgpu_family"] for f in per_family_info] + dist_amdgpu_families = ";".join(family_names) suffix = variant_config.get("build_variant_suffix", "") # Select build runner using weighted distribution build_runs_on = select_build_runner(platform, build_variant) + pytorch_build_matrix: list[dict[str, str]] = [] + build_pytorch = jobs.build_pytorch.action == JobAction.RUN + if build_pytorch: + pytorch_build_matrix = generate_pytorch_matrix_for_release_type( + release_type=ci_inputs.release_type, + amdgpu_families=dist_amdgpu_families, + platform=platform, + python_versions=ci_inputs.python_versions or None, + ) + # Flip back to False if the generated matrix is empty. + build_pytorch = bool(pytorch_build_matrix) + test_python_packages_matrix = build_rocm_python_test_matrix( per_family_info=per_family_info, platform=platform, @@ -967,13 +990,14 @@ def _expand_build_config_for_platform( return BuildConfig( per_family_info=per_family_info, - dist_amdgpu_families=";".join(family_names), + dist_amdgpu_families=dist_amdgpu_families, artifact_group=f"multi-arch-{suffix or 'release'}", build_variant_label=variant_config["build_variant_label"], build_variant_suffix=suffix, build_variant_cmake_preset=variant_config["build_variant_cmake_preset"], build_native_linux=(suffix != "asan"), - build_pytorch=(suffix != "asan"), + build_pytorch=build_pytorch, + pytorch_build_matrix=pytorch_build_matrix, build_runs_on=build_runs_on, test_python_packages_matrix=test_python_packages_matrix, prebuilt_stages=jobs.build_rocm.prebuilt_stages, diff --git a/build_tools/github_actions/configure_multi_arch_ci_summary.py b/build_tools/github_actions/configure_multi_arch_ci_summary.py index eb714ba117c..ba3858b99c3 100644 --- a/build_tools/github_actions/configure_multi_arch_ci_summary.py +++ b/build_tools/github_actions/configure_multi_arch_ci_summary.py @@ -68,6 +68,10 @@ def format_summary( lines.append("") _append_test_rocm(lines, outputs) + lines.append("### build-pytorch") + lines.append("") + _append_build_pytorch(lines, outputs) + return "\n".join(lines) @@ -199,6 +203,32 @@ def _append_build_rocm( ) +def _append_build_pytorch(lines: list[str], outputs: CIOutputs) -> None: + lines.append("| Platform | Python | PyTorch ref | Families |") + lines.append("|----------|--------|-------------|----------|") + + rows = 0 + for platform, config in [ + ("Linux", outputs.builds.linux), + ("Windows", outputs.builds.windows), + ]: + if config is None: + continue + for row in config.pytorch_build_matrix: + families = ", ".join( + f"`{family}`" for family in row["amdgpu_families"].split(";") + ) + lines.append( + f"| {platform} | `{row['python_version']}` | " + f"`{row['pytorch_git_ref']}` | {families} |" + ) + rows += 1 + + if rows == 0: + lines.append("| — | — | — | — |") + lines.append("") + + def _append_test_rocm(lines: list[str], outputs: CIOutputs) -> None: # Note: this assumes that the test_rocm job is never skipped. # We may decide to skip it under certain conditions in the future diff --git a/build_tools/github_actions/configure_pytorch_release_matrix.py b/build_tools/github_actions/configure_pytorch_release_matrix.py index 0bb1c05b80e..04f04630778 100644 --- a/build_tools/github_actions/configure_pytorch_release_matrix.py +++ b/build_tools/github_actions/configure_pytorch_release_matrix.py @@ -2,7 +2,7 @@ # Copyright Advanced Micro Devices, Inc. # SPDX-License-Identifier: MIT -"""Generate PyTorch release build matrix for workflows.""" +"""Generate PyTorch build matrices for CI and release workflows.""" import argparse import json @@ -15,93 +15,154 @@ from github_actions.github_actions_api import gha_set_output -PYTHON_VERSIONS = ["3.10", "3.11", "3.12", "3.13", "3.14"] - -# PyTorch git refs per platform. -# Each ref may optionally carry an `exclude_amdgpu_families` set: GPU families -# that should be omitted for this ref (e.g. because upstream support is not yet -# merged). When `exclude_amdgpu_families` is absent the ref inherits whatever -# families are passed in via --amdgpu-families. -# -# Format: list of dicts with keys: -# pytorch_git_ref – git branch/tag passed to the build job -# exclude_amdgpu_families – (optional) set[str] of family names to drop - -PYTORCH_REFS_LINUX: list[dict] = [ - { - "pytorch_git_ref": "release/2.9", +RELEASE_TYPES = ["ci", "dev", "nightly", "prerelease"] + +# TODO: add opt-ins for CI runs to use python versions and pytorch refs normally +# only included in release runs + +RELEASE_PYTHON_VERSIONS = ["3.10", "3.11", "3.12", "3.13", "3.14"] +CI_PYTHON_VERSIONS = { + "linux": ["3.12"], + "windows": ["3.12"], +} + +# TODO: separate out "nightly" pytorch refs from "prerelease" pytorch refs? +# That would let us: +# 1. choose to not build the "nightly" pytorch branch for prerelease builds, +# saving some CI resources and possibly simplifying package promotion +# scripts. +# 2. filter out some AMDGPU families from prereleases if we only want them +# built for nightly but not published to stable. +RELEASE_PYTORCH_REFS = { + "linux": [ + "release/2.9", + "release/2.10", + "release/2.11", + "release/2.12", + "nightly", + ], + "windows": [ + "release/2.9", + "release/2.10", + "release/2.11", + "release/2.12", + "nightly", + ], +} + +CI_PYTORCH_REFS = { + "linux": ["release/2.10", "release/2.11", "release/2.12"], + "windows": ["release/2.10"], +} + +# Unknown explicit refs are left unfiltered so bring-up branches can opt into +# new GPU families before the default PyTorch refs support them. +UNSUPPORTED_AMDGPU_FAMILIES = { + "linux": { # gfx125x not supported for PyTorch 2.9. - "exclude_amdgpu_families": {"gfx125x"}, - }, - { - "pytorch_git_ref": "release/2.10", + "release/2.9": {"gfx125X-dcgpu"}, # gfx125x not supported for PyTorch 2.10. - "exclude_amdgpu_families": {"gfx125x"}, - }, - { - "pytorch_git_ref": "release/2.11", - # gfx125x upstreamed via https://github.com/ROCm/pytorch/pull/3346. - }, - { - "pytorch_git_ref": "release/2.12", + "release/2.10": {"gfx125X-dcgpu"}, + # gfx125x supported for PyTorch 2.11 via https://github.com/ROCm/pytorch/pull/3346. + "release/2.11": {}, # gfx125x not yet upstreamed to pytorch/pytorch. Upstream expected # 2026-06-26, but the ROCm 7.14 release is cut before that date. # See https://github.com/ROCm/TheRock/issues/5833. - "exclude_amdgpu_families": {"gfx125x"}, - }, - { - "pytorch_git_ref": "nightly", + "release/2.12": {"gfx125X-dcgpu"}, # gfx125x not yet upstreamed to pytorch/pytorch. # See https://github.com/ROCm/TheRock/issues/5833. - "exclude_amdgpu_families": {"gfx125x"}, + "nightly": {"gfx125X-dcgpu"}, }, -] + "windows": {}, +} -# gfx125x is Linux-only; no exclusion needed for Windows. -PYTORCH_REFS_WINDOWS: list[dict] = [ - {"pytorch_git_ref": "release/2.9"}, - {"pytorch_git_ref": "release/2.10"}, - {"pytorch_git_ref": "release/2.11"}, - {"pytorch_git_ref": "release/2.12"}, - {"pytorch_git_ref": "nightly"}, -] +def _split_values(raw: str) -> list[str]: + """Split comma, semicolon, or whitespace-separated workflow input values.""" + return [ + value.strip() + for value in raw.replace(",", " ").replace(";", " ").split() + if value.strip() + ] -def _filter_families(families_str: str, exclude: set[str]) -> str: - """Remove excluded family names from a semicolon-separated families string. - Family names are matched case-insensitively against the exclude set so that - e.g. ``gfx125x`` matches ``gfx125X-dcgpu`` style entries. - """ +def _split_families(raw: str) -> list[str]: + return [family.strip() for family in raw.split(";") if family.strip()] + + +def _default_python_versions(*, release_type: str, platform: str) -> list[str]: + if release_type == "ci": + return list(CI_PYTHON_VERSIONS[platform]) + return list(RELEASE_PYTHON_VERSIONS) + + +def _default_pytorch_git_refs(*, release_type: str, platform: str) -> list[str]: + if release_type == "ci": + return list(CI_PYTORCH_REFS[platform]) + return list(RELEASE_PYTORCH_REFS[platform]) + + +def _filter_families(families_str: str, exclude: set[str]) -> str: + """Remove excluded canonical family names from a semicolon-separated list.""" if not exclude: - return families_str - result = [] - for fam in families_str.split(";"): - fam = fam.strip() - if not fam: - continue - # Match by checking whether any excluded name is a case-insensitive - # prefix/substring of the family token (e.g. "gfx125x" in "gfx125X-dcgpu"). - skip = any(exc.lower() in fam.lower() for exc in exclude) - if not skip: - result.append(fam) - return ";".join(result) - - -def generate_pytorch_matrix( - python_versions: list[str] | None, + return ";".join(_split_families(families_str)) + + exclude_lower = {family.lower() for family in exclude} + return ";".join( + family + for family in _split_families(families_str) + if family.lower() not in exclude_lower + ) + + +def generate_pytorch_matrix_for_release_type( + *, + release_type: str, amdgpu_families: str, - platform: str = "linux", -) -> list[dict]: - versions = python_versions if python_versions else PYTHON_VERSIONS - pytorch_refs = PYTORCH_REFS_WINDOWS if platform == "windows" else PYTORCH_REFS_LINUX - matrix = [] + platform: str, + python_versions: list[str] | None = None, + pytorch_git_refs: list[str] | None = None, +) -> list[dict[str, str]]: + if release_type not in RELEASE_TYPES: + raise ValueError(f"Unknown release_type: {release_type!r}") + if platform not in ["linux", "windows"]: + raise ValueError(f"Unknown platform: {platform!r}") + + versions = python_versions or _default_python_versions( + release_type=release_type, platform=platform + ) + refs = pytorch_git_refs or _default_pytorch_git_refs( + release_type=release_type, platform=platform + ) + + # Build one matrix row per requested Python version and PyTorch ref. Each + # row carries the AMDGPU families that the child build workflow should use + # for that ref after filtering out families that are not supported yet. + # + # Example Linux output for release_type="dev" and + # amdgpu_families="gfx94X-dcgpu;gfx125X-dcgpu": + # + # [ + # { + # "python_version": "3.10", + # "pytorch_git_ref": "release/2.9", + # "amdgpu_families": "gfx94X-dcgpu" + # }, + # ... + # { + # "python_version": "3.14", + # "pytorch_git_ref": "nightly", + # "amdgpu_families": "gfx94X-dcgpu" + # } + # ] + matrix: list[dict[str, str]] = [] for py in versions: - for ref_cfg in pytorch_refs: - ref = ref_cfg["pytorch_git_ref"] - exclude = ref_cfg.get("exclude_amdgpu_families", set()) + for ref in refs: + exclude = UNSUPPORTED_AMDGPU_FAMILIES[platform].get(ref, set()) families = _filter_families(amdgpu_families, exclude) - row: dict = { + if not families: + continue + row: dict[str, str] = { "python_version": py, "pytorch_git_ref": ref, "amdgpu_families": families, @@ -118,7 +179,19 @@ def main(argv: list[str] | None = None) -> int: "--python-versions", type=str, default="", - help="Comma or semicolon separated list of Python versions (default: all)", + help=( + "Comma, semicolon, or whitespace separated list of Python versions " + "(default depends on --release-type)" + ), + ) + parser.add_argument( + "--pytorch-git-refs", + type=str, + default="", + help=( + "Comma, semicolon, or whitespace separated list of PyTorch refs " + "(default depends on --release-type and --platform)" + ), ) parser.add_argument( "--platform", @@ -127,6 +200,13 @@ def main(argv: list[str] | None = None) -> int: choices=["linux", "windows"], help="Platform to generate matrix for (default: current system)", ) + parser.add_argument( + "--release-type", + type=str, + default="dev", + choices=RELEASE_TYPES, + help="Release type selecting default PyTorch/Python matrix (default: dev)", + ) parser.add_argument( "--amdgpu-families", type=str, @@ -139,15 +219,15 @@ def main(argv: list[str] | None = None) -> int: ) args = parser.parse_args(argv) - python_versions = None - if args.python_versions: - sep = ";" if ";" in args.python_versions else "," - python_versions = [ - v.strip() for v in args.python_versions.split(sep) if v.strip() - ] + python_versions = _split_values(args.python_versions) or None + pytorch_git_refs = _split_values(args.pytorch_git_refs) or None - matrix = generate_pytorch_matrix( - python_versions, args.amdgpu_families, args.platform + matrix = generate_pytorch_matrix_for_release_type( + release_type=args.release_type, + python_versions=python_versions, + pytorch_git_refs=pytorch_git_refs, + amdgpu_families=args.amdgpu_families, + platform=args.platform, ) gha_set_output({"pytorch_matrix": json.dumps(matrix)}) return 0 diff --git a/build_tools/github_actions/tests/configure_multi_arch_ci_test.py b/build_tools/github_actions/tests/configure_multi_arch_ci_test.py index 72789f5557b..1217adce3a4 100644 --- a/build_tools/github_actions/tests/configure_multi_arch_ci_test.py +++ b/build_tools/github_actions/tests/configure_multi_arch_ci_test.py @@ -158,12 +158,16 @@ def test_workflow_dispatch_reads_inputs_from_env(self): "WINDOWS_TEST_LABELS": "", "PREBUILT_STAGES": "compiler-runtime,runtime-tests", "BASELINE_RUN_ID": "12345", + "BUILD_PYTORCH": "false", + "PYTHON_VERSION": "3.12", }, ) self.assertEqual(inputs.linux_amdgpu_families, ["gfx94x", "gfx120x"]) self.assertEqual(inputs.linux_test_labels, ["test:rocprim"]) self.assertEqual(inputs.prebuilt_stages, "compiler-runtime,runtime-tests") self.assertEqual(inputs.baseline_run_id, "12345") + self.assertFalse(inputs.build_pytorch) + self.assertEqual(inputs.python_versions, ["3.12"]) def test_pull_request_extracts_labels(self): """PR labels are extracted from event.pull_request.labels.""" @@ -333,6 +337,15 @@ def test_all_job_groups_run(self): self.assertEqual(result.build_pytorch.action, cm.JobAction.RUN) self.assertEqual(result.test_pytorch.action, cm.JobAction.RUN) + def test_build_pytorch_input_skips_pytorch_jobs(self): + result = cm.decide_jobs( + self._inputs(build_pytorch=False), + git_context=cm.GitContext(), + ) + + self.assertEqual(result.build_pytorch.action, cm.JobAction.SKIP) + self.assertEqual(result.test_pytorch.action, cm.JobAction.SKIP) + def test_default_test_type_is_quick(self): """Default test_type for PR/push with no special conditions.""" git = cm.GitContext(changed_files=["CMakeLists.txt"]) @@ -963,6 +976,106 @@ def test_build_config_includes_python_package_test_matrix(self): ], ) + def test_build_config_includes_pytorch_build_matrix(self): + targets = cm.TargetSelection( + linux_families=["gfx94x"], + windows_families=["gfx110x"], + ) + result = cm.expand_build_configs( + ci_inputs=self._inputs(), + git_context=cm.GitContext(), + targets=targets, + jobs=_jobs(), + ) + + self.assertEqual( + result.linux.pytorch_build_matrix, + [ + { + "python_version": "3.12", + "pytorch_git_ref": "release/2.10", + "amdgpu_families": "gfx94X-dcgpu", + }, + { + "python_version": "3.12", + "pytorch_git_ref": "release/2.11", + "amdgpu_families": "gfx94X-dcgpu", + }, + { + "python_version": "3.12", + "pytorch_git_ref": "release/2.12", + "amdgpu_families": "gfx94X-dcgpu", + }, + ], + ) + self.assertEqual( + result.windows.pytorch_build_matrix, + [ + { + "python_version": "3.12", + "pytorch_git_ref": "release/2.10", + "amdgpu_families": "gfx110X-all", + } + ], + ) + + def test_build_config_uses_requested_pytorch_python_versions(self): + targets = cm.TargetSelection( + linux_families=["gfx94x"], + windows_families=[], + ) + result = cm.expand_build_configs( + ci_inputs=self._inputs( + release_type="dev", + python_versions=["3.13"], + ), + git_context=cm.GitContext(), + targets=targets, + jobs=_jobs(), + ) + + self.assertEqual( + {row["python_version"] for row in result.linux.pytorch_build_matrix}, + {"3.13"}, + ) + + def test_build_config_disables_pytorch_when_job_skipped(self): + targets = cm.TargetSelection( + linux_families=["gfx94x"], + windows_families=[], + ) + result = cm.expand_build_configs( + ci_inputs=self._inputs(), + git_context=cm.GitContext(), + targets=targets, + jobs=_jobs(build_pytorch=False), + ) + + self.assertFalse(result.linux.build_pytorch) + self.assertEqual(result.linux.pytorch_build_matrix, []) + + def test_build_config_disables_pytorch_when_matrix_is_empty(self): + targets = cm.TargetSelection( + linux_families=["gfx94x"], + windows_families=[], + ) + # If the pytorch matrix is empty for some reason (such as only + # trying to build one GPU target for a pytorch version where that + # GPU target is unsupported), the build_pytorch result should be false. + with patch( + "configure_multi_arch_ci.generate_pytorch_matrix_for_release_type", + return_value=[], + ): + result = cm.expand_build_configs( + ci_inputs=self._inputs(), + git_context=cm.GitContext(), + targets=targets, + jobs=_jobs(), + ) + + self.assertFalse(result.linux.build_pytorch) + self.assertEqual(result.linux.pytorch_build_matrix, []) + def test_variant_filters_by_platform_and_family_support(self): """ASAN: only gfx94x on linux supports it, gfx110x doesn't, windows has no ASAN config.""" # gfx94x supports asan, gfx110x is release-only, windows has no asan variant. diff --git a/build_tools/github_actions/tests/configure_pytorch_release_matrix_test.py b/build_tools/github_actions/tests/configure_pytorch_release_matrix_test.py new file mode 100644 index 00000000000..4cdf11cb476 --- /dev/null +++ b/build_tools/github_actions/tests/configure_pytorch_release_matrix_test.py @@ -0,0 +1,124 @@ +# Copyright Advanced Micro Devices, Inc. +# SPDX-License-Identifier: MIT + +import os +import sys +import unittest +from pathlib import Path + +sys.path.insert(0, os.fspath(Path(__file__).parent.parent)) + +import configure_pytorch_release_matrix as m + + +class ConfigurePytorchReleaseMatrixTest(unittest.TestCase): + def test_ci_linux_uses_reduced_matrix(self): + matrix = m.generate_pytorch_matrix_for_release_type( + release_type="ci", + amdgpu_families="gfx94X-dcgpu", + platform="linux", + ) + + # Compared to releases: + # * limited to python 3.12 + # * not including "nightly" pytorch_git_ref + self.assertEqual( + matrix, + [ + { + "python_version": "3.12", + "pytorch_git_ref": "release/2.10", + "amdgpu_families": "gfx94X-dcgpu", + }, + { + "python_version": "3.12", + "pytorch_git_ref": "release/2.11", + "amdgpu_families": "gfx94X-dcgpu", + }, + { + "python_version": "3.12", + "pytorch_git_ref": "release/2.12", + "amdgpu_families": "gfx94X-dcgpu", + }, + ], + ) + + def test_ci_windows_uses_reduced_matrix(self): + matrix = m.generate_pytorch_matrix_for_release_type( + release_type="ci", + amdgpu_families="gfx110X-all", + platform="windows", + ) + + # Compared to releases: + # * limited to python 3.12 + # Compared to Linux: + # * limited to only a single pytorch_git_ref + self.assertEqual( + matrix, + [ + { + "python_version": "3.12", + "pytorch_git_ref": "release/2.10", + "amdgpu_families": "gfx110X-all", + }, + ], + ) + + def test_explicit_versions_and_refs_narrow_matrix(self): + matrix = m.generate_pytorch_matrix_for_release_type( + release_type="nightly", + python_versions=["3.13"], + pytorch_git_refs=["nightly"], + amdgpu_families="gfx94X-dcgpu", + platform="linux", + ) + + self.assertEqual( + matrix, + [ + { + "python_version": "3.13", + "pytorch_git_ref": "nightly", + "amdgpu_families": "gfx94X-dcgpu", + } + ], + ) + + def test_filters_exact_unsupported_family(self): + matrix = m.generate_pytorch_matrix_for_release_type( + release_type="dev", + python_versions=["3.12"], + pytorch_git_refs=["release/2.10"], + amdgpu_families="gfx94X-dcgpu;gfx125X-dcgpu", + platform="linux", + ) + + # gfx125X-dcgpu not supported on the release/2.10 ref, should filter + self.assertEqual(matrix[0]["amdgpu_families"], "gfx94X-dcgpu") + matrix_families = ";".join(row["amdgpu_families"] for row in matrix) + self.assertNotIn("gfx125X", matrix_families) + + def test_unknown_explicit_ref_keeps_families(self): + matrix = m.generate_pytorch_matrix_for_release_type( + release_type="dev", + python_versions=["3.12"], + pytorch_git_refs=["users/alice/gfx125x-bringup"], + amdgpu_families="gfx125X-dcgpu", + platform="linux", + ) + + self.assertEqual( + matrix, + [ + { + "python_version": "3.12", + "pytorch_git_ref": "users/alice/gfx125x-bringup", + "amdgpu_families": "gfx125X-dcgpu", + } + ], + ) + + +if __name__ == "__main__": + unittest.main()