Skip to content

Commit 32eadf3

Browse files
shoumikhinfacebook-github-bot
authored andcommitted
Make the CUDA caller-stream guard a shared extension/cuda library
Summary: Move the caller-stream handshake (`CallerStreamGuard` + `getCallerStream()`) out of the CUDA backend's `backends/aoti/slim/cuda/guard` into a standalone `extension/cuda` library, and build that library as SHARED so several CUDA backends can share one caller-selected stream. The handshake is a process-wide thread-local: the caller records the stream it wants, and each backend reads it. That only works if there is exactly one copy of the thread-local in the process. If the library were static and linked into two shared objects (for example the CUDA backend and a TensorRT delegate, each whole-archived for backend registration), each shared object would get its own copy, so the caller would write one and the backend would read the other and silently ignore the caller's stream. Building `extension_cuda` as SHARED gives one definition that every consumer references. It must be linked PUBLIC and never whole-archived. The two public functions are exported through a visibility macro (`extension/cuda/export.h`, mirroring `backends/aoti/export.h`) while the thread-local stays internal to the library. The C++ API is used directly: `getCallerStream()` returns `std::optional<cudaStream_t>`, a trivially copyable pointer and bool that does not depend on the libstdc++ CXX11 ABI, so no C ABI is needed. The header is installed so an external project (such as a TensorRT delegate) can include it. Differential Revision: D108023495
1 parent 30fa8ec commit 32eadf3

18 files changed

Lines changed: 224 additions & 45 deletions

CMakeLists.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,20 @@ if(EXECUTORCH_BUILD_CUDA
764764
find_package_torch()
765765
endif()
766766

767+
# Backend-neutral caller-stream guard consumed by the CUDA AOTI backend (and the
768+
# vendored torch-tensorrt delegate). Built before backends/aoti and
769+
# backends/cuda, which link it.
770+
if(EXECUTORCH_BUILD_CUDA)
771+
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/extension/cuda)
772+
install(
773+
DIRECTORY extension/cuda/
774+
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/executorch/extension/cuda
775+
FILES_MATCHING
776+
PATTERN "*.h"
777+
)
778+
list(APPEND _executorch_extensions extension_cuda)
779+
endif()
780+
767781
# Build common AOTI functionality if needed by CUDA or Metal backends
768782
if(EXECUTORCH_BUILD_CUDA OR EXECUTORCH_BUILD_METAL)
769783
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/backends/aoti)

