diff --git a/.github/actions/rocprofiler-sdk-util/action.yml b/.github/actions/rocprofiler-sdk-util/action.yml index a34f2b51ea44..7dd1e0a8bf64 100644 --- a/.github/actions/rocprofiler-sdk-util/action.yml +++ b/.github/actions/rocprofiler-sdk-util/action.yml @@ -6,6 +6,10 @@ inputs: description: 'Path to ROCm installation' required: false default: '/opt/rocm' + python-venv-path: + description: 'Python virtual environment with the pinned cmake, relative to the workspace' + required: false + default: '' gpu-target: description: 'GPU target (e.g., gfx94X, gfx110X, gfx120X)' required: true @@ -37,6 +41,10 @@ inputs: description: 'Enable ROCJPEG build' required: false default: 'false' + enable-hipfile-build: + description: 'Enable hipFILE build' + required: false + default: 'false' enable-rocprof-trace-decoder-build: description: 'Enable rocprof-trace-decoder build' required: false @@ -70,13 +78,6 @@ inputs: runs: using: 'composite' steps: - - name: Setup environment variables - shell: bash - run: | - echo "PKG_CONFIG_PATH=/opt/amdgpu/lib64/pkgconfig:/opt/amdgpu/lib/pkgconfig:/opt/amdgpu/lib/$(uname -p)-linux-gnu/pkgconfig:${PKG_CONFIG_PATH}" >> $GITHUB_ENV - echo "LD_LIBRARY_PATH=${{ inputs.rocm-path }}/lib64:${{ inputs.rocm-path }}/lib:${{ inputs.rocm-path }}/llvm/lib:${LD_LIBRARY_PATH}" >> $GITHUB_ENV - echo "PATH=${{ inputs.rocm-path }}/bin:${{ inputs.rocm-path }}/llvm/bin:$HOME/.local/bin:${PATH}" >> $GITHUB_ENV - - name: Setup ccache if: ${{ inputs.enable-ccache == 'true' }} uses: hendrikmuhs/ccache-action@63069e3931dedbf3b63792097479563182fe70d1 # v1.2.18 @@ -98,6 +99,16 @@ runs: echo "Warning: Compiler launcher ${{ inputs.compiler-launcher }} not found or not executable" fi + - name: Setup environment variables + shell: bash + run: | + if [ -n "${{ inputs.python-venv-path }}" ]; then + echo "${GITHUB_WORKSPACE}/${{ inputs.python-venv-path }}/bin" >> $GITHUB_PATH + fi + echo "PKG_CONFIG_PATH=/opt/amdgpu/lib64/pkgconfig:/opt/amdgpu/lib/pkgconfig:/opt/amdgpu/lib/$(uname -p)-linux-gnu/pkgconfig:${PKG_CONFIG_PATH}" >> $GITHUB_ENV + echo "LD_LIBRARY_PATH=${{ inputs.rocm-path }}/lib64:${{ inputs.rocm-path }}/lib:${{ inputs.rocm-path }}/llvm/lib:${LD_LIBRARY_PATH}" >> $GITHUB_ENV + echo "PATH=${{ inputs.rocm-path }}/bin:${{ inputs.rocm-path }}/llvm/bin:$HOME/.local/bin:${PATH}" >> $GITHUB_ENV + - name: Build and Install ROCR-Runtime if: ${{ inputs.enable-rocr-build == 'true' }} shell: bash @@ -149,7 +160,7 @@ runs: shell: bash working-directory: projects/rocprofiler-register run: | - export PATH=${{ inputs.rocm-path }}/bin:${{ inputs.rocm-path }}/llvm/bin:/usr/local/bin:~/.local/bin:$PATH + export PATH=${{ inputs.rocm-path }}/bin:${{ inputs.rocm-path }}/llvm/bin:${PATH}:/usr/local/bin echo "Install ROCProfiler-Register" cmake -B build-rocprofiler-register \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ @@ -163,6 +174,40 @@ runs: cmake --build build-rocprofiler-register --target install echo "✅ ROCProfiler-Register Installation complete!" + - name: Build and Install hipFILE + if: ${{ inputs.enable-hipfile-build == 'true' }} + shell: bash + working-directory: projects/hipfile + run: | + export ROCM_PATH=${{ inputs.rocm-path }} + export HIP_PLATFORM=amd + export LD_LIBRARY_PATH=${{ inputs.rocm-path }}/lib:${{ inputs.rocm-path }}/lib/rocm_sysdeps/lib:${{ inputs.rocm-path }}/llvm/lib:$LD_LIBRARY_PATH + export PATH=${{ inputs.rocm-path }}/bin:${{ inputs.rocm-path }}/llvm/bin:${PATH}:/usr/local/bin + # Temporary workaround until hipFILE adds the ROCm sysdeps include path for libmount. + if [ -f "${ROCM_PATH}/lib/rocm_sysdeps/include/libmount/libmount.h" ]; then + install -D -m 0644 \ + "${ROCM_PATH}/lib/rocm_sysdeps/include/libmount/libmount.h" \ + "${ROCM_PATH}/include/libmount/libmount.h" + fi + echo "Install hipFILE..." + cmake -B build-hipfile \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DCMAKE_CXX_COMPILER=${{ inputs.rocm-path }}/llvm/bin/amdclang++ \ + -DCMAKE_HIP_PLATFORM=amd \ + -DCMAKE_PREFIX_PATH='${{ inputs.rocm-path }};${{ inputs.rocm-path }}/llvm;${{ inputs.rocm-path }}/lib/rocm_sysdeps' \ + -DCMAKE_LIBRARY_PATH=${{ inputs.rocm-path }}/lib/rocm_sysdeps/lib \ + -DCMAKE_INCLUDE_PATH=${{ inputs.rocm-path }}/lib/rocm_sysdeps/include \ + -DCMAKE_INSTALL_PREFIX=${{ inputs.rocm-path }} \ + -DCMAKE_C_COMPILER_LAUNCHER=${{ inputs.compiler-launcher }} \ + -DCMAKE_CXX_COMPILER_LAUNCHER=${{ inputs.compiler-launcher }} \ + -DBUILD_TESTING=OFF \ + -DAIS_INSTALL_EXAMPLES=OFF \ + -DAIS_INSTALL_TOOLS=OFF \ + . + cmake --build build-hipfile --target hipfile --parallel ${{ inputs.build-jobs }} + cmake --build build-hipfile --target install + echo "✅ hipFILE Installation complete!" + - name: Build and Install Aqlprofile if: ${{ inputs.enable-aqlprofile-build == 'true' }} shell: bash diff --git a/.github/actions/rocprofiler-sdk-util/resolve-ci-config/action.yml b/.github/actions/rocprofiler-sdk-util/resolve-ci-config/action.yml index 6060d1560c7b..a5a878ceed99 100644 --- a/.github/actions/rocprofiler-sdk-util/resolve-ci-config/action.yml +++ b/.github/actions/rocprofiler-sdk-util/resolve-ci-config/action.yml @@ -1,5 +1,5 @@ name: Resolve CI config -description: Resolve runner labels from ROCm/therock-ci-config +description: Resolve build and GPU runner labels from ROCm/therock-ci-config inputs: config-path: @@ -14,14 +14,63 @@ inputs: description: Sandbox runner label to use if the shared CI config cannot be loaded required: false default: linux-mi325-gpu-rocm-cpu-sandbox + fallback-gfx950-runner: + description: Runner label for gfx950 if the shared CI config cannot be loaded + required: false + default: linux-gfx950-1gpu-ccs-ossci-rocm + fallback-gfx90a-runner: + description: Runner label for gfx90a if the shared CI config cannot be loaded + required: false + default: linux-gfx90a-gpu-rocm + fallback-gfx103x-runner: + description: Runner label for gfx103x if the shared CI config cannot be loaded + required: false + default: linux-gfx1030-gpu-rocm + fallback-gfx110x-runner: + description: Runner label for gfx110x if the shared CI config cannot be loaded + required: false + default: linux-gfx110X-gpu-rocm + fallback-gfx120x-runner: + description: Runner label for gfx120x if the shared CI config cannot be loaded + required: false + default: linux-gfx120X-gpu-rocm + fallback-gfx1151-runner: + description: Runner label for gfx1151 if the shared CI config cannot be loaded + required: false + default: linux-gfx1151-gpu-rocm + fallback-linux-build-runner: + description: Linux build runner label if the shared CI config cannot be loaded + required: false + default: aws-linux-scale-rocm-prod outputs: + linux_build_runner: + description: Linux CPU build runner label + value: ${{ steps.runner.outputs.linux_build_runner }} + gfx90a_runner: + description: Linux gfx90a test runner label + value: ${{ steps.runner.outputs.gfx90a_runner }} gfx94x_runner: description: Linux gfx94x test runner label value: ${{ steps.runner.outputs.gfx94x_runner }} gfx94x_sandbox_runner: description: Linux gfx94x sandbox test runner label value: ${{ steps.runner.outputs.gfx94x_sandbox_runner }} + gfx950_runner: + description: Linux gfx950 test runner label + value: ${{ steps.runner.outputs.gfx950_runner }} + gfx103x_runner: + description: Linux gfx103x (Navi 2x) test runner label + value: ${{ steps.runner.outputs.gfx103x_runner }} + gfx110x_runner: + description: Linux gfx110x (Navi 3x) test runner label + value: ${{ steps.runner.outputs.gfx110x_runner }} + gfx120x_runner: + description: Linux gfx120x (Navi 4x) test runner label + value: ${{ steps.runner.outputs.gfx120x_runner }} + gfx1151_runner: + description: Linux gfx1151 test runner label + value: ${{ steps.runner.outputs.gfx1151_runner }} runs: using: composite @@ -41,4 +90,11 @@ runs: CI_CONFIG_PATH: ${{ inputs.config-path }} FALLBACK_GFX94X_RUNNER: ${{ inputs.fallback-gfx94x-runner }} FALLBACK_GFX94X_SANDBOX_RUNNER: ${{ inputs.fallback-gfx94x-sandbox-runner }} + FALLBACK_GFX950_RUNNER: ${{ inputs.fallback-gfx950-runner }} + FALLBACK_GFX90A_RUNNER: ${{ inputs.fallback-gfx90a-runner }} + FALLBACK_GFX103X_RUNNER: ${{ inputs.fallback-gfx103x-runner }} + FALLBACK_GFX110X_RUNNER: ${{ inputs.fallback-gfx110x-runner }} + FALLBACK_GFX120X_RUNNER: ${{ inputs.fallback-gfx120x-runner }} + FALLBACK_GFX1151_RUNNER: ${{ inputs.fallback-gfx1151-runner }} + FALLBACK_LINUX_BUILD_RUNNER: ${{ inputs.fallback-linux-build-runner }} run: python3 "${GITHUB_ACTION_PATH}/resolve_ci_config.py" diff --git a/.github/actions/rocprofiler-sdk-util/resolve-ci-config/resolve_ci_config.py b/.github/actions/rocprofiler-sdk-util/resolve-ci-config/resolve_ci_config.py index 2247dd81a99d..4dba6c129615 100644 --- a/.github/actions/rocprofiler-sdk-util/resolve-ci-config/resolve_ci_config.py +++ b/.github/actions/rocprofiler-sdk-util/resolve-ci-config/resolve_ci_config.py @@ -7,29 +7,58 @@ from pathlib import Path from typing import Any +GPU_FAMILIES = [ + "gfx94x", + "gfx950", + "gfx90a", + "gfx103x", + "gfx110x", + "gfx120x", + "gfx1151", +] +TRIGGER_TYPES = ["presubmit", "postsubmit", "nightly"] + def warn(message: str) -> None: print(f"::warning::{message}") -def load_gfx94x_linux_config(config_path: Path) -> dict[str, Any]: +def load_ci_configs( + config_path: Path, +) -> tuple[dict[str, dict[str, Any]], dict[str, Any]]: if not config_path.exists(): warn("CI config checkout missing. Using fallback runner labels.") - return {} + return {}, {} sys.path.insert(0, str(config_path)) try: from ci_config_api import load_config_v1 config = load_config_v1(config_path) - return ( - config.get_gpu_families(["presubmit"]) - .get("gfx94x", {}) - .get("linux", {}) - ) + all_families = config.get_gpu_families(TRIGGER_TYPES) + gpu_configs = { + family: all_families.get(family, {}).get("linux", {}) + for family in GPU_FAMILIES + } + return gpu_configs, config.build_runners except Exception as exc: warn(f"Failed to load CI config: {exc}. Using fallback runner labels.") - return {} + return {}, {} + + +def load_gpu_configs(config_path: Path) -> dict[str, dict[str, Any]]: + return load_ci_configs(config_path)[0] + + +def get_linux_build_runner(build_runners: dict[str, Any], fallback: str) -> str: + return next( + ( + runner["label"] + for runner in build_runners.get("linux", {}).get("default", []) + if runner.get("label") and runner.get("weight", 0) > 0 + ), + fallback, + ) def set_outputs(outputs: dict[str, str]) -> None: @@ -40,23 +69,32 @@ def set_outputs(outputs: dict[str, str]) -> None: def main() -> None: config_path = Path(os.environ["CI_CONFIG_PATH"]) - fallback_runner = os.environ["FALLBACK_GFX94X_RUNNER"] - fallback_sandbox_runner = os.environ["FALLBACK_GFX94X_SANDBOX_RUNNER"] + gpu_configs, build_runners = load_ci_configs(config_path) - gfx94x_linux_config = load_gfx94x_linux_config(config_path) - runner = gfx94x_linux_config.get("test-runs-on") or fallback_runner - sandbox_runner = ( - gfx94x_linux_config.get("test-runs-on-sandbox") or fallback_sandbox_runner + outputs: dict[str, str] = {} + fallback_linux_build_runner = os.environ.get("FALLBACK_LINUX_BUILD_RUNNER", "") + linux_build_runner = get_linux_build_runner( + build_runners, fallback_linux_build_runner ) - - print(f"Using gfx94x runner: {runner}") + outputs["linux_build_runner"] = linux_build_runner + print(f"Using Linux build runner: {linux_build_runner}") + + for family in GPU_FAMILIES: + linux_config = gpu_configs.get(family, {}) + fallback_env = f"FALLBACK_{family.upper()}_RUNNER" + fallback = os.environ.get(fallback_env, "") + + runner = linux_config.get("test-runs-on") or fallback + outputs[f"{family}_runner"] = runner + print(f"Using {family} runner: {runner}") + + fallback_sandbox = os.environ.get("FALLBACK_GFX94X_SANDBOX_RUNNER", "") + gfx94x_config = gpu_configs.get("gfx94x", {}) + sandbox_runner = gfx94x_config.get("test-runs-on-sandbox") or fallback_sandbox + outputs["gfx94x_sandbox_runner"] = sandbox_runner print(f"Using gfx94x sandbox runner: {sandbox_runner}") - set_outputs( - { - "gfx94x_runner": runner, - "gfx94x_sandbox_runner": sandbox_runner, - } - ) + + set_outputs(outputs) if __name__ == "__main__": diff --git a/.github/actions/rocprofiler-sdk-util/resolve-ci-config/test_resolve_ci_config.py b/.github/actions/rocprofiler-sdk-util/resolve-ci-config/test_resolve_ci_config.py new file mode 100644 index 000000000000..ac4fb1db4808 --- /dev/null +++ b/.github/actions/rocprofiler-sdk-util/resolve-ci-config/test_resolve_ci_config.py @@ -0,0 +1,326 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import json +import os +import tempfile +import textwrap +import unittest +from pathlib import Path +from unittest.mock import patch + +from resolve_ci_config import GPU_FAMILIES, TRIGGER_TYPES, load_gpu_configs, main + +SAMPLE_RUNNER_CONFIG = { + "version": "1", + "build_runners": { + "linux": { + "default": [ + {"label": "disabled-linux-runner", "weight": 0.0}, + {"label": "configured-linux-runner", "weight": 1.0}, + ] + } + }, + "gpu_families": { + "presubmit": { + "gfx94x": { + "linux": { + "test-runs-on": "linux-gfx942-1gpu-ccs-csp-ossci-rocm", + "test-runs-on-sandbox": "linux-mi325-gpu-rocm-cpu-sandbox", + "family": "gfx94X-dcgpu", + "fetch-gfx-targets": ["gfx942"], + } + }, + "gfx110x": { + "linux": { + "test-runs-on": "linux-gfx110X-gpu-rocm", + "family": "gfx110X-all", + "fetch-gfx-targets": [], + } + }, + "gfx120x": { + "linux": { + "test-runs-on": "linux-gfx120X-gpu-rocm", + "family": "gfx120X-all", + "fetch-gfx-targets": ["gfx1200", "gfx1201"], + } + }, + "gfx1151": { + "linux": { + "test-runs-on": "linux-gfx1151-gpu-rocm", + "family": "gfx1151", + "fetch-gfx-targets": ["gfx1151"], + } + }, + }, + "postsubmit": { + "gfx950": { + "linux": { + "test-runs-on": "linux-gfx950-1gpu-ccs-ossci-rocm", + "family": "gfx950-dcgpu", + "fetch-gfx-targets": ["gfx950"], + } + } + }, + "nightly": { + "gfx90a": { + "linux": { + "test-runs-on": "linux-gfx90a-gpu-rocm", + "family": "gfx90a", + "fetch-gfx-targets": ["gfx90a"], + } + }, + "gfx103x": { + "linux": { + "test-runs-on": "linux-gfx1030-gpu-rocm", + "family": "gfx103X-all", + "fetch-gfx-targets": ["gfx1030"], + } + }, + }, + }, +} + + +def _write_config(tmpdir: Path, config: dict) -> None: + (tmpdir / "runner-config.json").write_text(json.dumps(config)) + ci_api = textwrap.dedent("""\ + import json + from pathlib import Path + from dataclasses import dataclass + from typing import Any + + @dataclass + class ConfigV1: + build_runners: dict + gpu_families: dict + _raw: dict + def get_gpu_families(self, trigger_types): + result = {} + for tt in trigger_types: + if tt in self.gpu_families: + for name, cfg in self.gpu_families[tt].items(): + result[name] = cfg + return result + + def load_config_v1(config_path=None): + if config_path is None: + config_path = Path(__file__).parent + with open(config_path / "runner-config.json") as f: + raw = json.load(f) + return ConfigV1( + build_runners=raw["build_runners"], + gpu_families=raw["gpu_families"], + _raw=raw, + ) + """) + (tmpdir / "ci_config_api.py").write_text(ci_api) + + +class TestLoadGpuConfigs(unittest.TestCase): + def test_returns_empty_when_path_missing(self): + result = load_gpu_configs(Path("/nonexistent/path")) + self.assertEqual(result, {}) + + def test_loads_all_families_from_config(self): + with tempfile.TemporaryDirectory() as tmpdir: + tmpdir = Path(tmpdir) + _write_config(tmpdir, SAMPLE_RUNNER_CONFIG) + result = load_gpu_configs(tmpdir) + + self.assertEqual( + result["gfx94x"]["test-runs-on"], + "linux-gfx942-1gpu-ccs-csp-ossci-rocm", + ) + self.assertEqual( + result["gfx950"]["test-runs-on"], + "linux-gfx950-1gpu-ccs-ossci-rocm", + ) + self.assertEqual( + result["gfx90a"]["test-runs-on"], + "linux-gfx90a-gpu-rocm", + ) + self.assertEqual( + result["gfx103x"]["test-runs-on"], + "linux-gfx1030-gpu-rocm", + ) + self.assertEqual( + result["gfx110x"]["test-runs-on"], + "linux-gfx110X-gpu-rocm", + ) + self.assertEqual( + result["gfx120x"]["test-runs-on"], + "linux-gfx120X-gpu-rocm", + ) + self.assertEqual( + result["gfx1151"]["test-runs-on"], + "linux-gfx1151-gpu-rocm", + ) + + def test_missing_family_returns_empty_dict(self): + config = { + "version": "1", + "build_runners": {}, + "gpu_families": { + "presubmit": { + "gfx94x": { + "linux": { + "test-runs-on": "some-runner", + "family": "f", + "fetch-gfx-targets": [], + } + } + } + }, + } + with tempfile.TemporaryDirectory() as tmpdir: + tmpdir = Path(tmpdir) + _write_config(tmpdir, config) + result = load_gpu_configs(tmpdir) + + self.assertEqual(result["gfx94x"]["test-runs-on"], "some-runner") + self.assertEqual(result["gfx950"], {}) + self.assertEqual(result["gfx90a"], {}) + self.assertEqual(result["gfx103x"], {}) + self.assertEqual(result["gfx110x"], {}) + self.assertEqual(result["gfx120x"], {}) + self.assertEqual(result["gfx1151"], {}) + + def test_returns_empty_on_import_error(self): + with tempfile.TemporaryDirectory() as tmpdir: + tmpdir = Path(tmpdir) + (tmpdir / "ci_config_api.py").write_text("raise ImportError('broken')") + (tmpdir / "runner-config.json").write_text("{}") + result = load_gpu_configs(tmpdir) + self.assertEqual(result, {}) + + def test_sandbox_runner_available(self): + with tempfile.TemporaryDirectory() as tmpdir: + tmpdir = Path(tmpdir) + _write_config(tmpdir, SAMPLE_RUNNER_CONFIG) + result = load_gpu_configs(tmpdir) + self.assertEqual( + result["gfx94x"]["test-runs-on-sandbox"], + "linux-mi325-gpu-rocm-cpu-sandbox", + ) + + +class TestMain(unittest.TestCase): + def _run_main(self, config=None, env_overrides=None): + with tempfile.TemporaryDirectory() as tmpdir: + tmpdir = Path(tmpdir) + output_file = tmpdir / "github_output" + output_file.write_text("") + + if config is not None: + config_dir = tmpdir / "ci-config" + config_dir.mkdir() + _write_config(config_dir, config) + else: + config_dir = tmpdir / "no-config" + + env = { + "CI_CONFIG_PATH": str(config_dir), + "GITHUB_OUTPUT": str(output_file), + "FALLBACK_GFX94X_RUNNER": "fallback-gfx94x", + "FALLBACK_GFX94X_SANDBOX_RUNNER": "fallback-gfx94x-sandbox", + "FALLBACK_GFX950_RUNNER": "fallback-gfx950", + "FALLBACK_GFX90A_RUNNER": "fallback-gfx90a", + "FALLBACK_GFX103X_RUNNER": "fallback-gfx103x", + "FALLBACK_GFX110X_RUNNER": "fallback-gfx110x", + "FALLBACK_GFX120X_RUNNER": "fallback-gfx120x", + "FALLBACK_GFX1151_RUNNER": "fallback-gfx1151", + "FALLBACK_LINUX_BUILD_RUNNER": "fallback-linux-runner", + } + if env_overrides: + env.update(env_overrides) + + with patch.dict(os.environ, env, clear=False): + main() + + outputs = {} + for line in output_file.read_text().strip().splitlines(): + key, _, value = line.partition("=") + outputs[key] = value + return outputs + + def test_uses_config_values_when_available(self): + outputs = self._run_main(config=SAMPLE_RUNNER_CONFIG) + + self.assertEqual(outputs["linux_build_runner"], "configured-linux-runner") + self.assertEqual( + outputs["gfx94x_runner"], "linux-gfx942-1gpu-ccs-csp-ossci-rocm" + ) + self.assertEqual(outputs["gfx950_runner"], "linux-gfx950-1gpu-ccs-ossci-rocm") + self.assertEqual(outputs["gfx90a_runner"], "linux-gfx90a-gpu-rocm") + self.assertEqual(outputs["gfx103x_runner"], "linux-gfx1030-gpu-rocm") + self.assertEqual(outputs["gfx110x_runner"], "linux-gfx110X-gpu-rocm") + self.assertEqual(outputs["gfx120x_runner"], "linux-gfx120X-gpu-rocm") + self.assertEqual(outputs["gfx1151_runner"], "linux-gfx1151-gpu-rocm") + self.assertEqual( + outputs["gfx94x_sandbox_runner"], "linux-mi325-gpu-rocm-cpu-sandbox" + ) + + def test_falls_back_to_env_when_config_missing(self): + outputs = self._run_main(config=None) + + self.assertEqual(outputs["linux_build_runner"], "fallback-linux-runner") + self.assertEqual(outputs["gfx94x_runner"], "fallback-gfx94x") + self.assertEqual(outputs["gfx950_runner"], "fallback-gfx950") + self.assertEqual(outputs["gfx90a_runner"], "fallback-gfx90a") + self.assertEqual(outputs["gfx103x_runner"], "fallback-gfx103x") + self.assertEqual(outputs["gfx110x_runner"], "fallback-gfx110x") + self.assertEqual(outputs["gfx120x_runner"], "fallback-gfx120x") + self.assertEqual(outputs["gfx1151_runner"], "fallback-gfx1151") + self.assertEqual(outputs["gfx94x_sandbox_runner"], "fallback-gfx94x-sandbox") + + def test_partial_config_uses_fallback_for_missing_families(self): + partial_config = { + "version": "1", + "build_runners": {}, + "gpu_families": { + "presubmit": { + "gfx94x": { + "linux": { + "test-runs-on": "configured-gfx94x", + "test-runs-on-sandbox": "configured-sandbox", + "family": "f", + "fetch-gfx-targets": [], + } + } + } + }, + } + outputs = self._run_main(config=partial_config) + + self.assertEqual(outputs["linux_build_runner"], "fallback-linux-runner") + self.assertEqual(outputs["gfx94x_runner"], "configured-gfx94x") + self.assertEqual(outputs["gfx94x_sandbox_runner"], "configured-sandbox") + self.assertEqual(outputs["gfx950_runner"], "fallback-gfx950") + self.assertEqual(outputs["gfx90a_runner"], "fallback-gfx90a") + self.assertEqual(outputs["gfx103x_runner"], "fallback-gfx103x") + self.assertEqual(outputs["gfx110x_runner"], "fallback-gfx110x") + self.assertEqual(outputs["gfx120x_runner"], "fallback-gfx120x") + self.assertEqual(outputs["gfx1151_runner"], "fallback-gfx1151") + + def test_all_gpu_families_have_output(self): + outputs = self._run_main(config=SAMPLE_RUNNER_CONFIG) + for family in GPU_FAMILIES: + self.assertIn(f"{family}_runner", outputs, f"Missing output for {family}") + self.assertTrue(outputs[f"{family}_runner"], f"Empty output for {family}") + self.assertIn("gfx94x_sandbox_runner", outputs) + + +class TestConstants(unittest.TestCase): + def test_gpu_families_not_empty(self): + self.assertTrue(len(GPU_FAMILIES) > 0) + + def test_trigger_types_cover_all_scopes(self): + self.assertIn("presubmit", TRIGGER_TYPES) + self.assertIn("postsubmit", TRIGGER_TYPES) + self.assertIn("nightly", TRIGGER_TYPES) + + +if __name__ == "__main__": + unittest.main() diff --git a/.github/workflows/rocprofiler-sdk-code_coverage.yml b/.github/workflows/rocprofiler-sdk-code_coverage.yml index c7f713dfb38a..6f0b1e5b2451 100644 --- a/.github/workflows/rocprofiler-sdk-code_coverage.yml +++ b/.github/workflows/rocprofiler-sdk-code_coverage.yml @@ -10,6 +10,7 @@ on: - develop paths: - 'projects/rocprofiler-sdk/**' + - '.github/actions/rocprofiler-sdk-util/**' - '.github/workflows/rocprofiler-sdk-code_coverage.yml' - '.github/actions/rocprofiler-sdk-util/action.yml' - '.github/actions/rocprofiler-sdk-util/resolve-ci-config/**' @@ -25,6 +26,7 @@ on: pull_request: paths: - 'projects/rocprofiler-sdk/**' + - '.github/actions/rocprofiler-sdk-util/**' - '.github/workflows/rocprofiler-sdk-code_coverage.yml' - '.github/actions/rocprofiler-sdk-util/action.yml' - '.github/actions/rocprofiler-sdk-util/resolve-ci-config/**' @@ -45,6 +47,11 @@ concurrency: env: # TODO(jrmadsen): replace LD_RUNPATH_FLAG, GPU_TARGETS, etc. with internal handling in cmake ROCM_PATH: "/opt/rocm" + PYTHON_VENV_PATH: ".venv-rocprofiler-sdk" + # Held at 3.25 rather than develop's 4.x: this branch's external submodules + # (json, pybind11, sqlite, yaml-cpp) still declare cmake_minimum_required + # below 3.5, which CMake 4 rejects outright. + CMAKE_VERSION_DEB: "3.25.0" GPU_TARGETS: "gfx906 gfx908 gfx90a gfx942 gfx950 gfx1030 gfx1100 gfx1101 gfx1102 gfx1201" PATH: "/usr/bin:$PATH" SUBMODULE_PATHS: "projects/rocprofiler-sdk projects/aqlprofile projects/rocprofiler-register projects/rocr-runtime projects/clr projects/hip" @@ -74,6 +81,7 @@ env: ENABLE_AQLPROFILE_BUILD: "true" ENABLE_ROCDECODE_BUILD: "true" ENABLE_ROCJPEG_BUILD: "true" + ENABLE_HIPFILE_BUILD: "true" jobs: ci_config: @@ -137,6 +145,8 @@ jobs: projects/rocr-runtime projects/clr projects/hip + projects/hrr + projects/hipfile submodules: false set-safe-directory: true @@ -163,6 +173,8 @@ jobs: submods-scoped-v1-${{ runner.os }}- - name: Init/Update submodules + timeout-minutes: 15 + continue-on-error: true run: git submodule update --init --recursive --jobs 16 -- ${SUBMODULE_PATHS} - name: Clone ROCDecode @@ -195,12 +207,6 @@ jobs: run: | if [ -d .codecov ]; then cp -r .codecov .codecov.ref; fi - - name: Configure Env - shell: bash - run: | - echo "${PATH}:/usr/local/bin:${HOME}/.local/bin" >> $GITHUB_PATH - echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib:${HOME}/.local/lib" >> $GITHUB_ENV - - name: Install requirements timeout-minutes: 10 shell: bash @@ -208,9 +214,12 @@ jobs: run: | git config --global --add safe.directory '*' apt-get update - apt-get install -y build-essential ccache python3-pip gcovr wkhtmltopdf xvfb xfonts-base xfonts-75dpi xfonts-100dpi xfonts-utils xfonts-encodings libfontconfig libdw-dev libsqlite3-dev libdrm-dev file autoconf pkg-config rpm libzstd-dev - python3 -m pip install -U --user cmake==3.25.0 - python3 -m pip install -U --user -r requirements.txt + apt-get install -y build-essential ccache cmake python3-pip python3-venv gcovr wkhtmltopdf xvfb xfonts-base xfonts-75dpi xfonts-100dpi xfonts-utils xfonts-encodings libfontconfig libdw-dev libsqlite3-dev libdrm-dev file autoconf pkg-config rpm libzstd-dev + python3 -m venv --system-site-packages ${GITHUB_WORKSPACE}/${{ env.PYTHON_VENV_PATH }} + source ${GITHUB_WORKSPACE}/${{ env.PYTHON_VENV_PATH }}/bin/activate + python3 -m pip install --upgrade pip + python3 -m pip install --upgrade -r requirements.txt + python3 -m pip install --upgrade cmake==${{ env.CMAKE_VERSION_DEB }} - name: Sync gcov with compilers timeout-minutes: 10 @@ -233,6 +242,7 @@ jobs: uses: ./.github/actions/rocprofiler-sdk-util with: rocm-path: ${{ env.ROCM_PATH }} + python-venv-path: ${{ env.PYTHON_VENV_PATH }} gpu-target: ${{ matrix.system.gpu-target }} compiler-launcher: /usr/bin/ccache enable-rocr-build: ${{ env.ENABLE_ROCR_BUILD }} @@ -241,6 +251,7 @@ jobs: enable-aqlprofile-build: ${{ env.ENABLE_AQLPROFILE_BUILD }} enable-rocdecode-build: ${{ env.ENABLE_ROCDECODE_BUILD }} enable-rocjpeg-build: ${{ env.ENABLE_ROCJPEG_BUILD }} + enable-hipfile-build: ${{ env.ENABLE_HIPFILE_BUILD }} ccache-key: ccache-${{ matrix.system.os }}-${{ needs.ci_config.outputs.gfx94x_runner }}-${{ matrix.system.gpu }} ccache-variant: ccache @@ -249,6 +260,7 @@ jobs: shell: bash working-directory: projects/rocprofiler-sdk run: + source ${GITHUB_WORKSPACE}/${{ env.PYTHON_VENV_PATH }}/bin/activate && python3 ./source/scripts/run-ci.py -B build --name ${{ github.repository }}-${{ github.ref_name }}-${{ matrix.system.os }}-${{ matrix.system.gpu }}-codecov --build-jobs 16 @@ -270,6 +282,7 @@ jobs: shell: bash working-directory: projects/rocprofiler-sdk run: + source ${GITHUB_WORKSPACE}/${{ env.PYTHON_VENV_PATH }}/bin/activate && find build -type f | egrep '\.gcda$' | xargs rm && python3 ./source/scripts/run-ci.py -B build --name ${{ github.repository }}-${{ github.ref_name }}-${{ matrix.system.os }}-${{ matrix.system.gpu }}-codecov-tests @@ -292,6 +305,7 @@ jobs: working-directory: projects/rocprofiler-sdk shell: bash run: + source ${GITHUB_WORKSPACE}/${{ env.PYTHON_VENV_PATH }}/bin/activate && find build -type f | egrep '\.gcda$' | xargs rm && python3 ./source/scripts/run-ci.py -B build --name ${{ github.repository }}-${{ github.ref_name }}-${{ matrix.system.os }}-${{ matrix.system.gpu }}-codecov-samples @@ -324,6 +338,7 @@ jobs: working-directory: projects/rocprofiler-sdk shell: bash run: | + source ${GITHUB_WORKSPACE}/${{ env.PYTHON_VENV_PATH }}/bin/activate echo "PWD: ${PWD}" ls -la @@ -424,6 +439,7 @@ jobs: shell: bash working-directory: projects/rocprofiler-sdk run: | + source ${GITHUB_WORKSPACE}/${{ env.PYTHON_VENV_PATH }}/bin/activate pushd build # # if following fails, there is a test that does not have diff --git a/.github/workflows/rocprofiler-sdk-rocm_release_compatibility.yml b/.github/workflows/rocprofiler-sdk-rocm_release_compatibility.yml index fe7df53d01b9..cb4bbf6667c7 100644 --- a/.github/workflows/rocprofiler-sdk-rocm_release_compatibility.yml +++ b/.github/workflows/rocprofiler-sdk-rocm_release_compatibility.yml @@ -41,6 +41,7 @@ concurrency: env: ROCM_PATH: "/opt/rocm" PATH: "/usr/bin:$PATH" + CMAKE_PREFIX_PATH: "/opt/rocm/lib/rocm_sysdeps:/opt/rocm" jobs: rocm-release-compatibility: @@ -80,7 +81,7 @@ jobs: cd projects/rocprofiler-sdk git config --global --add safe.directory '*' apt update - apt install -y wget build-essential cmake g++-11 g++-12 python3-pip libdw-dev libsqlite3-dev libdrm-dev pkg-config + apt install -y wget build-essential g++-11 g++-12 python3-pip libdw-dev libsqlite3-dev libdrm-dev pkg-config # Older ROCm versions don't provide these packages. apt install -y rccl-dev rccl-unittests || true @@ -89,6 +90,14 @@ jobs: update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 10 --slave /usr/bin/g++ g++ /usr/bin/g++-11 --slave /usr/bin/gcov gcov /usr/bin/gcov-11 update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 20 --slave /usr/bin/g++ g++ /usr/bin/g++-12 --slave /usr/bin/gcov gcov /usr/bin/gcov-12 python3 -m pip install -U --user -r requirements.txt + # Held at 3.25 rather than the 4.x that requirements.txt resolves to: this + # branch's external submodules (json, pybind11, sqlite, yaml-cpp) still declare + # cmake_minimum_required below 3.5, which CMake 4 rejects outright. This must + # run after requirements.txt so the pin is not upgraded away. + python3 -m pip install -U --user cmake==3.25.0 + + # Add pip packages to path + echo "$HOME/.local/bin" >> "$GITHUB_PATH" - name: List Files shell: bash diff --git a/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/hsa/queue.cpp b/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/hsa/queue.cpp index 03d33873b7bb..c0f25f2ad492 100644 --- a/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/hsa/queue.cpp +++ b/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/hsa/queue.cpp @@ -171,7 +171,7 @@ AsyncSignalHandler(hsa_signal_value_t /*signal_v*/, void* data) // PC sampling completion is no longer routed through the per-queue // callback registry; invoke its hook explicitly. - pc_sampling::signal_completion_hook(queue_info_session.queue, + pc_sampling::signal_completion_hook(&queue_info_session.queue, packet.kernel_packet, _session, packet, @@ -367,8 +367,8 @@ WriteInterceptor(const void* packets, return; } - // these are for the services (dispatch counter collection, pc sampling, ATT) which use - // the queue/queue_controller callback mechanism + // Services that attach packet instrumentation or need dispatch correlation data. Some are + // still routed through queue-controller callbacks while migrated services use explicit hooks. const auto queue_callback_context_filter = [](const context::context* ctx) { return (ctx->dispatch_counter_collection || ctx->pc_sampler || ctx->dispatch_thread_trace || ctx->dispatch_spm); diff --git a/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/hsa_adapter.cpp b/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/hsa_adapter.cpp index 90c3416a780e..f9baa3ce6c91 100644 --- a/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/hsa_adapter.cpp +++ b/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/hsa_adapter.cpp @@ -132,15 +132,13 @@ amd_intercept_marker_handler_callback(const struct amd_aql_intercept_marker_s* p */ void kernel_completion_cb(const rocprofiler_agent_t* rocp_agent, - rocprofiler::hsa::rocprofiler_packet& /*kernel_pkt*/, + const rocprofiler::hsa::rocprofiler_packet& /*kernel_pkt*/, const rocprofiler::hsa::queue_info_session_t& session) { // No internal correlation IDs, meaning there is no need to call CID manager. if(!session.correlation_id) return; - // Check if the PC sampling service is configured on this agent. - if(!is_pc_sample_service_configured(rocp_agent->id)) return; - + // signal_completion_hook verifies that the service is configured before forwarding here. auto* agent_session = get_agent_session(rocp_agent->id); ROCP_FATAL_IF(agent_session == nullptr) << "No PC sampling sessions configured for the agent where kernel completion " @@ -355,7 +353,7 @@ pc_sampling_service_finish_configuration(context::pc_sampling_service* service) // controller. Kernel completion is delivered explicitly via // pc_sampling::signal_completion_hook, called from the HSA async signal // handler (see hsa/queue.cpp). The marker packet is still injected directly - // in the write interceptor, gated by pc_sampling::is_configured_on_agent. + // in the write interceptor, gated by is_pc_sample_service_configured. } rocprofiler_status_t diff --git a/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/hsa_adapter.hpp b/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/hsa_adapter.hpp index b3312bb357ad..e290b3ac782c 100644 --- a/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/hsa_adapter.hpp +++ b/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/hsa_adapter.hpp @@ -59,7 +59,7 @@ pc_sampling_service_finish_configuration(context::pc_sampling_service* service); // which is called by the HSA async signal handler in hsa/queue.cpp. void kernel_completion_cb(const rocprofiler_agent_t* rocp_agent, - rocprofiler::hsa::rocprofiler_packet& kernel_pkt, + const rocprofiler::hsa::rocprofiler_packet& kernel_pkt, const rocprofiler::hsa::queue_info_session_t& session); rocprofiler_status_t diff --git a/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/queue_hooks.cpp b/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/queue_hooks.cpp index 3797fa002628..9f6624ce9596 100644 --- a/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/queue_hooks.cpp +++ b/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/queue_hooks.cpp @@ -1,6 +1,6 @@ // MIT License // -// Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (c) 2026 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -33,6 +33,11 @@ namespace rocprofiler { namespace pc_sampling { +// The compile gate cannot move into is_pc_sample_service_configured: this file is +// added to the object library before the early return in CMakeLists.txt, so it is +// always built, while service.cpp (which defines that function) is added after and +// is absent from the build when PC sampling is compiled out. The guard has to stay +// at the call site to keep the write interceptor linkable in that configuration. bool is_configured_on_agent(rocprofiler_agent_id_t agent_id) { @@ -45,7 +50,7 @@ is_configured_on_agent(rocprofiler_agent_id_t agent_id) } void -signal_completion_hook(const ::rocprofiler::hsa::Queue& queue, +signal_completion_hook(const ::rocprofiler::hsa::Queue* queue, const ::rocprofiler::hsa::rocprofiler_packet& kernel_packet, std::shared_ptr<::rocprofiler::hsa::queue_info_session_t>& session, ::rocprofiler::hsa::packet_data_t& /*packet*/, @@ -54,10 +59,11 @@ signal_completion_hook(const ::rocprofiler::hsa::Queue& { #if ROCPROFILER_SDK_HSA_PC_SAMPLING > 0 if(!session) return; - // kernel_completion_cb takes a mutable reference to the kernel packet even - // though it does not modify it; copy to bind a non-const lvalue. - auto kern_pkt = kernel_packet; - hsa::kernel_completion_cb(queue.get_agent().get_rocp_agent(), kern_pkt, *session); + CHECK(queue); + const auto* agent = queue->get_agent().get_rocp_agent(); + CHECK(agent); + if(!is_pc_sample_service_configured(agent->id)) return; + hsa::kernel_completion_cb(agent, kernel_packet, *session); #else (void) queue; (void) kernel_packet; diff --git a/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/queue_hooks.hpp b/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/queue_hooks.hpp index 55dcef38bef3..d694e7e4c247 100644 --- a/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/queue_hooks.hpp +++ b/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/queue_hooks.hpp @@ -1,6 +1,6 @@ // MIT License // -// Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (c) 2026 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -48,7 +48,7 @@ is_configured_on_agent(rocprofiler_agent_id_t agent_id); // that the kernel's correlation ID has completed. No-op when PC sampling HSA // support is unavailable or when the service is not configured on the agent. void -signal_completion_hook(const ::rocprofiler::hsa::Queue& queue, +signal_completion_hook(const ::rocprofiler::hsa::Queue* queue, const ::rocprofiler::hsa::rocprofiler_packet& kernel_packet, std::shared_ptr<::rocprofiler::hsa::queue_info_session_t>& session, ::rocprofiler::hsa::packet_data_t& packet, diff --git a/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/tests/pc_sampling_internals.hpp b/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/tests/pc_sampling_internals.hpp index ef63c3b4440f..032698012395 100644 --- a/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/tests/pc_sampling_internals.hpp +++ b/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/tests/pc_sampling_internals.hpp @@ -40,14 +40,6 @@ amd_intercept_marker_handler_callback(const struct amd_aql_intercept_marker_s* p hsa_queue_t* queue, uint64_t packet_id); -extern void -kernel_completion_cb(const std::shared_ptr& info, - const rocprofiler_agent_t* rocp_agent, - rocprofiler::hsa::ClientID client_id, - const rocprofiler::hsa::rocprofiler_packet& kernel_pkt, - const rocprofiler::hsa::queue_info_session_t& session, - std::unique_ptr pkt); - extern void data_ready_callback(void* client_callback_data, size_t data_size, diff --git a/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/tests/queue_hooks_test.cpp b/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/tests/queue_hooks_test.cpp index ea420c7fa5b6..0384abb92559 100644 --- a/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/tests/queue_hooks_test.cpp +++ b/projects/rocprofiler-sdk/source/lib/rocprofiler-sdk/pc_sampling/tests/queue_hooks_test.cpp @@ -1,6 +1,6 @@ // MIT License // -// Copyright (c) 2025 Advanced Micro Devices, Inc. All rights reserved. +// Copyright (c) 2026 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -40,13 +40,13 @@ TEST(pc_sampling_queue_hooks, is_configured_on_agent_unconfigured) TEST(pc_sampling_queue_hooks, signal_completion_hook_null_session_is_noop) { - rocprofiler::hsa::rocprofiler_packet kern_pkt{}; + rocprofiler::hsa::rocprofiler_packet kern_pkt{}; std::shared_ptr null_session; rocprofiler::hsa::packet_data_t packet{}; rocprofiler::hsa::inst_pkt_t inst_pkt{}; rocprofiler::pc_sampling::signal_completion_hook( - *reinterpret_cast(nullptr), + nullptr, kern_pkt, null_session, packet,