diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a31cdcb..8b96f8dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,13 @@ The format is based on Keep a Changelog. fallback now consume the same source of truth, with runtime limit settings applied only when describing the active server. +### Runtime + +- refreshed the owned MLX and mlx-swift forks onto current upstream cutoffs, + retained the scoped 1-bit, NVFP4, CUDA, stream-safety, and M4/H3 patches, + made the generated NAX optimizations source-reproducible, and regenerated + the provenance-locked Metal library from the new immutable revisions. + ### Music - accelerated MiniMax Music 3 on Apple Silicon with a reachable 16,385-row diff --git a/Package.resolved b/Package.resolved index 25ad8b86..a755cda5 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "64edf531b07c049be9050a514f9b307d693b7feff677f33aa351c11bd7b33d9d", + "originHash" : "3c37bc1e7e3ec1a0e3a286cf5bf0f62289add03ddf860edb4d8b94f84a1bcfdb", "pins" : [ { "identity" : "async-http-client", @@ -33,7 +33,7 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/sawfwair/mlx-swift", "state" : { - "revision" : "22c76cc40edbae2c2af72532678d8e5c06cbfa46" + "revision" : "3e6df6d8163a8f212061d15739eeeec12d5b89e3" } }, { diff --git a/Package.swift b/Package.swift index 18acf0d1..a9454cfa 100644 --- a/Package.swift +++ b/Package.swift @@ -510,7 +510,7 @@ if !isLinuxPackage { var packageDependencies: [Package.Dependency] = (useLinuxPrebuiltMLX ? [] : [ .package( url: "https://github.com/sawfwair/mlx-swift", - revision: "22c76cc40edbae2c2af72532678d8e5c06cbfa46" + revision: "3e6df6d8163a8f212061d15739eeeec12d5b89e3" ) ]) + [ .package( diff --git a/Sources/MereRunCLI/Support/MLXBundleSupport.swift b/Sources/MereRunCLI/Support/MLXBundleSupport.swift index 37b6b2ea..ce4e5051 100644 --- a/Sources/MereRunCLI/Support/MLXBundleSupport.swift +++ b/Sources/MereRunCLI/Support/MLXBundleSupport.swift @@ -27,8 +27,8 @@ enum MLXBundleSupport { static let expectedProvenance = MetallibProvenance( coreVersion: "0.32.1", - swiftRevision: "22c76cc40edbae2c2af72532678d8e5c06cbfa46", - kernelSourcesSHA256: "961bc42bb4161801fb8b0f7fd9d4570e7e86318f1644520bb39eae04eed9820c" + swiftRevision: "3e6df6d8163a8f212061d15739eeeec12d5b89e3", + kernelSourcesSHA256: "fb0c62d372d6aaa75edfbcb950d9dd797fce944a7df7bcde24dce2a672024be5" ) /// Relationship between a bundle's metallib version stamp diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index eec0c859..ee7f946e 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -716,10 +716,10 @@ SOFTWARE. - source project: [`sawfwair/mlx-swift`](https://github.com/sawfwair/mlx-swift), based on upstream [`ml-explore/mlx-swift`](https://github.com/ml-explore/mlx-swift) 0.32.1 -- pinned package revision: `22c76cc40edbae2c2af72532678d8e5c06cbfa46` -- embedded MLX revision: `2a977448c20451eb4f100691bd2f6513e610f150` +- pinned package revision: `3e6df6d8163a8f212061d15739eeeec12d5b89e3` +- embedded MLX revision: `b57bd7640f3f7c743b76a58478faaf1e8ee084f2` - generated-kernel source SHA-256: - `961bc42bb4161801fb8b0f7fd9d4570e7e86318f1644520bb39eae04eed9820c` + `fb0c62d372d6aaa75edfbcb950d9dd797fce944a7df7bcde24dce2a672024be5` - license: MIT ``` diff --git a/Tests/MereRunCLITests/LinuxNativeBridgeTests.swift b/Tests/MereRunCLITests/LinuxNativeBridgeTests.swift index 67b6bff3..4e820809 100644 --- a/Tests/MereRunCLITests/LinuxNativeBridgeTests.swift +++ b/Tests/MereRunCLITests/LinuxNativeBridgeTests.swift @@ -110,6 +110,9 @@ final class LinuxNativeBridgeTests: XCTestCase { XCTAssertTrue(packageScript.contains("cuda_runtime_root")) XCTAssertTrue(packageScript.contains("export CUDA_HOME=\"$cuda_runtime_root\"")) XCTAssertTrue(packageScript.contains("export CUDA_PATH=\"$CUDA_HOME\"")) + XCTAssertTrue(packageScript.contains("cuda_runtime_library_candidates")) + XCTAssertTrue(packageScript.contains("$cuda_root/targets/$cuda_target/lib")) + XCTAssertTrue(packageScript.contains("LD_LIBRARY_PATH=\"$LD_LIBRARY_PATH:$cuda_runtime_library\"")) XCTAssertTrue(packageScript.contains("MERERUN_LLAMA_CLI")) XCTAssertTrue(packageScript.contains("$llama_prefix/bin/llama-cli")) XCTAssertTrue(packageScript.contains("cuda_root/include/cccl")) diff --git a/docs/mlx-swift-fork.md b/docs/mlx-swift-fork.md index c85f491a..1cdde403 100644 --- a/docs/mlx-swift-fork.md +++ b/docs/mlx-swift-fork.md @@ -1,23 +1,62 @@ # mlx-swift fork policy and compiled-call overhead -mere-run pins the public `sawfwair/mlx-swift` fork based on upstream 0.32.1. -That fork carries the Linux package bridge and Prism low-bit compatibility -needed by this repository. Its embedded `sawfwair/mlx` revision also provides -native affine 1-bit CUDA quantize, dequantize, and QMV execution, plus the -Metal affine 1-bit path and the generation-17 NAX correctness gate. The fork -retains upstream's NVFP4 split-K fix and drops the old duplicate `qmv_wide` -implementation now supplied upstream. Changes stay scoped to their bit width, -group size, quantization mode, and backend so stock 2-bit and wider models keep -their existing paths. +mere-run pins the public `sawfwair/mlx-swift` fork at +`3e6df6d8163a8f212061d15739eeeec12d5b89e3`. It is rebased onto upstream +`mlx-swift` `da318704cc0e972b61dcca43c62cd15e545362ae`, including the upstream +`MLXArray` finalizer fix and generated-source-list maintenance. The embedded +`sawfwair/mlx` revision is +`b57bd7640f3f7c743b76a58478faaf1e8ee084f2`, based on upstream MLX +`bd5c3a2b170bb95340482e35b2a49fb08aea4de3` and retaining the 0.32.1 ABI. + +The owned patch stack carries the Linux/CUDA package bridge, executor-safe +Swift streams, native affine 1-bit CUDA quantize/dequantize/QMV execution, the +Metal affine 1-bit path, custom quantized-kernel headers, NVFP4 staging, the +generation-17 NAX correctness gate, and M4/H3 tuning. The obsolete unaligned +1-bit fast-kernel tail was not replayed because upstream now requires aligned +fast dispatch; the fork instead tests matching host/kernel alignment directly. +Changes stay scoped to their bit width, group size, quantization mode, and +backend so stock 2-bit and wider models keep their existing paths. The current pin also lets an MLXFast custom Metal kernel explicitly request the core quantized helper headers. The source marker `MLX_INCLUDE_FP_QUANTIZED_HEADERS` exposes the NVFP4 helpers, while `MLX_INCLUDE_AFFINE_QUANTIZED_HEADERS` exposes the affine helpers. Kernels -without either marker compile from the unchanged default header set. The -embedded MLX core revision is `9bee51623d5a34806821e0f414fae293f90dda19`; -the mlx-swift revision pinned by mere.run is -`a9485c38b82b8e0cee76e8f1f5a3e5bf6f36d543`. +without either marker compile from the unchanged default header set. The NAX +attention and gather-tile optimizations now live in MLX core source, so +regenerating mlx-swift's AOT sources reproduces them instead of depending on +generated-file-only commits. + +## Refresh procedure + +Refresh the dependency chain from the bottom up and publish it in the same +order: + +1. Record immutable upstream cutoffs for both repositories and classify every + fork-only commit as replay, replace with upstream, or drop with a regression + test. Rebase the MLX core fork first. +2. Build an installable MLX wheel from the rebased core, run the full core gate, + and exercise every owned quantization mode on its actual backend. Do not + treat source compilation as runtime proof. +3. Update mlx-swift's MLX submodule to the reviewed core revision, regenerate + AOT sources, regenerate a second time to prove the tree is idempotent, and + run the full Xcode test plan so the Metal shader bundle is present. +4. Publish the reviewed core revision, then pin that immutable revision from + mlx-swift and publish the reviewed Swift revision. Never make mere.run depend + on an unpushed or floating dependency ref. +5. Pin the immutable mlx-swift revision in `Package.swift` and + `Package.resolved`, rebuild the vendored Metal library, and update all three + provenance fields: Swift revision, core version, and generated-source hash. +6. Run `./scripts/check.sh`, followed by both supported runtime gates: + `MERERUN_RUN_E2E=core ./scripts/check.sh` and + `MERERUN_RUN_E2E=installed ./scripts/check.sh`. Include a real generation + smoke for any model family implicated by the changed stream, quantization, + or kernel paths. +7. Open dependency-ordered draft pull requests (MLX, mlx-swift, mere.run), link + them explicitly, and merge only after the downstream pin and platform CI are + green against the exact advertised SHAs. + +Perform this audit at least once per upstream minor release, and sooner for a +security fix or a correctness/performance change in a path mere.run owns. A separate measured one-line compiled-call optimization exists on staging branches but is **deliberately not included in the pin**. The rest of this @@ -75,8 +114,8 @@ architecture exercises it" is past the threshold to hold it back. *independent* compiled functions (and new shapes of shared ones) from multiple threads. Repeated calls to a single closure — including the existing `MLXCompiledFunctionOverheadTests` micro-bench — cannot catch - this class. (Prerequisite: fix the `default.metallib` packaging issue that - currently blocks Metal-backed concurrency tests in the test bundle.) + this class. Run it through Xcode, which builds the Metal shader bundle; + command-line SwiftPM alone cannot build that bundle. Do **not** upstream or re-pin the lock removal alone. diff --git a/docs/runtime/geo.md b/docs/runtime/geo.md index de9ba0cf..70cf3ce8 100644 --- a/docs/runtime/geo.md +++ b/docs/runtime/geo.md @@ -1,7 +1,7 @@ # Geospatial Runtime `mere.run geo` is a local-first inference boundary for Earth-observation and -humanitarian workflows. Any +humanitarian workflows. Any workflow can prepare the documented tensors, run the native model locally, and carry the resulting candidates or embeddings into its own evidence process. diff --git a/scripts/e2e_smoke.sh b/scripts/e2e_smoke.sh index f0e73c00..45695bf9 100755 --- a/scripts/e2e_smoke.sh +++ b/scripts/e2e_smoke.sh @@ -180,7 +180,8 @@ core_suite() { if require_model "speech-asr-qwen3" && [[ -f "$speech_tts_wav" ]]; then run_step "speech_transcribe_qwen3" 300 \ "$MERERUN_BIN" speech transcribe "$speech_tts_wav" --backend qwen --model speech-asr-qwen3 --no-timestamps --quiet - assert_contains "speech_transcribe_qwen3_output" "$OUT_DIR/speech_transcribe_qwen3.stdout" "local inference smoke test" + assert_contains "speech_transcribe_qwen3_output" "$OUT_DIR/speech_transcribe_qwen3.stdout" \ + "local inference[^[:alnum:]]+smoke[^[:alnum:]]+test" fi if require_model "text-chat-q36-nano"; then diff --git a/scripts/package-linux.sh b/scripts/package-linux.sh index 3afe3533..db83cc21 100755 --- a/scripts/package-linux.sh +++ b/scripts/package-linux.sh @@ -246,6 +246,7 @@ mlx_swift_cuda_link_flags() { local local_openblas_root="$native_root/deps/apt-root" local cudnn_library_path="${CUDNN_LIBRARY_PATH:-}" local cuda_library_path="${CUDA_LIBRARY_PATH:-}" + local cuda_library_paths=() local cuda_stub_library_path="${CUDA_STUB_LIBRARY_PATH:-}" local flags=() @@ -292,11 +293,13 @@ mlx_swift_cuda_link_flags() { fi done fi - if [[ -z "$cuda_library_path" ]]; then + if [[ -n "$cuda_library_path" ]]; then + cuda_library_paths+=("$cuda_library_path") + else local cuda_library_candidates=() local cuda_root while IFS= read -r cuda_root; do - cuda_library_candidates+=("$cuda_root/lib64") + cuda_library_candidates+=("$cuda_root/lib64" "$cuda_root/lib") local cuda_target for cuda_target in "${cuda_target_names[@]}"; do cuda_library_candidates+=("$cuda_root/targets/$cuda_target/lib") @@ -304,13 +307,18 @@ mlx_swift_cuda_link_flags() { done < <(cuda_toolkit_root_candidates) for candidate in "${cuda_library_candidates[@]}"; do if [[ -f "$candidate/libcublasLt.so" || -f "$candidate/libnvrtc.so" || -f "$candidate/libcudart.so" ]]; then - cuda_library_path="$candidate" - break + cuda_library_paths+=("$candidate") fi done fi - if [[ -z "$cuda_stub_library_path" && - ( -z "$cuda_library_path" || ! -f "$cuda_library_path/libcuda.so" ) ]]; then + local cuda_driver_link_available=0 + for candidate in "${cuda_library_paths[@]}"; do + if [[ -f "$candidate/libcuda.so" ]]; then + cuda_driver_link_available=1 + break + fi + done + if [[ -z "$cuda_stub_library_path" && "$cuda_driver_link_available" != "1" ]]; then local cuda_stub_candidates=() local cuda_root while IFS= read -r cuda_root; do @@ -327,13 +335,13 @@ mlx_swift_cuda_link_flags() { fi done fi - if [[ -n "$cuda_library_path" ]]; then - flags+=("-L" "$cuda_library_path") - if [[ "$(basename "$cuda_library_path")" != "stubs" ]]; then - flags+=("-Xlinker" "-rpath" "-Xlinker" "$cuda_library_path") + for candidate in "${cuda_library_paths[@]}"; do + flags+=("-L" "$candidate") + if [[ "$(basename "$candidate")" != "stubs" ]]; then + flags+=("-Xlinker" "-rpath" "-Xlinker" "$candidate") fi - fi - if [[ -n "$cuda_stub_library_path" && "$cuda_stub_library_path" != "$cuda_library_path" ]]; then + done + if [[ -n "$cuda_stub_library_path" ]]; then flags+=("-L" "$cuda_stub_library_path") fi if [[ -d /usr/lib/$deb_multiarch ]]; then @@ -493,6 +501,29 @@ for cuda_cccl_include in "${cuda_cccl_candidates[@]}"; do fi done export LD_LIBRARY_PATH="$payload_dir/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" +if [[ -f "$payload_dir/.mererun-linux-cuda" ]]; then + cuda_runtime_library_candidates=() + for cuda_root in \ + "${CUDA_HOME:-}" \ + "${CUDA_PATH:-}" \ + /usr/local/cuda \ + /usr/local/cuda-* \ + /usr + do + [[ -n "$cuda_root" && -d "$cuda_root" ]] || continue + cuda_runtime_library_candidates+=("$cuda_root/lib64" "$cuda_root/lib") + for cuda_target in sbsa-linux aarch64-linux x86_64-linux; do + cuda_runtime_library_candidates+=("$cuda_root/targets/$cuda_target/lib") + done + done + for cuda_runtime_library in "${cuda_runtime_library_candidates[@]}"; do + [[ -d "$cuda_runtime_library" ]] || continue + case ":$LD_LIBRARY_PATH:" in + *":$cuda_runtime_library:"*) ;; + *) export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$cuda_runtime_library" ;; + esac + done +fi exec "$payload_dir/mere.run-bin" "$@" WRAPPER chmod +x "$payload_dir/mere.run" diff --git a/scripts/prepare-linux-native.sh b/scripts/prepare-linux-native.sh index f156d806..57eeebee 100755 --- a/scripts/prepare-linux-native.sh +++ b/scripts/prepare-linux-native.sh @@ -885,6 +885,7 @@ mlx_swift_cuda_link_flags() { local local_openblas_root="$native_root/deps/apt-root" local cudnn_library_path="${CUDNN_LIBRARY_PATH:-}" local cuda_library_path="${CUDA_LIBRARY_PATH:-}" + local cuda_library_paths=() local cuda_stub_library_path="${CUDA_STUB_LIBRARY_PATH:-}" local flags=() @@ -931,11 +932,13 @@ mlx_swift_cuda_link_flags() { fi done fi - if [[ -z "$cuda_library_path" ]]; then + if [[ -n "$cuda_library_path" ]]; then + cuda_library_paths+=("$cuda_library_path") + else local cuda_library_candidates=() local cuda_root while IFS= read -r cuda_root; do - cuda_library_candidates+=("$cuda_root/lib64") + cuda_library_candidates+=("$cuda_root/lib64" "$cuda_root/lib") local cuda_target for cuda_target in "${cuda_target_names[@]}"; do cuda_library_candidates+=("$cuda_root/targets/$cuda_target/lib") @@ -943,13 +946,18 @@ mlx_swift_cuda_link_flags() { done < <(cuda_toolkit_root_candidates) for candidate in "${cuda_library_candidates[@]}"; do if [[ -f "$candidate/libcublasLt.so" || -f "$candidate/libnvrtc.so" || -f "$candidate/libcudart.so" ]]; then - cuda_library_path="$candidate" - break + cuda_library_paths+=("$candidate") fi done fi - if [[ -z "$cuda_stub_library_path" && - ( -z "$cuda_library_path" || ! -f "$cuda_library_path/libcuda.so" ) ]]; then + local cuda_driver_link_available=0 + for candidate in "${cuda_library_paths[@]}"; do + if [[ -f "$candidate/libcuda.so" ]]; then + cuda_driver_link_available=1 + break + fi + done + if [[ -z "$cuda_stub_library_path" && "$cuda_driver_link_available" != "1" ]]; then local cuda_stub_candidates=() local cuda_root while IFS= read -r cuda_root; do @@ -966,13 +974,13 @@ mlx_swift_cuda_link_flags() { fi done fi - if [[ -n "$cuda_library_path" ]]; then - flags+=("-L" "$cuda_library_path") - if [[ "$(basename "$cuda_library_path")" != "stubs" ]]; then - flags+=("-Xlinker" "-rpath" "-Xlinker" "$cuda_library_path") + for candidate in "${cuda_library_paths[@]}"; do + flags+=("-L" "$candidate") + if [[ "$(basename "$candidate")" != "stubs" ]]; then + flags+=("-Xlinker" "-rpath" "-Xlinker" "$candidate") fi - fi - if [[ -n "$cuda_stub_library_path" && "$cuda_stub_library_path" != "$cuda_library_path" ]]; then + done + if [[ -n "$cuda_stub_library_path" ]]; then flags+=("-L" "$cuda_stub_library_path") fi if [[ -d /usr/lib/$deb_multiarch ]]; then diff --git a/scripts/test-package-linux.sh b/scripts/test-package-linux.sh index 5b553637..1c5888e1 100755 --- a/scripts/test-package-linux.sh +++ b/scripts/test-package-linux.sh @@ -50,6 +50,7 @@ if [[ "${1:-}" == "__print-env" ]]; then printf 'MERERUN_CUDA_CCCL_INCLUDE_PATH=%s\n' "${MERERUN_CUDA_CCCL_INCLUDE_PATH:-}" printf 'MERERUN_MLX_CUDA_JIT_INCLUDE_PATH=%s\n' "${MERERUN_MLX_CUDA_JIT_INCLUDE_PATH:-}" printf 'CPATH=%s\n' "${CPATH:-}" + printf 'LD_LIBRARY_PATH=%s\n' "${LD_LIBRARY_PATH:-}" exit 0 fi echo "mere.run package fixture" @@ -129,7 +130,9 @@ fi cuda_home_fixture="$fixture_root/cuda-13.0" cuda_cccl_fixture="$cuda_home_fixture/targets/sbsa-linux/include/cccl" -mkdir -p "$cuda_cccl_fixture/cuda/std" +cuda_lib64_fixture="$cuda_home_fixture/lib64" +cuda_sbsa_lib_fixture="$cuda_home_fixture/targets/sbsa-linux/lib" +mkdir -p "$cuda_cccl_fixture/cuda/std" "$cuda_lib64_fixture" "$cuda_sbsa_lib_fixture" wrapper_env_output="$(CUDA_HOME="$cuda_home_fixture" "$payload_dir/mere.run" __print-env)" if ! grep -q "^MERERUN_CUDA_CCCL_INCLUDE_PATH=$cuda_cccl_fixture$" <<<"$wrapper_env_output"; then echo "[test-package-linux] launcher did not export the target-specific CUDA CCCL include root:" >&2 @@ -183,6 +186,13 @@ if ! grep -q "$cuda_payload_dir/include" <<<"$cuda_wrapper_env_output" || printf '%s\n' "$cuda_wrapper_env_output" >&2 exit 1 fi +if ! grep -q "^LD_LIBRARY_PATH=$cuda_payload_dir/lib" <<<"$cuda_wrapper_env_output" || + ! grep -q "$cuda_lib64_fixture" <<<"$cuda_wrapper_env_output" || + ! grep -q "$cuda_sbsa_lib_fixture" <<<"$cuda_wrapper_env_output"; then + echo "[test-package-linux] CUDA launcher did not add both generic and SBSA toolkit libraries to LD_LIBRARY_PATH:" >&2 + printf '%s\n' "$cuda_wrapper_env_output" >&2 + exit 1 +fi if ! dpkg-deb --field "$cuda_deb" Depends | grep -q 'libcufft-13-0'; then echo "[test-package-linux] expected CUDA .deb dependencies to include libcufft-13-0:" >&2 dpkg-deb --field "$cuda_deb" Depends >&2 diff --git a/vendor/mlx-swift_Cmlx.bundle/Contents/Resources/default.metallib b/vendor/mlx-swift_Cmlx.bundle/Contents/Resources/default.metallib index 30cfca82..9d964708 100644 Binary files a/vendor/mlx-swift_Cmlx.bundle/Contents/Resources/default.metallib and b/vendor/mlx-swift_Cmlx.bundle/Contents/Resources/default.metallib differ diff --git a/vendor/mlx-swift_Cmlx.bundle/Contents/Resources/default.metallib.version b/vendor/mlx-swift_Cmlx.bundle/Contents/Resources/default.metallib.version index 7045afb5..e69afd1f 100644 --- a/vendor/mlx-swift_Cmlx.bundle/Contents/Resources/default.metallib.version +++ b/vendor/mlx-swift_Cmlx.bundle/Contents/Resources/default.metallib.version @@ -1,6 +1,6 @@ mlx-core-version: 0.32.1 mlx-swift-version: unknown -mlx-swift-revision: 22c76cc40edbae2c2af72532678d8e5c06cbfa46 -kernel-sources-sha256: 961bc42bb4161801fb8b0f7fd9d4570e7e86318f1644520bb39eae04eed9820c -built-at: 2026-08-08T20:47:45Z +mlx-swift-revision: 3e6df6d8163a8f212061d15739eeeec12d5b89e3 +kernel-sources-sha256: fb0c62d372d6aaa75edfbcb950d9dd797fce944a7df7bcde24dce2a672024be5 +built-at: 2026-08-14T11:27:04Z metal-compiler: Apple metal version 32023.883 (metalfe-32023.883)