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
61 changes: 61 additions & 0 deletions .github/workflows/lint_mps.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: Lint MPS

on:
pull_request:
push:
branches:
- main
- release/*
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}-${{ github.event_name == 'workflow_dispatch' }}-${{ github.event_name == 'schedule' }}
cancel-in-progress: true

jobs:
lintrunner-mps:
runs-on: macos-executorch
steps:
- uses: actions/checkout@v3
with:
submodules: 'true'
- uses: actions/setup-python@v4
with:
python-version: '3.10'
cache: pip
- name: Lintrunner
id: lint-mps
run: |
set -eux
source .ci/scripts/utils.sh
# This is a simple Python script but as it tries to import executorch.examples.models,
# it requires a whole bunch of ExecuTorch dependencies on the Docker image
install_pip_dependencies
install_executorch
brew install jq

source .ci/scripts/utils.sh

# Install lint depdendencies
pip install lintrunner==0.11.0
pip install lintrunner-adapters==0.11.0

CACHE_DIRECTORY="/tmp/.lintbin"
# Try to recover the cached binaries
if [[ -d "${CACHE_DIRECTORY}" ]]; then
# It's ok to fail this as lintrunner init would download these binaries
# again if they do not exist
cp -r "${CACHE_DIRECTORY}" . || true
fi

# This has already been cached in the docker image
lintrunner init 2> /dev/null

RC=0
# Run lintrunner on all files
if ! lintrunner --force-color --all-files --tee-json lint.json 2> /dev/null; then
echo ""
echo -e "\e[1m\e[36mYou can reproduce these results locally by using \`lintrunner\`. (If you don't get the same results, run \'lintrunner init\' to update your local linter)\e[0m"
echo -e "\e[1m\e[36mSee https://github.com/pytorch/pytorch/wiki/lintrunner for setup instructions.\e[0m"
RC=1
fi
31 changes: 28 additions & 3 deletions .github/workflows/pull_mps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ jobs:
runs-on: macos-executorch
outputs:
models: ${{ steps.gather-models-mps.outputs.models }}
mps_models: ${{ steps.gather-models-mps.outputs.mps_models }}
steps:
- uses: actions/checkout@v3
with:
Expand All @@ -34,8 +35,8 @@ jobs:
install_pip_dependencies
install_executorch
PYTHONPATH="${PWD}" python -m backends.apple.mps.ci.scripts.gather_test_models_mps
test-mps-delegate-macos:
name: test-mps-delegate-macos
test-mps-models:
name: test-mps-models
runs-on: macos-executorch
needs: gather-models-mps
strategy:
Expand All @@ -56,5 +57,29 @@ jobs:
PYTHON_EXECUTABLE=python bash .ci/scripts/setup-macos.sh "${BUILD_TOOL}"
PYTHON_EXECUTABLE=python bash backends/apple/mps/install_requirements.sh
# Build and test ExecuTorch
PYTHON_EXECUTABLE=python bash backends/apple/mps/ci/scripts/test-mps.sh "${MODEL_NAME}" "${BUILD_TOOL}"
PYTHON_EXECUTABLE=python bash backends/apple/mps/ci/scripts/test-mps.sh "${MODEL_NAME}" "${BUILD_TOOL}" false
popd
test-mps:
name: test-mps
runs-on: macos-executorch
needs: gather-models-mps
strategy:
matrix: ${{ fromJSON(needs.gather-models-mps.outputs.mps_models) }}
fail-fast: false
steps:
- uses: actions/checkout@v3
with:
submodules: 'true'
- name: Run test ${{ matrix.test }}
if: always()
run: |
WORKSPACE=$(pwd)
pushd "${WORKSPACE}"
MODEL_NAME=${{ matrix.model }}
BUILD_TOOL=${{ matrix.build-tool }}
# Setup MacOS dependencies as there is no Docker support on MacOS atm
PYTHON_EXECUTABLE=python bash .ci/scripts/setup-macos.sh "${BUILD_TOOL}"
PYTHON_EXECUTABLE=python bash backends/apple/mps/install_requirements.sh
# Build and test ExecuTorch
PYTHON_EXECUTABLE=python bash backends/apple/mps/ci/scripts/test-mps.sh "${MODEL_NAME}" "${BUILD_TOOL}" true
popd
47 changes: 43 additions & 4 deletions backends/apple/mps/ci/scripts/gather_test_models_mps.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@

import json
import os
import unittest
from typing import Any

from examples.models import MODEL_NAME_TO_MODEL
from examples.xnnpack import MODEL_NAME_TO_OPTIONS

MPS_TEST_SUITE_PATH = "backends/apple/mps/test"
MPS_SUITE = unittest.defaultTestLoader.discover(MPS_TEST_SUITE_PATH)

BUILD_TOOLS = {
"cmake": {"macos-14"},
Expand All @@ -17,6 +20,7 @@
"macos-14": "macos-executorch",
}


def parse_args() -> Any:
from argparse import ArgumentParser

Expand Down Expand Up @@ -44,6 +48,20 @@ def set_output(name: str, val: Any) -> None:
print(f"::set-output name={name}::{val}")


def gather_mps_test_list(suite, mps_test_list):
if hasattr(suite, "__iter__"):
for x in suite:
gather_mps_test_list(x, mps_test_list)
else:
mps_test_list.append(suite)


def gather_mps_tests(suite):
mps_test_list = []
gather_mps_test_list(suite, mps_test_list)
return mps_test_list


def export_models_for_ci() -> None:
"""
This gathers all the example models that we want to test on GitHub OSS CI
Expand All @@ -55,9 +73,6 @@ def export_models_for_ci() -> None:
# https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs
models = {"include": []}
for name in MODEL_NAME_TO_MODEL.keys():
delegation_configs = {
name in MODEL_NAME_TO_OPTIONS and MODEL_NAME_TO_OPTIONS[name].delegation,
}
for build_tool in BUILD_TOOLS.keys():
if target_os not in BUILD_TOOLS[build_tool]:
continue
Expand All @@ -72,6 +87,30 @@ def export_models_for_ci() -> None:

set_output("models", json.dumps(models))

# Gather the list of all mps tests
mps_models = {"include": []}
mps_test_list = gather_mps_tests(MPS_SUITE)
start_path = ".".join([MPS_TEST_SUITE_PATH.replace("/", "."), "test_mps"])
for testcase in mps_test_list:
if "test_mps" not in str(testcase.__class__):
continue
for build_tool in BUILD_TOOLS.keys():
if target_os not in BUILD_TOOLS[build_tool]:
continue

cmd = ".".join(
[start_path, testcase.__class__.__name__, testcase._testMethodName]
)
record = {
"build-tool": build_tool,
"model": cmd,
"runner": DEFAULT_RUNNERS.get(target_os),
}

mps_models["include"].append(record)

set_output("mps_models", json.dumps(mps_models))


if __name__ == "__main__":
export_models_for_ci()
31 changes: 30 additions & 1 deletion backends/apple/mps/ci/scripts/test-mps.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ if [[ -z "${BUILD_TOOL:-}" ]]; then
exit 1
fi

MPS_TESTS=$3
if [[ -z "${MPS_TESTS:-}" ]]; then
echo "Missing flag specifying which tests to run, exiting..."
exit 1
fi

which "${PYTHON_EXECUTABLE}"
CMAKE_OUTPUT_DIR=cmake-out

Expand Down Expand Up @@ -62,5 +68,28 @@ test_model_with_mps() {
fi
}

test_mps_model() {
"${PYTHON_EXECUTABLE}" -m unittest "${MODEL_NAME}"

TEST_NAME="${MODEL_NAME##*.}"
OUTPUT_MODEL_PATH="${TEST_NAME}.pte"
STR_LEN=${#OUTPUT_MODEL_PATH}
FINAL_OUTPUT_MODEL_PATH=${OUTPUT_MODEL_PATH:5:$STR_LEN-5}

if [[ "${BUILD_TOOL}" == "cmake" ]]; then
if [[ ! -f ${CMAKE_OUTPUT_DIR}/examples/apple/mps/mps_executor_runner ]]; then
build_cmake_mps_executor_runner
fi
./${CMAKE_OUTPUT_DIR}/examples/apple/mps/mps_executor_runner --model_path "${FINAL_OUTPUT_MODEL_PATH}" --bundled_program
else
echo "Invalid build tool ${BUILD_TOOL}. Only cmake is supported atm"
exit 1
fi
}

echo "Testing ${MODEL_NAME} with MPS..."
test_model_with_mps
if [[ "${MPS_TESTS}" == false ]]; then
test_model_with_mps
else
test_mps_model
fi
4 changes: 1 addition & 3 deletions backends/apple/mps/test/test_mps.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,7 @@ def forward(self, *args):
method_test_suites = [
MethodTestSuite(
method_name="forward",
test_cases=[
MethodTestCase(inputs=m_inputs, expected_outputs=model(*m_inputs))
],
test_cases=[MethodTestCase(inputs=m_inputs, expected_outputs=m(*m_inputs))],
)
]

Expand Down
4 changes: 2 additions & 2 deletions backends/apple/mps/test/test_mps_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ def forward(self, *args):
method_name="forward",
test_cases=[
MethodTestCase(
input=sample_inputs, expected_outputs=module(*sample_inputs)
inputs=sample_inputs, expected_outputs=module(*sample_inputs)
)
],
)
Expand All @@ -208,7 +208,7 @@ def forward(self, *args):
bundled_program
)

filename = f"{func_name}.bpte"
filename = f"{func_name}.pte"
logging.info(f"Step 5: Saving bundled program to {filename}...")
with open(filename, "wb") as file:
file.write(bundled_program_buffer)
Expand Down
11 changes: 8 additions & 3 deletions examples/apple/mps/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ add_custom_command(
OUTPUT ${_bundled_program_schema__outputs}
COMMAND
${FLATC_EXECUTABLE} --cpp --cpp-std c++11 --gen-mutable --scoped-enums -o
"${_program_schema__include_dir}/executorch/sdk/bundled_program/schema" ${_bundled_program_schema__srcs}
"${_program_schema__include_dir}/executorch/sdk/bundled_program/schema"
${_bundled_program_schema__srcs}
WORKING_DIRECTORY ${EXECUTORCH_ROOT}
DEPENDS ${FLATC_EXECUTABLE} ${_bundled_program_schema__srcs}
COMMENT "Generating bundled_program headers"
Expand All @@ -68,8 +69,12 @@ set(mps_executor_runner_libs "-framework Foundation"
"-weak_framework MetalPerformanceShaders"
"-weak_framework MetalPerformanceShadersGraph"
"-weak_framework Metal")
list(TRANSFORM _mps_executor_runner__srcs PREPEND "${EXECUTORCH_ROOT}/")
add_executable(mps_executor_runner ${_mps_executor_runner__srcs} ${_bundled_program_schema__outputs})
list(
TRANSFORM _mps_executor_runner__srcs PREPEND "${EXECUTORCH_ROOT}/")
add_executable(
mps_executor_runner
${_mps_executor_runner__srcs}
${_bundled_program_schema__outputs})
target_include_directories(
mps_executor_runner INTERFACE ${CMAKE_BINARY_DIR}/schema/include/
${EXECUTORCH_ROOT}/third-party/flatbuffers/include)
Expand Down