Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GPU] Enable Metal on macosx #47635

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion aten/src/ATen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ endif()

# Metal
if(USE_PYTORCH_METAL)
if(IOS)
if(APPLE)
set(all_cpu_cpp ${all_cpu_cpp} ${metal_cpp} ${native_metal_srcs})
else()
# Add files needed from optimized_for_mobile
Expand Down
10 changes: 5 additions & 5 deletions aten/src/ATen/native/metal/MetalPrepackOpRegister.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#include <ATen/ATen.h>


#if defined(C10_IOS)
#if (C10_IOS || TARGET_OS_MAC)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing wrong about this - just feel that having C10_IOS (defined by us) and TARGET_OS_MAC (defined by apple) on the same condition is a little unbalanced, lol.

If this condition is going to be used at other places, shall we create a dedicated macro? Not sure what's the best convention in PyTorch codebase (cc: @dzhulgakov):

  • if it's targeting apple devices, shall we introduce 'C10_APPLE'?
  • or, can we simply use some master feature switch? e.g. '#if AT_METAL_ENABLED()' seems to be one of the common pattern.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about (TARGET_OS_PHONE || TARGET_OS_MAC). Would that make you feel better 🤣

#import <ATen/native/metal/mpscnn/MPSCNNOps.h>
#endif

