brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.3 KiB · ab110dd Raw
146 lines · c
1//===- RPC.h - Interface for remote procedure calls from the GPU ----------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file provides the interface to support remote procedure calls (RPC) from10// the GPU. This is required to implement host services like printf or malloc.11// The interface to the RPC server is provided by the 'libc' project in LLVM.12// For more information visit https://libc.llvm.org/gpu/.13//14//===----------------------------------------------------------------------===//15 16#ifndef OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_COMMON_RPC_H17#define OPENMP_LIBOMPTARGET_PLUGINS_NEXTGEN_COMMON_RPC_H18 19#include "llvm/ADT/DenseMap.h"20#include "llvm/Support/Error.h"21 22#include <atomic>23#include <condition_variable>24#include <cstdint>25#include <mutex>26#include <thread>27 28namespace llvm::omp::target {29namespace plugin {30struct GenericPluginTy;31struct GenericDeviceTy;32class GenericGlobalHandlerTy;33class DeviceImageTy;34} // namespace plugin35 36/// A generic class implementing the interface between the RPC server provided37/// by the 'libc' project and 'libomptarget'. If the RPC server is not available38/// these routines will perform no action.39struct RPCServerTy {40public:41  /// Initializes the handles to the number of devices we may need to service.42  RPCServerTy(plugin::GenericPluginTy &Plugin);43 44  /// Deinitialize the associated memory and resources.45  llvm::Error shutDown();46 47  /// Initialize the worker thread.48  llvm::Error startThread();49 50  /// Check if this device image is using an RPC server. This checks for the51  /// presence of an externally visible symbol in the device image that will52  /// be present whenever RPC code is called.53  llvm::Expected<bool> isDeviceUsingRPC(plugin::GenericDeviceTy &Device,54                                        plugin::GenericGlobalHandlerTy &Handler,55                                        plugin::DeviceImageTy &Image);56 57  /// Initialize the RPC server for the given device. This will allocate host58  /// memory for the internal server and copy the data to the client on the59  /// device. The device must be loaded before this is valid.60  llvm::Error initDevice(plugin::GenericDeviceTy &Device,61                         plugin::GenericGlobalHandlerTy &Handler,62                         plugin::DeviceImageTy &Image);63 64  /// Deinitialize the RPC server for the given device. This will free the65  /// memory associated with the k66  llvm::Error deinitDevice(plugin::GenericDeviceTy &Device);67 68private:69  /// Array from this device's identifier to its attached devices.70  std::unique_ptr<void *[]> Buffers;71 72  /// Array of associated devices. These must be alive as long as the server is.73  std::unique_ptr<plugin::GenericDeviceTy *[]> Devices;74 75  /// Mutex that guards accesses to the buffers and device array.76  std::mutex BufferMutex{};77 78  /// A helper class for running the user thread that handles the RPC interface.79  /// Because we only need to check the RPC server while any kernels are80  /// working, we track submission / completion events to allow the thread to81  /// sleep when it is not needed.82  struct ServerThread {83    std::thread Worker;84 85    /// A boolean indicating whether or not the worker thread should continue.86    std::atomic<uint32_t> Running;87 88    /// The number of currently executing kernels across all devices that need89    /// the server thread to be running.90    std::atomic<uint32_t> NumUsers;91 92    /// The condition variable used to suspend the thread if no work is needed.93    std::condition_variable CV;94    std::mutex Mutex;95 96    /// A reference to the main server's mutex.97    std::mutex &BufferMutex;98 99    /// A reference to all the RPC interfaces that the server is handling.100    llvm::ArrayRef<void *> Buffers;101 102    /// A reference to the associated generic device for the buffer.103    llvm::ArrayRef<plugin::GenericDeviceTy *> Devices;104 105    /// Initialize the worker thread to run in the background.106    ServerThread(void *Buffers[], plugin::GenericDeviceTy *Devices[],107                 size_t Length, std::mutex &BufferMutex)108        : Running(false), NumUsers(0), CV(), Mutex(), BufferMutex(BufferMutex),109          Buffers(Buffers, Length), Devices(Devices, Length) {}110 111    ~ServerThread() { assert(!Running && "Thread not shut down explicitly\n"); }112 113    /// Notify the worker thread that there is a user that needs it.114    void notify() {115      std::lock_guard<decltype(Mutex)> Lock(Mutex);116      NumUsers.fetch_add(1, std::memory_order_relaxed);117      CV.notify_all();118    }119 120    /// Indicate that one of the dependent users has finished.121    void finish() {122      [[maybe_unused]] uint32_t Old =123          NumUsers.fetch_sub(1, std::memory_order_relaxed);124      assert(Old > 0 && "Attempt to signal finish with no pending work");125    }126 127    /// Destroy the worker thread and wait.128    void shutDown();129 130    /// Initialize the worker thread.131    void startThread();132 133    /// Run the server thread to continuously check the RPC interface for work134    /// to be done for the device.135    void run();136  };137 138public:139  /// Pointer to the server thread instance.140  std::unique_ptr<ServerThread> Thread;141};142 143} // namespace llvm::omp::target144 145#endif146