Skip to content

Commit 2060252

Browse files
authored
build: add MLXCEL_CXX_MARCH override and pin the x86_64 CUDA release asset to x86-64-v3 (#208)
build.rs reads MLXCEL_CXX_MARCH in release builds: unset keeps -march=native (default unchanged), `none` omits the flag, and any other value is passed as -march=<value> via flag_if_supported, so a value the host compiler rejects is dropped rather than failing the build. The existing build-linux-x86_64-cuda release job now sets MLXCEL_CXX_MARCH=x86-64-v3 and RUSTFLAGS=-C target-cpu=x86-64-v3, pinning the C++ bridge and rustc to a portable AVX2 (~2013+) baseline. Without this the redistributable asset inherited the build host's -march=native ISA (possibly AVX-512) and could SIGILL on older customer CPUs. Local and per-machine GB10/GH200 builds keep native. Docs: MLXCEL_CXX_MARCH reference in environment-variables.md and installation.md, plus troubleshooting for the qmm Error 137 OOM and the liblapacke-dev (lapacke.h) build requirement. Co-authored-by: Joongi Kim <joongi@lablup.com>
1 parent a0788c2 commit 2060252

4 files changed

Lines changed: 56 additions & 2 deletions

File tree

.github/workflows/release.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,14 @@ jobs:
655655
- name: Build release binaries
656656
run: cargo build --release --features cuda --locked
657657
# MLX_CUDA_ARCHITECTURES is inherited from the job env above.
658+
env:
659+
# Redistributable asset: pin the C++ bridge and Rust code to the
660+
# portable x86-64-v3 baseline (AVX2, ~2013+) instead of inheriting
661+
# this build host's native ISA. build.rs defaults the bridge to
662+
# -march=native, which on a newer runner could bake in AVX-512 and
663+
# SIGILL on older customer CPUs. Set MLXCEL_CXX_MARCH=none to omit.
664+
MLXCEL_CXX_MARCH: x86-64-v3
665+
RUSTFLAGS: "-C target-cpu=x86-64-v3"
658666

659667
- name: Smoke test (10-token generate on GPU)
660668
run: |

docs/environment-variables.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ These are read by the `mlxcel-core` build script.
6565
|----------|--------|---------|-------|
6666
| `MLXCEL_BUILD_METAL` | `1/0`, `on/off`, `true/false`, `yes/no` | `on` on macOS | Overrides the CMake `MLX_BUILD_METAL` setting for local builds. Invalid values fail the build. |
6767
| `MLXCEL_BUILD_ACCELERATE` | `1/0`, `on/off`, `true/false`, `yes/no` | `on` on macOS | Overrides the CMake `MLX_BUILD_ACCELERATE` setting for local builds. Invalid values fail the build. |
68+
| `MLXCEL_CXX_MARCH` | a `-march=` value, or `none` | `native` | ISA baseline for the C++ bridge in release builds. Set a portable baseline (e.g. `x86-64-v3`) for binaries that run on machines other than the build host; `none` omits the flag. See [Installation](installation.md#c-isa-baseline-mlxcel_cxx_march). |
6869

6970
CUDA builds also use non-`MLXCEL_*` variables such as `CUDA_HOME` and
7071
`MLX_CUDA_ARCHITECTURES`; see [Installation](installation.md#linux-with-cuda).

docs/installation.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,12 +145,30 @@ system temp dir), so only the first run of each kernel variant pays the NVRTC
145145
cost. Point `MLX_PTX_CACHE_DIR` at a persistent path to keep the cache across
146146
sessions.
147147

148+
### C++ ISA baseline (`MLXCEL_CXX_MARCH`)
149+
150+
In release builds the C++ bridge defaults to `-march=native`, which tunes for
151+
(and only runs on) the build host's CPU. That is correct for builds that run
152+
where they are built (developer machines, the per-machine GB10/GH200 release
153+
assets). For a binary that must run on other machines, set `MLXCEL_CXX_MARCH`
154+
to a portable baseline; the release workflow's x86-64 assets use `x86-64-v3`
155+
(AVX2):
156+
157+
```bash
158+
# Portable x86-64 build (any AVX2-capable CPU, ~2013+).
159+
MLXCEL_CXX_MARCH=x86-64-v3 cargo build --release --features cuda
160+
161+
# Omit -march entirely (compiler default baseline).
162+
MLXCEL_CXX_MARCH=none cargo build --release --features cuda
163+
```
164+
148165
## Runtime environment variables
149166

150167
| Variable | Description | Default |
151168
|----------|-------------|---------|
152169
| `CUDA_HOME` | CUDA toolkit root, build-time and for runtime NVRTC headers | `/usr/local/cuda` when present |
153170
| `MLX_CUDA_ARCHITECTURES` | CUDA SM target list, build-time | auto-detect via `nvidia-smi`, then `90a` fallback |
171+
| `MLXCEL_CXX_MARCH` | C++ bridge `-march` value, build-time; `none` omits the flag | `native` |
154172
| `MLXCEL_CCCL_DIR` | Override for the bundled CCCL (libcu++) header dir used by the CUDA NVRTC JIT | bundled `<exe-dir>/../include/cccl`, then build-time fallback |
155173
| `MLX_PTX_CACHE_DIR` | On-disk cache for JIT-compiled CUDA kernels | system temp dir |
156174
| `MLXCEL_QUIET_JIT` | Suppress the one-time "compiling CUDA kernels" notice on a cold first run | unset (notice shown) |
@@ -190,3 +208,13 @@ explicitly.
190208
MLX version are installed and discoverable by the linker. The root build script
191209
links CUDA runtime/math libraries directly and relies on the system driver for
192210
`libcuda`.
211+
212+
**`gmake: *** Error 137` (SIGKILL) while compiling `qmm_*.cu`** — the build ran
213+
out of memory. The CUTLASS-heavy quantized-matmul kernels peak at ~4-5 GB of
214+
compiler memory per parallel job, so a default `-j$(nproc)` build needs roughly
215+
`5 GB × cores`. Cap the parallelism with `cargo build -j N ...` (cargo forwards
216+
`N` to the CMake subbuild); pick `N ≈ available_RAM_GB / 5`.
217+
218+
**CMake error: `LAPACK_INCLUDE_DIRS ... NOTFOUND`** — install `liblapacke-dev`
219+
(MLX needs `lapacke.h`, which `liblapack-dev` alone does not provide) and
220+
`libopenblas-dev`.

src/lib/mlxcel-core/build.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,24 @@ fn main() {
7272
bridge
7373
.flag_if_supported("-O3")
7474
.flag_if_supported("-DNDEBUG")
75-
.flag_if_supported("-ffast-math")
76-
.flag_if_supported("-march=native");
75+
.flag_if_supported("-ffast-math");
76+
// ISA baseline for the bridge C++. Defaults to the build host's ISA
77+
// (-march=native), which is correct for builds that run where they
78+
// are built (developer machines, the per-machine gb10/gh200 release
79+
// assets). Redistributable release builds must override this with a
80+
// portable baseline via MLXCEL_CXX_MARCH (e.g. "x86-64-v3" for the
81+
// generic Linux x86-64 asset), otherwise the binary inherits the
82+
// build runner's ISA (possibly AVX-512) and SIGILLs on older CPUs.
83+
// Set MLXCEL_CXX_MARCH=none to omit the flag entirely.
84+
match env::var("MLXCEL_CXX_MARCH").as_deref() {
85+
Err(_) => {
86+
bridge.flag_if_supported("-march=native");
87+
}
88+
Ok("none") => {}
89+
Ok(march) => {
90+
bridge.flag_if_supported(&format!("-march={march}"));
91+
}
92+
}
7793
// On macOS, Clang produces LLVM bitcode with -flto, which is compatible
7894
// with Rust's LLVM LTO. On Linux with GCC, -flto produces GIMPLE IR
7995
// objects that are incompatible, causing undefined-reference linker errors.
@@ -155,6 +171,7 @@ fn main() {
155171
println!("cargo:rerun-if-env-changed=MLX_CUDA_ARCHITECTURES");
156172
println!("cargo:rerun-if-env-changed=MLXCEL_BUILD_METAL");
157173
println!("cargo:rerun-if-env-changed=MLXCEL_BUILD_ACCELERATE");
174+
println!("cargo:rerun-if-env-changed=MLXCEL_CXX_MARCH");
158175
}
159176

160177
/// Expected MLX git commit — must match GIT_TAG in mlx-cpp/CMakeLists.txt.

0 commit comments

Comments
 (0)