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
2 changes: 1 addition & 1 deletion .ci/docker/ci_commit_pins/pytorch.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
release/2.12
release/2.13
18 changes: 17 additions & 1 deletion .ci/docker/common/install_pytorch.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,21 @@ install_domains() {
pip_install --no-build-isolation --user "git+https://github.com/pytorch/vision.git@${TORCHVISION_VERSION}"
}

configure_pytorch_compiler() {
local cxx_version
cxx_version=$(/usr/bin/c++ --version | head -n1)
if [[ "${cxx_version}" == *clang* ]]; then
local clang_major
clang_major=$(/usr/bin/c++ -dumpversion | cut -d. -f1)
if [[ "${clang_major}" =~ ^[0-9]+$ && "${clang_major}" -lt 16 ]] &&
command -v gcc >/dev/null &&
command -v g++ >/dev/null; then
export CC=gcc
export CXX=g++
fi
fi
}

install_pytorch_and_domains() {
git clone https://github.com/pytorch/pytorch.git

Expand All @@ -33,14 +48,15 @@ install_pytorch_and_domains() {
if [[ -n "${PYTORCH_BUILD_MAX_JOBS:-}" ]]; then
export MAX_JOBS="${PYTORCH_BUILD_MAX_JOBS}"
fi
configure_pytorch_compiler
# Then build and install PyTorch
conda_run python setup.py bdist_wheel
pip_install "$(echo dist/*.whl)"

# Grab the pinned audio and vision commits from PyTorch
TORCHAUDIO_VERSION=release/2.11
export TORCHAUDIO_VERSION
TORCHVISION_VERSION=release/0.27
TORCHVISION_VERSION=release/0.28
export TORCHVISION_VERSION

install_domains
Expand Down
4 changes: 4 additions & 0 deletions .ci/scripts/setup-windows.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ conda activate et
# Install test dependencies
pip install -r .ci/docker/requirements-ci.txt

# PyTorch 2.13 headers use designated initializers in c10, which require C++20
# with MSVC.
$env:CMAKE_ARGS = "$env:CMAKE_ARGS -DCMAKE_CXX_STANDARD=20"

# The Windows CI image ships CUDA toolkits on PATH, so install_executorch
# (setup.py) auto-enables EXECUTORCH_BUILD_CUDA whenever the detected nvcc
# version is in SUPPORTED_CUDA_VERSIONS. CPU-only jobs install CPU torch, so a
Expand Down
18 changes: 15 additions & 3 deletions .ci/scripts/test_model_e2e_windows.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -172,22 +172,34 @@ try {
"-DCUDAToolkit_ROOT=$env:CUDA_HOME"
)
}
$cmakeCommonArgs = @("-DCMAKE_CXX_STANDARD=20")
Write-Host "::endgroup::"

Write-Host "::group::Build ExecuTorch (CUDA)"
$numCores = [Math]::Max([Environment]::ProcessorCount - 1, 1)
$cmakeOut = Join-Path -Path $executorchRoot -ChildPath "cmake-out"
$executorchCmakeDir = Join-Path -Path $cmakeOut -ChildPath "lib\cmake\ExecuTorch"
$executorchConfig = Join-Path -Path $executorchCmakeDir -ChildPath "executorch-config.cmake"
# EXECUTORCH_BUILD_EXTENSION_IMAGE defaults OFF in the preset, so it must be
# enabled explicitly here (matching the Makefile CUDA target used on Linux).
# The dinov2 runner links the installed extension_image.lib; without this the
# main install never builds it and dinov2_runner fails to link (LNK1181).
cmake --preset llm-release-cuda -DEXECUTORCH_BUILD_EXTENSION_IMAGE=ON @cmakeCudaArgs
cmake --build cmake-out --target install --config Release -j $numCores
cmake --preset llm-release-cuda -DEXECUTORCH_BUILD_EXTENSION_IMAGE=ON @cmakeCommonArgs @cmakeCudaArgs
cmake --build $cmakeOut --target install --config Release -j $numCores
if (-not (Test-Path -Path $executorchConfig -PathType Leaf)) {
throw "ExecuTorch CMake package config not found after install: $executorchConfig"
}
Write-Host "::endgroup::"

Write-Host "::group::Build $runnerTarget"
$cmakePackageArgs = @(
"-DCMAKE_FIND_ROOT_PATH=$cmakeOut",
"-DCMAKE_PREFIX_PATH=$cmakeOut;$executorchCmakeDir",
"-Dexecutorch_DIR=$executorchCmakeDir"
)
Push-Location (Join-Path -Path $executorchRoot -ChildPath "examples\models\$runnerPath")
try {
cmake --preset $runnerPreset @cmakeCudaArgs
cmake --preset $runnerPreset @cmakeCommonArgs @cmakePackageArgs @cmakeCudaArgs
cmake --build (Join-Path -Path $executorchRoot -ChildPath "cmake-out\examples\models\$runnerPath") --target $runnerTarget --config Release -j $numCores
}
finally {
Expand Down
4 changes: 2 additions & 2 deletions .ci/scripts/utils.sh
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ install_pytorch_and_domains() {
local torch_release=$(cat version.txt)
# Download key must match the upload key below (basename of dist/*.whl,
# which always carries setup.py's resolved +gitHASH). Branch-ref pins
# like `release/2.12` would otherwise produce `+gitrelease` here and
# like `release/2.13` would otherwise produce `+gitrelease` here and
# never hit the cache.
local torch_short_hash=$(git rev-parse --short=7 HEAD)
local torch_wheel_path="cached_artifacts/pytorch/executorch/pytorch_wheels/${system_name}/${python_version}"
Expand Down Expand Up @@ -178,7 +178,7 @@ install_pytorch_and_domains() {
# Grab the pinned audio and vision commits from PyTorch
TORCHAUDIO_VERSION=release/2.11
export TORCHAUDIO_VERSION
TORCHVISION_VERSION=release/0.27
TORCHVISION_VERSION=release/0.28
export TORCHVISION_VERSION

install_domains
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/_unittest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ on:
required: false
type: string
default: '3.10'
linux-timeout:
required: false
type: number
default: 90

jobs:
linux:
Expand All @@ -36,7 +40,7 @@ jobs:
docker-image: ${{ inputs.docker-image }}
submodules: 'recursive'
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
timeout: 90
timeout: ${{ inputs.linux-timeout }}
script: |
set -eux
.ci/scripts/unittest-linux.sh --build-tool "${{ inputs.build-tool }}" --build-mode "${{ inputs.build-mode }}" --editable "${{ inputs.editable }}"
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/mlx.yml
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,10 @@ jobs:
--prompt-len 4 \
--max-new-tokens 5 2>&1)
echo "$OUTPUT"
if echo "$OUTPUT" | grep -q "Generated token ids: \[167, 94, 253, 88, 227\]"; then
if echo "$OUTPUT" | grep -q "Generated token ids: \[167, 180, 167, 180, 167\]"; then
echo "Success: Qwen 3.5 MoE MLX export + inference completed with expected output"
else
echo "Failed: unexpected output (expected [167, 94, 253, 88, 227])"
echo "Failed: unexpected output (expected [167, 180, 167, 180, 167])"
exit 1
fi
echo "::endgroup::"
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/trunk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1006,6 +1006,7 @@ jobs:
build-mode: Release
build-tool: cmake
docker-image: ci-image:executorch-ubuntu-22.04-clang12
linux-timeout: 120

llm-server:
needs: [changed-files, run-decision]
Expand Down
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ project(executorch
VERSION "${ET_VERSION_MAJOR}.${ET_VERSION_MINOR}.${ET_VERSION_PATCH}"
)

if(WIN32)
add_compile_definitions(NOMINMAX)
endif()

# Hexagon toolchain with release build complains about code in third party
# libraries. Must come after project(), which runs the toolchain file that sets
# CMAKE_SYSTEM_PROCESSOR, and before add_subdirectory(third-party).
Expand Down
5 changes: 5 additions & 0 deletions backends/aoti/common_shims.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,11 @@ AOTITorchError aoti_torch_get_dim(Tensor* tensor, int64_t* ret_dim) {
return Error::Ok;
}

AOTITorchError aoti_torch_get_numel(Tensor* tensor, int64_t* ret_numel) {
*ret_numel = static_cast<int64_t>(tensor->numel());
return Error::Ok;
}

// Device and layout utility functions
int32_t aoti_torch_device_type_cpu() {
// Let's say cpu is 0 for ET as well
Expand Down
3 changes: 3 additions & 0 deletions backends/aoti/common_shims.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ aoti_torch_get_device_index(Tensor* tensor, int32_t* ret_device_index);
AOTI_SHIM_EXPORT AOTITorchError
aoti_torch_get_dim(Tensor* tensor, int64_t* ret_dim);

AOTI_SHIM_EXPORT AOTITorchError
aoti_torch_get_numel(Tensor* tensor, int64_t* ret_numel);

// Utility functions for device and layout information
AOTI_SHIM_EXPORT int32_t aoti_torch_device_type_cpu();
AOTI_SHIM_EXPORT int32_t aoti_torch_layout_strided();
Expand Down
8 changes: 8 additions & 0 deletions backends/aoti/common_shims_slim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@ AOTITorchError aoti_torch_get_dim(Tensor* tensor, int64_t* ret_dim) {
return Error::Ok;
}

AOTITorchError aoti_torch_get_numel(Tensor* tensor, int64_t* ret_numel) {
if (tensor == nullptr || ret_numel == nullptr) {
return Error::InvalidArgument;
}
*ret_numel = static_cast<int64_t>(tensor->numel());
return Error::Ok;
}

int32_t aoti_torch_layout_strided() {
// Slimtensor only support strided layout, the return value will always be 0,
// a.k.a at::Layout::Strided;
Expand Down
3 changes: 3 additions & 0 deletions backends/aoti/common_shims_slim.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ aoti_torch_get_dtype(Tensor* tensor, int32_t* ret_dtype);
AOTI_SHIM_EXPORT AOTITorchError
aoti_torch_get_dim(Tensor* tensor, int64_t* ret_dim);

AOTI_SHIM_EXPORT AOTITorchError
aoti_torch_get_numel(Tensor* tensor, int64_t* ret_numel);

AOTI_SHIM_EXPORT int32_t aoti_torch_layout_strided();

// ============================================================
Expand Down
20 changes: 20 additions & 0 deletions backends/aoti/tests/test_common_shims.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,21 @@ TEST_F(CommonShimsTest, ScalarTensor) {
error = aoti_torch_get_sizes(tensor_0d, &sizes_ptr2);
EXPECT_EQ(error, Error::Ok);
EXPECT_EQ(sizes_ptr, sizes_ptr2);

int64_t numel = -1;
error = aoti_torch_get_numel(tensor_0d, &numel);
EXPECT_EQ(error, Error::Ok);
EXPECT_EQ(numel, 1);
}

TEST_F(CommonShimsTest, GetNumel) {
auto tensor = create_tracked_tensor({2, 3, 4});

int64_t numel = -1;
AOTITorchError error = aoti_torch_get_numel(tensor, &numel);

EXPECT_EQ(error, Error::Ok);
EXPECT_EQ(numel, 24);
}

// Test large tensor dimensions
Expand All @@ -266,6 +281,11 @@ TEST_F(CommonShimsTest, LargeTensorDimensions) {
EXPECT_EQ(strides_ptr[1], 120000);
EXPECT_EQ(strides_ptr[2], 400);
EXPECT_EQ(strides_ptr[3], 1);

int64_t numel = -1;
error = aoti_torch_get_numel(tensor, &numel);
EXPECT_EQ(error, Error::Ok);
EXPECT_EQ(numel, 2400000000);
}

// Test that cleanup_tensor_metadata clears the cache
Expand Down
66 changes: 66 additions & 0 deletions backends/aoti/tests/test_common_shims_slim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,50 @@ void runGetDimTest(slim_c10::DeviceType device_type) {
}
}

void runGetNumelTest(slim_c10::DeviceType device_type) {
slim_c10::Device device(device_type, 0);

// Test 0D tensor (scalar)
{
std::vector<int64_t> sizes = {};
std::vector<int64_t> strides = {};

Tensor* tensor = new Tensor(slim::empty_strided(
slim::makeArrayRef(sizes),
slim::makeArrayRef(strides),
slim_c10::ScalarType::Float,
device));

int64_t ret_numel = -1;
AOTITorchError error = aoti_torch_get_numel(tensor, &ret_numel);

EXPECT_EQ(error, Error::Ok);
EXPECT_EQ(ret_numel, 1);

delete tensor;
}

// Test 3D tensor
{
std::vector<int64_t> sizes = {2, 3, 4};
std::vector<int64_t> strides = calculateContiguousStrides(sizes);

Tensor* tensor = new Tensor(slim::empty_strided(
slim::makeArrayRef(sizes),
slim::makeArrayRef(strides),
slim_c10::ScalarType::Float,
device));

int64_t ret_numel = -1;
AOTITorchError error = aoti_torch_get_numel(tensor, &ret_numel);

EXPECT_EQ(error, Error::Ok);
EXPECT_EQ(ret_numel, 24);

delete tensor;
}
}

// ============================================================================
// Storage & Device Property Tests
// ============================================================================
Expand Down Expand Up @@ -400,6 +444,10 @@ TEST_F(CommonShimsSlimTest, GetDim_CPU) {
runGetDimTest(slim_c10::DeviceType::CPU);
}

TEST_F(CommonShimsSlimTest, GetNumel_CPU) {
runGetNumelTest(slim_c10::DeviceType::CPU);
}

TEST_F(CommonShimsSlimTest, GetStorageOffset_CPU) {
runGetStorageOffsetTest(slim_c10::DeviceType::CPU);
}
Expand Down Expand Up @@ -456,6 +504,13 @@ TEST_F(CommonShimsSlimTest, GetDim_CUDA) {
runGetDimTest(slim_c10::DeviceType::CUDA);
}

TEST_F(CommonShimsSlimTest, GetNumel_CUDA) {
if (!isCudaAvailable()) {
GTEST_SKIP() << "CUDA not available";
}
runGetNumelTest(slim_c10::DeviceType::CUDA);
}

TEST_F(CommonShimsSlimTest, GetStorageOffset_CUDA) {
if (!isCudaAvailable()) {
GTEST_SKIP() << "CUDA not available";
Expand Down Expand Up @@ -495,13 +550,15 @@ TEST_F(CommonShimsSlimTest, NullTensorArgument) {
int64_t* strides = nullptr;
int32_t dtype = -1;
int64_t dim = -1;
int64_t numel = -1;

EXPECT_EQ(
aoti_torch_get_data_ptr(nullptr, &data_ptr), Error::InvalidArgument);
EXPECT_EQ(aoti_torch_get_sizes(nullptr, &sizes), Error::InvalidArgument);
EXPECT_EQ(aoti_torch_get_strides(nullptr, &strides), Error::InvalidArgument);
EXPECT_EQ(aoti_torch_get_dtype(nullptr, &dtype), Error::InvalidArgument);
EXPECT_EQ(aoti_torch_get_dim(nullptr, &dim), Error::InvalidArgument);
EXPECT_EQ(aoti_torch_get_numel(nullptr, &numel), Error::InvalidArgument);
}

TEST_F(CommonShimsSlimTest, NullReturnPointer) {
Expand All @@ -512,6 +569,7 @@ TEST_F(CommonShimsSlimTest, NullReturnPointer) {
EXPECT_EQ(aoti_torch_get_strides(tensor, nullptr), Error::InvalidArgument);
EXPECT_EQ(aoti_torch_get_dtype(tensor, nullptr), Error::InvalidArgument);
EXPECT_EQ(aoti_torch_get_dim(tensor, nullptr), Error::InvalidArgument);
EXPECT_EQ(aoti_torch_get_numel(tensor, nullptr), Error::InvalidArgument);
}

// ============================================================================
Expand All @@ -534,6 +592,7 @@ TEST_F(CommonShimsSlimTest, ScalarTensor) {
int64_t* ret_sizes = nullptr;
int64_t* ret_strides = nullptr;
int64_t ret_dim = -1;
int64_t ret_numel = -1;

EXPECT_EQ(aoti_torch_get_sizes(tensor, &ret_sizes), Error::Ok);
EXPECT_NE(ret_sizes, nullptr);
Expand All @@ -543,6 +602,9 @@ TEST_F(CommonShimsSlimTest, ScalarTensor) {

EXPECT_EQ(aoti_torch_get_dim(tensor, &ret_dim), Error::Ok);
EXPECT_EQ(ret_dim, 0);

EXPECT_EQ(aoti_torch_get_numel(tensor, &ret_numel), Error::Ok);
EXPECT_EQ(ret_numel, 1);
}

TEST_F(CommonShimsSlimTest, LargeTensor) {
Expand All @@ -559,6 +621,7 @@ TEST_F(CommonShimsSlimTest, LargeTensor) {

int64_t* ret_sizes = nullptr;
int64_t* ret_strides = nullptr;
int64_t ret_numel = -1;

EXPECT_EQ(aoti_torch_get_sizes(tensor, &ret_sizes), Error::Ok);
EXPECT_EQ(ret_sizes[0], 100);
Expand All @@ -569,6 +632,9 @@ TEST_F(CommonShimsSlimTest, LargeTensor) {
EXPECT_EQ(ret_strides[0], 60000); // 200 * 300
EXPECT_EQ(ret_strides[1], 300); // 300
EXPECT_EQ(ret_strides[2], 1);

EXPECT_EQ(aoti_torch_get_numel(tensor, &ret_numel), Error::Ok);
EXPECT_EQ(ret_numel, 6000000);
}

TEST_F(CommonShimsSlimTest, ConsistentPointerReturn) {
Expand Down
Loading
Loading