From ec8a03ecf619509f5d61523fa877544e4e8604ef Mon Sep 17 00:00:00 2001 From: da03 Date: Sat, 3 Oct 2026 18:15:15 -0400 Subject: [PATCH 1/7] Support llama-cpp-python 0.3.36 and build Apple Silicon wheels --- .github/workflows/runtime-wheels.yml | 25 ++++++++++++------------ .github/workflows/test.yml | 2 +- pyproject.toml | 2 +- scripts/runtime-wheels/macos-arm64.cmake | 13 ++++++++++++ scripts/runtime-wheels/source.txt | 2 +- 5 files changed, 29 insertions(+), 15 deletions(-) create mode 100644 scripts/runtime-wheels/macos-arm64.cmake diff --git a/.github/workflows/runtime-wheels.yml b/.github/workflows/runtime-wheels.yml index 2c7d50b..22b50d2 100644 --- a/.github/workflows/runtime-wheels.yml +++ b/.github/workflows/runtime-wheels.yml @@ -11,16 +11,19 @@ permissions: contents: read jobs: - macos-intel: - runs-on: macos-15-intel + macos: + runs-on: ${{ matrix.platform.runner }} strategy: fail-fast: false matrix: python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] + platform: + - {name: intel, runner: macos-15-intel, arch: x64, wheel-arch: x86_64} + - {name: arm64, runner: macos-15, arch: arm64, wheel-arch: arm64} env: - CMAKE_ARGS: -C "${{ github.workspace }}/scripts/runtime-wheels/macos-intel.cmake" + CMAKE_ARGS: -C "${{ github.workspace }}/scripts/runtime-wheels/macos-${{ matrix.platform.name }}.cmake" MACOSX_DEPLOYMENT_TARGET: "11.0" - ARCHFLAGS: -arch x86_64 + ARCHFLAGS: -arch ${{ matrix.platform.wheel-arch }} CMAKE_BUILD_PARALLEL_LEVEL: "4" CC: /usr/bin/clang CXX: /usr/bin/clang++ @@ -29,7 +32,7 @@ jobs: - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - architecture: x64 + architecture: ${{ matrix.platform.arch }} - name: Install build tools run: python -m pip install -r scripts/runtime-wheels/macos-intel-requirements.txt - name: Build pinned upstream source @@ -39,10 +42,9 @@ jobs: - name: Verify installation and offline inference shell: python run: | - import pathlib, subprocess, sys, tempfile, venv + import pathlib, subprocess, tempfile, venv wheel, = pathlib.Path("wheelhouse").glob("*.whl") - tag = "cp%d%d" % sys.version_info[:2] - assert wheel.name == f"llama_cpp_python-0.3.19-{tag}-{tag}-macosx_11_0_x86_64.whl" + assert wheel.name == "llama_cpp_python-0.3.36-py3-none-macosx_11_0_${{ matrix.platform.wheel-arch }}.whl" with tempfile.TemporaryDirectory() as root: venv.create(root, with_pip=True) python = str(pathlib.Path(root) / "bin/python") @@ -57,7 +59,7 @@ jobs: subprocess.run([python, *args], check=True) - uses: actions/upload-artifact@v4 with: - name: llama-cpp-macos-intel-py${{ matrix.python-version }} + name: llama-cpp-macos-${{ matrix.platform.name }}-py${{ matrix.python-version }} path: wheelhouse/*.whl if-no-files-found: error @@ -89,8 +91,7 @@ jobs: run: | import pathlib, subprocess, sys, tempfile, venv wheel, = pathlib.Path("wheelhouse").glob("*.whl") - tag = "cp%d%d" % sys.version_info[:2] - assert wheel.name == f"llama_cpp_python-0.3.19-{tag}-{tag}-win_amd64.whl" + assert wheel.name == "llama_cpp_python-0.3.36-py3-none-win_amd64.whl" subprocess.run([ sys.executable, "-I", "scripts/runtime-wheels/audit_windows_dependencies.py", str(wheel.resolve()), @@ -141,7 +142,7 @@ jobs: run: | import pathlib, subprocess, tempfile, venv wheel, = pathlib.Path("wheelhouse").glob("*.whl") - assert wheel.name == "llama_cpp_python-0.3.19-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" + assert wheel.name == "llama_cpp_python-0.3.36-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" with tempfile.TemporaryDirectory() as root: venv.create(root, with_pip=True) python = str(pathlib.Path(root) / "bin/python") diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 86bd49d..21d5bfe 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -144,7 +144,7 @@ jobs: platform: - {runner: ubuntu-24.04, arch: x64} - {runner: windows-2022, arch: x64} - - {runner: macos-14, arch: arm64} + - {runner: macos-15, arch: arm64} - {runner: macos-15-intel, arch: x64} steps: - uses: actions/checkout@v4 diff --git a/pyproject.toml b/pyproject.toml index d4bcb33..292b08b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,7 +31,7 @@ classifiers = [ ] dependencies = [ "httpx>=0.27.0,<1.0", - "llama-cpp-python>=0.3.0,<=0.3.19", + "llama-cpp-python>=0.3.0,<=0.3.36", ] [project.urls] diff --git a/scripts/runtime-wheels/macos-arm64.cmake b/scripts/runtime-wheels/macos-arm64.cmake new file mode 100644 index 0000000..45b33bd --- /dev/null +++ b/scripts/runtime-wheels/macos-arm64.cmake @@ -0,0 +1,13 @@ +set(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "") +set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0" CACHE STRING "") +set(GGML_BLAS_VENDOR "Apple" CACHE STRING "") + +foreach(feature IN ITEMS + GGML_METAL GGML_METAL_EMBED_LIBRARY GGML_ACCELERATE GGML_BLAS) + set(${feature} ON CACHE BOOL "") +endforeach() + +foreach(feature IN ITEMS + GGML_NATIVE GGML_OPENMP GGML_RPC GGML_CCACHE LLAMA_OPENSSL) + set(${feature} OFF CACHE BOOL "") +endforeach() diff --git a/scripts/runtime-wheels/source.txt b/scripts/runtime-wheels/source.txt index 1f53c0c..206eeab 100644 --- a/scripts/runtime-wheels/source.txt +++ b/scripts/runtime-wheels/source.txt @@ -1 +1 @@ -https://files.pythonhosted.org/packages/d7/0f/b26ceec20294f5d592ac137ccc2f10e91fa1f35bb8555906b5718a625ac1/llama_cpp_python-0.3.19.tar.gz#sha256=6816e4a0a74ae9a356e7a0546e13147543f01f695c86a28d940e4b86519acf13 +https://files.pythonhosted.org/packages/ec/e9/e7de2b0463ea3ffbf0ede6cb21b58c1258a8f6521aae45ca773a59fe7cf3/llama_cpp_python-0.3.36.tar.gz#sha256=832db0699007f1be95a7e41ef12e88926b02ba836461e36a36372db2760c1a2e From 3820c1235e0835026aa4ba5079723b783f97cfa7 Mon Sep 17 00:00:00 2001 From: da03 Date: Sat, 3 Oct 2026 18:26:21 -0400 Subject: [PATCH 2/7] Set Linux wheel library search paths for llama-common --- scripts/runtime-wheels/linux.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/runtime-wheels/linux.cmake b/scripts/runtime-wheels/linux.cmake index d8f7cbd..b563ff3 100644 --- a/scripts/runtime-wheels/linux.cmake +++ b/scripts/runtime-wheels/linux.cmake @@ -1,3 +1,5 @@ +set(CMAKE_INSTALL_RPATH "$ORIGIN" CACHE STRING "") + foreach(feature IN ITEMS GGML_SSE42 GGML_AVX GGML_AVX2 GGML_FMA GGML_F16C GGML_BMI2 GGML_LLAMAFILE GGML_OPENMP GGML_CPU_REPACK) From b49e082f083ba187bd376d15963caa77d9590029 Mon Sep 17 00:00:00 2001 From: da03 Date: Sat, 3 Oct 2026 18:44:23 -0400 Subject: [PATCH 3/7] Disable unused OpenSSL dependency in Windows runtime wheels --- scripts/runtime-wheels/windows.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/runtime-wheels/windows.cmake b/scripts/runtime-wheels/windows.cmake index 6d0ce69..96bc971 100644 --- a/scripts/runtime-wheels/windows.cmake +++ b/scripts/runtime-wheels/windows.cmake @@ -6,6 +6,7 @@ set(GGML_AVX_VNNI OFF CACHE BOOL "") set(GGML_CUDA OFF CACHE BOOL "") set(GGML_BLAS OFF CACHE BOOL "") set(GGML_OPENMP ON CACHE BOOL "") +set(LLAMA_OPENSSL OFF CACHE BOOL "") set(CMAKE_PROJECT_llama_cpp_INCLUDE "${CMAKE_CURRENT_LIST_DIR}/windows-runtime.cmake" CACHE FILEPATH "") From 292ed4627adfb09fe69513ccbdeed5d9127368ae Mon Sep 17 00:00:00 2001 From: da03 Date: Sat, 3 Oct 2026 18:47:57 -0400 Subject: [PATCH 4/7] Recognize Windows shell and networking system DLLs --- scripts/runtime-wheels/audit_windows_dependencies.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/runtime-wheels/audit_windows_dependencies.py b/scripts/runtime-wheels/audit_windows_dependencies.py index 000a8c8..520c433 100644 --- a/scripts/runtime-wheels/audit_windows_dependencies.py +++ b/scripts/runtime-wheels/audit_windows_dependencies.py @@ -8,7 +8,10 @@ import pefile # Windows 10+ components. MSVC and OpenMP redistributables are not OS libraries. -SYSTEM_DLLS = {"advapi32.dll", "kernel32.dll", "ntdll.dll", "ucrtbase.dll"} +SYSTEM_DLLS = { + "advapi32.dll", "kernel32.dll", "ntdll.dll", + "shell32.dll", "ucrtbase.dll", "ws2_32.dll", +} IMPORT_TABLES = ("IMPORT", "DELAY_IMPORT") REQUIRED_DLLS = {"llama.dll", "ggml.dll", "ggml-base.dll", "ggml-cpu.dll", "mtmd.dll"} From 520d3b320b72bc198ad01bc46ca7e17892b41c94 Mon Sep 17 00:00:00 2001 From: da03 Date: Sat, 3 Oct 2026 22:15:03 -0400 Subject: [PATCH 5/7] Build modern and compatible Apple Silicon runtime wheels --- .github/workflows/runtime-wheels.yml | 10 ++++++---- scripts/runtime-wheels/macos-arm64-modern.cmake | 13 +++++++++++++ scripts/runtime-wheels/macos-arm64.cmake | 5 ++--- 3 files changed, 21 insertions(+), 7 deletions(-) create mode 100644 scripts/runtime-wheels/macos-arm64-modern.cmake diff --git a/.github/workflows/runtime-wheels.yml b/.github/workflows/runtime-wheels.yml index 22b50d2..9072d0d 100644 --- a/.github/workflows/runtime-wheels.yml +++ b/.github/workflows/runtime-wheels.yml @@ -18,11 +18,12 @@ jobs: matrix: python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] platform: - - {name: intel, runner: macos-15-intel, arch: x64, wheel-arch: x86_64} - - {name: arm64, runner: macos-15, arch: arm64, wheel-arch: arm64} + - {name: intel, runner: macos-15-intel, arch: x64, wheel-arch: x86_64, deployment-target: "11.0"} + - {name: arm64, runner: macos-15, arch: arm64, wheel-arch: arm64, deployment-target: "11.0"} + - {name: arm64-modern, runner: macos-15, arch: arm64, wheel-arch: arm64, deployment-target: "14.0"} env: CMAKE_ARGS: -C "${{ github.workspace }}/scripts/runtime-wheels/macos-${{ matrix.platform.name }}.cmake" - MACOSX_DEPLOYMENT_TARGET: "11.0" + MACOSX_DEPLOYMENT_TARGET: ${{ matrix.platform.deployment-target }} ARCHFLAGS: -arch ${{ matrix.platform.wheel-arch }} CMAKE_BUILD_PARALLEL_LEVEL: "4" CC: /usr/bin/clang @@ -44,7 +45,8 @@ jobs: run: | import pathlib, subprocess, tempfile, venv wheel, = pathlib.Path("wheelhouse").glob("*.whl") - assert wheel.name == "llama_cpp_python-0.3.36-py3-none-macosx_11_0_${{ matrix.platform.wheel-arch }}.whl" + target = "${{ matrix.platform.deployment-target }}".replace(".", "_") + assert wheel.name == f"llama_cpp_python-0.3.36-py3-none-macosx_{target}_${{ matrix.platform.wheel-arch }}.whl" with tempfile.TemporaryDirectory() as root: venv.create(root, with_pip=True) python = str(pathlib.Path(root) / "bin/python") diff --git a/scripts/runtime-wheels/macos-arm64-modern.cmake b/scripts/runtime-wheels/macos-arm64-modern.cmake new file mode 100644 index 0000000..bc4d0fc --- /dev/null +++ b/scripts/runtime-wheels/macos-arm64-modern.cmake @@ -0,0 +1,13 @@ +set(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "") +set(CMAKE_OSX_DEPLOYMENT_TARGET "14.0" CACHE STRING "") +set(GGML_BLAS_VENDOR "Apple" CACHE STRING "") + +foreach(feature IN ITEMS + GGML_METAL GGML_METAL_EMBED_LIBRARY GGML_ACCELERATE GGML_BLAS) + set(${feature} ON CACHE BOOL "") +endforeach() + +foreach(feature IN ITEMS + GGML_NATIVE GGML_OPENMP GGML_RPC GGML_CCACHE LLAMA_OPENSSL) + set(${feature} OFF CACHE BOOL "") +endforeach() diff --git a/scripts/runtime-wheels/macos-arm64.cmake b/scripts/runtime-wheels/macos-arm64.cmake index 45b33bd..8026684 100644 --- a/scripts/runtime-wheels/macos-arm64.cmake +++ b/scripts/runtime-wheels/macos-arm64.cmake @@ -1,13 +1,12 @@ set(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "") set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0" CACHE STRING "") -set(GGML_BLAS_VENDOR "Apple" CACHE STRING "") foreach(feature IN ITEMS - GGML_METAL GGML_METAL_EMBED_LIBRARY GGML_ACCELERATE GGML_BLAS) + GGML_METAL GGML_METAL_EMBED_LIBRARY GGML_ACCELERATE) set(${feature} ON CACHE BOOL "") endforeach() foreach(feature IN ITEMS - GGML_NATIVE GGML_OPENMP GGML_RPC GGML_CCACHE LLAMA_OPENSSL) + GGML_BLAS GGML_NATIVE GGML_OPENMP GGML_RPC GGML_CCACHE LLAMA_OPENSSL) set(${feature} OFF CACHE BOOL "") endforeach() From a8d16a3cc05fb90d7662276d5d4f85e088f3a864 Mon Sep 17 00:00:00 2001 From: da03 Date: Sat, 3 Oct 2026 22:59:19 -0400 Subject: [PATCH 6/7] Audit native macOS wheel compatibility in CI --- .github/workflows/runtime-wheels.yml | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/.github/workflows/runtime-wheels.yml b/.github/workflows/runtime-wheels.yml index 9072d0d..5587029 100644 --- a/.github/workflows/runtime-wheels.yml +++ b/.github/workflows/runtime-wheels.yml @@ -43,11 +43,36 @@ jobs: - name: Verify installation and offline inference shell: python run: | - import pathlib, subprocess, tempfile, venv + import pathlib, re, subprocess, tempfile, venv, zipfile wheel, = pathlib.Path("wheelhouse").glob("*.whl") target = "${{ matrix.platform.deployment-target }}".replace(".", "_") assert wheel.name == f"llama_cpp_python-0.3.36-py3-none-macosx_{target}_${{ matrix.platform.wheel-arch }}.whl" with tempfile.TemporaryDirectory() as root: + native_root = pathlib.Path(root) / "native" + with zipfile.ZipFile(wheel) as archive: + archive.extractall(native_root) + libraries = [ + p for p in native_root.rglob("*") + if p.is_file() and p.suffix in (".dylib", ".so") + ] + assert libraries, "Wheel contains no native libraries" + assert any("libggml-blas" in p.name for p in libraries) == (target == "14_0") + minimum_target = target.replace("_", ".") + for library in libraries: + architecture = subprocess.check_output( + ["lipo", "-archs", str(library)], text=True + ).strip() + assert architecture == "${{ matrix.platform.wheel-arch }}", (library, architecture) + commands = subprocess.check_output( + ["otool", "-l", str(library)], text=True + ) + minima = re.findall(r"^\s*minos ([\d.]+)$", commands, re.MULTILINE) + assert minima in ([minimum_target], [minimum_target + ".0"]), (library, minima) + if target == "11_0": + imports = subprocess.check_output( + ["nm", "-u", str(library)], text=True + ) + assert not re.search(r"NEWLAPACK|ILP64", imports, re.IGNORECASE), library venv.create(root, with_pip=True) python = str(pathlib.Path(root) / "bin/python") fixtures = str(pathlib.Path(root) / "fixtures") From 3463bb4d4e1ce3ca898fb3ce28ff4c5318aa951a Mon Sep 17 00:00:00 2001 From: da03 Date: Sun, 4 Oct 2026 19:32:08 -0400 Subject: [PATCH 7/7] Build Linux runtime wheels with CPU dispatch and compatibility checks --- .github/workflows/runtime-wheels.yml | 49 ++++++++++---- scripts/runtime-wheels/build-linux-wheel.sh | 64 +++++++++++++++++++ .../check_linux_cpu_eligibility.py | 64 +++++++++++++++++++ .../runtime-wheels/check_native_inference.py | 45 +++++++++++++ .../runtime-wheels/install-linux-toolchain.sh | 16 +++++ scripts/runtime-wheels/linux-amx-gcc11.patch | 17 +++++ .../runtime-wheels/linux-amx-permission.patch | 42 ++++++++++++ .../linux-backend-install-dir.patch | 14 ++++ .../linux-backend-packaging.patch | 30 +++++++++ .../linux-backend-search-path.patch | 37 +++++++++++ .../runtime-wheels/linux-cpu-os-state.patch | 38 +++++++++++ scripts/runtime-wheels/linux-dispatch.cmake | 9 +++ scripts/runtime-wheels/linux-q6k-avx512.patch | 10 +++ scripts/runtime-wheels/linux-toolchain.sha256 | 5 ++ .../linux_eligibility_probe.cpp | 52 +++++++++++++++ 15 files changed, 481 insertions(+), 11 deletions(-) create mode 100644 scripts/runtime-wheels/build-linux-wheel.sh create mode 100644 scripts/runtime-wheels/check_linux_cpu_eligibility.py create mode 100644 scripts/runtime-wheels/install-linux-toolchain.sh create mode 100644 scripts/runtime-wheels/linux-amx-gcc11.patch create mode 100644 scripts/runtime-wheels/linux-amx-permission.patch create mode 100644 scripts/runtime-wheels/linux-backend-install-dir.patch create mode 100644 scripts/runtime-wheels/linux-backend-packaging.patch create mode 100644 scripts/runtime-wheels/linux-backend-search-path.patch create mode 100644 scripts/runtime-wheels/linux-cpu-os-state.patch create mode 100644 scripts/runtime-wheels/linux-dispatch.cmake create mode 100644 scripts/runtime-wheels/linux-q6k-avx512.patch create mode 100644 scripts/runtime-wheels/linux-toolchain.sha256 create mode 100644 scripts/runtime-wheels/linux_eligibility_probe.cpp diff --git a/.github/workflows/runtime-wheels.yml b/.github/workflows/runtime-wheels.yml index 5587029..e5d4e38 100644 --- a/.github/workflows/runtime-wheels.yml +++ b/.github/workflows/runtime-wheels.yml @@ -152,25 +152,51 @@ jobs: - name: Build and repair the Python 3.8 wheel run: | docker run --rm --volume "$PWD:/io" --workdir /io \ - --env CMAKE_GENERATOR="Unix Makefiles" \ - --env CMAKE_ARGS="-C /io/scripts/runtime-wheels/linux.cmake" \ --env CMAKE_BUILD_PARALLEL_LEVEL=4 \ quay.io/pypa/manylinux2014_x86_64@sha256:f09bf382e4bcbd5b3cab130f8d0f12dbe474833f95f54182e80e8c0aaa269ff0 \ - bash -euxo pipefail -c ' - export PATH="/opt/python/cp38-cp38/bin:$PATH" - python -m pip install -r scripts/runtime-wheels/linux-requirements.txt - python -m pip wheel --no-cache-dir --no-deps --no-build-isolation \ - -r scripts/runtime-wheels/source.txt --wheel-dir /tmp/raw-wheels - auditwheel repair --plat manylinux2014_x86_64 --only-plat \ - --wheel-dir wheelhouse /tmp/raw-wheels/*.whl - ' + bash scripts/runtime-wheels/build-linux-wheel.sh /io/wheelhouse - name: Verify installation and offline inference shell: python run: | - import pathlib, subprocess, tempfile, venv + import os, pathlib, re, subprocess, tempfile, venv, zipfile wheel, = pathlib.Path("wheelhouse").glob("*.whl") assert wheel.name == "llama_cpp_python-0.3.36-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" + with zipfile.ZipFile(wheel) as archive: + members = archive.namelist() + assert len(members) == len(set(members)), "Duplicate wheel archive members" + variants = ( + "x64 sse42 sandybridge ivybridge piledriver haswell skylakex " + "cannonlake cascadelake icelake cooperlake zen4 alderlake sapphirerapids" + ).split() + expected = {"llama_cpp/lib/libggml-cpu-" + name + ".so" for name in variants} + modules = {name for name in members + if pathlib.PurePosixPath(name).name.startswith("libggml-cpu-")} + assert modules == expected, {"missing": sorted(expected - modules), + "unexpected": sorted(modules - expected)} + for name in ("libggml.so", "libggml-base.so", "libllama.so", "libmtmd.so"): + assert "llama_cpp/lib/" + name in members, "Missing runtime library: " + name with tempfile.TemporaryDirectory() as root: + native_root = pathlib.Path(root) / "native" + readelf_env = dict(os.environ, LC_ALL="C") + with zipfile.ZipFile(wheel) as archive: + libraries = [name for name in archive.namelist() if re.search(r"\.so(?:\.\d+)*$", name)] + assert libraries, "Wheel contains no native libraries" + for name in libraries: + library = archive.extract(name, native_root) + with open(library, "rb") as binary: + header = binary.read(20) + assert header[:6] == b"\x7fELF\x02\x01" and int.from_bytes(header[18:20], "little") == 62, name + dynamic = subprocess.check_output(["readelf", "-dW", library], text=True, env=readelf_env) + rpaths = re.findall(r"\((?:RPATH|RUNPATH)\).*?\[(.*?)\]", dynamic) + assert all(re.fullmatch(r"\$(?:ORIGIN|\{ORIGIN\})(?:/.*)?", path) + for entry in rpaths for path in entry.split(":")), (name, rpaths) + versions = subprocess.check_output(["readelf", "--version-info", "-W", library], text=True, env=readelf_env) + needs = re.search(r"(?ms)^Version needs section.*?(?=^Version |\Z)", versions) + for namespace, maximum in (("GLIBC", (2, 17)), ("GLIBCXX", (3, 4, 19)), ("CXXABI", (1, 3, 7))): + required = re.findall(r"\bName: " + namespace + r"_([^\s]+)", needs.group() if needs else "") + assert all(re.fullmatch(r"\d+(?:\.\d+)+", version) and + tuple(map(int, version.split("."))) <= maximum + for version in required), (name, namespace, required) venv.create(root, with_pip=True) python = str(pathlib.Path(root) / "bin/python") fixtures = str(pathlib.Path(root) / "fixtures") @@ -180,6 +206,7 @@ jobs: ["-I", "-c", "import llama_cpp; print(llama_cpp.llama_print_system_info().decode())"], ["-I", "scripts/runtime-wheels/prepare_native_fixtures.py", fixtures], ["-I", "scripts/runtime-wheels/check_native_inference.py", fixtures], + ["-I", "scripts/runtime-wheels/check_native_inference.py", fixtures, "--cpu-variant", "x64"], ): subprocess.run([python, *args], check=True) - uses: actions/upload-artifact@v4 diff --git a/scripts/runtime-wheels/build-linux-wheel.sh b/scripts/runtime-wheels/build-linux-wheel.sh new file mode 100644 index 0000000..f9678d4 --- /dev/null +++ b/scripts/runtime-wheels/build-linux-wheel.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +set -euo pipefail + +script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) +mkdir -p -- "${1:-wheelhouse}" +wheelhouse=$(cd -- "${1:-wheelhouse}" && pwd) +build_dir=$(mktemp -d) +trap 'rm -rf -- "$build_dir"' EXIT + +read -r source_spec < "$script_dir/source.txt" +curl --fail --location --retry 3 --output "$build_dir/source.tar.gz" "${source_spec%%#sha256=*}" +printf '%s %s\n' "${source_spec##*#sha256=}" "$build_dir/source.tar.gz" | sha256sum --check +tar -xzf "$build_dir/source.tar.gz" -C "$build_dir" +cd "$build_dir/llama_cpp_python-0.3.36" +for patch_name in linux-backend-install-dir linux-backend-packaging linux-backend-search-path \ + linux-cpu-os-state linux-amx-permission linux-amx-gcc11 linux-q6k-avx512; do + patch --batch --fuzz=0 -p1 < "$script_dir/$patch_name.patch" +done + +bash "$script_dir/install-linux-toolchain.sh" +export PATH=/opt/python/cp38-cp38/bin:/opt/rh/devtoolset-11/root/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +export LD_LIBRARY_PATH=/opt/rh/devtoolset-11/root/usr/lib64:/opt/rh/devtoolset-11/root/usr/lib:/usr/local/lib64 +export CC=/opt/rh/devtoolset-11/root/usr/bin/gcc +export CXX=/opt/rh/devtoolset-11/root/usr/bin/g++ +export LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 +export SSL_CERT_FILE=/opt/_internal/certs.pem +export CMAKE_GENERATOR='Unix Makefiles' +export CMAKE_BUILD_PARALLEL_LEVEL=${CMAKE_BUILD_PARALLEL_LEVEL:-2} +export CMAKE_ARGS="-C $script_dir/linux-dispatch.cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON" +export SKBUILD_BUILD_DIR="$build_dir/build" + +python "$script_dir/check_linux_cpu_eligibility.py" \ + vendor/llama.cpp/ggml/src/ggml-cpu/arch/x86/cpu-feats.cpp + +python -m pip install -r "$script_dir/linux-requirements.txt" +python -m pip wheel --no-cache-dir --no-deps --no-build-isolation \ + . --wheel-dir "$build_dir/raw-wheels" +python - "$build_dir/build/compile_commands.json" <<'PY' +import json, pathlib, re, shlex, sys +commands = json.loads(pathlib.Path(sys.argv[1]).read_text()) +variants = ( + "x64 sse42 sandybridge ivybridge piledriver haswell skylakex " + "cannonlake cascadelake icelake cooperlake zen4 alderlake sapphirerapids" +).split() +optimized = {"ggml-cpu-" + name for name in variants if name != "x64"} +baseline = {"-march=x86-64", "-mtune=generic"} +scorers = [] +for command in commands: + args = command.get("arguments") or shlex.split(command["command"]) + assert not any(arg.startswith("@") for arg in args), command + assert not any(arg in ("-march=native", "-mtune=native", "-mcpu=native") or arg.startswith("-flto") + for arg in args), command + output = args[args.index("-o") + 1] + target = re.search(r"(?:^|/)CMakeFiles/([^/]+)\.dir/", output).group(1) + if target not in optimized: + assert baseline <= set(args), command + assert all(arg in baseline for arg in args if arg.startswith("-m")), command + if command["file"].endswith("/arch/x86/cpu-feats.cpp"): + scorers.append(target) + assert "-fno-lto" in args, command +assert sorted(scorers) == sorted("ggml-cpu-" + name + "-feats" for name in variants), scorers +PY +auditwheel repair --plat manylinux2014_x86_64 --only-plat \ + --wheel-dir "$wheelhouse" "$build_dir"/raw-wheels/*.whl diff --git a/scripts/runtime-wheels/check_linux_cpu_eligibility.py b/scripts/runtime-wheels/check_linux_cpu_eligibility.py new file mode 100644 index 0000000..795b0ef --- /dev/null +++ b/scripts/runtime-wheels/check_linux_cpu_eligibility.py @@ -0,0 +1,64 @@ +"""Check scorer OS-state gates using injected hardware/kernel responses.""" +import ctypes +import os +from pathlib import Path +import shlex +import subprocess +import sys +import tempfile + +source = Path(sys.argv[1]).read_text() +start = "static int ggml_backend_cpu_x86_score() {" +end = "GGML_BACKEND_DL_SCORE_IMPL(ggml_backend_cpu_x86_score)" +assert source.count(start) == source.count(end) == 1 +scorer = start + source.split(start, 1)[1].split(end, 1)[0] +xgetbv = ' __asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0));' +assert scorer.count(xgetbv) == 1 +assert scorer.count("syscall(SYS_arch_prctl, ") == 3 +scorer = scorer.replace(xgetbv, " test_xgetbv(eax, edx);") +scorer = scorer.replace("syscall(SYS_arch_prctl, ", "test_arch_prctl(") +variants = {"x64": [], "avx": ["AVX"], "avx512": ["AVX", "AVX512"], + "amx": ["AVX", "AVX512", "AMX_TILE", "AMX_INT8"]} +tile = (1 << 17) | (1 << 18) +full = tile | 0xe7 +defaults = [0, full, tile, tile, 0] +cases = [("all available", defaults, set(variants))] + +def add_case(name, index, value, eligible): + inputs = defaults.copy() + inputs[index] = value + cases.append((name, inputs, set(eligible))) + +for missing, name in enumerate(("AVX", "XSAVE", "OSXSAVE"), 1): + add_case("missing " + name, 0, missing, ["x64"]) +for bit in (1, 2, 5, 6, 7, 17, 18): + eligible = ["x64"] if bit < 3 else ["x64", "avx"] + if bit > 7: + eligible.append("avx512") + add_case("missing XCR0 bit " + str(bit), 1, full & ~(1 << bit), eligible) +without_amx = ["x64", "avx", "avx512"] +add_case("missing AMX_TILE", 0, 4, without_amx) +for index, name in ((2, "kernel support"), (3, "kernel permission")): + for bit in (17, 18): + add_case(name + " missing bit " + str(bit), index, tile & ~(1 << bit), without_amx) +for request in (0x1021, 0x1022, 0x1023): + add_case("failed arch_prctl " + hex(request), 4, request, without_amx) + +with tempfile.TemporaryDirectory(prefix="cpu-eligibility-") as temporary: + output = Path(temporary) + (output / "scorer-under-test.inc").write_text(scorer) + for name, features in variants.items(): + library = output / (name + ".so") + command = shlex.split(os.environ.get("CXX", "c++")) + [ + "-std=c++17", "-O2", "-shared", "-fPIC", "-fno-lto", + "-march=x86-64", "-mtune=generic", "-I", str(output), + *["-DGGML_" + feature for feature in features], + str(Path(__file__).with_name("linux_eligibility_probe.cpp")), "-o", str(library)] + subprocess.run(command, check=True) + score = ctypes.CDLL(str(library)).score_case + score.argtypes = [ctypes.c_int, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_int] + score.restype = ctypes.c_int + for case, inputs, eligible in cases: + actual = score(*inputs) + assert (actual > 0) == (name in eligible), (name, case, actual) + print("Passed", name, len(cases), "OS-state eligibility cases", flush=True) diff --git a/scripts/runtime-wheels/check_native_inference.py b/scripts/runtime-wheels/check_native_inference.py index ec9629a..8755dff 100644 --- a/scripts/runtime-wheels/check_native_inference.py +++ b/scripts/runtime-wheels/check_native_inference.py @@ -1,6 +1,7 @@ """Check offline CPU inference and native prefix-cache save/reload.""" import argparse +import ctypes import json import os import sys @@ -12,15 +13,58 @@ def prohibit_network(event, args): raise AssertionError("Network use during offline inference: " + event) +def check_linux_cpu_backend(llama_cpp, expected_variant=None): + if sys.platform != "linux": + return + + class DlInfo(ctypes.Structure): + _fields_ = [("filename", ctypes.c_char_p), ("base", ctypes.c_void_p), + ("symbol", ctypes.c_char_p), ("address", ctypes.c_void_p)] + + dynamic = ctypes.CDLL("libdl.so.2") + dynamic.dladdr.argtypes = [ctypes.c_void_p, ctypes.POINTER(DlInfo)] + dynamic.dladdr.restype = ctypes.c_int + native = llama_cpp.llama_cpp._lib + native.ggml_backend_reg_by_name.argtypes = [ctypes.c_char_p] + native.ggml_backend_reg_by_name.restype = ctypes.c_void_p + native.ggml_backend_reg_get_proc_address.argtypes = [ctypes.c_void_p, ctypes.c_char_p] + native.ggml_backend_reg_get_proc_address.restype = ctypes.c_void_p + registry = native.ggml_backend_reg_by_name(b"CPU") + assert registry, "CPU backend is not registered" + function = native.ggml_backend_reg_get_proc_address(registry, b"ggml_backend_get_features") + assert function, "Registered CPU backend lacks its feature function" + location = DlInfo() + assert dynamic.dladdr(function, ctypes.byref(location)) and location.filename, "Cannot locate CPU backend" + module = Path(os.fsdecode(location.filename)).resolve() + library_dir = (Path(llama_cpp.__file__).resolve().parent / "lib").resolve() + assert module.parent == library_dir, (module, library_dir) + assert module.name.startswith("libggml-cpu-") and module.name.endswith(".so"), module + if expected_variant: + assert module.name == "libggml-cpu-" + expected_variant + ".so", module + print("CPU backend:", module.name, flush=True) + + def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("cache_dir", type=Path) + parser.add_argument("--cpu-variant", choices=("x64",)) args = parser.parse_args() os.environ["PAW_CACHE_DIR"] = str(args.cache_dir.resolve()) os.environ["PAW_OFFLINE"] = "1" os.environ["GGML_METAL_DEVICES"] = "0" sys.addaudithook(prohibit_network) import llama_cpp + if args.cpu_variant: + assert sys.platform == "linux", "Explicit CPU variants require Linux" + native = llama_cpp.llama_cpp._lib + native.ggml_backend_reg_count.argtypes = [] + native.ggml_backend_reg_count.restype = ctypes.c_size_t + assert native.ggml_backend_reg_count() == 0, "Backends were initialized before explicit loading" + native.ggml_backend_load.argtypes = [ctypes.c_char_p] + native.ggml_backend_load.restype = ctypes.c_void_p + module = Path(llama_cpp.__file__).resolve().parent / "lib" / ("libggml-cpu-" + args.cpu_variant + ".so") + assert native.ggml_backend_load(os.fsencode(module)), module + assert native.ggml_backend_reg_count() == 1, "Expected one explicitly loaded backend" import programasweights as paw events = [] @@ -47,6 +91,7 @@ def traced(*values, _native=native, _name=name): events.clear() with paw.function(program_id, offline=True, n_gpu_layers=0) as fn: assert fn._adapter is not None and fn._n_prefix > 0 + check_linux_cpu_backend(llama_cpp, args.cpu_variant) for text, expected in cases: actual = fn(text) assert actual == expected, (fixture["label"], state, text, actual) diff --git a/scripts/runtime-wheels/install-linux-toolchain.sh b/scripts/runtime-wheels/install-linux-toolchain.sh new file mode 100644 index 0000000..9a6e1ac --- /dev/null +++ b/scripts/runtime-wheels/install-linux-toolchain.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail + +script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) +download_dir=$(mktemp -d) +trap 'rm -rf -- "$download_dir"' EXIT +base_url=https://vault.centos.org/7.9.2009/sclo/x86_64/rh/Packages/d + +while read -r expected_sha256 package; do + curl --fail --location --retry 3 \ + --output "$download_dir/$package" "$base_url/$package" +done < "$script_dir/linux-toolchain.sha256" + +cd "$download_dir" +sha256sum --check "$script_dir/linux-toolchain.sha256" +rpm -Uvh ./*.rpm diff --git a/scripts/runtime-wheels/linux-amx-gcc11.patch b/scripts/runtime-wheels/linux-amx-gcc11.patch new file mode 100644 index 0000000..bc0a2eb --- /dev/null +++ b/scripts/runtime-wheels/linux-amx-gcc11.patch @@ -0,0 +1,17 @@ +--- a/vendor/llama.cpp/ggml/src/ggml-cpu/amx/mmq.cpp ++++ b/vendor/llama.cpp/ggml/src/ggml-cpu/amx/mmq.cpp +@@ -220,7 +220,14 @@ + tc.rows[6] = 16; tc.colsb[6] = 64; + tc.rows[7] = 16; tc.colsb[7] = 64; + ++#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ == 11 ++ // GCC PR114098: GCC 11's intrinsic declares only an 8-byte memory input, ++ // but LDTILECFG reads all 64 bytes. Preserve the entire configuration. ++ static_assert(sizeof(tile_config_t) == 64, "Unexpected AMX tile configuration size"); ++ __asm__ volatile ("ldtilecfg\t%X0" :: "m" (tc) : "memory"); ++#else + _tile_loadconfig(&tc); ++#endif + done = true; + } + diff --git a/scripts/runtime-wheels/linux-amx-permission.patch b/scripts/runtime-wheels/linux-amx-permission.patch new file mode 100644 index 0000000..8df85ba --- /dev/null +++ b/scripts/runtime-wheels/linux-amx-permission.patch @@ -0,0 +1,42 @@ +--- a/vendor/llama.cpp/ggml/src/ggml-cpu/arch/x86/cpu-feats.cpp ++++ b/vendor/llama.cpp/ggml/src/ggml-cpu/arch/x86/cpu-feats.cpp +@@ -14,2 +14,7 @@ + #include ++ ++#if defined(__linux__) && (defined(GGML_AMX_TILE) || defined(GGML_AMX_INT8) || defined(GGML_AMX_BF16)) ++#include ++#include ++#endif + +@@ -315,2 +320,8 @@ + #endif ++#if defined(GGML_AMX_TILE) || defined(GGML_AMX_INT8) || defined(GGML_AMX_BF16) ++ if (!is.AMX_TILE()) { return 0; } ++#endif ++#ifdef GGML_AMX_BF16 ++ if (!is.AMX_BF16()) { return 0; } ++#endif + #ifdef GGML_AMX_INT8 +@@ -342,2 +353,22 @@ + #endif ++#if defined(GGML_AMX_TILE) || defined(GGML_AMX_INT8) || defined(GGML_AMX_BF16) ++ constexpr uint64_t tile_state = (uint64_t(1) << 17) | (uint64_t(1) << 18); ++ if ((xcr0 & tile_state) != tile_state) { return 0; } ++#if defined(__linux__) ++ constexpr int arch_get_xcomp_supp = 0x1021; ++ constexpr int arch_get_xcomp_perm = 0x1022; ++ constexpr int arch_req_xcomp_perm = 0x1023; ++ uint64_t supported = 0, permitted = 0; ++ // XCR0 alone does not grant AMX permission; the kernel may deny it, for ++ // example when an existing signal altstack cannot hold the larger state. ++ if (syscall(SYS_arch_prctl, arch_get_xcomp_supp, &supported) != 0 || ++ (supported & tile_state) != tile_state || ++ syscall(SYS_arch_prctl, arch_req_xcomp_perm, 18) != 0 || ++ syscall(SYS_arch_prctl, arch_get_xcomp_perm, &permitted) != 0 || ++ (permitted & tile_state) != tile_state) { return 0; } ++#else ++ // AMX dispatch requires the Linux permission API. ++ return 0; ++#endif ++#endif + #endif diff --git a/scripts/runtime-wheels/linux-backend-install-dir.patch b/scripts/runtime-wheels/linux-backend-install-dir.patch new file mode 100644 index 0000000..8246d21 --- /dev/null +++ b/scripts/runtime-wheels/linux-backend-install-dir.patch @@ -0,0 +1,14 @@ +--- a/vendor/llama.cpp/ggml/src/CMakeLists.txt ++++ b/vendor/llama.cpp/ggml/src/CMakeLists.txt +@@ -385,7 +385,10 @@ + set_target_properties(${backend} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + target_compile_definitions(${backend} PRIVATE GGML_BACKEND_DL) + add_dependencies(ggml ${backend}) +- if (GGML_BACKEND_DIR) ++ if (GGML_BACKEND_INSTALL_DIR) ++ # Allow package-local installation without compiling that path into ggml. ++ install(TARGETS ${backend} LIBRARY DESTINATION ${GGML_BACKEND_INSTALL_DIR}) ++ elseif (GGML_BACKEND_DIR) + install(TARGETS ${backend} LIBRARY DESTINATION ${GGML_BACKEND_DIR}) + else() + install(TARGETS ${backend} LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/scripts/runtime-wheels/linux-backend-packaging.patch b/scripts/runtime-wheels/linux-backend-packaging.patch new file mode 100644 index 0000000..afae284 --- /dev/null +++ b/scripts/runtime-wheels/linux-backend-packaging.patch @@ -0,0 +1,30 @@ +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -131,6 +131,12 @@ + endif() + + ++ # Keep dynamically loaded CPU variants inside the Python package. This is ++ # an install destination only, not a build-machine backend search path. ++ if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND GGML_BACKEND_DL AND GGML_CPU_ALL_VARIANTS) ++ set(GGML_BACKEND_INSTALL_DIR "${SKBUILD_PLATLIB_DIR}/llama_cpp/lib") ++ endif() ++ + add_subdirectory(vendor/llama.cpp) + + if (WIN32) +@@ -148,6 +154,14 @@ + llama_cpp_python_install_target(ggml-blas) + llama_cpp_python_install_target(ggml-can) + llama_cpp_python_install_target(ggml-cpu) ++ if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND GGML_BACKEND_DL AND GGML_CPU_ALL_VARIANTS) ++ foreach(backend IN LISTS GGML_AVAILABLE_BACKENDS) ++ if(backend MATCHES "^ggml-cpu-" AND TARGET ${backend}) ++ llama_cpp_python_install_target(${backend}) ++ set_target_properties(${backend} PROPERTIES INSTALL_RPATH_USE_LINK_PATH FALSE) ++ endif() ++ endforeach() ++ endif() + llama_cpp_python_install_target(ggml-cuda) + llama_cpp_python_install_target(ggml-hip) + llama_cpp_python_install_target(ggml-kompute) diff --git a/scripts/runtime-wheels/linux-backend-search-path.patch b/scripts/runtime-wheels/linux-backend-search-path.patch new file mode 100644 index 0000000..f224dea --- /dev/null +++ b/scripts/runtime-wheels/linux-backend-search-path.patch @@ -0,0 +1,37 @@ +--- a/vendor/llama.cpp/ggml/src/ggml-backend-reg.cpp ++++ b/vendor/llama.cpp/ggml/src/ggml-backend-reg.cpp +@@ -461,6 +461,18 @@ + #endif + } + ++#if defined(__linux__) ++static fs::path get_library_path() { ++ // An internal data address identifies this library without PLT interposition. ++ static int library_anchor; ++ Dl_info info = {}; ++ if (dladdr(&library_anchor, &info) != 0 && info.dli_fname && info.dli_fname[0]) { ++ return fs::u8path(info.dli_fname).parent_path(); ++ } ++ return {}; ++} ++#endif ++ + static fs::path backend_filename_prefix() { + #ifdef _WIN32 + return fs::u8path("ggml-"); +@@ -488,7 +500,14 @@ + #ifdef GGML_BACKEND_DIR + search_paths.push_back(fs::u8path(GGML_BACKEND_DIR)); + #endif +- // default search paths: executable directory, current directory ++ // Python wheels keep backends beside this library, not the interpreter. ++#if defined(__linux__) ++ const fs::path library_path = get_library_path(); ++ if (!library_path.empty()) { ++ search_paths.push_back(library_path); ++ } ++#endif ++ // Also preserve the executable-directory and current-directory defaults. + search_paths.push_back(get_executable_path()); + std::error_code cwd_ec; + const fs::path cwd = fs::current_path(cwd_ec); diff --git a/scripts/runtime-wheels/linux-cpu-os-state.patch b/scripts/runtime-wheels/linux-cpu-os-state.patch new file mode 100644 index 0000000..c1f4c10 --- /dev/null +++ b/scripts/runtime-wheels/linux-cpu-os-state.patch @@ -0,0 +1,38 @@ +--- a/vendor/llama.cpp/ggml/src/ggml-cpu/arch/x86/cpu-feats.cpp ++++ b/vendor/llama.cpp/ggml/src/ggml-cpu/arch/x86/cpu-feats.cpp +@@ -8,2 +8,3 @@ + ++#include + #include +@@ -263,4 +264,2 @@ + static int ggml_backend_cpu_x86_score() { +- // FIXME: this does not check for OS support +- + int score = 1; +@@ -321,2 +320,26 @@ + ++ ++#if defined(GGML_AVX) || defined(GGML_AVX2) || defined(GGML_FMA) || defined(GGML_F16C) || \ ++ defined(GGML_AVX_VNNI) || defined(GGML_AVX512) || defined(GGML_AVX512_VBMI) || \ ++ defined(GGML_AVX512_VNNI) || defined(GGML_AVX512_BF16) || \ ++ defined(GGML_AMX_TILE) || defined(GGML_AMX_INT8) || defined(GGML_AMX_BF16) ++ // XGETBV itself is unsafe until the CPU and OS advertise XSAVE support. ++ if (!is.AVX() || !is.XSAVE() || !is.OSXSAVE()) { return 0; } ++ uint64_t xcr0; ++#ifdef _MSC_VER ++ xcr0 = _xgetbv(0); ++#else ++ uint32_t eax, edx; ++ __asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0)); ++ xcr0 = (uint64_t(edx) << 32) | eax; ++#endif ++ // AVX, FMA and F16C all require OS preservation of XMM and YMM state. ++ if ((xcr0 & 0x6) != 0x6) { return 0; } ++#if defined(GGML_AVX512) || defined(GGML_AVX512_VBMI) || \ ++ defined(GGML_AVX512_VNNI) || defined(GGML_AVX512_BF16) ++ // AVX-512 additionally requires opmask, ZMM_Hi256 and Hi16_ZMM state. ++ if ((xcr0 & 0xe6) != 0xe6) { return 0; } ++#endif ++#endif ++ + return score; diff --git a/scripts/runtime-wheels/linux-dispatch.cmake b/scripts/runtime-wheels/linux-dispatch.cmake new file mode 100644 index 0000000..6705545 --- /dev/null +++ b/scripts/runtime-wheels/linux-dispatch.cmake @@ -0,0 +1,9 @@ +set(CMAKE_INSTALL_RPATH "$ORIGIN" CACHE STRING "") +set(CMAKE_C_FLAGS "-march=x86-64 -mtune=generic" CACHE STRING "") +set(CMAKE_CXX_FLAGS "-march=x86-64 -mtune=generic" CACHE STRING "") +foreach(feature IN ITEMS GGML_BACKEND_DL GGML_CPU_ALL_VARIANTS GGML_LLAMAFILE GGML_OPENMP GGML_CPU_REPACK) + set(${feature} ON CACHE BOOL "" FORCE) +endforeach() +foreach(feature IN ITEMS GGML_NATIVE GGML_BLAS GGML_CUDA LLAMA_OPENSSL GGML_CCACHE GGML_LTO) + set(${feature} OFF CACHE BOOL "" FORCE) +endforeach() diff --git a/scripts/runtime-wheels/linux-q6k-avx512.patch b/scripts/runtime-wheels/linux-q6k-avx512.patch new file mode 100644 index 0000000..72eba5b --- /dev/null +++ b/scripts/runtime-wheels/linux-q6k-avx512.patch @@ -0,0 +1,10 @@ +--- a/vendor/llama.cpp/ggml/src/ggml-cpu/amx/amx.cpp ++++ b/vendor/llama.cpp/ggml/src/ggml-cpu/amx/amx.cpp +@@ -170,7 +170,6 @@ + break; + case GGML_TYPE_Q4_K: + case GGML_TYPE_Q5_K: +- case GGML_TYPE_Q6_K: + case GGML_TYPE_IQ4_XS: + alignment = 256; // QK_K + break; diff --git a/scripts/runtime-wheels/linux-toolchain.sha256 b/scripts/runtime-wheels/linux-toolchain.sha256 new file mode 100644 index 0000000..9a074b3 --- /dev/null +++ b/scripts/runtime-wheels/linux-toolchain.sha256 @@ -0,0 +1,5 @@ +ac350205a9316c777f842fa3451dc786ba9b058ca997776b73e4aa221908c84e devtoolset-11-runtime-11.1-2.el7.x86_64.rpm +dde2f4b967e4a379caf1c38f756029799d610d8911f0c13b1f4f94a5d7a93561 devtoolset-11-binutils-2.36.1-1.el7.2.x86_64.rpm +7049c0fdcee4412cf0e2570e2ed90e4879019aa58b9c7d1112e85260ead0ec30 devtoolset-11-gcc-11.2.1-9.1.el7.x86_64.rpm +adbf4b0743fa1227da7d93ef8236e20aa7ea5bda67965baadf782095bfee540f devtoolset-11-gcc-c++-11.2.1-9.1.el7.x86_64.rpm +b42d3c7ff9f4da0f7fedd354051b002fe68dbb56dc59c713c61bdf92773b3d9c devtoolset-11-libstdc++-devel-11.2.1-9.1.el7.x86_64.rpm diff --git a/scripts/runtime-wheels/linux_eligibility_probe.cpp b/scripts/runtime-wheels/linux_eligibility_probe.cpp new file mode 100644 index 0000000..ffd26c0 --- /dev/null +++ b/scripts/runtime-wheels/linux_eligibility_probe.cpp @@ -0,0 +1,52 @@ +// Test only: the generated include contains the actual patched scorer function. +#include +#include + +enum MissingFeature { NONE, CPU_AVX, CPU_XSAVE, CPU_OSXSAVE, CPU_AMX_TILE }; +static int missing_feature, failed_request; +static uint64_t xcr0_value, supported_state, permitted_state; + +struct cpuid_x86 { + bool AVX() { return missing_feature != CPU_AVX; } + bool XSAVE() { return missing_feature != CPU_XSAVE; } + bool OSXSAVE() { return missing_feature != CPU_OSXSAVE; } + bool AMX_TILE() { return missing_feature != CPU_AMX_TILE; } + bool AMX_INT8() { return true; } + bool AVX512F() { return true; } + bool AVX512CD() { return true; } + bool AVX512VL() { return true; } + bool AVX512DQ() { return true; } + bool AVX512BW() { return true; } +}; + +static void test_xgetbv(uint32_t & eax, uint32_t & edx) { + // A regressed guard must fail even on a host where XGETBV would succeed. + if (missing_feature >= CPU_AVX && missing_feature <= CPU_OSXSAVE) { + std::abort(); + } + eax = uint32_t(xcr0_value); + edx = uint32_t(xcr0_value >> 32); +} + +static long test_arch_prctl(int request, uint64_t * state) { + if (request != 0x1021 && request != 0x1022) { std::abort(); } + *state = request == 0x1021 ? supported_state : permitted_state; + return request == failed_request ? -1 : 0; +} + +static long test_arch_prctl(int request, int feature) { + if (request != 0x1023 || feature != 18) { std::abort(); } + return request == failed_request ? -1 : 0; +} + +#include "scorer-under-test.inc" + +extern "C" int score_case(int missing, uint64_t xcr0, uint64_t supported, + uint64_t permitted, int denied_request) { + missing_feature = missing; + xcr0_value = xcr0; + supported_state = supported; + permitted_state = permitted; + failed_request = denied_request; + return ggml_backend_cpu_x86_score(); +}