summaryrefslogtreecommitdiff
path: root/offload/plugins-nextgen/common/src/RPC.cpp
diff options
context:
space:
mode:
authorJoseph Huber <huberjn@outlook.com>2025-01-24 11:36:45 -0600
committerGitHub <noreply@github.com>2025-01-24 11:36:45 -0600
commit134401deea5e86d646bb99fab39c182cfa8e5292 (patch)
treed927a2c6c73fb89fe5ed9d1df0558fc55ec04e4c /offload/plugins-nextgen/common/src/RPC.cpp
parentc025b96ef9bb364c79f73fc3afb45c851c2efb17 (diff)
[Offload] Move RPC server handling to a dedicated thread (#112988)
Summary: Handling the RPC server requires running through list of jobs that the device has requested to be done. Currently this is handled by the thread that does the waiting for the kernel to finish. However, this is not sound on NVIDIA architectures and only works for async launches in the OpenMP model that uses helper threads. However, we also don't want to have this thread doing work unnnecessarily. For this reason we track the execution of kernels and cause the thread to sleep via a condition variable (usually backed by some kind of futex or other intelligent sleeping mechanism) so that the thread will be idle while no kernels are running.
Diffstat (limited to 'offload/plugins-nextgen/common/src/RPC.cpp')
-rw-r--r--offload/plugins-nextgen/common/src/RPC.cpp123
1 files changed, 90 insertions, 33 deletions
diff --git a/offload/plugins-nextgen/common/src/RPC.cpp b/offload/plugins-nextgen/common/src/RPC.cpp
index f20c8f7bcc5c..81ad9ca66808 100644
--- a/offload/plugins-nextgen/common/src/RPC.cpp
+++ b/offload/plugins-nextgen/common/src/RPC.cpp
@@ -21,8 +21,8 @@ using namespace omp;
using namespace target;
template <uint32_t NumLanes>
-rpc::Status handle_offload_opcodes(plugin::GenericDeviceTy &Device,
- rpc::Server::Port &Port) {
+rpc::Status handleOffloadOpcodes(plugin::GenericDeviceTy &Device,
+ rpc::Server::Port &Port) {
switch (Port.get_opcode()) {
case LIBC_MALLOC: {
@@ -62,21 +62,99 @@ rpc::Status handle_offload_opcodes(plugin::GenericDeviceTy &Device,
return rpc::RPC_SUCCESS;
}
-static rpc::Status handle_offload_opcodes(plugin::GenericDeviceTy &Device,
- rpc::Server::Port &Port,
- uint32_t NumLanes) {
+static rpc::Status handleOffloadOpcodes(plugin::GenericDeviceTy &Device,
+ rpc::Server::Port &Port,
+ uint32_t NumLanes) {
if (NumLanes == 1)
- return handle_offload_opcodes<1>(Device, Port);
+ return handleOffloadOpcodes<1>(Device, Port);
else if (NumLanes == 32)
- return handle_offload_opcodes<32>(Device, Port);
+ return handleOffloadOpcodes<32>(Device, Port);
else if (NumLanes == 64)
- return handle_offload_opcodes<64>(Device, Port);
+ return handleOffloadOpcodes<64>(Device, Port);
else
return rpc::RPC_ERROR;
}
+static rpc::Status runServer(plugin::GenericDeviceTy &Device, void *Buffer) {
+ uint64_t NumPorts =
+ std::min(Device.requestedRPCPortCount(), rpc::MAX_PORT_COUNT);
+ rpc::Server Server(NumPorts, Buffer);
+
+ auto Port = Server.try_open(Device.getWarpSize());
+ if (!Port)
+ return rpc::RPC_SUCCESS;
+
+ rpc::Status Status =
+ handleOffloadOpcodes(Device, *Port, Device.getWarpSize());
+
+ // Let the `libc` library handle any other unhandled opcodes.
+#ifdef LIBOMPTARGET_RPC_SUPPORT
+ if (Status == rpc::RPC_UNHANDLED_OPCODE)
+ Status = handle_libc_opcodes(*Port, Device.getWarpSize());
+#endif
+
+ Port->close();
+
+ return Status;
+}
+
+void RPCServerTy::ServerThread::startThread() {
+ Worker = std::thread([this]() { run(); });
+}
+
+void RPCServerTy::ServerThread::shutDown() {
+ {
+ std::lock_guard<decltype(Mutex)> Lock(Mutex);
+ Running.store(false, std::memory_order_release);
+ CV.notify_all();
+ }
+ if (Worker.joinable())
+ Worker.join();
+}
+
+void RPCServerTy::ServerThread::run() {
+ std::unique_lock<decltype(Mutex)> Lock(Mutex);
+ for (;;) {
+ CV.wait(Lock, [&]() {
+ return NumUsers.load(std::memory_order_acquire) > 0 ||
+ !Running.load(std::memory_order_acquire);
+ });
+
+ if (!Running.load(std::memory_order_acquire))
+ return;
+
+ Lock.unlock();
+ while (NumUsers.load(std::memory_order_relaxed) > 0 &&
+ Running.load(std::memory_order_relaxed)) {
+ for (const auto &[Buffer, Device] : llvm::zip_equal(Buffers, Devices)) {
+ if (!Buffer || !Device)
+ continue;
+
+ // If running the server failed, print a message but keep running.
+ if (runServer(*Device, Buffer) != rpc::RPC_SUCCESS)
+ FAILURE_MESSAGE("Unhandled or invalid RPC opcode!");
+ }
+ }
+ Lock.lock();
+ }
+}
+
RPCServerTy::RPCServerTy(plugin::GenericPluginTy &Plugin)
- : Buffers(Plugin.getNumDevices()) {}
+ : Buffers(std::make_unique<void *[]>(Plugin.getNumDevices())),
+ Devices(std::make_unique<plugin::GenericDeviceTy *[]>(
+ Plugin.getNumDevices())),
+ Thread(new ServerThread(Buffers.get(), Devices.get(),
+ Plugin.getNumDevices())) {}
+
+llvm::Error RPCServerTy::startThread() {
+ Thread->startThread();
+ return Error::success();
+}
+
+llvm::Error RPCServerTy::shutDown() {
+ Thread->shutDown();
+ return Error::success();
+}
llvm::Expected<bool>
RPCServerTy::isDeviceUsingRPC(plugin::GenericDeviceTy &Device,
@@ -108,35 +186,14 @@ Error RPCServerTy::initDevice(plugin::GenericDeviceTy &Device,
sizeof(rpc::Client), nullptr))
return Err;
Buffers[Device.getDeviceId()] = RPCBuffer;
-
- return Error::success();
-}
-
-Error RPCServerTy::runServer(plugin::GenericDeviceTy &Device) {
- uint64_t NumPorts =
- std::min(Device.requestedRPCPortCount(), rpc::MAX_PORT_COUNT);
- rpc::Server Server(NumPorts, Buffers[Device.getDeviceId()]);
-
- auto Port = Server.try_open(Device.getWarpSize());
- if (!Port)
- return Error::success();
-
- int Status = handle_offload_opcodes(Device, *Port, Device.getWarpSize());
-
- // Let the `libc` library handle any other unhandled opcodes.
-#ifdef LIBOMPTARGET_RPC_SUPPORT
- if (Status == rpc::RPC_UNHANDLED_OPCODE)
- Status = handle_libc_opcodes(*Port, Device.getWarpSize());
-#endif
-
- Port->close();
- if (Status != rpc::RPC_SUCCESS)
- return createStringError("RPC server given invalid opcode!");
+ Devices[Device.getDeviceId()] = &Device;
return Error::success();
}
Error RPCServerTy::deinitDevice(plugin::GenericDeviceTy &Device) {
Device.free(Buffers[Device.getDeviceId()], TARGET_ALLOC_HOST);
+ Buffers[Device.getDeviceId()] = nullptr;
+ Devices[Device.getDeviceId()] = nullptr;
return Error::success();
}