13de4cd12SGeorge Rokos //===----RTLs/cuda/src/rtl.cpp - Target RTLs Implementation ------- C++ -*-===// 23de4cd12SGeorge Rokos // 357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 63de4cd12SGeorge Rokos // 73de4cd12SGeorge Rokos //===----------------------------------------------------------------------===// 83de4cd12SGeorge Rokos // 93de4cd12SGeorge Rokos // RTL for CUDA machine 103de4cd12SGeorge Rokos // 113de4cd12SGeorge Rokos //===----------------------------------------------------------------------===// 123de4cd12SGeorge Rokos 13a5153dbcSJohannes Doerfert #include <atomic> 143de4cd12SGeorge Rokos #include <cassert> 153de4cd12SGeorge Rokos #include <cstddef> 163de4cd12SGeorge Rokos #include <cuda.h> 173de4cd12SGeorge Rokos #include <list> 18a5153dbcSJohannes Doerfert #include <memory> 19*feed674dSShilei Tian #include <mutex> 203de4cd12SGeorge Rokos #include <string> 213de4cd12SGeorge Rokos #include <vector> 223de4cd12SGeorge Rokos 231546d319SGeorge Rokos #include "omptargetplugin.h" 243de4cd12SGeorge Rokos 253de4cd12SGeorge Rokos #ifndef TARGET_NAME 263de4cd12SGeorge Rokos #define TARGET_NAME CUDA 273de4cd12SGeorge Rokos #endif 283de4cd12SGeorge Rokos 29b305d26bSSergey Dmitriev #ifdef OMPTARGET_DEBUG 30b305d26bSSergey Dmitriev static int DebugLevel = 0; 31b305d26bSSergey Dmitriev 323de4cd12SGeorge Rokos #define GETNAME2(name) #name 333de4cd12SGeorge Rokos #define GETNAME(name) GETNAME2(name) 34b305d26bSSergey Dmitriev #define DP(...) \ 35b305d26bSSergey Dmitriev do { \ 36b305d26bSSergey Dmitriev if (DebugLevel > 0) { \ 37b305d26bSSergey Dmitriev DEBUGP("Target " GETNAME(TARGET_NAME) " RTL", __VA_ARGS__); \ 38b305d26bSSergey Dmitriev } \ 39b305d26bSSergey Dmitriev } while (false) 4078769ec4SMichael Kruse 4178769ec4SMichael Kruse // Utility for retrieving and printing CUDA error string. 4278769ec4SMichael Kruse #define CUDA_ERR_STRING(err) \ 4378769ec4SMichael Kruse do { \ 4478769ec4SMichael Kruse if (DebugLevel > 0) { \ 4578769ec4SMichael Kruse const char *errStr; \ 4678769ec4SMichael Kruse cuGetErrorString(err, &errStr); \ 4778769ec4SMichael Kruse DEBUGP("Target " GETNAME(TARGET_NAME) " RTL", "CUDA error is: %s\n", errStr); \ 4878769ec4SMichael Kruse } \ 4978769ec4SMichael Kruse } while (false) 50b305d26bSSergey Dmitriev #else // OMPTARGET_DEBUG 51b305d26bSSergey Dmitriev #define DP(...) {} 5278769ec4SMichael Kruse #define CUDA_ERR_STRING(err) {} 53b305d26bSSergey Dmitriev #endif // OMPTARGET_DEBUG 543de4cd12SGeorge Rokos 553de4cd12SGeorge Rokos #include "../../common/elf_common.c" 563de4cd12SGeorge Rokos 573de4cd12SGeorge Rokos /// Keep entries table per device. 583de4cd12SGeorge Rokos struct FuncOrGblEntryTy { 593de4cd12SGeorge Rokos __tgt_target_table Table; 603de4cd12SGeorge Rokos std::vector<__tgt_offload_entry> Entries; 613de4cd12SGeorge Rokos }; 623de4cd12SGeorge Rokos 633de4cd12SGeorge Rokos enum ExecutionModeType { 64c13df8e5SGeorge Rokos SPMD, // constructors, destructors, 65c13df8e5SGeorge Rokos // combined constructs (`teams distribute parallel for [simd]`) 66c13df8e5SGeorge Rokos GENERIC, // everything else 673de4cd12SGeorge Rokos NONE 683de4cd12SGeorge Rokos }; 693de4cd12SGeorge Rokos 70dc34b1c9SRon Lieberman /// Use a single entity to encode a kernel and a set of flags. 713de4cd12SGeorge Rokos struct KernelTy { 723de4cd12SGeorge Rokos CUfunction Func; 733de4cd12SGeorge Rokos 743de4cd12SGeorge Rokos // execution mode of kernel 753de4cd12SGeorge Rokos // 0 - SPMD mode (without master warp) 763de4cd12SGeorge Rokos // 1 - Generic mode (with master warp) 773de4cd12SGeorge Rokos int8_t ExecutionMode; 783de4cd12SGeorge Rokos 793de4cd12SGeorge Rokos KernelTy(CUfunction _Func, int8_t _ExecutionMode) 803de4cd12SGeorge Rokos : Func(_Func), ExecutionMode(_ExecutionMode) {} 813de4cd12SGeorge Rokos }; 823de4cd12SGeorge Rokos 834c6a098aSKazuaki Ishizaki /// Device environment data 84*feed674dSShilei Tian /// Manually sync with the deviceRTL side for now, move to a dedicated header 85*feed674dSShilei Tian /// file later. 86e1c7a46dSGuansong Zhang struct omptarget_device_environmentTy { 87e1c7a46dSGuansong Zhang int32_t debug_level; 88e1c7a46dSGuansong Zhang }; 89e1c7a46dSGuansong Zhang 903de4cd12SGeorge Rokos /// List that contains all the kernels. 913de4cd12SGeorge Rokos /// FIXME: we may need this to be per device and per library. 923de4cd12SGeorge Rokos std::list<KernelTy> KernelsList; 933de4cd12SGeorge Rokos 94*feed674dSShilei Tian namespace { 95*feed674dSShilei Tian bool checkResult(CUresult Err, const char *ErrMsg) { 96*feed674dSShilei Tian if (Err == CUDA_SUCCESS) 97*feed674dSShilei Tian return true; 98*feed674dSShilei Tian 99*feed674dSShilei Tian DP(ErrMsg); 100*feed674dSShilei Tian CUDA_ERR_STRING(Err); 101*feed674dSShilei Tian return false; 102*feed674dSShilei Tian } 103*feed674dSShilei Tian } // namespace 104*feed674dSShilei Tian 105*feed674dSShilei Tian class StreamManagerTy { 106*feed674dSShilei Tian int NumberOfDevices; 107*feed674dSShilei Tian // Per-device stream mutex 108*feed674dSShilei Tian std::vector<std::unique_ptr<std::mutex>> StreamMtx; 109*feed674dSShilei Tian // Per-device stream Id indicates the next available stream in the pool 110*feed674dSShilei Tian std::vector<int> NextStreamId; 111*feed674dSShilei Tian // Per-device stream pool 112*feed674dSShilei Tian std::vector<std::vector<CUstream>> StreamPool; 113*feed674dSShilei Tian // Pointer to per-device context 114*feed674dSShilei Tian std::vector<CUcontext> &ContextsPtr; 115*feed674dSShilei Tian 116*feed674dSShilei Tian // If there is no CUstream left in the pool, we will resize the pool to 117*feed674dSShilei Tian // allocate more CUstream. This function should be called with device mutex, 118*feed674dSShilei Tian // and we do not resize to smaller one. 119*feed674dSShilei Tian void resizeStreamPool(const int DeviceId, const size_t NewSize) { 120*feed674dSShilei Tian std::vector<CUstream> &Pool = StreamPool[DeviceId]; 121*feed674dSShilei Tian const size_t CurrentSize = Pool.size(); 122*feed674dSShilei Tian assert(NewSize > CurrentSize && "new size is not larger than current size"); 123*feed674dSShilei Tian 124*feed674dSShilei Tian Pool.resize(NewSize, nullptr); 125*feed674dSShilei Tian 126*feed674dSShilei Tian CUresult err = cuCtxSetCurrent(ContextsPtr[DeviceId]); 127*feed674dSShilei Tian if (!checkResult(err, "Error when setting current CUDA context\n")) { 128*feed674dSShilei Tian // We will return if cannot switch to the right context in case of 129*feed674dSShilei Tian // creating bunch of streams that are not corresponding to the right 130*feed674dSShilei Tian // device. The offloading will fail later because selected CUstream is 131*feed674dSShilei Tian // nullptr. 132*feed674dSShilei Tian return; 133*feed674dSShilei Tian } 134*feed674dSShilei Tian 135*feed674dSShilei Tian for (size_t I = CurrentSize; I < NewSize; ++I) { 136*feed674dSShilei Tian err = cuStreamCreate(&Pool[I], CU_STREAM_NON_BLOCKING); 137*feed674dSShilei Tian checkResult(err, 138*feed674dSShilei Tian "Error when creating CUDA stream to resize stream pool\n"); 139*feed674dSShilei Tian } 140*feed674dSShilei Tian } 141*feed674dSShilei Tian 142*feed674dSShilei Tian public: 143*feed674dSShilei Tian StreamManagerTy(const int NumberOfDevices, std::vector<CUcontext> &CtxPtr) 144*feed674dSShilei Tian : NumberOfDevices(NumberOfDevices), ContextsPtr(CtxPtr) { 145*feed674dSShilei Tian StreamPool.resize(NumberOfDevices); 146*feed674dSShilei Tian NextStreamId.resize(NumberOfDevices); 147*feed674dSShilei Tian StreamMtx.resize(NumberOfDevices); 148*feed674dSShilei Tian 149*feed674dSShilei Tian // Initially let's create 32 streams for each device 150*feed674dSShilei Tian int EnvNumInitialStreams = 32; 151*feed674dSShilei Tian char *envStr = getenv("LIBOMPTARGET_NUM_INITIAL_STREAMS"); 152*feed674dSShilei Tian if (envStr) 153*feed674dSShilei Tian EnvNumInitialStreams = std::stoi(envStr); 154*feed674dSShilei Tian 155*feed674dSShilei Tian // Initialize the stream pool for each device 156*feed674dSShilei Tian for (std::vector<CUstream> &S : StreamPool) 157*feed674dSShilei Tian S.resize(EnvNumInitialStreams); 158*feed674dSShilei Tian 159*feed674dSShilei Tian // Initialize the next stream id 160*feed674dSShilei Tian std::fill(NextStreamId.begin(), NextStreamId.end(), 0); 161*feed674dSShilei Tian 162*feed674dSShilei Tian // Initialize stream mutex 163*feed674dSShilei Tian for (std::unique_ptr<std::mutex> &Ptr : StreamMtx) 164*feed674dSShilei Tian Ptr = std::make_unique<std::mutex>(); 165*feed674dSShilei Tian } 166*feed674dSShilei Tian 167*feed674dSShilei Tian ~StreamManagerTy() { 168*feed674dSShilei Tian // Destroy streams 169*feed674dSShilei Tian for (int I = 0; I < NumberOfDevices; ++I) { 170*feed674dSShilei Tian CUresult err = cuCtxSetCurrent(ContextsPtr[I]); 171*feed674dSShilei Tian checkResult(err, "Error when setting current CUDA context\n"); 172*feed674dSShilei Tian 173*feed674dSShilei Tian for (CUstream &S : StreamPool[I]) { 174*feed674dSShilei Tian if (!S) 175*feed674dSShilei Tian continue; 176*feed674dSShilei Tian err = cuStreamDestroy(S); 177*feed674dSShilei Tian checkResult(err, "Error when destroying CUDA stream\n"); 178*feed674dSShilei Tian } 179*feed674dSShilei Tian } 180*feed674dSShilei Tian } 181*feed674dSShilei Tian 182*feed674dSShilei Tian // Get a CUstream from pool. Per-device next stream id always points to the 183*feed674dSShilei Tian // next available CUstream. That means, CUstreams [0, id-1] have been 184*feed674dSShilei Tian // assigned, and [id,] are still available. If there is no CUstream left, we 185*feed674dSShilei Tian // will ask more CUstreams from CUDA RT. Each time a CUstream is assigned, 186*feed674dSShilei Tian // the id will increase one. 187*feed674dSShilei Tian // xxxxxs+++++++++ 188*feed674dSShilei Tian // ^ 189*feed674dSShilei Tian // id 190*feed674dSShilei Tian // After assignment, the pool becomes the following and s is assigned. 191*feed674dSShilei Tian // xxxxxs+++++++++ 192*feed674dSShilei Tian // ^ 193*feed674dSShilei Tian // id 194*feed674dSShilei Tian CUstream getStream(const int DeviceId) { 195*feed674dSShilei Tian assert(DeviceId >= 0 && 196*feed674dSShilei Tian static_cast<size_t>(DeviceId) < NextStreamId.size() && 197*feed674dSShilei Tian "Unexpected device id"); 198*feed674dSShilei Tian 199*feed674dSShilei Tian const std::lock_guard<std::mutex> Lock(*StreamMtx[DeviceId]); 200*feed674dSShilei Tian int &Id = NextStreamId[DeviceId]; 201*feed674dSShilei Tian // No CUstream left in the pool, we need to request from CUDA RT 202*feed674dSShilei Tian if (Id == StreamPool[DeviceId].size()) { 203*feed674dSShilei Tian // By default we double the stream pool every time 204*feed674dSShilei Tian resizeStreamPool(DeviceId, Id * 2); 205*feed674dSShilei Tian } 206*feed674dSShilei Tian return StreamPool[DeviceId][Id++]; 207*feed674dSShilei Tian } 208*feed674dSShilei Tian 209*feed674dSShilei Tian // Return a CUstream back to pool. As mentioned above, per-device next 210*feed674dSShilei Tian // stream is always points to the next available CUstream, so when we return 211*feed674dSShilei Tian // a CUstream, we need to first decrease the id, and then copy the CUstream 212*feed674dSShilei Tian // back. 213*feed674dSShilei Tian // It is worth noting that, the order of streams return might be different 214*feed674dSShilei Tian // from that they're assigned, that saying, at some point, there might be 215*feed674dSShilei Tian // two identical CUstreams. 216*feed674dSShilei Tian // xxax+a+++++ 217*feed674dSShilei Tian // ^ 218*feed674dSShilei Tian // id 219*feed674dSShilei Tian // However, it doesn't matter, because they're always on the two sides of 220*feed674dSShilei Tian // id. The left one will in the end be overwritten by another CUstream. 221*feed674dSShilei Tian // Therefore, after several execution, the order of pool might be different 222*feed674dSShilei Tian // from its initial state. 223*feed674dSShilei Tian void returnStream(const int DeviceId, CUstream Stream) { 224*feed674dSShilei Tian assert(DeviceId >= 0 && 225*feed674dSShilei Tian static_cast<size_t>(DeviceId) < NextStreamId.size() && 226*feed674dSShilei Tian "Unexpected device id"); 227*feed674dSShilei Tian 228*feed674dSShilei Tian const std::lock_guard<std::mutex> Lock(*StreamMtx[DeviceId]); 229*feed674dSShilei Tian int &Id = NextStreamId[DeviceId]; 230*feed674dSShilei Tian assert(Id > 0 && "Wrong stream ID"); 231*feed674dSShilei Tian StreamPool[DeviceId][--Id] = Stream; 232*feed674dSShilei Tian } 233*feed674dSShilei Tian 234*feed674dSShilei Tian void initializeDevice(int DeviceId) { 235*feed674dSShilei Tian // This function should be called after setting right context 236*feed674dSShilei Tian for (CUstream &Stream : StreamPool[DeviceId]) { 237*feed674dSShilei Tian CUresult Err = cuStreamCreate(&Stream, CU_STREAM_NON_BLOCKING); 238*feed674dSShilei Tian checkResult(Err, "Error when creating CUDA stream\n"); 239*feed674dSShilei Tian } 240*feed674dSShilei Tian } 241*feed674dSShilei Tian }; 242*feed674dSShilei Tian 2433de4cd12SGeorge Rokos /// Class containing all the device information. 2443de4cd12SGeorge Rokos class RTLDeviceInfoTy { 2452622e9e5SAlexey Bataev std::vector<std::list<FuncOrGblEntryTy>> FuncGblEntries; 246*feed674dSShilei Tian std::shared_ptr<StreamManagerTy> StreamManager; 2473de4cd12SGeorge Rokos 2483de4cd12SGeorge Rokos public: 2493de4cd12SGeorge Rokos int NumberOfDevices; 2503de4cd12SGeorge Rokos std::vector<CUmodule> Modules; 2513de4cd12SGeorge Rokos std::vector<CUcontext> Contexts; 2523de4cd12SGeorge Rokos 2533de4cd12SGeorge Rokos // Device properties 2543de4cd12SGeorge Rokos std::vector<int> ThreadsPerBlock; 2553de4cd12SGeorge Rokos std::vector<int> BlocksPerGrid; 2563de4cd12SGeorge Rokos std::vector<int> WarpSize; 2573de4cd12SGeorge Rokos 2583de4cd12SGeorge Rokos // OpenMP properties 2593de4cd12SGeorge Rokos std::vector<int> NumTeams; 2603de4cd12SGeorge Rokos std::vector<int> NumThreads; 2613de4cd12SGeorge Rokos 2623de4cd12SGeorge Rokos // OpenMP Environment properties 2633de4cd12SGeorge Rokos int EnvNumTeams; 2643de4cd12SGeorge Rokos int EnvTeamLimit; 2653de4cd12SGeorge Rokos 266c5fe030cSGheorghe-Teodor Bercea // OpenMP Requires Flags 267c5fe030cSGheorghe-Teodor Bercea int64_t RequiresFlags; 268c5fe030cSGheorghe-Teodor Bercea 2693de4cd12SGeorge Rokos // static int EnvNumThreads; 2703de4cd12SGeorge Rokos static const int HardTeamLimit = 1 << 16; // 64k 2713de4cd12SGeorge Rokos static const int HardThreadLimit = 1024; 2723de4cd12SGeorge Rokos static const int DefaultNumTeams = 128; 273c13df8e5SGeorge Rokos static const int DefaultNumThreads = 128; 2743de4cd12SGeorge Rokos 275*feed674dSShilei Tian std::shared_ptr<StreamManagerTy> getStreamManager() { return StreamManager; } 276*feed674dSShilei Tian 277*feed674dSShilei Tian CUstream getStream(const int DeviceId) { 278*feed674dSShilei Tian return StreamManager->getStream(DeviceId); 279*feed674dSShilei Tian } 280*feed674dSShilei Tian 281*feed674dSShilei Tian void returnStream(const int DeviceId, __tgt_async_info *AsyncInfoPtr) { 282*feed674dSShilei Tian assert(AsyncInfoPtr && "AsyncInfoPtr is nullptr"); 283*feed674dSShilei Tian assert(AsyncInfoPtr->Queue && "AsyncInfoPtr->Queue is nullptr"); 284*feed674dSShilei Tian 285*feed674dSShilei Tian StreamManager->returnStream( 286*feed674dSShilei Tian DeviceId, reinterpret_cast<CUstream>(AsyncInfoPtr->Queue)); 287*feed674dSShilei Tian AsyncInfoPtr->Queue = nullptr; 288*feed674dSShilei Tian } 289*feed674dSShilei Tian 2903de4cd12SGeorge Rokos // Record entry point associated with device 2913de4cd12SGeorge Rokos void addOffloadEntry(int32_t device_id, __tgt_offload_entry entry) { 2923de4cd12SGeorge Rokos assert(device_id < (int32_t)FuncGblEntries.size() && 2933de4cd12SGeorge Rokos "Unexpected device id!"); 2942622e9e5SAlexey Bataev FuncOrGblEntryTy &E = FuncGblEntries[device_id].back(); 2953de4cd12SGeorge Rokos 2963de4cd12SGeorge Rokos E.Entries.push_back(entry); 2973de4cd12SGeorge Rokos } 2983de4cd12SGeorge Rokos 2993de4cd12SGeorge Rokos // Return true if the entry is associated with device 3003de4cd12SGeorge Rokos bool findOffloadEntry(int32_t device_id, void *addr) { 3013de4cd12SGeorge Rokos assert(device_id < (int32_t)FuncGblEntries.size() && 3023de4cd12SGeorge Rokos "Unexpected device id!"); 3032622e9e5SAlexey Bataev FuncOrGblEntryTy &E = FuncGblEntries[device_id].back(); 3043de4cd12SGeorge Rokos 3053de4cd12SGeorge Rokos for (auto &it : E.Entries) { 3063de4cd12SGeorge Rokos if (it.addr == addr) 3073de4cd12SGeorge Rokos return true; 3083de4cd12SGeorge Rokos } 3093de4cd12SGeorge Rokos 3103de4cd12SGeorge Rokos return false; 3113de4cd12SGeorge Rokos } 3123de4cd12SGeorge Rokos 3133de4cd12SGeorge Rokos // Return the pointer to the target entries table 3143de4cd12SGeorge Rokos __tgt_target_table *getOffloadEntriesTable(int32_t device_id) { 3153de4cd12SGeorge Rokos assert(device_id < (int32_t)FuncGblEntries.size() && 3163de4cd12SGeorge Rokos "Unexpected device id!"); 3172622e9e5SAlexey Bataev FuncOrGblEntryTy &E = FuncGblEntries[device_id].back(); 3183de4cd12SGeorge Rokos 3193de4cd12SGeorge Rokos int32_t size = E.Entries.size(); 3203de4cd12SGeorge Rokos 3213de4cd12SGeorge Rokos // Table is empty 3223de4cd12SGeorge Rokos if (!size) 3233de4cd12SGeorge Rokos return 0; 3243de4cd12SGeorge Rokos 3253de4cd12SGeorge Rokos __tgt_offload_entry *begin = &E.Entries[0]; 3263de4cd12SGeorge Rokos __tgt_offload_entry *end = &E.Entries[size - 1]; 3273de4cd12SGeorge Rokos 3283de4cd12SGeorge Rokos // Update table info according to the entries and return the pointer 3293de4cd12SGeorge Rokos E.Table.EntriesBegin = begin; 3303de4cd12SGeorge Rokos E.Table.EntriesEnd = ++end; 3313de4cd12SGeorge Rokos 3323de4cd12SGeorge Rokos return &E.Table; 3333de4cd12SGeorge Rokos } 3343de4cd12SGeorge Rokos 3353de4cd12SGeorge Rokos // Clear entries table for a device 3363de4cd12SGeorge Rokos void clearOffloadEntriesTable(int32_t device_id) { 3373de4cd12SGeorge Rokos assert(device_id < (int32_t)FuncGblEntries.size() && 3383de4cd12SGeorge Rokos "Unexpected device id!"); 3392622e9e5SAlexey Bataev FuncGblEntries[device_id].emplace_back(); 3402622e9e5SAlexey Bataev FuncOrGblEntryTy &E = FuncGblEntries[device_id].back(); 3413de4cd12SGeorge Rokos E.Entries.clear(); 3423de4cd12SGeorge Rokos E.Table.EntriesBegin = E.Table.EntriesEnd = 0; 3433de4cd12SGeorge Rokos } 3443de4cd12SGeorge Rokos 3453de4cd12SGeorge Rokos RTLDeviceInfoTy() { 346b305d26bSSergey Dmitriev #ifdef OMPTARGET_DEBUG 347b305d26bSSergey Dmitriev if (char *envStr = getenv("LIBOMPTARGET_DEBUG")) { 348b305d26bSSergey Dmitriev DebugLevel = std::stoi(envStr); 349b305d26bSSergey Dmitriev } 350b305d26bSSergey Dmitriev #endif // OMPTARGET_DEBUG 351b305d26bSSergey Dmitriev 3523de4cd12SGeorge Rokos DP("Start initializing CUDA\n"); 3533de4cd12SGeorge Rokos 3543de4cd12SGeorge Rokos CUresult err = cuInit(0); 3553de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 3563de4cd12SGeorge Rokos DP("Error when initializing CUDA\n"); 3573de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 3583de4cd12SGeorge Rokos return; 3593de4cd12SGeorge Rokos } 3603de4cd12SGeorge Rokos 3613de4cd12SGeorge Rokos NumberOfDevices = 0; 3623de4cd12SGeorge Rokos 3633de4cd12SGeorge Rokos err = cuDeviceGetCount(&NumberOfDevices); 3643de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 3653de4cd12SGeorge Rokos DP("Error when getting CUDA device count\n"); 3663de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 3673de4cd12SGeorge Rokos return; 3683de4cd12SGeorge Rokos } 3693de4cd12SGeorge Rokos 3703de4cd12SGeorge Rokos if (NumberOfDevices == 0) { 3713de4cd12SGeorge Rokos DP("There are no devices supporting CUDA.\n"); 3723de4cd12SGeorge Rokos return; 3733de4cd12SGeorge Rokos } 3743de4cd12SGeorge Rokos 3753de4cd12SGeorge Rokos FuncGblEntries.resize(NumberOfDevices); 3763de4cd12SGeorge Rokos Contexts.resize(NumberOfDevices); 3773de4cd12SGeorge Rokos ThreadsPerBlock.resize(NumberOfDevices); 3783de4cd12SGeorge Rokos BlocksPerGrid.resize(NumberOfDevices); 3793de4cd12SGeorge Rokos WarpSize.resize(NumberOfDevices); 3803de4cd12SGeorge Rokos NumTeams.resize(NumberOfDevices); 3813de4cd12SGeorge Rokos NumThreads.resize(NumberOfDevices); 3823de4cd12SGeorge Rokos 3833de4cd12SGeorge Rokos // Get environment variables regarding teams 3843de4cd12SGeorge Rokos char *envStr = getenv("OMP_TEAM_LIMIT"); 3853de4cd12SGeorge Rokos if (envStr) { 3863de4cd12SGeorge Rokos // OMP_TEAM_LIMIT has been set 3873de4cd12SGeorge Rokos EnvTeamLimit = std::stoi(envStr); 3883de4cd12SGeorge Rokos DP("Parsed OMP_TEAM_LIMIT=%d\n", EnvTeamLimit); 3893de4cd12SGeorge Rokos } else { 3903de4cd12SGeorge Rokos EnvTeamLimit = -1; 3913de4cd12SGeorge Rokos } 3923de4cd12SGeorge Rokos envStr = getenv("OMP_NUM_TEAMS"); 3933de4cd12SGeorge Rokos if (envStr) { 3943de4cd12SGeorge Rokos // OMP_NUM_TEAMS has been set 3953de4cd12SGeorge Rokos EnvNumTeams = std::stoi(envStr); 3963de4cd12SGeorge Rokos DP("Parsed OMP_NUM_TEAMS=%d\n", EnvNumTeams); 3973de4cd12SGeorge Rokos } else { 3983de4cd12SGeorge Rokos EnvNumTeams = -1; 3993de4cd12SGeorge Rokos } 400c5fe030cSGheorghe-Teodor Bercea 401*feed674dSShilei Tian StreamManager = 402*feed674dSShilei Tian std::make_shared<StreamManagerTy>(NumberOfDevices, Contexts); 403a5153dbcSJohannes Doerfert 404c5fe030cSGheorghe-Teodor Bercea // Default state. 405c5fe030cSGheorghe-Teodor Bercea RequiresFlags = OMP_REQ_UNDEFINED; 4063de4cd12SGeorge Rokos } 4073de4cd12SGeorge Rokos 4083de4cd12SGeorge Rokos ~RTLDeviceInfoTy() { 409*feed674dSShilei Tian // First destruct stream manager in case of Contexts is destructed before it 410*feed674dSShilei Tian StreamManager = nullptr; 411*feed674dSShilei Tian 4123de4cd12SGeorge Rokos // Close modules 4133de4cd12SGeorge Rokos for (auto &module : Modules) 4143de4cd12SGeorge Rokos if (module) { 4153de4cd12SGeorge Rokos CUresult err = cuModuleUnload(module); 4163de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 4173de4cd12SGeorge Rokos DP("Error when unloading CUDA module\n"); 4183de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 4193de4cd12SGeorge Rokos } 4203de4cd12SGeorge Rokos } 4213de4cd12SGeorge Rokos 4223de4cd12SGeorge Rokos // Destroy contexts 4233de4cd12SGeorge Rokos for (auto &ctx : Contexts) 4243de4cd12SGeorge Rokos if (ctx) { 4253de4cd12SGeorge Rokos CUresult err = cuCtxDestroy(ctx); 4263de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 4273de4cd12SGeorge Rokos DP("Error when destroying CUDA context\n"); 4283de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 4293de4cd12SGeorge Rokos } 4303de4cd12SGeorge Rokos } 4313de4cd12SGeorge Rokos } 4323de4cd12SGeorge Rokos }; 4333de4cd12SGeorge Rokos 4343de4cd12SGeorge Rokos static RTLDeviceInfoTy DeviceInfo; 4353de4cd12SGeorge Rokos 43632ed2927SShilei Tian namespace { 437*feed674dSShilei Tian CUstream getStream(int32_t DeviceId, __tgt_async_info *AsyncInfoPtr) { 438*feed674dSShilei Tian assert(AsyncInfoPtr && "AsyncInfoPtr is nullptr"); 43932ed2927SShilei Tian 440*feed674dSShilei Tian if (!AsyncInfoPtr->Queue) 441*feed674dSShilei Tian AsyncInfoPtr->Queue = DeviceInfo.getStream(DeviceId); 44232ed2927SShilei Tian 443*feed674dSShilei Tian return reinterpret_cast<CUstream>(AsyncInfoPtr->Queue); 44432ed2927SShilei Tian } 44532ed2927SShilei Tian 44632ed2927SShilei Tian int32_t dataRetrieve(int32_t DeviceId, void *HstPtr, void *TgtPtr, int64_t Size, 44732ed2927SShilei Tian __tgt_async_info *AsyncInfoPtr) { 44832ed2927SShilei Tian assert(AsyncInfoPtr && "AsyncInfoPtr is nullptr"); 44932ed2927SShilei Tian // Set the context we are using. 45032ed2927SShilei Tian CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[DeviceId]); 45132ed2927SShilei Tian if (err != CUDA_SUCCESS) { 45232ed2927SShilei Tian DP("Error when setting CUDA context\n"); 45332ed2927SShilei Tian CUDA_ERR_STRING(err); 45432ed2927SShilei Tian return OFFLOAD_FAIL; 45532ed2927SShilei Tian } 45632ed2927SShilei Tian 457*feed674dSShilei Tian CUstream Stream = getStream(DeviceId, AsyncInfoPtr); 45832ed2927SShilei Tian 45932ed2927SShilei Tian err = cuMemcpyDtoHAsync(HstPtr, (CUdeviceptr)TgtPtr, Size, Stream); 46032ed2927SShilei Tian if (err != CUDA_SUCCESS) { 46132ed2927SShilei Tian DP("Error when copying data from device to host. Pointers: host = " DPxMOD 46232ed2927SShilei Tian ", device = " DPxMOD ", size = %" PRId64 "\n", 46332ed2927SShilei Tian DPxPTR(HstPtr), DPxPTR(TgtPtr), Size); 46432ed2927SShilei Tian CUDA_ERR_STRING(err); 46532ed2927SShilei Tian return OFFLOAD_FAIL; 46632ed2927SShilei Tian } 46732ed2927SShilei Tian 46832ed2927SShilei Tian return OFFLOAD_SUCCESS; 46932ed2927SShilei Tian } 47032ed2927SShilei Tian 47132ed2927SShilei Tian int32_t dataSubmit(int32_t DeviceId, void *TgtPtr, void *HstPtr, int64_t Size, 47232ed2927SShilei Tian __tgt_async_info *AsyncInfoPtr) { 47332ed2927SShilei Tian assert(AsyncInfoPtr && "AsyncInfoPtr is nullptr"); 47432ed2927SShilei Tian // Set the context we are using. 47532ed2927SShilei Tian CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[DeviceId]); 47632ed2927SShilei Tian if (err != CUDA_SUCCESS) { 47732ed2927SShilei Tian DP("Error when setting CUDA context\n"); 47832ed2927SShilei Tian CUDA_ERR_STRING(err); 47932ed2927SShilei Tian return OFFLOAD_FAIL; 48032ed2927SShilei Tian } 48132ed2927SShilei Tian 482*feed674dSShilei Tian CUstream Stream = getStream(DeviceId, AsyncInfoPtr); 48332ed2927SShilei Tian 48432ed2927SShilei Tian err = cuMemcpyHtoDAsync((CUdeviceptr)TgtPtr, HstPtr, Size, Stream); 48532ed2927SShilei Tian if (err != CUDA_SUCCESS) { 48632ed2927SShilei Tian DP("Error when copying data from host to device. Pointers: host = " DPxMOD 48732ed2927SShilei Tian ", device = " DPxMOD ", size = %" PRId64 "\n", 48832ed2927SShilei Tian DPxPTR(HstPtr), DPxPTR(TgtPtr), Size); 48932ed2927SShilei Tian CUDA_ERR_STRING(err); 49032ed2927SShilei Tian return OFFLOAD_FAIL; 49132ed2927SShilei Tian } 49232ed2927SShilei Tian 49332ed2927SShilei Tian return OFFLOAD_SUCCESS; 49432ed2927SShilei Tian } 49532ed2927SShilei Tian } // namespace 49632ed2927SShilei Tian 4973de4cd12SGeorge Rokos #ifdef __cplusplus 4983de4cd12SGeorge Rokos extern "C" { 4993de4cd12SGeorge Rokos #endif 5003de4cd12SGeorge Rokos 5013de4cd12SGeorge Rokos int32_t __tgt_rtl_is_valid_binary(__tgt_device_image *image) { 5023de4cd12SGeorge Rokos return elf_check_machine(image, 190); // EM_CUDA = 190. 5033de4cd12SGeorge Rokos } 5043de4cd12SGeorge Rokos 5053de4cd12SGeorge Rokos int32_t __tgt_rtl_number_of_devices() { return DeviceInfo.NumberOfDevices; } 5063de4cd12SGeorge Rokos 507c5fe030cSGheorghe-Teodor Bercea int64_t __tgt_rtl_init_requires(int64_t RequiresFlags) { 508c5fe030cSGheorghe-Teodor Bercea DP("Init requires flags to %ld\n", RequiresFlags); 509c5fe030cSGheorghe-Teodor Bercea DeviceInfo.RequiresFlags = RequiresFlags; 510c5fe030cSGheorghe-Teodor Bercea return RequiresFlags; 511c5fe030cSGheorghe-Teodor Bercea } 512c5fe030cSGheorghe-Teodor Bercea 5133de4cd12SGeorge Rokos int32_t __tgt_rtl_init_device(int32_t device_id) { 5143de4cd12SGeorge Rokos 5153de4cd12SGeorge Rokos CUdevice cuDevice; 5163de4cd12SGeorge Rokos DP("Getting device %d\n", device_id); 5173de4cd12SGeorge Rokos CUresult err = cuDeviceGet(&cuDevice, device_id); 5183de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 5193de4cd12SGeorge Rokos DP("Error when getting CUDA device with id = %d\n", device_id); 5203de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 5213de4cd12SGeorge Rokos return OFFLOAD_FAIL; 5223de4cd12SGeorge Rokos } 5233de4cd12SGeorge Rokos 5243de4cd12SGeorge Rokos // Create the context and save it to use whenever this device is selected. 5253de4cd12SGeorge Rokos err = cuCtxCreate(&DeviceInfo.Contexts[device_id], CU_CTX_SCHED_BLOCKING_SYNC, 5263de4cd12SGeorge Rokos cuDevice); 5273de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 5283de4cd12SGeorge Rokos DP("Error when creating a CUDA context\n"); 5293de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 5303de4cd12SGeorge Rokos return OFFLOAD_FAIL; 5313de4cd12SGeorge Rokos } 5323de4cd12SGeorge Rokos 533a5153dbcSJohannes Doerfert err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]); 534a5153dbcSJohannes Doerfert if (err != CUDA_SUCCESS) { 535a5153dbcSJohannes Doerfert DP("Error when setting current CUDA context\n"); 536a5153dbcSJohannes Doerfert CUDA_ERR_STRING(err); 537a5153dbcSJohannes Doerfert } 538a5153dbcSJohannes Doerfert 539*feed674dSShilei Tian // Initialize stream pool 540*feed674dSShilei Tian DeviceInfo.getStreamManager()->initializeDevice(device_id); 541a5153dbcSJohannes Doerfert 542bb51d398SJonas Hahnfeld // Query attributes to determine number of threads/block and blocks/grid. 543bb51d398SJonas Hahnfeld int maxGridDimX; 544bb51d398SJonas Hahnfeld err = cuDeviceGetAttribute(&maxGridDimX, CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_X, 545bb51d398SJonas Hahnfeld cuDevice); 546c1895235SJonas Hahnfeld if (err != CUDA_SUCCESS) { 547bb51d398SJonas Hahnfeld DP("Error getting max grid dimension, use default\n"); 5483de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id] = RTLDeviceInfoTy::DefaultNumTeams; 549bb51d398SJonas Hahnfeld } else if (maxGridDimX <= RTLDeviceInfoTy::HardTeamLimit) { 550bb51d398SJonas Hahnfeld DeviceInfo.BlocksPerGrid[device_id] = maxGridDimX; 551bb51d398SJonas Hahnfeld DP("Using %d CUDA blocks per grid\n", maxGridDimX); 5523de4cd12SGeorge Rokos } else { 5533de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id] = RTLDeviceInfoTy::HardTeamLimit; 5543de4cd12SGeorge Rokos DP("Max CUDA blocks per grid %d exceeds the hard team limit %d, capping " 555bb51d398SJonas Hahnfeld "at the hard limit\n", 556bb51d398SJonas Hahnfeld maxGridDimX, RTLDeviceInfoTy::HardTeamLimit); 5573de4cd12SGeorge Rokos } 5583de4cd12SGeorge Rokos 559bb51d398SJonas Hahnfeld // We are only exploiting threads along the x axis. 560bb51d398SJonas Hahnfeld int maxBlockDimX; 561bb51d398SJonas Hahnfeld err = cuDeviceGetAttribute(&maxBlockDimX, CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_X, 562bb51d398SJonas Hahnfeld cuDevice); 563bb51d398SJonas Hahnfeld if (err != CUDA_SUCCESS) { 564bb51d398SJonas Hahnfeld DP("Error getting max block dimension, use default\n"); 565bb51d398SJonas Hahnfeld DeviceInfo.ThreadsPerBlock[device_id] = RTLDeviceInfoTy::DefaultNumThreads; 566bb51d398SJonas Hahnfeld } else if (maxBlockDimX <= RTLDeviceInfoTy::HardThreadLimit) { 567bb51d398SJonas Hahnfeld DeviceInfo.ThreadsPerBlock[device_id] = maxBlockDimX; 568bb51d398SJonas Hahnfeld DP("Using %d CUDA threads per block\n", maxBlockDimX); 5693de4cd12SGeorge Rokos } else { 5703de4cd12SGeorge Rokos DeviceInfo.ThreadsPerBlock[device_id] = RTLDeviceInfoTy::HardThreadLimit; 571bb51d398SJonas Hahnfeld DP("Max CUDA threads per block %d exceeds the hard thread limit %d, capping" 572bb51d398SJonas Hahnfeld "at the hard limit\n", 573bb51d398SJonas Hahnfeld maxBlockDimX, RTLDeviceInfoTy::HardThreadLimit); 5743de4cd12SGeorge Rokos } 5753de4cd12SGeorge Rokos 576bb51d398SJonas Hahnfeld int warpSize; 577bb51d398SJonas Hahnfeld err = 578bb51d398SJonas Hahnfeld cuDeviceGetAttribute(&warpSize, CU_DEVICE_ATTRIBUTE_WARP_SIZE, cuDevice); 579bb51d398SJonas Hahnfeld if (err != CUDA_SUCCESS) { 580bb51d398SJonas Hahnfeld DP("Error getting warp size, assume default\n"); 581bb51d398SJonas Hahnfeld DeviceInfo.WarpSize[device_id] = 32; 582bb51d398SJonas Hahnfeld } else { 583bb51d398SJonas Hahnfeld DeviceInfo.WarpSize[device_id] = warpSize; 5843de4cd12SGeorge Rokos } 5853de4cd12SGeorge Rokos 5863de4cd12SGeorge Rokos // Adjust teams to the env variables 5873de4cd12SGeorge Rokos if (DeviceInfo.EnvTeamLimit > 0 && 5883de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id] > DeviceInfo.EnvTeamLimit) { 5893de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id] = DeviceInfo.EnvTeamLimit; 5903de4cd12SGeorge Rokos DP("Capping max CUDA blocks per grid to OMP_TEAM_LIMIT=%d\n", 5913de4cd12SGeorge Rokos DeviceInfo.EnvTeamLimit); 5923de4cd12SGeorge Rokos } 5933de4cd12SGeorge Rokos 5943de4cd12SGeorge Rokos DP("Max number of CUDA blocks %d, threads %d & warp size %d\n", 5953de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id], DeviceInfo.ThreadsPerBlock[device_id], 5963de4cd12SGeorge Rokos DeviceInfo.WarpSize[device_id]); 5973de4cd12SGeorge Rokos 5983de4cd12SGeorge Rokos // Set default number of teams 5993de4cd12SGeorge Rokos if (DeviceInfo.EnvNumTeams > 0) { 6003de4cd12SGeorge Rokos DeviceInfo.NumTeams[device_id] = DeviceInfo.EnvNumTeams; 6013de4cd12SGeorge Rokos DP("Default number of teams set according to environment %d\n", 6023de4cd12SGeorge Rokos DeviceInfo.EnvNumTeams); 6033de4cd12SGeorge Rokos } else { 6043de4cd12SGeorge Rokos DeviceInfo.NumTeams[device_id] = RTLDeviceInfoTy::DefaultNumTeams; 6053de4cd12SGeorge Rokos DP("Default number of teams set according to library's default %d\n", 6063de4cd12SGeorge Rokos RTLDeviceInfoTy::DefaultNumTeams); 6073de4cd12SGeorge Rokos } 6083de4cd12SGeorge Rokos if (DeviceInfo.NumTeams[device_id] > DeviceInfo.BlocksPerGrid[device_id]) { 6093de4cd12SGeorge Rokos DeviceInfo.NumTeams[device_id] = DeviceInfo.BlocksPerGrid[device_id]; 6103de4cd12SGeorge Rokos DP("Default number of teams exceeds device limit, capping at %d\n", 6113de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id]); 6123de4cd12SGeorge Rokos } 6133de4cd12SGeorge Rokos 6143de4cd12SGeorge Rokos // Set default number of threads 6153de4cd12SGeorge Rokos DeviceInfo.NumThreads[device_id] = RTLDeviceInfoTy::DefaultNumThreads; 6163de4cd12SGeorge Rokos DP("Default number of threads set according to library's default %d\n", 6173de4cd12SGeorge Rokos RTLDeviceInfoTy::DefaultNumThreads); 6183de4cd12SGeorge Rokos if (DeviceInfo.NumThreads[device_id] > 6193de4cd12SGeorge Rokos DeviceInfo.ThreadsPerBlock[device_id]) { 6203de4cd12SGeorge Rokos DeviceInfo.NumTeams[device_id] = DeviceInfo.ThreadsPerBlock[device_id]; 6213de4cd12SGeorge Rokos DP("Default number of threads exceeds device limit, capping at %d\n", 6223de4cd12SGeorge Rokos DeviceInfo.ThreadsPerBlock[device_id]); 6233de4cd12SGeorge Rokos } 6243de4cd12SGeorge Rokos 6253de4cd12SGeorge Rokos return OFFLOAD_SUCCESS; 6263de4cd12SGeorge Rokos } 6273de4cd12SGeorge Rokos 6283de4cd12SGeorge Rokos __tgt_target_table *__tgt_rtl_load_binary(int32_t device_id, 6293de4cd12SGeorge Rokos __tgt_device_image *image) { 6303de4cd12SGeorge Rokos 6313de4cd12SGeorge Rokos // Set the context we are using. 6323de4cd12SGeorge Rokos CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]); 6333de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 6343de4cd12SGeorge Rokos DP("Error when setting a CUDA context for device %d\n", device_id); 6353de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 6363de4cd12SGeorge Rokos return NULL; 6373de4cd12SGeorge Rokos } 6383de4cd12SGeorge Rokos 6393de4cd12SGeorge Rokos // Clear the offload table as we are going to create a new one. 6403de4cd12SGeorge Rokos DeviceInfo.clearOffloadEntriesTable(device_id); 6413de4cd12SGeorge Rokos 6423de4cd12SGeorge Rokos // Create the module and extract the function pointers. 6433de4cd12SGeorge Rokos 6443de4cd12SGeorge Rokos CUmodule cumod; 6453de4cd12SGeorge Rokos DP("Load data from image " DPxMOD "\n", DPxPTR(image->ImageStart)); 6463de4cd12SGeorge Rokos err = cuModuleLoadDataEx(&cumod, image->ImageStart, 0, NULL, NULL); 6473de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 6483de4cd12SGeorge Rokos DP("Error when loading CUDA module\n"); 6493de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 6503de4cd12SGeorge Rokos return NULL; 6513de4cd12SGeorge Rokos } 6523de4cd12SGeorge Rokos 6533de4cd12SGeorge Rokos DP("CUDA module successfully loaded!\n"); 6543de4cd12SGeorge Rokos DeviceInfo.Modules.push_back(cumod); 6553de4cd12SGeorge Rokos 6563de4cd12SGeorge Rokos // Find the symbols in the module by name. 6573de4cd12SGeorge Rokos __tgt_offload_entry *HostBegin = image->EntriesBegin; 6583de4cd12SGeorge Rokos __tgt_offload_entry *HostEnd = image->EntriesEnd; 6593de4cd12SGeorge Rokos 6603de4cd12SGeorge Rokos for (__tgt_offload_entry *e = HostBegin; e != HostEnd; ++e) { 6613de4cd12SGeorge Rokos 6623de4cd12SGeorge Rokos if (!e->addr) { 6633de4cd12SGeorge Rokos // We return NULL when something like this happens, the host should have 6643de4cd12SGeorge Rokos // always something in the address to uniquely identify the target region. 6653de4cd12SGeorge Rokos DP("Invalid binary: host entry '<null>' (size = %zd)...\n", e->size); 6663de4cd12SGeorge Rokos 6673de4cd12SGeorge Rokos return NULL; 6683de4cd12SGeorge Rokos } 6693de4cd12SGeorge Rokos 6703de4cd12SGeorge Rokos if (e->size) { 6713de4cd12SGeorge Rokos __tgt_offload_entry entry = *e; 6723de4cd12SGeorge Rokos 6733de4cd12SGeorge Rokos CUdeviceptr cuptr; 6743de4cd12SGeorge Rokos size_t cusize; 6753de4cd12SGeorge Rokos err = cuModuleGetGlobal(&cuptr, &cusize, cumod, e->name); 6763de4cd12SGeorge Rokos 6773de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 6783de4cd12SGeorge Rokos DP("Loading global '%s' (Failed)\n", e->name); 6793de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 6803de4cd12SGeorge Rokos return NULL; 6813de4cd12SGeorge Rokos } 6823de4cd12SGeorge Rokos 6833de4cd12SGeorge Rokos if (cusize != e->size) { 6843de4cd12SGeorge Rokos DP("Loading global '%s' - size mismatch (%zd != %zd)\n", e->name, 6853de4cd12SGeorge Rokos cusize, e->size); 6863de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 6873de4cd12SGeorge Rokos return NULL; 6883de4cd12SGeorge Rokos } 6893de4cd12SGeorge Rokos 6903de4cd12SGeorge Rokos DP("Entry point " DPxMOD " maps to global %s (" DPxMOD ")\n", 6913de4cd12SGeorge Rokos DPxPTR(e - HostBegin), e->name, DPxPTR(cuptr)); 6923de4cd12SGeorge Rokos entry.addr = (void *)cuptr; 6933de4cd12SGeorge Rokos 694aace6d28SGheorghe-Teodor Bercea // Note: In the current implementation declare target variables 695aace6d28SGheorghe-Teodor Bercea // can either be link or to. This means that once unified 696aace6d28SGheorghe-Teodor Bercea // memory is activated via the requires directive, the variable 697aace6d28SGheorghe-Teodor Bercea // can be used directly from the host in both cases. 698aace6d28SGheorghe-Teodor Bercea // TODO: when variables types other than to or link are added, 6994c6a098aSKazuaki Ishizaki // the below condition should be changed to explicitly 700aace6d28SGheorghe-Teodor Bercea // check for to and link variables types: 701aace6d28SGheorghe-Teodor Bercea // (DeviceInfo.RequiresFlags & OMP_REQ_UNIFIED_SHARED_MEMORY && 702aace6d28SGheorghe-Teodor Bercea // (e->flags & OMP_DECLARE_TARGET_LINK || 703aace6d28SGheorghe-Teodor Bercea // e->flags == OMP_DECLARE_TARGET_TO)) 704aace6d28SGheorghe-Teodor Bercea if (DeviceInfo.RequiresFlags & OMP_REQ_UNIFIED_SHARED_MEMORY) { 705aace6d28SGheorghe-Teodor Bercea // If unified memory is present any target link or to variables 706c5fe030cSGheorghe-Teodor Bercea // can access host addresses directly. There is no longer a 707c5fe030cSGheorghe-Teodor Bercea // need for device copies. 708c5fe030cSGheorghe-Teodor Bercea cuMemcpyHtoD(cuptr, e->addr, sizeof(void *)); 709c5fe030cSGheorghe-Teodor Bercea DP("Copy linked variable host address (" DPxMOD ")" 710c5fe030cSGheorghe-Teodor Bercea "to device address (" DPxMOD ")\n", 711c5fe030cSGheorghe-Teodor Bercea DPxPTR(*((void**)e->addr)), DPxPTR(cuptr)); 712c5fe030cSGheorghe-Teodor Bercea } 713c5fe030cSGheorghe-Teodor Bercea 7143de4cd12SGeorge Rokos DeviceInfo.addOffloadEntry(device_id, entry); 7153de4cd12SGeorge Rokos 7163de4cd12SGeorge Rokos continue; 7173de4cd12SGeorge Rokos } 7183de4cd12SGeorge Rokos 7193de4cd12SGeorge Rokos CUfunction fun; 7203de4cd12SGeorge Rokos err = cuModuleGetFunction(&fun, cumod, e->name); 7213de4cd12SGeorge Rokos 7223de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 7233de4cd12SGeorge Rokos DP("Loading '%s' (Failed)\n", e->name); 7243de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 7253de4cd12SGeorge Rokos return NULL; 7263de4cd12SGeorge Rokos } 7273de4cd12SGeorge Rokos 7283de4cd12SGeorge Rokos DP("Entry point " DPxMOD " maps to %s (" DPxMOD ")\n", 7293de4cd12SGeorge Rokos DPxPTR(e - HostBegin), e->name, DPxPTR(fun)); 7303de4cd12SGeorge Rokos 7313de4cd12SGeorge Rokos // default value GENERIC (in case symbol is missing from cubin file) 7323de4cd12SGeorge Rokos int8_t ExecModeVal = ExecutionModeType::GENERIC; 7333de4cd12SGeorge Rokos std::string ExecModeNameStr (e->name); 7343de4cd12SGeorge Rokos ExecModeNameStr += "_exec_mode"; 7353de4cd12SGeorge Rokos const char *ExecModeName = ExecModeNameStr.c_str(); 7363de4cd12SGeorge Rokos 7373de4cd12SGeorge Rokos CUdeviceptr ExecModePtr; 7383de4cd12SGeorge Rokos size_t cusize; 7393de4cd12SGeorge Rokos err = cuModuleGetGlobal(&ExecModePtr, &cusize, cumod, ExecModeName); 7403de4cd12SGeorge Rokos if (err == CUDA_SUCCESS) { 7413de4cd12SGeorge Rokos if ((size_t)cusize != sizeof(int8_t)) { 7423de4cd12SGeorge Rokos DP("Loading global exec_mode '%s' - size mismatch (%zd != %zd)\n", 7433de4cd12SGeorge Rokos ExecModeName, cusize, sizeof(int8_t)); 7443de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 7453de4cd12SGeorge Rokos return NULL; 7463de4cd12SGeorge Rokos } 7473de4cd12SGeorge Rokos 7483de4cd12SGeorge Rokos err = cuMemcpyDtoH(&ExecModeVal, ExecModePtr, cusize); 7493de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 7503de4cd12SGeorge Rokos DP("Error when copying data from device to host. Pointers: " 7513de4cd12SGeorge Rokos "host = " DPxMOD ", device = " DPxMOD ", size = %zd\n", 7523de4cd12SGeorge Rokos DPxPTR(&ExecModeVal), DPxPTR(ExecModePtr), cusize); 7533de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 7543de4cd12SGeorge Rokos return NULL; 7553de4cd12SGeorge Rokos } 7563de4cd12SGeorge Rokos 7573de4cd12SGeorge Rokos if (ExecModeVal < 0 || ExecModeVal > 1) { 7583de4cd12SGeorge Rokos DP("Error wrong exec_mode value specified in cubin file: %d\n", 7593de4cd12SGeorge Rokos ExecModeVal); 7603de4cd12SGeorge Rokos return NULL; 7613de4cd12SGeorge Rokos } 7623de4cd12SGeorge Rokos } else { 7633de4cd12SGeorge Rokos DP("Loading global exec_mode '%s' - symbol missing, using default value " 7643de4cd12SGeorge Rokos "GENERIC (1)\n", ExecModeName); 7653de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 7663de4cd12SGeorge Rokos } 7673de4cd12SGeorge Rokos 7683de4cd12SGeorge Rokos KernelsList.push_back(KernelTy(fun, ExecModeVal)); 7693de4cd12SGeorge Rokos 7703de4cd12SGeorge Rokos __tgt_offload_entry entry = *e; 7713de4cd12SGeorge Rokos entry.addr = (void *)&KernelsList.back(); 7723de4cd12SGeorge Rokos DeviceInfo.addOffloadEntry(device_id, entry); 7733de4cd12SGeorge Rokos } 7743de4cd12SGeorge Rokos 775e1c7a46dSGuansong Zhang // send device environment data to the device 776e1c7a46dSGuansong Zhang { 777e1c7a46dSGuansong Zhang omptarget_device_environmentTy device_env; 778e1c7a46dSGuansong Zhang 779e1c7a46dSGuansong Zhang device_env.debug_level = 0; 780e1c7a46dSGuansong Zhang 781e1c7a46dSGuansong Zhang #ifdef OMPTARGET_DEBUG 782e1c7a46dSGuansong Zhang if (char *envStr = getenv("LIBOMPTARGET_DEVICE_RTL_DEBUG")) { 783e1c7a46dSGuansong Zhang device_env.debug_level = std::stoi(envStr); 784e1c7a46dSGuansong Zhang } 785e1c7a46dSGuansong Zhang #endif 786e1c7a46dSGuansong Zhang 787e1c7a46dSGuansong Zhang const char * device_env_Name="omptarget_device_environment"; 788e1c7a46dSGuansong Zhang CUdeviceptr device_env_Ptr; 789e1c7a46dSGuansong Zhang size_t cusize; 790e1c7a46dSGuansong Zhang 791e1c7a46dSGuansong Zhang err = cuModuleGetGlobal(&device_env_Ptr, &cusize, cumod, device_env_Name); 792e1c7a46dSGuansong Zhang 793e1c7a46dSGuansong Zhang if (err == CUDA_SUCCESS) { 794e1c7a46dSGuansong Zhang if ((size_t)cusize != sizeof(device_env)) { 795e1c7a46dSGuansong Zhang DP("Global device_environment '%s' - size mismatch (%zu != %zu)\n", 796e1c7a46dSGuansong Zhang device_env_Name, cusize, sizeof(int32_t)); 797e1c7a46dSGuansong Zhang CUDA_ERR_STRING(err); 798e1c7a46dSGuansong Zhang return NULL; 799e1c7a46dSGuansong Zhang } 800e1c7a46dSGuansong Zhang 801e1c7a46dSGuansong Zhang err = cuMemcpyHtoD(device_env_Ptr, &device_env, cusize); 802e1c7a46dSGuansong Zhang if (err != CUDA_SUCCESS) { 803e1c7a46dSGuansong Zhang DP("Error when copying data from host to device. Pointers: " 804e1c7a46dSGuansong Zhang "host = " DPxMOD ", device = " DPxMOD ", size = %zu\n", 805e1c7a46dSGuansong Zhang DPxPTR(&device_env), DPxPTR(device_env_Ptr), cusize); 806e1c7a46dSGuansong Zhang CUDA_ERR_STRING(err); 807e1c7a46dSGuansong Zhang return NULL; 808e1c7a46dSGuansong Zhang } 809e1c7a46dSGuansong Zhang 810e1c7a46dSGuansong Zhang DP("Sending global device environment data %zu bytes\n", (size_t)cusize); 811e1c7a46dSGuansong Zhang } else { 812e1c7a46dSGuansong Zhang DP("Finding global device environment '%s' - symbol missing.\n", device_env_Name); 8134c6a098aSKazuaki Ishizaki DP("Continue, considering this is a device RTL which does not accept environment setting.\n"); 814e1c7a46dSGuansong Zhang } 815e1c7a46dSGuansong Zhang } 816e1c7a46dSGuansong Zhang 8173de4cd12SGeorge Rokos return DeviceInfo.getOffloadEntriesTable(device_id); 8183de4cd12SGeorge Rokos } 8193de4cd12SGeorge Rokos 8201546d319SGeorge Rokos void *__tgt_rtl_data_alloc(int32_t device_id, int64_t size, void *hst_ptr) { 8213de4cd12SGeorge Rokos if (size == 0) { 8223de4cd12SGeorge Rokos return NULL; 8233de4cd12SGeorge Rokos } 8243de4cd12SGeorge Rokos 8253de4cd12SGeorge Rokos // Set the context we are using. 8263de4cd12SGeorge Rokos CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]); 8273de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 8283de4cd12SGeorge Rokos DP("Error while trying to set CUDA current context\n"); 8293de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 8303de4cd12SGeorge Rokos return NULL; 8313de4cd12SGeorge Rokos } 8323de4cd12SGeorge Rokos 8333de4cd12SGeorge Rokos CUdeviceptr ptr; 8343de4cd12SGeorge Rokos err = cuMemAlloc(&ptr, size); 8353de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 8363de4cd12SGeorge Rokos DP("Error while trying to allocate %d\n", err); 8373de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 8383de4cd12SGeorge Rokos return NULL; 8393de4cd12SGeorge Rokos } 8403de4cd12SGeorge Rokos 8413de4cd12SGeorge Rokos void *vptr = (void *)ptr; 8423de4cd12SGeorge Rokos return vptr; 8433de4cd12SGeorge Rokos } 8443de4cd12SGeorge Rokos 8453de4cd12SGeorge Rokos int32_t __tgt_rtl_data_submit(int32_t device_id, void *tgt_ptr, void *hst_ptr, 84603ff643dSShilei Tian int64_t size) { 84732ed2927SShilei Tian __tgt_async_info async_info; 84803ff643dSShilei Tian int32_t rc = __tgt_rtl_data_submit_async(device_id, tgt_ptr, hst_ptr, size, 84903ff643dSShilei Tian &async_info); 85032ed2927SShilei Tian if (rc != OFFLOAD_SUCCESS) 8513de4cd12SGeorge Rokos return OFFLOAD_FAIL; 8523de4cd12SGeorge Rokos 85332ed2927SShilei Tian return __tgt_rtl_synchronize(device_id, &async_info); 8543de4cd12SGeorge Rokos } 8553de4cd12SGeorge Rokos 85603ff643dSShilei Tian int32_t __tgt_rtl_data_submit_async(int32_t device_id, void *tgt_ptr, 85703ff643dSShilei Tian void *hst_ptr, int64_t size, 85832ed2927SShilei Tian __tgt_async_info *async_info_ptr) { 85903ff643dSShilei Tian assert(async_info_ptr && "async_info_ptr is nullptr"); 86003ff643dSShilei Tian return dataSubmit(device_id, tgt_ptr, hst_ptr, size, async_info_ptr); 86103ff643dSShilei Tian } 86232ed2927SShilei Tian 86303ff643dSShilei Tian int32_t __tgt_rtl_data_retrieve(int32_t device_id, void *hst_ptr, void *tgt_ptr, 86403ff643dSShilei Tian int64_t size) { 86532ed2927SShilei Tian __tgt_async_info async_info; 86603ff643dSShilei Tian int32_t rc = __tgt_rtl_data_retrieve_async(device_id, hst_ptr, tgt_ptr, size, 86703ff643dSShilei Tian &async_info); 86832ed2927SShilei Tian if (rc != OFFLOAD_SUCCESS) 8693de4cd12SGeorge Rokos return OFFLOAD_FAIL; 8703de4cd12SGeorge Rokos 87132ed2927SShilei Tian return __tgt_rtl_synchronize(device_id, &async_info); 8723de4cd12SGeorge Rokos } 8733de4cd12SGeorge Rokos 87403ff643dSShilei Tian int32_t __tgt_rtl_data_retrieve_async(int32_t device_id, void *hst_ptr, 87503ff643dSShilei Tian void *tgt_ptr, int64_t size, 87603ff643dSShilei Tian __tgt_async_info *async_info_ptr) { 87703ff643dSShilei Tian assert(async_info_ptr && "async_info_ptr is nullptr"); 87803ff643dSShilei Tian return dataRetrieve(device_id, hst_ptr, tgt_ptr, size, async_info_ptr); 87903ff643dSShilei Tian } 88003ff643dSShilei Tian 8813de4cd12SGeorge Rokos int32_t __tgt_rtl_data_delete(int32_t device_id, void *tgt_ptr) { 8823de4cd12SGeorge Rokos // Set the context we are using. 8833de4cd12SGeorge Rokos CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]); 8843de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 8853de4cd12SGeorge Rokos DP("Error when setting CUDA context\n"); 8863de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 8873de4cd12SGeorge Rokos return OFFLOAD_FAIL; 8883de4cd12SGeorge Rokos } 8893de4cd12SGeorge Rokos 8903de4cd12SGeorge Rokos err = cuMemFree((CUdeviceptr)tgt_ptr); 8913de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 8923de4cd12SGeorge Rokos DP("Error when freeing CUDA memory\n"); 8933de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 8943de4cd12SGeorge Rokos return OFFLOAD_FAIL; 8953de4cd12SGeorge Rokos } 8963de4cd12SGeorge Rokos return OFFLOAD_SUCCESS; 8973de4cd12SGeorge Rokos } 8983de4cd12SGeorge Rokos 8993de4cd12SGeorge Rokos int32_t __tgt_rtl_run_target_team_region(int32_t device_id, void *tgt_entry_ptr, 90032ed2927SShilei Tian void **tgt_args, 90132ed2927SShilei Tian ptrdiff_t *tgt_offsets, 90232ed2927SShilei Tian int32_t arg_num, int32_t team_num, 90332ed2927SShilei Tian int32_t thread_limit, 90403ff643dSShilei Tian uint64_t loop_tripcount) { 90503ff643dSShilei Tian __tgt_async_info async_info; 90603ff643dSShilei Tian int32_t rc = __tgt_rtl_run_target_team_region_async( 90703ff643dSShilei Tian device_id, tgt_entry_ptr, tgt_args, tgt_offsets, arg_num, team_num, 90803ff643dSShilei Tian thread_limit, loop_tripcount, &async_info); 90903ff643dSShilei Tian if (rc != OFFLOAD_SUCCESS) 91003ff643dSShilei Tian return OFFLOAD_FAIL; 91103ff643dSShilei Tian 91203ff643dSShilei Tian return __tgt_rtl_synchronize(device_id, &async_info); 91303ff643dSShilei Tian } 91403ff643dSShilei Tian 91503ff643dSShilei Tian int32_t __tgt_rtl_run_target_team_region_async( 91603ff643dSShilei Tian int32_t device_id, void *tgt_entry_ptr, void **tgt_args, 91703ff643dSShilei Tian ptrdiff_t *tgt_offsets, int32_t arg_num, int32_t team_num, 91803ff643dSShilei Tian int32_t thread_limit, uint64_t loop_tripcount, 91932ed2927SShilei Tian __tgt_async_info *async_info) { 9203de4cd12SGeorge Rokos // Set the context we are using. 9213de4cd12SGeorge Rokos CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]); 9223de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 9233de4cd12SGeorge Rokos DP("Error when setting CUDA context\n"); 9243de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 9253de4cd12SGeorge Rokos return OFFLOAD_FAIL; 9263de4cd12SGeorge Rokos } 9273de4cd12SGeorge Rokos 9283de4cd12SGeorge Rokos // All args are references. 9293de4cd12SGeorge Rokos std::vector<void *> args(arg_num); 9301546d319SGeorge Rokos std::vector<void *> ptrs(arg_num); 9313de4cd12SGeorge Rokos 9321546d319SGeorge Rokos for (int32_t i = 0; i < arg_num; ++i) { 9331546d319SGeorge Rokos ptrs[i] = (void *)((intptr_t)tgt_args[i] + tgt_offsets[i]); 9341546d319SGeorge Rokos args[i] = &ptrs[i]; 9351546d319SGeorge Rokos } 9363de4cd12SGeorge Rokos 9373de4cd12SGeorge Rokos KernelTy *KernelInfo = (KernelTy *)tgt_entry_ptr; 9383de4cd12SGeorge Rokos 9393de4cd12SGeorge Rokos int cudaThreadsPerBlock; 9403de4cd12SGeorge Rokos 9413de4cd12SGeorge Rokos if (thread_limit > 0) { 9423de4cd12SGeorge Rokos cudaThreadsPerBlock = thread_limit; 9433de4cd12SGeorge Rokos DP("Setting CUDA threads per block to requested %d\n", thread_limit); 9443de4cd12SGeorge Rokos // Add master warp if necessary 9453de4cd12SGeorge Rokos if (KernelInfo->ExecutionMode == GENERIC) { 9463de4cd12SGeorge Rokos cudaThreadsPerBlock += DeviceInfo.WarpSize[device_id]; 9473de4cd12SGeorge Rokos DP("Adding master warp: +%d threads\n", DeviceInfo.WarpSize[device_id]); 9483de4cd12SGeorge Rokos } 949c13df8e5SGeorge Rokos } else { 950c13df8e5SGeorge Rokos cudaThreadsPerBlock = DeviceInfo.NumThreads[device_id]; 951c13df8e5SGeorge Rokos DP("Setting CUDA threads per block to default %d\n", 952c13df8e5SGeorge Rokos DeviceInfo.NumThreads[device_id]); 953c13df8e5SGeorge Rokos } 9543de4cd12SGeorge Rokos 9553de4cd12SGeorge Rokos if (cudaThreadsPerBlock > DeviceInfo.ThreadsPerBlock[device_id]) { 9563de4cd12SGeorge Rokos cudaThreadsPerBlock = DeviceInfo.ThreadsPerBlock[device_id]; 9573de4cd12SGeorge Rokos DP("Threads per block capped at device limit %d\n", 9583de4cd12SGeorge Rokos DeviceInfo.ThreadsPerBlock[device_id]); 9593de4cd12SGeorge Rokos } 9603de4cd12SGeorge Rokos 9613de4cd12SGeorge Rokos int kernel_limit; 9623de4cd12SGeorge Rokos err = cuFuncGetAttribute(&kernel_limit, 9633de4cd12SGeorge Rokos CU_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK, KernelInfo->Func); 9643de4cd12SGeorge Rokos if (err == CUDA_SUCCESS) { 9653de4cd12SGeorge Rokos if (kernel_limit < cudaThreadsPerBlock) { 9663de4cd12SGeorge Rokos cudaThreadsPerBlock = kernel_limit; 9673de4cd12SGeorge Rokos DP("Threads per block capped at kernel limit %d\n", kernel_limit); 9683de4cd12SGeorge Rokos } 9693de4cd12SGeorge Rokos } 9703de4cd12SGeorge Rokos 9713de4cd12SGeorge Rokos int cudaBlocksPerGrid; 9723de4cd12SGeorge Rokos if (team_num <= 0) { 9733de4cd12SGeorge Rokos if (loop_tripcount > 0 && DeviceInfo.EnvNumTeams < 0) { 974c13df8e5SGeorge Rokos if (KernelInfo->ExecutionMode == SPMD) { 975c13df8e5SGeorge Rokos // We have a combined construct, i.e. `target teams distribute parallel 976c13df8e5SGeorge Rokos // for [simd]`. We launch so many teams so that each thread will 977c13df8e5SGeorge Rokos // execute one iteration of the loop. 9783de4cd12SGeorge Rokos // round up to the nearest integer 9793de4cd12SGeorge Rokos cudaBlocksPerGrid = ((loop_tripcount - 1) / cudaThreadsPerBlock) + 1; 980c13df8e5SGeorge Rokos } else { 981c13df8e5SGeorge Rokos // If we reach this point, then we have a non-combined construct, i.e. 982c13df8e5SGeorge Rokos // `teams distribute` with a nested `parallel for` and each team is 983c13df8e5SGeorge Rokos // assigned one iteration of the `distribute` loop. E.g.: 984c13df8e5SGeorge Rokos // 985c13df8e5SGeorge Rokos // #pragma omp target teams distribute 986c13df8e5SGeorge Rokos // for(...loop_tripcount...) { 987c13df8e5SGeorge Rokos // #pragma omp parallel for 988c13df8e5SGeorge Rokos // for(...) {} 989c13df8e5SGeorge Rokos // } 990c13df8e5SGeorge Rokos // 991c13df8e5SGeorge Rokos // Threads within a team will execute the iterations of the `parallel` 992c13df8e5SGeorge Rokos // loop. 993c13df8e5SGeorge Rokos cudaBlocksPerGrid = loop_tripcount; 994c13df8e5SGeorge Rokos } 9953de4cd12SGeorge Rokos DP("Using %d teams due to loop trip count %" PRIu64 " and number of " 9963de4cd12SGeorge Rokos "threads per block %d\n", cudaBlocksPerGrid, loop_tripcount, 9973de4cd12SGeorge Rokos cudaThreadsPerBlock); 9983de4cd12SGeorge Rokos } else { 9993de4cd12SGeorge Rokos cudaBlocksPerGrid = DeviceInfo.NumTeams[device_id]; 10003de4cd12SGeorge Rokos DP("Using default number of teams %d\n", DeviceInfo.NumTeams[device_id]); 10013de4cd12SGeorge Rokos } 10023de4cd12SGeorge Rokos } else if (team_num > DeviceInfo.BlocksPerGrid[device_id]) { 10033de4cd12SGeorge Rokos cudaBlocksPerGrid = DeviceInfo.BlocksPerGrid[device_id]; 10043de4cd12SGeorge Rokos DP("Capping number of teams to team limit %d\n", 10053de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id]); 10063de4cd12SGeorge Rokos } else { 10073de4cd12SGeorge Rokos cudaBlocksPerGrid = team_num; 10083de4cd12SGeorge Rokos DP("Using requested number of teams %d\n", team_num); 10093de4cd12SGeorge Rokos } 10103de4cd12SGeorge Rokos 10113de4cd12SGeorge Rokos // Run on the device. 10123de4cd12SGeorge Rokos DP("Launch kernel with %d blocks and %d threads\n", cudaBlocksPerGrid, 10133de4cd12SGeorge Rokos cudaThreadsPerBlock); 10143de4cd12SGeorge Rokos 1015*feed674dSShilei Tian CUstream Stream = getStream(device_id, async_info); 10163de4cd12SGeorge Rokos err = cuLaunchKernel(KernelInfo->Func, cudaBlocksPerGrid, 1, 1, 1017a5153dbcSJohannes Doerfert cudaThreadsPerBlock, 1, 1, 0 /*bytes of shared memory*/, 1018a5153dbcSJohannes Doerfert Stream, &args[0], 0); 10193de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 10203de4cd12SGeorge Rokos DP("Device kernel launch failed!\n"); 10213de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 10223de4cd12SGeorge Rokos return OFFLOAD_FAIL; 10233de4cd12SGeorge Rokos } 10243de4cd12SGeorge Rokos 10253de4cd12SGeorge Rokos DP("Launch of entry point at " DPxMOD " successful!\n", 10263de4cd12SGeorge Rokos DPxPTR(tgt_entry_ptr)); 10273de4cd12SGeorge Rokos 10283de4cd12SGeorge Rokos return OFFLOAD_SUCCESS; 10293de4cd12SGeorge Rokos } 10303de4cd12SGeorge Rokos 10313de4cd12SGeorge Rokos int32_t __tgt_rtl_run_target_region(int32_t device_id, void *tgt_entry_ptr, 103232ed2927SShilei Tian void **tgt_args, ptrdiff_t *tgt_offsets, 103303ff643dSShilei Tian int32_t arg_num) { 103403ff643dSShilei Tian __tgt_async_info async_info; 103503ff643dSShilei Tian int32_t rc = __tgt_rtl_run_target_region_async( 103603ff643dSShilei Tian device_id, tgt_entry_ptr, tgt_args, tgt_offsets, arg_num, &async_info); 103703ff643dSShilei Tian if (rc != OFFLOAD_SUCCESS) 103803ff643dSShilei Tian return OFFLOAD_FAIL; 103903ff643dSShilei Tian 104003ff643dSShilei Tian return __tgt_rtl_synchronize(device_id, &async_info); 104103ff643dSShilei Tian } 104203ff643dSShilei Tian 104303ff643dSShilei Tian int32_t __tgt_rtl_run_target_region_async(int32_t device_id, 104403ff643dSShilei Tian void *tgt_entry_ptr, void **tgt_args, 104503ff643dSShilei Tian ptrdiff_t *tgt_offsets, 104632ed2927SShilei Tian int32_t arg_num, 104732ed2927SShilei Tian __tgt_async_info *async_info) { 10483de4cd12SGeorge Rokos // use one team and the default number of threads. 10493de4cd12SGeorge Rokos const int32_t team_num = 1; 10503de4cd12SGeorge Rokos const int32_t thread_limit = 0; 105103ff643dSShilei Tian return __tgt_rtl_run_target_team_region_async( 105203ff643dSShilei Tian device_id, tgt_entry_ptr, tgt_args, tgt_offsets, arg_num, team_num, 105332ed2927SShilei Tian thread_limit, 0, async_info); 105432ed2927SShilei Tian } 105532ed2927SShilei Tian 105632ed2927SShilei Tian int32_t __tgt_rtl_synchronize(int32_t device_id, __tgt_async_info *async_info) { 105732ed2927SShilei Tian assert(async_info && "async_info is nullptr"); 105832ed2927SShilei Tian assert(async_info->Queue && "async_info->Queue is nullptr"); 105932ed2927SShilei Tian 106032ed2927SShilei Tian CUstream Stream = reinterpret_cast<CUstream>(async_info->Queue); 106132ed2927SShilei Tian CUresult Err = cuStreamSynchronize(Stream); 106232ed2927SShilei Tian if (Err != CUDA_SUCCESS) { 106332ed2927SShilei Tian DP("Error when synchronizing stream. stream = " DPxMOD 106432ed2927SShilei Tian ", async info ptr = " DPxMOD "\n", 106532ed2927SShilei Tian DPxPTR(Stream), DPxPTR(async_info)); 106632ed2927SShilei Tian CUDA_ERR_STRING(Err); 106732ed2927SShilei Tian return OFFLOAD_FAIL; 106832ed2927SShilei Tian } 1069*feed674dSShilei Tian 1070*feed674dSShilei Tian // Once the stream is synchronized, return it to stream pool and reset 1071*feed674dSShilei Tian // async_info. This is to make sure the synchronization only works for its own 1072*feed674dSShilei Tian // tasks. 1073*feed674dSShilei Tian DeviceInfo.returnStream(device_id, async_info); 1074*feed674dSShilei Tian 107532ed2927SShilei Tian return OFFLOAD_SUCCESS; 10763de4cd12SGeorge Rokos } 10773de4cd12SGeorge Rokos 10783de4cd12SGeorge Rokos #ifdef __cplusplus 10793de4cd12SGeorge Rokos } 10803de4cd12SGeorge Rokos #endif 1081