backends/aoti/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ target_compile_definitions(
8787
if(EXECUTORCH_BUILD_CUDA)
8888
find_package(CUDAToolkit REQUIRED)
8989
target_include_directories(slimtensor INTERFACE ${CUDAToolkit_INCLUDE_DIRS})
90-
target_link_libraries(slimtensor INTERFACE CUDA::cudart)
90+
target_link_libraries(slimtensor INTERFACE CUDA::cudart extension_cuda)
9191
endif()
9292

9393
install(

backends/aoti/slim/core/storage.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#ifdef CUDA_AVAILABLE
1414
#include <executorch/backends/aoti/slim/c10/cuda/Exception.h>
1515
#include <executorch/backends/aoti/slim/cuda/guard.h>
16+
#include <executorch/extension/cuda/caller_stream.h>
1617
#include <executorch/backends/cuda/runtime/cuda_allocator.h>
1718
#endif
1819

@@ -181,7 +182,7 @@ struct DeviceTraits<c10::DeviceType::CUDA> {
181182
// green context would not confine. When a caller stream is active, copy
182183
// on it asynchronously and synchronize it to preserve blocking
183184
// semantics; otherwise fall back to the plain synchronous copy.
184-
const auto caller_stream = executorch::backends::cuda::getCallerStream();
185+
const auto caller_stream = executorch::extension::cuda::getCallerStream();
185186
if (caller_stream) {
186187
ET_CUDA_CHECK(
187188
cudaMemcpyAsync(dst, src, nbytes, direction, *caller_stream));

backends/aoti/slim/core/targets.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ def define_common_targets():
2020
"//executorch/backends/aoti/slim/c10/cuda:exception",
2121
"//executorch/backends/aoti/slim/cuda:guard",
2222
"//executorch/backends/cuda/runtime:cuda_allocator",
23+
"//executorch/extension/cuda:caller_stream",
2324
],
2425
)
2526

backends/aoti/slim/cuda/guard.cpp

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ namespace executorch::backends::cuda {
1717
namespace {
1818
// Thread-local stream storage (private to this file)
1919
thread_local std::unordered_map<DeviceIndex, cudaStream_t> current_streams_;
20-
thread_local std::optional<cudaStream_t> caller_stream_;
2120
} // namespace
2221

2322
Error setCurrentCUDAStream(cudaStream_t stream, DeviceIndex device_index) {
@@ -81,19 +80,6 @@ void clearCurrentCUDAStream(DeviceIndex device_index) {
8180
current_streams_.erase(device_index);
8281
}
8382

84-
std::optional<cudaStream_t> getCallerStream() {
85-
return caller_stream_;
86-
}
87-
88-
CallerStreamGuard::CallerStreamGuard(cudaStream_t stream)
89-
: previous_(caller_stream_) {
90-
caller_stream_ = stream;
91-
}
92-
93-
CallerStreamGuard::~CallerStreamGuard() {
94-
caller_stream_ = previous_;
95-
}
96-
9783
CUDAGuard::CUDAGuard(CUDAGuard&& other) noexcept
9884
: original_device_index_(other.original_device_index_),
9985
current_device_index_(other.current_device_index_) {

backends/aoti/slim/cuda/guard.h

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -66,33 +66,6 @@ std::optional<cudaStream_t> peekCurrentCUDAStream(
6666
*/
6767
void clearCurrentCUDAStream(DeviceIndex device_index = -1);
6868

69-
/**
70-
* The CUDA stream the caller selected for this thread (via CallerStreamGuard),
71-
* or std::nullopt if none. The CUDA backend runs on it when set, otherwise it
72-
* uses its own stream. Kept separate from getCurrentCUDAStream so an explicit
73-
* caller choice is distinguishable from a lazily-created stream.
74-
*/
75-
std::optional<cudaStream_t> getCallerStream();
76-
77-
/**
78-
* Scopes the CUDA stream the backend should run on for the calling thread, and
79-
* restores the previous selection on destruction. One value per thread; a
80-
* cuGreenCtxStreamCreate stream confines work to that green context's SM
81-
* partition.
82-
*/
83-
class CallerStreamGuard {
84-
public:
85-
explicit CallerStreamGuard(cudaStream_t stream);
86-
~CallerStreamGuard();
87-
CallerStreamGuard(const CallerStreamGuard&) = delete;
88-
CallerStreamGuard& operator=(const CallerStreamGuard&) = delete;
89-
CallerStreamGuard(CallerStreamGuard&&) = delete;
90-
CallerStreamGuard& operator=(CallerStreamGuard&&) = delete;
91-
92-
private:
93-
std::optional<cudaStream_t> previous_;
94-
};
95-
9669
/**
9770
* RAII guard that sets the current CUDA device and restores it on destruction.
9871
* This ensures that the device is properly restored even if an exception

backends/aoti/slim/cuda/test/targets.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ def cuda_slim_cpp_unittest(name):
99
],
1010
deps = [
1111
"//executorch/backends/aoti/slim/cuda:guard",
12+
"//executorch/extension/cuda:caller_stream",
1213
"//executorch/runtime/core:core",
1314
"//executorch/runtime/core/exec_aten:lib",
1415
"//executorch/runtime/platform:platform",

backends/aoti/slim/cuda/test/test_cuda_stream_guard.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@
88

99
#include <cuda_runtime.h>
1010
#include <executorch/backends/aoti/slim/cuda/guard.h>
11+
#include <executorch/extension/cuda/caller_stream.h>
1112
#include <executorch/runtime/platform/platform.h>
1213
#include <gtest/gtest.h>
1314

1415
#include <type_traits>
1516

1617
using namespace executorch::backends::cuda;
18+
using namespace executorch::extension::cuda;
1719
using namespace executorch::runtime;
1820

1921
// TODO(gasoonjia): Multiple device tests were not included due to test

backends/cuda/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ endif()
213213
# consumers.
214214
target_link_libraries(
215215
aoti_cuda_backend PUBLIC cuda_platform extension_tensor CUDA::cudart
216-
${CMAKE_DL_LIBS}
216+
extension_cuda ${CMAKE_DL_LIBS}
217217
)
218218

219219
if(_cuda_is_msvc_toolchain)

backends/cuda/runtime/TARGETS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ runtime.cxx_library(
126126
"//executorch/backends/aoti/slim/factory:empty",
127127
"//executorch/backends/aoti/slim/factory:from_blob",
128128
"//executorch/backends/aoti/slim/factory:from_etensor",
129+
"//executorch/extension/cuda:caller_stream",
129130
"//executorch/extension/tensor:tensor",
130131
"//executorch/runtime/backend:interface",
131132
"//executorch/runtime/core/exec_aten/util:tensor_util",

0 commit comments

Comments
 (0)