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
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
9 changes: 8 additions & 1 deletion .ci/scripts/test_model_e2e_windows.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,16 @@ try {
Write-Host "::endgroup::"

Write-Host "::group::Build $runnerTarget"
$cmakeOut = Join-Path -Path $executorchRoot -ChildPath "cmake-out"
$executorchCmakeDir = Join-Path -Path $cmakeOut -ChildPath "lib\cmake\ExecuTorch"
$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 @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
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
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
29 changes: 29 additions & 0 deletions backends/cuda/cuda_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@
return passes

@classmethod
def get_aoti_compile_options(

Check warning on line 428 in backends/cuda/cuda_backend.py

View workflow job for this annotation

GitHub Actions / lintrunner

FLAKE8 C901

'CudaBackend.get_aoti_compile_options' is too complex (15) See https://www.flake8rules.com/rules/C901.html.
cls, compile_specs: List[CompileSpec]
) -> Dict[str, typing.Any]:
"""
Expand Down Expand Up @@ -496,12 +496,41 @@
# Parse compile_specs to check for platform

platform = "linux"
emulate_precision_casts = "ON"
max_autotune = "ON"
autotune_at_compile_time = None
shim_library_path = None
for spec in compile_specs:
if spec.key == "platform":
platform = spec.value.decode("utf-8")
if spec.key == "emulate_precision_casts":
emulate_precision_casts = spec.value.decode("utf-8").upper()
if emulate_precision_casts not in ["ON", "OFF"]:
raise ValueError(
"Invalid emulate_precision_casts: "
f"{emulate_precision_casts}. Expected 'ON' or 'OFF'."
)
if spec.key == "max_autotune":
max_autotune = spec.value.decode("utf-8").upper()
if max_autotune not in ["ON", "OFF"]:
raise ValueError(
f"Invalid max_autotune: {max_autotune}. Expected 'ON' or 'OFF'."
)
if spec.key == "autotune_at_compile_time":
autotune_at_compile_time = spec.value.decode("utf-8").upper()
if autotune_at_compile_time not in ["ON", "OFF"]:
raise ValueError(
"Invalid autotune_at_compile_time: "
f"{autotune_at_compile_time}. Expected 'ON' or 'OFF'."
)
if spec.key == "shim_library_path":
shim_library_path = spec.value.decode("utf-8")
options["emulate_precision_casts"] = emulate_precision_casts == "ON"
options["max_autotune"] = max_autotune == "ON"
if autotune_at_compile_time is not None:
options["triton.autotune_at_compile_time"] = (
autotune_at_compile_time == "ON"
)
# Add platform-specific options

if platform == "windows":
Expand Down
Binary file modified backends/cuda/runtime/aoti_cuda_shims.lib
Binary file not shown.
41 changes: 41 additions & 0 deletions backends/cuda/tests/test_cuda_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,47 @@
from torch.export import export


class TestCudaBackendCompileOptions(unittest.TestCase):
def test_emulate_precision_casts_compile_spec(self):
options = CudaBackend.get_aoti_compile_options(
[CompileSpec(key="emulate_precision_casts", value=b"OFF")]
)

self.assertFalse(options["emulate_precision_casts"])

def test_invalid_emulate_precision_casts_compile_spec(self):
with self.assertRaisesRegex(ValueError, "Invalid emulate_precision_casts"):
CudaBackend.get_aoti_compile_options(
[CompileSpec(key="emulate_precision_casts", value=b"MAYBE")]
)

def test_max_autotune_compile_spec(self):
options = CudaBackend.get_aoti_compile_options(
[CompileSpec(key="max_autotune", value=b"OFF")]
)

self.assertFalse(options["max_autotune"])

def test_invalid_max_autotune_compile_spec(self):
with self.assertRaisesRegex(ValueError, "Invalid max_autotune"):
CudaBackend.get_aoti_compile_options(
[CompileSpec(key="max_autotune", value=b"MAYBE")]
)

def test_autotune_at_compile_time_compile_spec(self):
options = CudaBackend.get_aoti_compile_options(
[CompileSpec(key="autotune_at_compile_time", value=b"OFF")]
)

self.assertFalse(options["triton.autotune_at_compile_time"])

def test_invalid_autotune_at_compile_time_compile_spec(self):
with self.assertRaisesRegex(ValueError, "Invalid autotune_at_compile_time"):
CudaBackend.get_aoti_compile_options(
[CompileSpec(key="autotune_at_compile_time", value=b"MAYBE")]
)


class TestCudaExport(unittest.TestCase):
"""Test CUDA export functionality for various operations using to_edge_transform_and_lower."""

Expand Down
Loading
Loading