Skip to content

ci(mlx): GMM-T transposed-B sweep + t2 contigB probe #28

ci(mlx): GMM-T transposed-B sweep + t2 contigB probe

ci(mlx): GMM-T transposed-B sweep + t2 contigB probe #28

name: MLX PR check (fork)
# CAMPAGNE v8.1 — identique à v8, à un détail près : le selfcheck GMM-T
# est désormais DÉFINI dans runtime/MLXBackend.cpp (TU qui possède les
# includes MLX) et le runner ne porte qu'une déclaration extern "C" +
# les appels t0/t1. Le v8 initial ne compilait pas : le target CMake du
# runner n'a pas les chemins d'include MLX (ils sont PRIVATE au
# delegate), d'où 'mlx/mlx.h' file not found. Résolution au link via la
# dépendance mlxdelegate existante — zéro plomberie CMake.
#
# Le reste (objectif, sondes t0/t1/t2, grille de lecture) : voir v8.
# t0 default >>0 -> la géométrie exacte échoue à froid : les repros
# historiques ne testaient pas la bonne géométrie -> repro upstream
# minimal en main.
# t0 ~0, t1 >>0 -> poison dans [Module.load .. init delegate].
# t0/t1 ~0, t2 >>0 -> contexte d'execute / stream du delegate.
# default ~0 mais newstream >>0 (ou inverse) -> scope stream.
#
# Prérequis : probe v1+v2+v3 (MLXInterpreter.h), probe-runner-t.patch
# PUIS probe-runner-t-fix.patch appliqués ; repro_gather_mm.cpp à la
# racine.
on:
workflow_dispatch:
push:
branches:
- ci-mlx-check
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
provenance-vs-link:
runs-on: macos-14
timeout-minutes: 300
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Preuve — commit, sondes présentes (t2 interp, t0/t1 backend)
run: |
set -eux
git log --oneline -3
grep -c "GMM-PROBE" backends/mlx/runtime/MLXInterpreter.h
grep -c "GMM-T" backends/mlx/runtime/MLXBackend.cpp
grep -c "et_mlx_gmm_selfcheck" backends/mlx/test/op_test_runner.cpp
- name: Install ExecuTorch
run: |
set -eux
python -m pip install --upgrade pip
python install_executorch.py
- name: Configure + build op_test_runner
id: build
run: |
set -eux
cmake --preset mlx-release \
-DEXECUTORCH_BUILD_TESTS=ON \
-DEXECUTORCH_MLX_ENABLE_SANITIZERS=OFF
cmake --build cmake-out --target op_test_runner -j2
df -h /
- name: SONDE — harnais famille gather_mm (t0/t1/t2 via stdout)
if: steps.build.outcome == 'success'
continue-on-error: true
run: |
set -eux
export ET_MLX_GMM_PROBE=1
python -m executorch.backends.mlx.test.run_all_tests gather_mm -v \
2>&1 | tee /tmp/harness.log
echo "=== lignes sondes ==="
grep -nE 'GMM-T|GMM-PROBE' /tmp/harness.log || echo "AUCUNE"
echo "=== contexte configs sorted ==="
grep -n -B3 -A20 'e4_i64_o128_sorted' /tmp/harness.log | head -160
- name: SONDE — directe, flux bruts + A/B perturbation
if: steps.build.outcome == 'success'
continue-on-error: true
run: |
set -eux
CFG=gather_mm_e4_i64_o128_sorted
R=$(python -c "import executorch.backends.mlx.test.test_utils as t; print(t.find_op_test_runner())")
D=$(python -c "import executorch.backends.mlx.test.test_utils as t, pathlib; print(pathlib.Path(t.__file__).parent/'op_tests'/'$CFG')")
echo "runner=$R"; echo "testdir=$D"
echo "sondes-in-binary: $(strings "$R" | grep -cE 'GMM-T|GMM-PROBE')"
if [ ! -f "$D/model.pte" ]; then
python -c "import executorch.backends.mlx.test.test_ops as _reg; from executorch.backends.mlx.test.test_utils import get_all_test_configs; c=dict(get_all_test_configs())['$CFG']; print(c.generate_test_files(verbose=False))"
fi
ls -la "$D"
set +e
ET_MLX_GMM_PROBE=1 "$R" \
--pte "$D/model.pte" --input "$D/input.bin" \
--output /tmp/out_probe.bin --verbose \
> /tmp/p_out.txt 2> /tmp/p_err.txt
rc1=$?
"$R" \
--pte "$D/model.pte" --input "$D/input.bin" \
--output /tmp/out_noprobe.bin --verbose \
> /tmp/n_out.txt 2> /tmp/n_err.txt
rc2=$?
set -e
echo "=== rc probe=$rc1 / noprobe=$rc2 ==="
echo "=== STDOUT (probe) ==="; cat /tmp/p_out.txt
echo "=== STDERR (probe) ==="; cat /tmp/p_err.txt
echo "=== lignes sondes ==="
grep -hE 'GMM-T|GMM-PROBE' /tmp/p_out.txt /tmp/p_err.txt \
|| echo "AUCUNE"
echo "=== A/B perturbation ==="
if [ "$rc1" -eq 0 ] && [ "$rc2" -eq 0 ]; then
cmp /tmp/out_probe.bin /tmp/out_noprobe.bin \
&& echo "SORTIES IDENTIQUES" \
|| echo "SORTIES DIFFERENTES (sonde perturbante !)"
else
echo "cmp saute (rc non nuls)"
fi
- name: ÉCHELLE — L0 mlx seul (contrôle)
if: steps.build.outcome == 'success'
continue-on-error: true
run: |
set -eux
MLXA=$(find cmake-out -name libmlx.a | head -1)
METALLIB=$(find cmake-out -name mlx.metallib | head -1)
cp "$METALLIB" .
clang++ -std=c++17 -O2 repro_gather_mm.cpp \
-I backends/mlx/third-party/mlx \
-I "$(dirname "$MLXA")" \
"$MLXA" \
-framework Metal -framework Foundation -framework QuartzCore \
-o rung_L0
./rung_L0 && echo "L0: OK" || echo "L0: DIVERGE/CRASH rc=$?"
- name: ÉCHELLE — L3 closure exacte (contrôle de régression)
if: steps.build.outcome == 'success'
continue-on-error: true
run: |
set -eux
MLXA=$(find cmake-out -name libmlx.a | head -1)
LINKTXT=$(find cmake-out -path "*op_test_runner.dir/link.txt" | head -1)
BLD=$(dirname "$(dirname "$(dirname "$LINKTXT")")")
clang++ -std=c++17 -O2 -c repro_gather_mm.cpp \
-I backends/mlx/third-party/mlx \
-I "$(dirname "$MLXA")" \
-o /tmp/repro.o
sed -E \
-e "s#[^ ]*op_test_runner\.cpp\.o#/tmp/repro.o#" \
-e "s# -o [^ ]*op_test_runner# -o $PWD/rung_L3#" \
"$LINKTXT" > /tmp/l3cmd.sh
(cd "$BLD" && bash /tmp/l3cmd.sh) 2>&1 | tail -40
./rung_L3 && echo "L3: OK" || echo "L3: DIVERGE/CRASH rc=$?"
- name: Diagnostics finaux
if: always()
run: df -h /