| //===----------------- Server.cpp - Server Implementation -----------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Offloading gRPC server for remote host. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include <cmath> |
| #include <future> |
| |
| #include "Server.h" |
| #include "omptarget.h" |
| #include "openmp.grpc.pb.h" |
| #include "openmp.pb.h" |
| |
| using grpc::WriteOptions; |
| |
| extern std::promise<void> ShutdownPromise; |
| |
| Status RemoteOffloadImpl::Shutdown(ServerContext *Context, const Null *Request, |
| I32 *Reply) { |
| SERVER_DBG("Shutting down the server"); |
| |
| Reply->set_number(0); |
| ShutdownPromise.set_value(); |
| return Status::OK; |
| } |
| |
| Status |
| RemoteOffloadImpl::RegisterLib(ServerContext *Context, |
| const TargetBinaryDescription *Description, |
| I32 *Reply) { |
| SERVER_DBG("Registering library"); |
| |
| auto Desc = std::make_unique<__tgt_bin_desc>(); |
| |
| unloadTargetBinaryDescription(Description, Desc.get(), |
| HostToRemoteDeviceImage); |
| PM->RTLs.RegisterLib(Desc.get()); |
| |
| if (Descriptions.find((void *)Description->bin_ptr()) != Descriptions.end()) |
| freeTargetBinaryDescription( |
| Descriptions[(void *)Description->bin_ptr()].get()); |
| else |
| Descriptions[(void *)Description->bin_ptr()] = std::move(Desc); |
| |
| SERVER_DBG("Registered library"); |
| Reply->set_number(0); |
| return Status::OK; |
| } |
| |
| Status RemoteOffloadImpl::UnregisterLib(ServerContext *Context, |
| const Pointer *Request, I32 *Reply) { |
| SERVER_DBG("Unregistering library"); |
| |
| if (Descriptions.find((void *)Request->number()) == Descriptions.end()) { |
| Reply->set_number(1); |
| return Status::OK; |
| } |
| |
| PM->RTLs.UnregisterLib(Descriptions[(void *)Request->number()].get()); |
| freeTargetBinaryDescription(Descriptions[(void *)Request->number()].get()); |
| Descriptions.erase((void *)Request->number()); |
| |
| SERVER_DBG("Unregistered library"); |
| Reply->set_number(0); |
| return Status::OK; |
| } |
| |
| Status RemoteOffloadImpl::IsValidBinary(ServerContext *Context, |
| const TargetDeviceImagePtr *DeviceImage, |
| I32 *IsValid) { |
| SERVER_DBG("Checking if binary (%p) is valid", |
| (void *)(DeviceImage->image_ptr())); |
| |
| __tgt_device_image *Image = |
| HostToRemoteDeviceImage[(void *)DeviceImage->image_ptr()]; |
| |
| IsValid->set_number(0); |
| |
| for (auto &RTL : PM->RTLs.AllRTLs) |
| if (auto Ret = RTL.is_valid_binary(Image)) { |
| IsValid->set_number(Ret); |
| break; |
| } |
| |
| SERVER_DBG("Checked if binary (%p) is valid", |
| (void *)(DeviceImage->image_ptr())); |
| return Status::OK; |
| } |
| |
| Status RemoteOffloadImpl::GetNumberOfDevices(ServerContext *Context, |
| const Null *Null, |
| I32 *NumberOfDevices) { |
| SERVER_DBG("Getting number of devices"); |
| std::call_once(PM->RTLs.initFlag, &RTLsTy::LoadRTLs, &PM->RTLs); |
| |
| int32_t Devices = 0; |
| PM->RTLsMtx.lock(); |
| for (auto &RTL : PM->RTLs.AllRTLs) |
| Devices += RTL.NumberOfDevices; |
| PM->RTLsMtx.unlock(); |
| |
| NumberOfDevices->set_number(Devices); |
| |
| SERVER_DBG("Got number of devices"); |
| return Status::OK; |
| } |
| |
| Status RemoteOffloadImpl::InitDevice(ServerContext *Context, |
| const I32 *DeviceNum, I32 *Reply) { |
| SERVER_DBG("Initializing device %d", DeviceNum->number()); |
| |
| Reply->set_number(PM->Devices[DeviceNum->number()].RTL->init_device( |
| mapHostRTLDeviceId(DeviceNum->number()))); |
| |
| SERVER_DBG("Initialized device %d", DeviceNum->number()); |
| return Status::OK; |
| } |
| |
| Status RemoteOffloadImpl::InitRequires(ServerContext *Context, |
| const I64 *RequiresFlag, I32 *Reply) { |
| SERVER_DBG("Initializing requires for devices"); |
| |
| for (auto &Device : PM->Devices) |
| if (Device.RTL->init_requires) |
| Device.RTL->init_requires(RequiresFlag->number()); |
| Reply->set_number(RequiresFlag->number()); |
| |
| SERVER_DBG("Initialized requires for devices"); |
| return Status::OK; |
| } |
| |
| Status RemoteOffloadImpl::LoadBinary(ServerContext *Context, |
| const Binary *Binary, TargetTable *Reply) { |
| SERVER_DBG("Loading binary (%p) to device %d", (void *)Binary->image_ptr(), |
| Binary->device_id()); |
| |
| __tgt_device_image *Image = |
| HostToRemoteDeviceImage[(void *)Binary->image_ptr()]; |
| |
| Table = PM->Devices[Binary->device_id()].RTL->load_binary( |
| mapHostRTLDeviceId(Binary->device_id()), Image); |
| if (Table) |
| loadTargetTable(Table, *Reply, Image); |
| |
| SERVER_DBG("Loaded binary (%p) to device %d", (void *)Binary->image_ptr(), |
| Binary->device_id()); |
| return Status::OK; |
| } |
| |
| Status RemoteOffloadImpl::Synchronize(ServerContext *Context, |
| const SynchronizeDevice *Info, |
| I32 *Reply) { |
| SERVER_DBG("Synchronizing device %d (probably won't work)", |
| Info->device_id()); |
| |
| void *AsyncInfoPtr = (void *)Info->queue_ptr(); |
| Reply->set_number(0); |
| if (PM->Devices[Info->device_id()].RTL->synchronize) |
| Reply->set_number(PM->Devices[Info->device_id()].synchronize( |
| (__tgt_async_info *)AsyncInfoPtr)); |
| |
| SERVER_DBG("Synchronized device %d", Info->device_id()); |
| return Status::OK; |
| } |
| |
| Status RemoteOffloadImpl::IsDataExchangeable(ServerContext *Context, |
| const DevicePair *Request, |
| I32 *Reply) { |
| SERVER_DBG("Checking if data exchangable between device %d and device %d", |
| Request->src_dev_id(), Request->dst_dev_id()); |
| |
| Reply->set_number(-1); |
| if (PM->Devices[mapHostRTLDeviceId(Request->src_dev_id())] |
| .RTL->is_data_exchangable) |
| Reply->set_number(PM->Devices[mapHostRTLDeviceId(Request->src_dev_id())] |
| .RTL->is_data_exchangable(Request->src_dev_id(), |
| Request->dst_dev_id())); |
| |
| SERVER_DBG("Checked if data exchangable between device %d and device %d", |
| Request->src_dev_id(), Request->dst_dev_id()); |
| return Status::OK; |
| } |
| |
| Status RemoteOffloadImpl::DataAlloc(ServerContext *Context, |
| const AllocData *Request, Pointer *Reply) { |
| SERVER_DBG("Allocating %ld bytes on sevice %d", Request->size(), |
| Request->device_id()); |
| |
| uint64_t TgtPtr = (uint64_t)PM->Devices[Request->device_id()].RTL->data_alloc( |
| mapHostRTLDeviceId(Request->device_id()), Request->size(), |
| (void *)Request->hst_ptr()); |
| Reply->set_number(TgtPtr); |
| |
| SERVER_DBG("Allocated at " DPxMOD "", DPxPTR((void *)TgtPtr)); |
| |
| return Status::OK; |
| } |
| |
| Status RemoteOffloadImpl::DataSubmitAsync(ServerContext *Context, |
| ServerReader<SubmitDataAsync> *Reader, |
| I32 *Reply) { |
| SubmitDataAsync Request; |
| uint8_t *HostCopy = nullptr; |
| while (Reader->Read(&Request)) { |
| if (Request.start() == 0 && Request.size() == Request.data().size()) { |
| SERVER_DBG("Submitting %lu bytes async to (%p) on device %d", |
| Request.data().size(), (void *)Request.tgt_ptr(), |
| Request.device_id()); |
| |
| SERVER_DBG(" Host Pointer Info: %p, %p", (void *)Request.hst_ptr(), |
| static_cast<const void *>(Request.data().data())); |
| |
| Reader->SendInitialMetadata(); |
| |
| Reply->set_number(PM->Devices[Request.device_id()].RTL->data_submit( |
| mapHostRTLDeviceId(Request.device_id()), (void *)Request.tgt_ptr(), |
| (void *)Request.data().data(), Request.data().size())); |
| |
| SERVER_DBG("Submitted %lu bytes async to (%p) on device %d", |
| Request.data().size(), (void *)Request.tgt_ptr(), |
| Request.device_id()); |
| |
| return Status::OK; |
| } |
| if (!HostCopy) { |
| HostCopy = new uint8_t[Request.size()]; |
| Reader->SendInitialMetadata(); |
| } |
| |
| SERVER_DBG("Submitting %lu-%lu/%lu bytes async to (%p) on device %d", |
| Request.start(), Request.start() + Request.data().size(), |
| Request.size(), (void *)Request.tgt_ptr(), Request.device_id()); |
| |
| memcpy((void *)((char *)HostCopy + Request.start()), Request.data().data(), |
| Request.data().size()); |
| } |
| SERVER_DBG(" Host Pointer Info: %p, %p", (void *)Request.hst_ptr(), |
| static_cast<const void *>(Request.data().data())); |
| |
| Reply->set_number(PM->Devices[Request.device_id()].RTL->data_submit( |
| mapHostRTLDeviceId(Request.device_id()), (void *)Request.tgt_ptr(), |
| HostCopy, Request.size())); |
| |
| delete[] HostCopy; |
| |
| SERVER_DBG("Submitted %lu bytes to (%p) on device %d", Request.data().size(), |
| (void *)Request.tgt_ptr(), Request.device_id()); |
| |
| return Status::OK; |
| } |
| |
| Status RemoteOffloadImpl::DataRetrieveAsync(ServerContext *Context, |
| const RetrieveDataAsync *Request, |
| ServerWriter<Data> *Writer) { |
| auto HstPtr = std::make_unique<char[]>(Request->size()); |
| auto Ret = PM->Devices[Request->device_id()].RTL->data_retrieve( |
| mapHostRTLDeviceId(Request->device_id()), HstPtr.get(), |
| (void *)Request->tgt_ptr(), Request->size()); |
| |
| if (Arena->SpaceAllocated() >= MaxSize) |
| Arena->Reset(); |
| |
| if (Request->size() > BlockSize) { |
| uint64_t Start = 0, End = BlockSize; |
| for (auto I = 0; I < ceil((float)Request->size() / BlockSize); I++) { |
| auto *Reply = protobuf::Arena::CreateMessage<Data>(Arena.get()); |
| |
| Reply->set_start(Start); |
| Reply->set_size(Request->size()); |
| Reply->set_data((char *)HstPtr.get() + Start, End - Start); |
| Reply->set_ret(Ret); |
| |
| SERVER_DBG("Retrieving %lu-%lu/%lu bytes from (%p) on device %d", Start, |
| End, Request->size(), (void *)Request->tgt_ptr(), |
| mapHostRTLDeviceId(Request->device_id())); |
| |
| if (!Writer->Write(*Reply)) { |
| CLIENT_DBG("Broken stream when submitting data"); |
| } |
| |
| SERVER_DBG("Retrieved %lu-%lu/%lu bytes from (%p) on device %d", Start, |
| End, Request->size(), (void *)Request->tgt_ptr(), |
| mapHostRTLDeviceId(Request->device_id())); |
| |
| Start += BlockSize; |
| End += BlockSize; |
| if (End >= Request->size()) |
| End = Request->size(); |
| } |
| } else { |
| auto *Reply = protobuf::Arena::CreateMessage<Data>(Arena.get()); |
| |
| SERVER_DBG("Retrieve %lu bytes from (%p) on device %d", Request->size(), |
| (void *)Request->tgt_ptr(), |
| mapHostRTLDeviceId(Request->device_id())); |
| |
| Reply->set_start(0); |
| Reply->set_size(Request->size()); |
| Reply->set_data((char *)HstPtr.get(), Request->size()); |
| Reply->set_ret(Ret); |
| |
| SERVER_DBG("Retrieved %lu bytes from (%p) on device %d", Request->size(), |
| (void *)Request->tgt_ptr(), |
| mapHostRTLDeviceId(Request->device_id())); |
| |
| Writer->WriteLast(*Reply, WriteOptions()); |
| } |
| |
| return Status::OK; |
| } |
| |
| Status RemoteOffloadImpl::DataExchangeAsync(ServerContext *Context, |
| const ExchangeDataAsync *Request, |
| I32 *Reply) { |
| SERVER_DBG( |
| "Exchanging data asynchronously from device %d (%p) to device %d (%p) of " |
| "size %lu", |
| mapHostRTLDeviceId(Request->src_dev_id()), (void *)Request->src_ptr(), |
| mapHostRTLDeviceId(Request->dst_dev_id()), (void *)Request->dst_ptr(), |
| Request->size()); |
| |
| if (PM->Devices[Request->src_dev_id()].RTL->data_exchange) { |
| int32_t Ret = PM->Devices[Request->src_dev_id()].RTL->data_exchange( |
| mapHostRTLDeviceId(Request->src_dev_id()), (void *)Request->src_ptr(), |
| mapHostRTLDeviceId(Request->dst_dev_id()), (void *)Request->dst_ptr(), |
| Request->size()); |
| Reply->set_number(Ret); |
| } else |
| Reply->set_number(-1); |
| |
| SERVER_DBG( |
| "Exchanged data asynchronously from device %d (%p) to device %d (%p) of " |
| "size %lu", |
| mapHostRTLDeviceId(Request->src_dev_id()), (void *)Request->src_ptr(), |
| mapHostRTLDeviceId(Request->dst_dev_id()), (void *)Request->dst_ptr(), |
| Request->size()); |
| return Status::OK; |
| } |
| |
| Status RemoteOffloadImpl::DataDelete(ServerContext *Context, |
| const DeleteData *Request, I32 *Reply) { |
| SERVER_DBG("Deleting data from (%p) on device %d", (void *)Request->tgt_ptr(), |
| mapHostRTLDeviceId(Request->device_id())); |
| |
| auto Ret = PM->Devices[Request->device_id()].RTL->data_delete( |
| mapHostRTLDeviceId(Request->device_id()), (void *)Request->tgt_ptr()); |
| Reply->set_number(Ret); |
| |
| SERVER_DBG("Deleted data from (%p) on device %d", (void *)Request->tgt_ptr(), |
| mapHostRTLDeviceId(Request->device_id())); |
| return Status::OK; |
| } |
| |
| Status RemoteOffloadImpl::RunTargetRegionAsync(ServerContext *Context, |
| const TargetRegionAsync *Request, |
| I32 *Reply) { |
| SERVER_DBG("Running TargetRegionAsync on device %d with %d args", |
| mapHostRTLDeviceId(Request->device_id()), Request->arg_num()); |
| |
| std::vector<uint8_t> TgtArgs(Request->arg_num()); |
| for (auto I = 0; I < Request->arg_num(); I++) |
| TgtArgs[I] = (uint64_t)Request->tgt_args()[I]; |
| |
| std::vector<ptrdiff_t> TgtOffsets(Request->arg_num()); |
| const auto *TgtOffsetItr = Request->tgt_offsets().begin(); |
| for (auto I = 0; I < Request->arg_num(); I++, TgtOffsetItr++) |
| TgtOffsets[I] = (ptrdiff_t)*TgtOffsetItr; |
| |
| void *TgtEntryPtr = ((__tgt_offload_entry *)Request->tgt_entry_ptr())->addr; |
| |
| int32_t Ret = PM->Devices[Request->device_id()].RTL->run_region( |
| mapHostRTLDeviceId(Request->device_id()), TgtEntryPtr, |
| (void **)TgtArgs.data(), TgtOffsets.data(), Request->arg_num()); |
| |
| Reply->set_number(Ret); |
| |
| SERVER_DBG("Ran TargetRegionAsync on device %d with %d args", |
| mapHostRTLDeviceId(Request->device_id()), Request->arg_num()); |
| return Status::OK; |
| } |
| |
| Status RemoteOffloadImpl::RunTargetTeamRegionAsync( |
| ServerContext *Context, const TargetTeamRegionAsync *Request, I32 *Reply) { |
| SERVER_DBG("Running TargetTeamRegionAsync on device %d with %d args", |
| mapHostRTLDeviceId(Request->device_id()), Request->arg_num()); |
| |
| std::vector<uint64_t> TgtArgs(Request->arg_num()); |
| for (auto I = 0; I < Request->arg_num(); I++) |
| TgtArgs[I] = (uint64_t)Request->tgt_args()[I]; |
| |
| std::vector<ptrdiff_t> TgtOffsets(Request->arg_num()); |
| const auto *TgtOffsetItr = Request->tgt_offsets().begin(); |
| for (auto I = 0; I < Request->arg_num(); I++, TgtOffsetItr++) |
| TgtOffsets[I] = (ptrdiff_t)*TgtOffsetItr; |
| |
| void *TgtEntryPtr = ((__tgt_offload_entry *)Request->tgt_entry_ptr())->addr; |
| int32_t Ret = PM->Devices[Request->device_id()].RTL->run_team_region( |
| mapHostRTLDeviceId(Request->device_id()), TgtEntryPtr, |
| (void **)TgtArgs.data(), TgtOffsets.data(), Request->arg_num(), |
| Request->team_num(), Request->thread_limit(), Request->loop_tripcount()); |
| |
| Reply->set_number(Ret); |
| |
| SERVER_DBG("Ran TargetTeamRegionAsync on device %d with %d args", |
| mapHostRTLDeviceId(Request->device_id()), Request->arg_num()); |
| return Status::OK; |
| } |
| |
| int32_t RemoteOffloadImpl::mapHostRTLDeviceId(int32_t RTLDeviceID) { |
| for (auto &RTL : PM->RTLs.UsedRTLs) { |
| if (RTLDeviceID - RTL->NumberOfDevices >= 0) |
| RTLDeviceID -= RTL->NumberOfDevices; |
| else |
| break; |
| } |
| return RTLDeviceID; |
| } |