diff --git a/ggml/src/ggml-hrx/CMakeLists.txt b/ggml/src/ggml-hrx/CMakeLists.txt index 6e15ce13931e..16e77e8ad2f3 100644 --- a/ggml/src/ggml-hrx/CMakeLists.txt +++ b/ggml/src/ggml-hrx/CMakeLists.txt @@ -1,4 +1,5 @@ set(HRX_SOURCE_DIR "" CACHE PATH "Optional HRX source tree to build instead of using installed hrx and loomc packages") +find_package(Python3 REQUIRED COMPONENTS Interpreter) if(HRX_SOURCE_DIR) include(ExternalProject) @@ -9,6 +10,21 @@ if(HRX_SOURCE_DIR) message(FATAL_ERROR "HRX_SOURCE_DIR does not contain a CMakeLists.txt: ${HRX_SOURCE_DIR}") endif() + # Enforce the HRX compatibility floor before building dependencies; rerun configure when the pin or checker changes. + set(GGML_HRX_REVISION_CHECK "${CMAKE_CURRENT_SOURCE_DIR}/tools/check_hrx_revision.py") + set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/hrx-minimum-commit.txt" "${GGML_HRX_REVISION_CHECK}") + execute_process( + COMMAND "${Python3_EXECUTABLE}" "${GGML_HRX_REVISION_CHECK}" "${HRX_SOURCE_DIR}" + RESULT_VARIABLE GGML_HRX_REVISION_RESULT + OUTPUT_VARIABLE GGML_HRX_REVISION_OUTPUT + ERROR_VARIABLE GGML_HRX_REVISION_ERROR + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT GGML_HRX_REVISION_RESULT EQUAL 0) + message(FATAL_ERROR "${GGML_HRX_REVISION_ERROR}") + endif() + message(STATUS "${GGML_HRX_REVISION_OUTPUT}") + set(GGML_HRX_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/hrx") set(GGML_HRX_BUILD_DIR "${GGML_HRX_PREFIX}/src/ggml-hrx-deps-build") set(GGML_HRX_LIB "${GGML_HRX_BUILD_DIR}/libhrx/src/libhrx/${CMAKE_SHARED_LIBRARY_PREFIX}hrx${CMAKE_SHARED_LIBRARY_SUFFIX}") @@ -69,8 +85,6 @@ else() find_program(GGML_HRX_IREE_BENCHMARK_LOOM NAMES iree-benchmark-loom) endif() -find_package(Python3 REQUIRED COMPONENTS Interpreter) - set(GGML_HRX_KERNEL_CORPUS_SOURCE_FORMAT "binary" CACHE STRING "Embedded Loom corpus source format: text or binary") set_property(CACHE GGML_HRX_KERNEL_CORPUS_SOURCE_FORMAT PROPERTY STRINGS text binary) if(GGML_HRX_KERNEL_CORPUS_SOURCE_FORMAT STREQUAL "binary") diff --git a/ggml/src/ggml-hrx/README.md b/ggml/src/ggml-hrx/README.md new file mode 100644 index 000000000000..cf00e3131c6f --- /dev/null +++ b/ggml/src/ggml-hrx/README.md @@ -0,0 +1,17 @@ +# HRX Backend + +## `hrx-system` backend compatibility + +`hrx-minimum-commit.txt` records the minimum required commit in ROCm/hrx-system. It contains one full Git commit SHA. The backend's C++ APIs, Loom syntax, and numerical behavior can all depend on that revision. When `GGML_HRX=ON` and `HRX_SOURCE_DIR` is set, CMake requires the HRX checkout's HEAD to equal or descend from the recorded commit. + +For builds using installed packages, check the source revision used to produce both HRX and Loom against this floor before validating a repair. From the staging checkout: + +```sh +python3 llama.cpp/ggml/src/ggml-hrx/tools/check_hrx_revision.py hrx-system +``` + +### Updating the minimum + +Raise the minimum in the same llama.cpp commit that introduces a newer HRX dependency. This includes new API calls, new Loom syntax, and removing a numerical workaround after an HRX compiler or runtime fix. Unrelated repairs do not require a bump. + +Choose the earliest demonstrated required commit that retains the previous floor in its ancestry. Do not replace the floor with the latest tested revision merely because it is available. Record the dependency and its HRX commit or PR in the change's validation evidence. A minimum is not a promise that every future HRX revision is compatible. diff --git a/ggml/src/ggml-hrx/hrx-minimum-commit.txt b/ggml/src/ggml-hrx/hrx-minimum-commit.txt new file mode 100644 index 000000000000..82d19141ff2b --- /dev/null +++ b/ggml/src/ggml-hrx/hrx-minimum-commit.txt @@ -0,0 +1 @@ +40b7cc13717d9d4c7f7eb0e6885563042153566b diff --git a/ggml/src/ggml-hrx/tools/check_hrx_revision.py b/ggml/src/ggml-hrx/tools/check_hrx_revision.py new file mode 100644 index 000000000000..9ce6a441e2da --- /dev/null +++ b/ggml/src/ggml-hrx/tools/check_hrx_revision.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +"""Check an HRX checkout against the backend's recorded minimum commit. + +CMake and callers using installed packages share this local ancestry check. +Success prints the accepted revision; failure prints context and exits nonzero. +No history is fetched and no source files are changed. +""" + +import argparse +from pathlib import Path +import subprocess +import sys + + +def check_revision(source: Path) -> int: + minimum = (Path(__file__).resolve().parents[1] / "hrx-minimum-commit.txt").read_text(encoding="utf-8").strip() + head = "unknown" + + def git(*args: str) -> str: + return subprocess.run( + ["git", "-C", str(source), *args], check=True, text=True, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, + ).stdout.strip() + + try: + head = git("rev-parse", "--verify", "HEAD^{commit}") + git("cat-file", "-e", f"{minimum}^{{commit}}") + git("merge-base", "--is-ancestor", minimum, head) + except (OSError, subprocess.CalledProcessError) as error: + if isinstance(error, subprocess.CalledProcessError): + reason = error.stderr.strip() or "HRX HEAD does not have the required commit in its available ancestry." + else: + reason = str(error) + print( + f"{reason}\nHRX_SOURCE_DIR: {source}\nRequired HRX commit: {minimum}\nActual HRX HEAD: {head}\n" + "Use an HRX Git checkout at the required commit or a descendant. Ensure Git is installed, " + "fetch missing history manually (unshallow a shallow clone if needed), then rerun the check.", + file=sys.stderr, + ) + return 1 + + print(f"HRX revision {head} satisfies minimum {minimum}") + return 0 + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("source", type=Path, help="HRX source checkout") + args = parser.parse_args() + return check_revision(args.source.resolve()) + + +if __name__ == "__main__": + sys.exit(main())