Files
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

160 lines
5.0 KiB
Python

"""
Common utilities for artifact manipulation.
This module provides reusable utilities for working with TheRock artifacts,
including manifest handling, directory traversal, and file classification.
"""
import os
from pathlib import Path
from typing import Iterator, Tuple, Callable, Optional
from rocm_kpack.binutils import Toolchain
from rocm_kpack.coff.surgery import CoffSurgery
from rocm_kpack.elf.surgery import ElfSurgery
from rocm_kpack.format_detect import detect_binary_format, UnsupportedBinaryFormat
def read_artifact_manifest(artifact_dir: Path) -> list[str]:
"""
Read the artifact manifest file from a TheRock artifact directory.
The artifact_manifest.txt file format is a simple text file with one prefix
per line. Each prefix represents a directory path relative to the artifact
root directory. Empty lines are ignored.
Example artifact_manifest.txt:
math-libs/BLAS/rocBLAS/stage
math-libs/BLAS/hipBLASLt/stage
kpack/stage
Args:
artifact_dir: Path to artifact directory containing artifact_manifest.txt
Returns:
List of prefixes (directory paths) from the manifest
Raises:
FileNotFoundError: If artifact_manifest.txt does not exist
"""
manifest_path = artifact_dir / "artifact_manifest.txt"
if not manifest_path.exists():
raise FileNotFoundError(f"artifact_manifest.txt not found in {artifact_dir}")
with open(manifest_path, "r") as f:
return [line.strip() for line in f if line.strip()]
def write_artifact_manifest(artifact_dir: Path, prefixes: list[str]) -> None:
"""
Write an artifact manifest file to a TheRock artifact directory.
Args:
artifact_dir: Path to artifact directory
prefixes: List of prefix paths to write
"""
manifest_path = artifact_dir / "artifact_manifest.txt"
with open(manifest_path, "w") as f:
for prefix in prefixes:
f.write(f"{prefix}\n")
def scan_directory(
root_dir: Path, predicate: Optional[Callable[[Path, os.DirEntry], bool]] = None
) -> Iterator[Tuple[Path, os.DirEntry]]:
"""
Robustly scan a directory tree without following symlinks.
This uses os.scandir for performance and correctly handles symlinks by not
following them, preventing infinite loops and other issues.
Args:
root_dir: Root directory to scan
predicate: Optional filter function that takes (path, direntry) and returns True to include
Yields:
Tuples of (absolute_path, direntry) for each file/directory found
"""
def scan_recursive(current_dir: Path):
with os.scandir(current_dir) as it:
for entry in it:
full_path = current_dir / entry.name
# Apply predicate if provided
if predicate and not predicate(full_path, entry):
continue
yield full_path, entry
# Recursively scan subdirectories (not following symlinks)
if entry.is_dir(follow_symlinks=False):
yield from scan_recursive(full_path)
yield from scan_recursive(root_dir)
def is_fat_binary(file_path: Path, toolchain: Toolchain) -> bool:
"""
Check if a file is a fat binary (contains GPU device code).
For ELF binaries, checks for .hip_fatbin section.
For PE/COFF binaries, checks for .hip_fat section.
Args:
file_path: Path to the file to check
toolchain: Toolchain instance with readelf path
Returns:
True if the file contains device code, False if it's not a fat binary
Raises:
RuntimeError: If binary analysis fails
FileNotFoundError: If file doesn't exist
"""
# Fast check: Is file empty?
try:
if file_path.stat().st_size == 0:
return False
except FileNotFoundError:
raise
except OSError as e:
raise RuntimeError(f"Cannot stat file {file_path}: {e}") from e
try:
fmt = detect_binary_format(file_path)
except UnsupportedBinaryFormat:
return False
if fmt == "elf":
surgery = ElfSurgery.load(file_path)
return surgery.find_section(".hip_fatbin") is not None
else:
surgery = CoffSurgery.load(file_path)
return surgery.find_section(".hip_fat") is not None
def extract_architecture_from_target(target: str) -> Optional[str]:
"""
Extract GPU architecture from a clang target string.
Handles both simple and "cooked" architectures (e.g., gfx942:xnack+).
Looks for the last "--" in the target string and takes everything after it.
Args:
target: Target string like "hipv4-amdgcn-amd-amdhsa--gfx906"
or "hipv4-amdgcn-amd-amdhsa--gfx942:xnack+"
Returns:
The architecture string (e.g., "gfx906", "gfx942:xnack+") or None if not found
"""
if not target:
return None
# Find the last occurrence of "--" and take everything after it
parts = target.rsplit("--", 1)
if len(parts) == 2:
return parts[1]
return None