Expand Down Expand Up @@ -94,19 +94,19 @@ c10::intrusive_ptr<Conv2dOpContext> conv2d_prepack(
Tensor conv2d_prepack_run(
const Tensor& input,
const c10::intrusive_ptr<Conv2dOpContext>& op_context) {
#if defined(C10_IOS)
#if (C10_IOS || TARGET_OS_MAC)
return mpscnn::conv2d(input, *op_context);
#else
TORCH_CHECK(false, "conv2d_prepack_run can only be invoked on iOS");
TORCH_CHECK(false, "conv2d_prepack_run can only be invoked on iOS and MacOS");
return input;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I don't think we need 'return input;' here as TORCH_CHECK(false, ...) throws.

#endif
}

Tensor copy_to_host(const Tensor& input) {
#if defined(C10_IOS)
#if (C10_IOS || TARGET_OS_MAC)
return mpscnn::copy_to_host(input);
#else
TORCH_CHECK(false, "copy_to_host can only be invoked on iOS");
TORCH_CHECK(false, "copy_to_host can only be invoked on iOS and MacOS");
return input;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

#endif
}
Expand Down
28 changes: 23 additions & 5 deletions aten/src/ATen/native/metal/mpscnn/MPSCNNContext.mm
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
#include <torch/script.h>
#include <mutex>

#if defined(C10_IOS)
#if C10_IOS
#import <UIKit/UIKit.h>
#elif TARGET_OS_MAC
#import <Foundation/NSProcessInfo.h>
#endif

@implementation MPSCNNContext {
Expand All @@ -31,10 +33,11 @@ + (instancetype)sharedInstance {
}

- (BOOL)available {
#if defined(C10_IOS)
#if TARGET_IPHONE_SIMULATOR
#if !defined(__APPLE__)
return false;
#else
#elif TARGET_IPHONE_SIMULATOR
return false;
#elif TARGET_OS_IPHONE
if (!MPSSupportsMTLDevice(_device)) {
return false;
}
Expand All @@ -45,8 +48,23 @@ - (BOOL)available {
supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v2]) {
return false;
}
#elif TARGET_OS_MAC
if (!MPSSupportsMTLDevice(_device)) {
return false;
}
NSOperatingSystemVersion supportedVer = {10, 13, 0};
if (![[NSProcessInfo processInfo]
isOperatingSystemAtLeastVersion:supportedVer]) {
return false;
}
if (![MTLCreateSystemDefaultDevice()
supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v3]) {
return false;
}
#else
return false;
#endif
#endif

return _device && _library && _commandQueue;
}

Expand Down
12 changes: 12 additions & 0 deletions caffe2/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1195,6 +1195,18 @@ if(USE_CUDA)

endif()

# ---[ Metal(OSX) modification
if(APPLE AND USE_PYTORCH_METAL)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can we make 'USE_PYTORCH_METAL' only enabled when 'APPLE' is true?

Copy link
Contributor Author

@xta0 xta0 Nov 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

USE_PYTORCH_METAL is also available on Linux. In that case, only one cpp file under aten/native/metal will be compiled. The reason is that users can still do optimize_for_mobile on Linux machines to export models for metal.

if(NOT INTERN_BUILD_MOBILE)
include(../cmake/Metal.cmake)
# We need to link the system frameworks explicitly
find_library(metal NAMES Metal)
find_library(mps NAMES MetalPerformanceShaders)
find_library(foundation NAMES Foundation)
find_library(accelerate NAMES Accelerate)
target_link_libraries(torch_cpu PUBLIC ${metal} ${mps} ${foundation} ${accelerate})
endif()
endif()

# Note [Global dependencies]
# Some libraries (e.g. OpenMPI) like to dlopen plugins after they're initialized,
Expand Down
45 changes: 45 additions & 0 deletions cmake/Metal.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
if(NOT APPLE)
return()
endif()

if(NOT USE_PYTORCH_METAL)
return()
endif()

if(IOS OR INTERN_BUILD_MOBILE)
return()
endif()

set(OSX_PLATFORM "MacOSX.platform")
exec_program(/usr/bin/xcode-select ARGS -print-path OUTPUT_VARIABLE CMAKE_XCODE_DEVELOPER_DIR)
set(XCODE_POST_43_ROOT "${CMAKE_XCODE_DEVELOPER_DIR}/Platforms/${OSX_PLATFORM}/Developer")
set(XCODE_PRE_43_ROOT "/Developer/Platforms/${OSX_PLATFORM}/Developer")
if(NOT DEFINED CMAKE_OSX_DEVELOPER_ROOT)
if(EXISTS ${XCODE_POST_43_ROOT})
set(CMAKE_OSX_DEVELOPER_ROOT ${XCODE_POST_43_ROOT})
elseif(EXISTS ${XCODE_PRE_43_ROOT})
set(CMAKE_OSX_DEVELOPER_ROOT ${XCODE_PRE_43_ROOT})
endif(EXISTS ${XCODE_POST_43_ROOT})
endif(NOT DEFINED CMAKE_OSX_DEVELOPER_ROOT)
set(CMAKE_OSX_DEVELOPER_ROOT ${CMAKE_OSX_DEVELOPER_ROOT} CACHE PATH "Location of OSX SDKs root directory")

if(NOT DEFINED CMAKE_OSX_SDK_ROOT)
file(GLOB _CMAKE_OSX_SDKS "${CMAKE_OSX_DEVELOPER_ROOT}/SDKs/*")
if(_CMAKE_OSX_SDKS)
list(SORT _CMAKE_OSX_SDKS)
list(REVERSE _CMAKE_OSX_SDKS)
list(GET _CMAKE_OSX_SDKS 0 CMAKE_OSX_SDK_ROOT)
message(STATUS "_CMAKE_OSX_SDKS: ${_CMAKE_OSX_SDKS}")
else(_CMAKE_OSX_SDKS)
message(FATAL_ERROR "No OSX SDK's found in default search path ${CMAKE_OSX_DEVELOPER_ROOT}.")
endif(_CMAKE_OSX_SDKS)
message(STATUS "Toolchain using default OSX SDK: ${CMAKE_OSX_SDK_ROOT}")
endif(NOT DEFINED CMAKE_OSX_SDK_ROOT)
set(CMAKE_OSX_SDK_ROOT ${CMAKE_OSX_SDK_ROOT} CACHE PATH "Location of the selected OSX SDK")
set(CMAKE_FRAMEWORK_PATH
${CMAKE_OSX_SDK_ROOT}/System/Library/Frameworks
${CMAKE_OSX_SDK_ROOT}/System/Library/PrivateFrameworks
${CMAKE_OSX_SDK_ROOT}/Developer/Library/Frameworks
)
message(STATUS "CMAKE_FRAMEWORK_PATH: ${CMAKE_FRAMEWORK_PATH}")
set(CMAKE_FIND_FRAMEWORK FIRST)