diff --git a/AbstractAPI.h b/AbstractAPI.h index bde98ee..27192b0 100644 --- a/AbstractAPI.h +++ b/AbstractAPI.h @@ -114,6 +114,15 @@ struct AbstractAPI { virtual void putProfilingMark(const std::string& name, ProfilingColors color) = 0; virtual void popLastProfilingMark() = 0; + virtual bool canAccessPeer(int otherDeviceId) = 0; + virtual void switchPeerAccess(int otherDeviceId, bool enable) = 0; + + virtual std::vector makeIpcMemHandle(void* ptr) = 0; + virtual void* openIpcMemHandle(const std::vector& handle) = 0; + virtual void closeIpcMemHandle(void* ptr) = 0; + virtual std::vector makeIpcEventHandle(void* event) = 0; + virtual void* openIpcEventHandle(const std::vector& handle) = 0; + virtual void setupPrinting(int rank) = 0; bool hasFinalized() { return m_isFinalized; } diff --git a/cuda.cmake b/cuda.cmake index 3c5e0d6..9cff6d7 100644 --- a/cuda.cmake +++ b/cuda.cmake @@ -13,6 +13,7 @@ add_library(device ${DEVICE_LIBTYPE} device.cpp interfaces/cuda/Streams.cu interfaces/cuda/Graphs.cu interfaces/cuda/Internals.cu + interfaces/cuda/Interop.cu algorithms/cudahip/ArrayManip.cpp algorithms/cudahip/BatchManip.cpp algorithms/cudahip/Debugging.cpp diff --git a/hip.cmake b/hip.cmake index f8b3d88..90f5ba7 100644 --- a/hip.cmake +++ b/hip.cmake @@ -65,6 +65,7 @@ set(DEVICE_SOURCE_FILES device.cpp interfaces/hip/Memory.cpp interfaces/hip/Streams.cpp interfaces/hip/Graphs.cpp + interfaces/hip/Interop.cpp algorithms/cudahip/ArrayManip.cpp algorithms/cudahip/BatchManip.cpp algorithms/cudahip/Debugging.cpp diff --git a/interfaces/cuda/CudaWrappedAPI.h b/interfaces/cuda/CudaWrappedAPI.h index 6233474..790da92 100644 --- a/interfaces/cuda/CudaWrappedAPI.h +++ b/interfaces/cuda/CudaWrappedAPI.h @@ -20,6 +20,7 @@ #include namespace device { + class ConcreteAPI : public AbstractAPI { public: ConcreteAPI(); @@ -111,6 +112,15 @@ class ConcreteAPI : public AbstractAPI { bool isUnifiedMemoryDefault() override; + bool canAccessPeer(int otherDeviceId) override; + void switchPeerAccess(int otherDeviceId, bool enable) override; + + std::vector makeIpcMemHandle(void* ptr) override; + void* openIpcMemHandle(const std::vector& handle) override; + void closeIpcMemHandle(void* ptr) override; + std::vector makeIpcEventHandle(void* event) override; + void* openIpcEventHandle(const std::vector& handle) override; + void setupPrinting(int rank) override; private: diff --git a/interfaces/cuda/Interop.cu b/interfaces/cuda/Interop.cu new file mode 100644 index 0000000..d8bb336 --- /dev/null +++ b/interfaces/cuda/Interop.cu @@ -0,0 +1,69 @@ +// SPDX-FileCopyrightText: 2026 SeisSol Group +// +// SPDX-License-Identifier: BSD-3-Clause + +#include "AbstractAPI.h" +#include "CudaWrappedAPI.h" +#include "Internals.h" +#include "utils/logger.h" + +using namespace device; + +namespace { + +template +std::vector serialize(const T& data) { + std::vector ser(sizeof(T)); + memcpy(ser.data(), &data, sizeof(T)); + return ser; +} + +template +T deserialize(const std::vector& ser) { + T data{}; + memcpy(&data, ser.data(), sizeof(T)); + return data; +} + +} // namespace + +bool ConcreteAPI::canAccessPeer(int otherDeviceId) { + int result = 0; + APIWRAP(cudaDeviceCanAccessPeer(&result, getDeviceId(), otherDeviceId)); + return result != 0; +} + +void ConcreteAPI::switchPeerAccess(int otherDeviceId, bool enable) { + if (enable) { + APIWRAP(cudaDeviceEnablePeerAccess(otherDeviceId, 0)); + } else { + APIWRAP(cudaDeviceDisablePeerAccess(otherDeviceId)); + } +} + +std::vector ConcreteAPI::makeIpcMemHandle(void* ptr) { + cudaIpcMemHandle_t handle{}; + APIWRAP(cudaIpcGetMemHandle(&handle, ptr)); + return serialize(handle); +} + +void* ConcreteAPI::openIpcMemHandle(const std::vector& handle) { + void* ptr = nullptr; + APIWRAP(cudaIpcOpenMemHandle( + &ptr, deserialize(handle), cudaIpcMemLazyEnablePeerAccess)); + return ptr; +} + +void ConcreteAPI::closeIpcMemHandle(void* ptr) { APIWRAP(cudaIpcCloseMemHandle(ptr)); } + +std::vector ConcreteAPI::makeIpcEventHandle(void* event) { + cudaIpcEventHandle_t handle{}; + APIWRAP(cudaIpcGetEventHandle(&handle, static_cast(event))); + return serialize(handle); +} + +void* ConcreteAPI::openIpcEventHandle(const std::vector& handle) { + cudaEvent_t event{}; + APIWRAP(cudaIpcOpenEventHandle(&event, deserialize(handle))); + return static_cast(event); +} diff --git a/interfaces/hip/HipWrappedAPI.h b/interfaces/hip/HipWrappedAPI.h index 121b55b..967633a 100644 --- a/interfaces/hip/HipWrappedAPI.h +++ b/interfaces/hip/HipWrappedAPI.h @@ -110,6 +110,15 @@ class ConcreteAPI : public AbstractAPI { bool isUnifiedMemoryDefault() override; + bool canAccessPeer(int otherDeviceId) override; + void switchPeerAccess(int otherDeviceId, bool enable) override; + + std::vector makeIpcMemHandle(void* ptr) override; + void* openIpcMemHandle(const std::vector& handle) override; + void closeIpcMemHandle(void* ptr) override; + std::vector makeIpcEventHandle(void* event) override; + void* openIpcEventHandle(const std::vector& handle) override; + void setupPrinting(int rank) override; private: diff --git a/interfaces/hip/Interop.cpp b/interfaces/hip/Interop.cpp new file mode 100644 index 0000000..ca6b7f5 --- /dev/null +++ b/interfaces/hip/Interop.cpp @@ -0,0 +1,72 @@ +// SPDX-FileCopyrightText: 2026 SeisSol Group +// +// SPDX-License-Identifier: BSD-3-Clause + +#include "AbstractAPI.h" +#include "HipWrappedAPI.h" +#include "Internals.h" +#include "utils/logger.h" + +#include +#include + +using namespace device; + +namespace { + +template +std::vector serialize(const T& data) { + std::vector ser(sizeof(T)); + memcpy(ser.data(), &data, sizeof(T)); + return ser; +} + +template +T deserialize(const std::vector& ser) { + T data{}; + memcpy(&data, ser.data(), sizeof(T)); + return data; +} + +} // namespace + +bool ConcreteAPI::canAccessPeer(int otherDeviceId) { + int result = 0; + APIWRAP(hipDeviceCanAccessPeer(&result, getDeviceId(), otherDeviceId)); + return result != 0; +} + +void ConcreteAPI::switchPeerAccess(int otherDeviceId, bool enable) { + if (enable) { + APIWRAP(hipDeviceEnablePeerAccess(otherDeviceId, 0)); + } else { + APIWRAP(hipDeviceDisablePeerAccess(otherDeviceId)); + } +} + +std::vector ConcreteAPI::makeIpcMemHandle(void* ptr) { + hipIpcMemHandle_t handle{}; + APIWRAP(hipIpcGetMemHandle(&handle, ptr)); + return serialize(handle); +} + +void* ConcreteAPI::openIpcMemHandle(const std::vector& handle) { + void* ptr = nullptr; + APIWRAP(hipIpcOpenMemHandle( + &ptr, deserialize(handle), hipIpcMemLazyEnablePeerAccess)); + return ptr; +} + +void ConcreteAPI::closeIpcMemHandle(void* ptr) { APIWRAP(hipIpcCloseMemHandle(ptr)); } + +std::vector ConcreteAPI::makeIpcEventHandle(void* event) { + hipIpcEventHandle_t handle{}; + APIWRAP(hipIpcGetEventHandle(&handle, static_cast(event))); + return serialize(handle); +} + +void* ConcreteAPI::openIpcEventHandle(const std::vector& handle) { + hipEvent_t event{}; + APIWRAP(hipIpcOpenEventHandle(&event, deserialize(handle))); + return static_cast(event); +} diff --git a/interfaces/sycl/SyclWrappedAPI.h b/interfaces/sycl/SyclWrappedAPI.h index 3f854b4..690ff24 100644 --- a/interfaces/sycl/SyclWrappedAPI.h +++ b/interfaces/sycl/SyclWrappedAPI.h @@ -146,6 +146,15 @@ class ConcreteAPI : public AbstractAPI { bool isUnifiedMemoryDefault() override; + bool canAccessPeer(int otherDeviceId) override; + void switchPeerAccess(int otherDeviceId, bool enable) override; + + std::vector makeIpcMemHandle(void* ptr) override; + void* openIpcMemHandle(const std::vector& handle) override; + void closeIpcMemHandle(void* ptr) override; + std::vector makeIpcEventHandle(void* event) override; + void* openIpcEventHandle(const std::vector& handle) override; + void setupPrinting(int rank) override; private: