Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions .github/workflows/mlx.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
name: MLX

on:
push:
branches:
- main
- release/*
pull_request:
paths:
- .github/workflows/mlx.yml
- backends/mlx/**
workflow_dispatch:

permissions: {}

jobs:
test-mlx:
uses: pytorch/test-infra/.github/workflows/macos_job.yml@main
with:
job-name: test-mlx
runner: macos-14-xlarge
python-version: "3.12"
submodules: recursive
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
timeout: 90
script: |
set -eux

echo "::group::Install ExecuTorch and configure build"
${CONDA_RUN} python install_executorch.py > /dev/null
# The sanitizers fail on github VM runner, but pass on real device
# TODO: figure out why
${CONDA_RUN} cmake --preset mlx-release -DEXECUTORCH_BUILD_TESTS=ON -DEXECUTORCH_MLX_ENABLE_SANITIZERS=OFF
echo "::endgroup::"

${CONDA_RUN} pip list

echo "::group::Build test runners"
${CONDA_RUN} cmake --build cmake-out --target op_test_runner -j$(( $(sysctl -n hw.ncpu) - 1 ))
echo "::endgroup::"

echo "::group::Run op unit tests"
${CONDA_RUN} python -m executorch.backends.mlx.test.run_all_tests -j4 --max-tasks-per-worker 10 --clean-after
echo "::endgroup::"

echo "::group::Run Python unit tests"
${CONDA_RUN} python -m pytest \
backends/mlx/test/test_passes.py \
backends/mlx/test/test_pattern_utils.py \
backends/mlx/test/test_partitioner.py \
-v
echo "::endgroup::"

backend-tester:
strategy:
fail-fast: false
matrix:
suite: [models, operators]
uses: pytorch/test-infra/.github/workflows/macos_job.yml@main
with:
job-name: test-mlx-backend-${{ matrix.suite }}
runner: macos-14-xlarge
python-version: "3.12"
submodules: recursive
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
timeout: 120
script: |
set -eux

echo "::group::Install ExecuTorch"
${CONDA_RUN} python install_executorch.py > /dev/null
echo "::endgroup::"

${CONDA_RUN} pip list

echo "::group::Run backend test suite (${{ matrix.suite }})"
${CONDA_RUN} pytest -c /dev/null backends/test/suite/${{ matrix.suite }}/ -m flow_mlx -n auto 2>&1 | tee pytest_output.txt || true
echo "::endgroup::"

# Parse pytest summary and check failure threshold
if grep -E "^=+ .* =+$" pytest_output.txt | tail -1 | grep -q "failed"; then
FAILED=$(grep -E "^=+ .* =+$" pytest_output.txt | tail -1 | grep -oE "[0-9]+ failed" | grep -oE "[0-9]+")
else
FAILED=0
fi

if [ "${{ matrix.suite }}" = "operators" ]; then
MAX_FAILURES=0
else
MAX_FAILURES=3
fi

echo "Failed tests: $FAILED (max allowed: $MAX_FAILURES)"
if [ "$FAILED" -gt "$MAX_FAILURES" ]; then
echo "::error::Too many test failures: $FAILED > $MAX_FAILURES"
exit 1
fi
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,7 @@ xcuserdata/
*.dll
*.pyd


# Agents
.claude/*.local.*
extension/pybindings/mlx.metallib
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,7 @@
[submodule "third-party/json"]
path = third-party/json
url = https://github.com/nlohmann/json.git
[submodule "backends/mlx/third-party/mlx"]
path = backends/mlx/third-party/mlx
url = https://github.com/ml-explore/mlx.git
shallow = true
15 changes: 15 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,11 @@ if(EXECUTORCH_BUILD_MPS)
list(APPEND _executorch_backends mpsdelegate)
endif()

if(EXECUTORCH_BUILD_MLX)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/backends/mlx)
list(APPEND _executorch_backends mlxdelegate)
endif()

if(EXECUTORCH_BUILD_NEURON)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/backends/mediatek)
list(APPEND _executorch_backends neuron_backend)
Expand Down Expand Up @@ -956,6 +961,10 @@ if(EXECUTORCH_BUILD_PYBIND)
list(APPEND _dep_libs mpsdelegate)
endif()

if(EXECUTORCH_BUILD_MLX)
list(APPEND _dep_libs mlxdelegate)
endif()

if(EXECUTORCH_BUILD_OPENVINO)
list(APPEND _dep_libs openvino_backend)
endif()
Expand Down Expand Up @@ -1056,6 +1065,12 @@ if(EXECUTORCH_BUILD_PYBIND)
install(TARGETS data_loader
LIBRARY DESTINATION executorch/extension/pybindings
)

# Copy MLX metallib next to _portable_lib.so for editable installs. MLX uses
# dladdr() to find the directory containing the library with MLX code, then
# looks for mlx.metallib in that directory. When MLX is statically linked into
# _portable_lib.so, we need the metallib colocated with it.
executorch_target_copy_mlx_metallib(portable_lib)
endif()

if(EXECUTORCH_BUILD_WASM)
Expand Down
85 changes: 84 additions & 1 deletion CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
"inherits": ["common"],
"cacheVariables": {
"EXECUTORCH_BUILD_PRESET_FILE": "${sourceDir}/tools/cmake/preset/pybind.cmake",
"CMAKE_OSX_DEPLOYMENT_TARGET": "12.0"
"CMAKE_OSX_DEPLOYMENT_TARGET": "14.0"
},
"condition": {
"type": "inList",
Expand Down Expand Up @@ -294,6 +294,43 @@
"EXECUTORCH_BUILD_PRESET_FILE": "${sourceDir}/tools/cmake/preset/arm_ethosu_linux.cmake",
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/examples/arm/ethos-u-setup/aarch64-linux-musl-toolchain.cmake"
}
},
{
"name": "mlx",
"displayName": "Build MLX delegate",
"inherits": ["common"],
"cacheVariables": {
"EXECUTORCH_BUILD_PRESET_FILE": "${sourceDir}/tools/cmake/preset/mlx.cmake",
"EXECUTORCH_ENABLE_LOGGING": "ON",
"CMAKE_OSX_DEPLOYMENT_TARGET": "14.0"
},
"condition": {
"lhs": "${hostSystemName}",
"type": "equals",
"rhs": "Darwin"
}
},
{
"name": "mlx-release",
"displayName": "MLX delegate release build",
"inherits": ["mlx"],
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/cmake-out",
"ET_MLX_ENABLE_OP_LOGGING": "OFF",
"ET_MIN_LOG_LEVEL": "Error"
}
},
{
"name": "mlx-debug",
"displayName": "MLX delegate debug build with op logging",
"inherits": ["mlx"],
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/cmake-out",
"ET_MLX_ENABLE_OP_LOGGING": "ON",
"ET_MIN_LOG_LEVEL": "Debug"
}
}
],
"buildPresets": [
Expand Down Expand Up @@ -362,6 +399,24 @@
"install"
],
"jobs": 0
},
{
"name": "mlx-release-install",
"displayName": "Build and install MLX delegate release artifacts",
"configurePreset": "mlx-release",
"targets": [
"install"
],
"jobs": 0
},
{
"name": "mlx-debug-install",
"displayName": "Build and install MLX delegate debug artifacts",
"configurePreset": "mlx-debug",
"targets": [
"install"
],
"jobs": 0
}
],
"workflowPresets": [
Expand Down Expand Up @@ -462,6 +517,34 @@
"name": "llm-metal-stats-install"
}
]
},
{
"name": "mlx-release",
"displayName": "Configure, build and install ExecuTorch MLX delegate",
"steps": [
{
"type": "configure",
"name": "mlx-release"
},
{
"type": "build",
"name": "mlx-release-install"
}
]
},
{
"name": "mlx-debug",
"displayName": "Configure, build and install ExecuTorch MLX delegate with op logging (Debug)",
"steps": [
{
"type": "configure",
"name": "mlx-debug"
},
{
"type": "build",
"name": "mlx-debug-install"
}
]
}
]
}
Loading
Loading