Skip to content
Merged
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
39 changes: 0 additions & 39 deletions .github/actions/build-macos/action.yml

This file was deleted.

34 changes: 28 additions & 6 deletions .github/actions/build/action.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: 'Build'
description: 'Build C++ and Python binaries for testing on Linux and Windows'
description: 'Build C++ and Python binaries for testing'

inputs:
cmake-args:
Expand All @@ -8,23 +8,46 @@ inputs:
debug:
description: 'Do debug build'
required: true
macos-target:
description: 'The target macOS version to build for'
required: false
default: '26.2'

runs:
using: 'composite'
steps:
- name: Install Python package
shell: bash
env:
DEBUG: ${{ inputs.debug == 'true' && 1 || 0 }}
CMAKE_ARGS: ${{ inputs.cmake-args }}
DEBUG: ${{ inputs.debug == 'true' && 1 || 0 }}
MACOSX_DEPLOYMENT_TARGET: ${{ inputs.macos-target }}
run: |
# Install cpu-only torch to save space.
uv pip install torch --torch-backend=cpu
if ${{ runner.os != 'macOS' }}; then
# Install cpu-only torch to save space.
uv pip install torch --torch-backend=cpu
fi
uv pip install --no-build-isolation -e ".[dev]" -v

- name: Get number of CPU cores
id: cpu-cores
shell: bash
run: |
if ${{ runner.os == 'Linux' }} ; then
CORES=$(nproc)
elif ${{ runner.os == 'macOS' }}; then
CORES=$(sysctl -n hw.ncpu)
elif ${{ runner.os == 'Windows' }}; then
CORES=$NUMBER_OF_PROCESSORS
else
CORES=2
fi
echo "result=$CORES" >> $GITHUB_OUTPUT

- name: Build CPP only
shell: bash
env:
MACOSX_DEPLOYMENT_TARGET: ${{ inputs.macos-target }}
# The cpp build is using some extra settings to reuse the compile cache
# generated by the python install:
# 1. Use the same ccache options with setup.py.
Expand All @@ -36,5 +59,4 @@ runs:
cmake . -B build/cpp/mlx ${{ inputs.cmake-args }} \
-DBUILD_SHARED_LIBS=ON \
-DCMAKE_BUILD_TYPE=${{ inputs.debug == 'true' && 'Debug' || 'Release' }}
cmake --build build/cpp/mlx \
-j ${{ runner.os == 'Windows' && '$NUMBER_OF_PROCESSORS' || '$(nproc)' }}
cmake --build build/cpp/mlx -j ${{ steps.cpu-cores.outputs.result }}
6 changes: 4 additions & 2 deletions .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,13 @@ runs:
if: runner.os == 'macOS'
shell: bash
run: |
brew update
brew trust aws/tap # suppress warning in github actions
brew install openmpi ninja
xcodebuild -showComponent MetalToolchain
sysctl -a | grep machdep.cpu
if ${{ runner.environment == 'self-hosted' }} ; then
echo DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer >> $GITHUB_ENV
echo SDKROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk >> $GITHUB_ENV
fi

- name: Setup Windows environment
if: runner.os == 'Windows'
Expand Down
42 changes: 42 additions & 0 deletions .github/actions/test-array-api/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: 'Run Array API tests'
description: 'Run Array API tests'

runs:
using: 'composite'
steps:
- name: Checkout array-api-tests
uses: actions/checkout@v7
with:
repository: data-apis/array-api-tests
ref: 'ef5b39f1190d54dca0d9a12646033d2d123afdd5' # v2026.09.08
submodules: 'true'
path: 'array-api-tests'
persist-credentials: false
- name: Install dependencies
shell: bash
run: uv pip install -r array-api-tests/requirements.txt
- name: Run the test suite
shell: bash
env:
ARRAY_API_TESTS_MODULE: mlx.core
ARRAY_API_TESTS_SKIP_DTYPES: 'float64,complex128'
PYTHONWARNINGS: 'ignore::UserWarning::,ignore::DeprecationWarning::,ignore::RuntimeWarning::'
METAL_DEBUG_ERROR_MODE: 0
METAL_DEVICE_WRAPPER_TYPE: 1
run: |
cd array-api-tests
if ${{ runner.environment == 'self-hosted' }} ; then
JOBS=4
else
JOBS=2
fi
uv run pytest array_api_tests \
--durations=5 \
-n $JOBS \
-c pytest.ini \
--derandomize \
--disable-data-dependent-shapes \
--disable-deadline \
-o strict_xfail=False \
--skips-file "${GITHUB_WORKSPACE}/python/tests/xp-tests/skips.txt" \
--xfails-file "${GITHUB_WORKSPACE}/python/tests/xp-tests/xfail.txt"
99 changes: 42 additions & 57 deletions .github/actions/test-macos/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,69 +20,54 @@ runs:
METAL_DEBUG_ERROR_MODE: 0
METAL_DEVICE_WRAPPER_TYPE: 1
run: |
run_tests() {
for WHEEL in dist/*.whl; do
break
done

for WHEEL in dist/*.whl; do
echo "::group::Install $WHEEL"
uv pip install $WHEEL
echo "::endgroup::"
break
done

echo "::group::Run CPP tests"
./build/tests/tests
echo "::endgroup::"

echo "::group::Run distributed tests"
# TODO: Re-enable for GPU after openmpi updating their libprrte
# dependency: https://github.com/openpmix/prrte/issues/2416
if ${{ inputs.toolkit == 'cpu' }} ; then
mpirun --bind-to none -host localhost:8 -np 8 -x MLX_MPI_LIBNAME=/opt/homebrew/lib/libmpi.dylib uv run python/tests/mpi_test_distributed.py
fi
mlx.launch --verbose -n 8 uv run python/tests/ring_test_distributed.py -v 2> >(tee -a stderr.log >&2)
if $(grep "\[WARN\]" stderr.log); then
echo "Distributed ring test failed"
exit 1
fi
echo "::endgroup::"
echo "::group::Run CPP tests"
./build/*/mlx.core/tests/tests
echo "::endgroup::"

echo "::group::Run Python tests"
if ${{ inputs.toolkit == 'cpu' }} ; then
uv run pytest --durations=10 -n 4 || uv run pytest --last-failed
else
uv run pytest --durations=10
fi
echo "::endgroup::"
echo "::group::Run distributed tests"
# TODO: Re-enable for GPU after openmpi updating their libprrte
# dependency: https://github.com/openpmix/prrte/issues/2416
if ${{ inputs.toolkit == 'cpu' }} ; then
mpirun --bind-to none -host localhost:8 -np 8 -x \
MLX_MPI_LIBNAME=/opt/homebrew/lib/libmpi.dylib \
uv run python/tests/mpi_test_distributed.py
fi
mlx.launch --verbose -n 8 uv run python/tests/ring_test_distributed.py -v 2> >(tee -a stderr.log >&2)
if $(grep "\[WARN\]" stderr.log); then
echo "Distributed ring test failed"
exit 1
fi
echo "::endgroup::"

if ${{ inputs.toolkit != 'cpu' }} ; then
echo "::group::Build example extension"
pushd examples/cmake_extension
uv pip install -r requirements.txt
uv run setup.py build_ext --inplace
uv run test.py
popd
echo "::endgroup::"
echo "::group::Run Python tests"
if ${{ inputs.toolkit == 'cpu' || runner.environment == 'self-hosted' }} ; then
uv run pytest --durations=10 -n 4 || uv run pytest --last-failed
else
uv run pytest --durations=10
fi
echo "::endgroup::"

echo "::group::Build Metal extension example"
pushd examples/metal_extension
uv pip install -r requirements.txt
uv run setup.py build_ext --inplace
uv run test.py
popd
echo "::endgroup::"
fi
}
if ${{ inputs.toolkit != 'cpu' }} ; then
echo "::group::Build example extension"
pushd examples/cmake_extension
uv pip install -r requirements.txt
uv run setup.py build_ext --inplace
uv run test.py
popd
echo "::endgroup::"

if [[ -d artifact ]] ; then
for SUBDIR in artifact/*; do
rm -rf build dist
mv $SUBDIR/* .
# Downloaded binaries all lose executable permission.
find build -type f -exec chmod 755 {} \;
# Path to metallib is hard-coded so move it besides executable.
mv build/mlx/backend/metal/kernels/mlx.metallib build/tests
run_tests
done
else
run_tests
echo "::group::Build Metal extension example"
pushd examples/metal_extension
uv pip install -r requirements.txt
uv run setup.py build_ext --inplace
uv run test.py
popd
echo "::endgroup::"
fi
Loading
Loading