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> 193de4cd12SGeorge Rokos #include <string> 203de4cd12SGeorge Rokos #include <vector> 213de4cd12SGeorge Rokos 221546d319SGeorge Rokos #include "omptargetplugin.h" 233de4cd12SGeorge Rokos 243de4cd12SGeorge Rokos #ifndef TARGET_NAME 253de4cd12SGeorge Rokos #define TARGET_NAME CUDA 263de4cd12SGeorge Rokos #endif 273de4cd12SGeorge Rokos 28b305d26bSSergey Dmitriev #ifdef OMPTARGET_DEBUG 29b305d26bSSergey Dmitriev static int DebugLevel = 0; 30b305d26bSSergey Dmitriev 313de4cd12SGeorge Rokos #define GETNAME2(name) #name 323de4cd12SGeorge Rokos #define GETNAME(name) GETNAME2(name) 33b305d26bSSergey Dmitriev #define DP(...) \ 34b305d26bSSergey Dmitriev do { \ 35b305d26bSSergey Dmitriev if (DebugLevel > 0) { \ 36b305d26bSSergey Dmitriev DEBUGP("Target " GETNAME(TARGET_NAME) " RTL", __VA_ARGS__); \ 37b305d26bSSergey Dmitriev } \ 38b305d26bSSergey Dmitriev } while (false) 3978769ec4SMichael Kruse 4078769ec4SMichael Kruse // Utility for retrieving and printing CUDA error string. 4178769ec4SMichael Kruse #define CUDA_ERR_STRING(err) \ 4278769ec4SMichael Kruse do { \ 4378769ec4SMichael Kruse if (DebugLevel > 0) { \ 4478769ec4SMichael Kruse const char *errStr; \ 4578769ec4SMichael Kruse cuGetErrorString(err, &errStr); \ 4678769ec4SMichael Kruse DEBUGP("Target " GETNAME(TARGET_NAME) " RTL", "CUDA error is: %s\n", errStr); \ 4778769ec4SMichael Kruse } \ 4878769ec4SMichael Kruse } while (false) 49b305d26bSSergey Dmitriev #else // OMPTARGET_DEBUG 50b305d26bSSergey Dmitriev #define DP(...) {} 5178769ec4SMichael Kruse #define CUDA_ERR_STRING(err) {} 52b305d26bSSergey Dmitriev #endif // OMPTARGET_DEBUG 533de4cd12SGeorge Rokos 543de4cd12SGeorge Rokos #include "../../common/elf_common.c" 553de4cd12SGeorge Rokos 563de4cd12SGeorge Rokos /// Keep entries table per device. 573de4cd12SGeorge Rokos struct FuncOrGblEntryTy { 583de4cd12SGeorge Rokos __tgt_target_table Table; 593de4cd12SGeorge Rokos std::vector<__tgt_offload_entry> Entries; 603de4cd12SGeorge Rokos }; 613de4cd12SGeorge Rokos 623de4cd12SGeorge Rokos enum ExecutionModeType { 63c13df8e5SGeorge Rokos SPMD, // constructors, destructors, 64c13df8e5SGeorge Rokos // combined constructs (`teams distribute parallel for [simd]`) 65c13df8e5SGeorge Rokos GENERIC, // everything else 663de4cd12SGeorge Rokos NONE 673de4cd12SGeorge Rokos }; 683de4cd12SGeorge Rokos 69dc34b1c9SRon Lieberman /// Use a single entity to encode a kernel and a set of flags. 703de4cd12SGeorge Rokos struct KernelTy { 713de4cd12SGeorge Rokos CUfunction Func; 723de4cd12SGeorge Rokos 733de4cd12SGeorge Rokos // execution mode of kernel 743de4cd12SGeorge Rokos // 0 - SPMD mode (without master warp) 753de4cd12SGeorge Rokos // 1 - Generic mode (with master warp) 763de4cd12SGeorge Rokos int8_t ExecutionMode; 773de4cd12SGeorge Rokos 783de4cd12SGeorge Rokos KernelTy(CUfunction _Func, int8_t _ExecutionMode) 793de4cd12SGeorge Rokos : Func(_Func), ExecutionMode(_ExecutionMode) {} 803de4cd12SGeorge Rokos }; 813de4cd12SGeorge Rokos 824c6a098aSKazuaki Ishizaki /// Device environment data 83e1c7a46dSGuansong Zhang /// Manually sync with the deviceRTL side for now, move to a dedicated header file later. 84e1c7a46dSGuansong Zhang struct omptarget_device_environmentTy { 85e1c7a46dSGuansong Zhang int32_t debug_level; 86e1c7a46dSGuansong Zhang }; 87e1c7a46dSGuansong Zhang 883de4cd12SGeorge Rokos /// List that contains all the kernels. 893de4cd12SGeorge Rokos /// FIXME: we may need this to be per device and per library. 903de4cd12SGeorge Rokos std::list<KernelTy> KernelsList; 913de4cd12SGeorge Rokos 923de4cd12SGeorge Rokos /// Class containing all the device information. 933de4cd12SGeorge Rokos class RTLDeviceInfoTy { 942622e9e5SAlexey Bataev std::vector<std::list<FuncOrGblEntryTy>> FuncGblEntries; 95a5153dbcSJohannes Doerfert std::vector<std::unique_ptr<std::atomic_uint>> NextStreamId; 963de4cd12SGeorge Rokos 973de4cd12SGeorge Rokos public: 983de4cd12SGeorge Rokos int NumberOfDevices; 993de4cd12SGeorge Rokos std::vector<CUmodule> Modules; 1003de4cd12SGeorge Rokos std::vector<CUcontext> Contexts; 101a5153dbcSJohannes Doerfert std::vector<std::vector<CUstream>> Streams; 1023de4cd12SGeorge Rokos 1033de4cd12SGeorge Rokos // Device properties 1043de4cd12SGeorge Rokos std::vector<int> ThreadsPerBlock; 1053de4cd12SGeorge Rokos std::vector<int> BlocksPerGrid; 1063de4cd12SGeorge Rokos std::vector<int> WarpSize; 1073de4cd12SGeorge Rokos 1083de4cd12SGeorge Rokos // OpenMP properties 1093de4cd12SGeorge Rokos std::vector<int> NumTeams; 1103de4cd12SGeorge Rokos std::vector<int> NumThreads; 1113de4cd12SGeorge Rokos 1123de4cd12SGeorge Rokos // OpenMP Environment properties 1133de4cd12SGeorge Rokos int EnvNumTeams; 1143de4cd12SGeorge Rokos int EnvTeamLimit; 115a5153dbcSJohannes Doerfert int EnvNumStreams; 1163de4cd12SGeorge Rokos 117c5fe030cSGheorghe-Teodor Bercea // OpenMP Requires Flags 118c5fe030cSGheorghe-Teodor Bercea int64_t RequiresFlags; 119c5fe030cSGheorghe-Teodor Bercea 1203de4cd12SGeorge Rokos //static int EnvNumThreads; 1213de4cd12SGeorge Rokos static const int HardTeamLimit = 1<<16; // 64k 1223de4cd12SGeorge Rokos static const int HardThreadLimit = 1024; 1233de4cd12SGeorge Rokos static const int DefaultNumTeams = 128; 124c13df8e5SGeorge Rokos static const int DefaultNumThreads = 128; 1253de4cd12SGeorge Rokos 1263de4cd12SGeorge Rokos // Record entry point associated with device 1273de4cd12SGeorge Rokos void addOffloadEntry(int32_t device_id, __tgt_offload_entry entry) { 1283de4cd12SGeorge Rokos assert(device_id < (int32_t)FuncGblEntries.size() && 1293de4cd12SGeorge Rokos "Unexpected device id!"); 1302622e9e5SAlexey Bataev FuncOrGblEntryTy &E = FuncGblEntries[device_id].back(); 1313de4cd12SGeorge Rokos 1323de4cd12SGeorge Rokos E.Entries.push_back(entry); 1333de4cd12SGeorge Rokos } 1343de4cd12SGeorge Rokos 1353de4cd12SGeorge Rokos // Return true if the entry is associated with device 1363de4cd12SGeorge Rokos bool findOffloadEntry(int32_t device_id, void *addr) { 1373de4cd12SGeorge Rokos assert(device_id < (int32_t)FuncGblEntries.size() && 1383de4cd12SGeorge Rokos "Unexpected device id!"); 1392622e9e5SAlexey Bataev FuncOrGblEntryTy &E = FuncGblEntries[device_id].back(); 1403de4cd12SGeorge Rokos 1413de4cd12SGeorge Rokos for (auto &it : E.Entries) { 1423de4cd12SGeorge Rokos if (it.addr == addr) 1433de4cd12SGeorge Rokos return true; 1443de4cd12SGeorge Rokos } 1453de4cd12SGeorge Rokos 1463de4cd12SGeorge Rokos return false; 1473de4cd12SGeorge Rokos } 1483de4cd12SGeorge Rokos 1493de4cd12SGeorge Rokos // Return the pointer to the target entries table 1503de4cd12SGeorge Rokos __tgt_target_table *getOffloadEntriesTable(int32_t device_id) { 1513de4cd12SGeorge Rokos assert(device_id < (int32_t)FuncGblEntries.size() && 1523de4cd12SGeorge Rokos "Unexpected device id!"); 1532622e9e5SAlexey Bataev FuncOrGblEntryTy &E = FuncGblEntries[device_id].back(); 1543de4cd12SGeorge Rokos 1553de4cd12SGeorge Rokos int32_t size = E.Entries.size(); 1563de4cd12SGeorge Rokos 1573de4cd12SGeorge Rokos // Table is empty 1583de4cd12SGeorge Rokos if (!size) 1593de4cd12SGeorge Rokos return 0; 1603de4cd12SGeorge Rokos 1613de4cd12SGeorge Rokos __tgt_offload_entry *begin = &E.Entries[0]; 1623de4cd12SGeorge Rokos __tgt_offload_entry *end = &E.Entries[size - 1]; 1633de4cd12SGeorge Rokos 1643de4cd12SGeorge Rokos // Update table info according to the entries and return the pointer 1653de4cd12SGeorge Rokos E.Table.EntriesBegin = begin; 1663de4cd12SGeorge Rokos E.Table.EntriesEnd = ++end; 1673de4cd12SGeorge Rokos 1683de4cd12SGeorge Rokos return &E.Table; 1693de4cd12SGeorge Rokos } 1703de4cd12SGeorge Rokos 1713de4cd12SGeorge Rokos // Clear entries table for a device 1723de4cd12SGeorge Rokos void clearOffloadEntriesTable(int32_t device_id) { 1733de4cd12SGeorge Rokos assert(device_id < (int32_t)FuncGblEntries.size() && 1743de4cd12SGeorge Rokos "Unexpected device id!"); 1752622e9e5SAlexey Bataev FuncGblEntries[device_id].emplace_back(); 1762622e9e5SAlexey Bataev FuncOrGblEntryTy &E = FuncGblEntries[device_id].back(); 1773de4cd12SGeorge Rokos E.Entries.clear(); 1783de4cd12SGeorge Rokos E.Table.EntriesBegin = E.Table.EntriesEnd = 0; 1793de4cd12SGeorge Rokos } 1803de4cd12SGeorge Rokos 181a5153dbcSJohannes Doerfert // Get the next stream on a given device in a round robin manner 182a5153dbcSJohannes Doerfert CUstream &getNextStream(const int DeviceId) { 183a5153dbcSJohannes Doerfert assert(DeviceId >= 0 && 184a5153dbcSJohannes Doerfert static_cast<size_t>(DeviceId) < NextStreamId.size() && 185a5153dbcSJohannes Doerfert "Unexpected device id!"); 186a5153dbcSJohannes Doerfert const unsigned int Id = NextStreamId[DeviceId]->fetch_add(1); 187a5153dbcSJohannes Doerfert return Streams[DeviceId][Id % EnvNumStreams]; 188a5153dbcSJohannes Doerfert } 189a5153dbcSJohannes Doerfert 1903de4cd12SGeorge Rokos RTLDeviceInfoTy() { 191b305d26bSSergey Dmitriev #ifdef OMPTARGET_DEBUG 192b305d26bSSergey Dmitriev if (char *envStr = getenv("LIBOMPTARGET_DEBUG")) { 193b305d26bSSergey Dmitriev DebugLevel = std::stoi(envStr); 194b305d26bSSergey Dmitriev } 195b305d26bSSergey Dmitriev #endif // OMPTARGET_DEBUG 196b305d26bSSergey Dmitriev 1973de4cd12SGeorge Rokos DP("Start initializing CUDA\n"); 1983de4cd12SGeorge Rokos 1993de4cd12SGeorge Rokos CUresult err = cuInit(0); 2003de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 2013de4cd12SGeorge Rokos DP("Error when initializing CUDA\n"); 2023de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 2033de4cd12SGeorge Rokos return; 2043de4cd12SGeorge Rokos } 2053de4cd12SGeorge Rokos 2063de4cd12SGeorge Rokos NumberOfDevices = 0; 2073de4cd12SGeorge Rokos 2083de4cd12SGeorge Rokos err = cuDeviceGetCount(&NumberOfDevices); 2093de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 2103de4cd12SGeorge Rokos DP("Error when getting CUDA device count\n"); 2113de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 2123de4cd12SGeorge Rokos return; 2133de4cd12SGeorge Rokos } 2143de4cd12SGeorge Rokos 2153de4cd12SGeorge Rokos if (NumberOfDevices == 0) { 2163de4cd12SGeorge Rokos DP("There are no devices supporting CUDA.\n"); 2173de4cd12SGeorge Rokos return; 2183de4cd12SGeorge Rokos } 2193de4cd12SGeorge Rokos 2203de4cd12SGeorge Rokos FuncGblEntries.resize(NumberOfDevices); 2213de4cd12SGeorge Rokos Contexts.resize(NumberOfDevices); 222a5153dbcSJohannes Doerfert Streams.resize(NumberOfDevices); 223a5153dbcSJohannes Doerfert NextStreamId.resize(NumberOfDevices); 2243de4cd12SGeorge Rokos ThreadsPerBlock.resize(NumberOfDevices); 2253de4cd12SGeorge Rokos BlocksPerGrid.resize(NumberOfDevices); 2263de4cd12SGeorge Rokos WarpSize.resize(NumberOfDevices); 2273de4cd12SGeorge Rokos NumTeams.resize(NumberOfDevices); 2283de4cd12SGeorge Rokos NumThreads.resize(NumberOfDevices); 2293de4cd12SGeorge Rokos 2303de4cd12SGeorge Rokos // Get environment variables regarding teams 2313de4cd12SGeorge Rokos char *envStr = getenv("OMP_TEAM_LIMIT"); 2323de4cd12SGeorge Rokos if (envStr) { 2333de4cd12SGeorge Rokos // OMP_TEAM_LIMIT has been set 2343de4cd12SGeorge Rokos EnvTeamLimit = std::stoi(envStr); 2353de4cd12SGeorge Rokos DP("Parsed OMP_TEAM_LIMIT=%d\n", EnvTeamLimit); 2363de4cd12SGeorge Rokos } else { 2373de4cd12SGeorge Rokos EnvTeamLimit = -1; 2383de4cd12SGeorge Rokos } 2393de4cd12SGeorge Rokos envStr = getenv("OMP_NUM_TEAMS"); 2403de4cd12SGeorge Rokos if (envStr) { 2413de4cd12SGeorge Rokos // OMP_NUM_TEAMS has been set 2423de4cd12SGeorge Rokos EnvNumTeams = std::stoi(envStr); 2433de4cd12SGeorge Rokos DP("Parsed OMP_NUM_TEAMS=%d\n", EnvNumTeams); 2443de4cd12SGeorge Rokos } else { 2453de4cd12SGeorge Rokos EnvNumTeams = -1; 2463de4cd12SGeorge Rokos } 247c5fe030cSGheorghe-Teodor Bercea 248a5153dbcSJohannes Doerfert // By default let's create 256 streams per device 249a5153dbcSJohannes Doerfert EnvNumStreams = 256; 250a5153dbcSJohannes Doerfert envStr = getenv("LIBOMPTARGET_NUM_STREAMS"); 251a5153dbcSJohannes Doerfert if (envStr) { 252a5153dbcSJohannes Doerfert EnvNumStreams = std::stoi(envStr); 253a5153dbcSJohannes Doerfert } 254a5153dbcSJohannes Doerfert 255a5153dbcSJohannes Doerfert // Initialize streams for each device 256a5153dbcSJohannes Doerfert for (std::vector<CUstream> &S : Streams) { 257a5153dbcSJohannes Doerfert S.resize(EnvNumStreams); 258a5153dbcSJohannes Doerfert } 259a5153dbcSJohannes Doerfert 260a5153dbcSJohannes Doerfert // Initialize the next stream id 261a5153dbcSJohannes Doerfert for (std::unique_ptr<std::atomic_uint> &Ptr : NextStreamId) { 262a5153dbcSJohannes Doerfert Ptr = std::make_unique<std::atomic_uint>(0); 263a5153dbcSJohannes Doerfert } 264a5153dbcSJohannes Doerfert 265c5fe030cSGheorghe-Teodor Bercea // Default state. 266c5fe030cSGheorghe-Teodor Bercea RequiresFlags = OMP_REQ_UNDEFINED; 2673de4cd12SGeorge Rokos } 2683de4cd12SGeorge Rokos 2693de4cd12SGeorge Rokos ~RTLDeviceInfoTy() { 2703de4cd12SGeorge Rokos // Close modules 2713de4cd12SGeorge Rokos for (auto &module : Modules) 2723de4cd12SGeorge Rokos if (module) { 2733de4cd12SGeorge Rokos CUresult err = cuModuleUnload(module); 2743de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 2753de4cd12SGeorge Rokos DP("Error when unloading CUDA module\n"); 2763de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 2773de4cd12SGeorge Rokos } 2783de4cd12SGeorge Rokos } 2793de4cd12SGeorge Rokos 280a5153dbcSJohannes Doerfert // Destroy streams before contexts 281a5153dbcSJohannes Doerfert for (int I = 0; I < NumberOfDevices; ++I) { 282a5153dbcSJohannes Doerfert CUresult err = cuCtxSetCurrent(Contexts[I]); 283a5153dbcSJohannes Doerfert if (err != CUDA_SUCCESS) { 284a5153dbcSJohannes Doerfert DP("Error when setting current CUDA context\n"); 285a5153dbcSJohannes Doerfert CUDA_ERR_STRING(err); 286a5153dbcSJohannes Doerfert } 287a5153dbcSJohannes Doerfert 288a5153dbcSJohannes Doerfert for (auto &S : Streams[I]) 289a5153dbcSJohannes Doerfert if (S) { 290a5153dbcSJohannes Doerfert err = cuStreamDestroy(S); 291a5153dbcSJohannes Doerfert if (err != CUDA_SUCCESS) { 292a5153dbcSJohannes Doerfert DP("Error when destroying CUDA stream\n"); 293a5153dbcSJohannes Doerfert CUDA_ERR_STRING(err); 294a5153dbcSJohannes Doerfert } 295a5153dbcSJohannes Doerfert } 296a5153dbcSJohannes Doerfert } 297a5153dbcSJohannes Doerfert 2983de4cd12SGeorge Rokos // Destroy contexts 2993de4cd12SGeorge Rokos for (auto &ctx : Contexts) 3003de4cd12SGeorge Rokos if (ctx) { 3013de4cd12SGeorge Rokos CUresult err = cuCtxDestroy(ctx); 3023de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 3033de4cd12SGeorge Rokos DP("Error when destroying CUDA context\n"); 3043de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 3053de4cd12SGeorge Rokos } 3063de4cd12SGeorge Rokos } 3073de4cd12SGeorge Rokos } 3083de4cd12SGeorge Rokos }; 3093de4cd12SGeorge Rokos 3103de4cd12SGeorge Rokos static RTLDeviceInfoTy DeviceInfo; 3113de4cd12SGeorge Rokos 31232ed2927SShilei Tian namespace { 31332ed2927SShilei Tian CUstream selectStream(int32_t Id, __tgt_async_info *AsyncInfo) { 31432ed2927SShilei Tian if (!AsyncInfo) 31532ed2927SShilei Tian return DeviceInfo.getNextStream(Id); 31632ed2927SShilei Tian 31732ed2927SShilei Tian if (!AsyncInfo->Queue) 31832ed2927SShilei Tian AsyncInfo->Queue = DeviceInfo.getNextStream(Id); 31932ed2927SShilei Tian 32032ed2927SShilei Tian return reinterpret_cast<CUstream>(AsyncInfo->Queue); 32132ed2927SShilei Tian } 32232ed2927SShilei Tian 32332ed2927SShilei Tian int32_t dataRetrieve(int32_t DeviceId, void *HstPtr, void *TgtPtr, int64_t Size, 32432ed2927SShilei Tian __tgt_async_info *AsyncInfoPtr) { 32532ed2927SShilei Tian assert(AsyncInfoPtr && "AsyncInfoPtr is nullptr"); 32632ed2927SShilei Tian // Set the context we are using. 32732ed2927SShilei Tian CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[DeviceId]); 32832ed2927SShilei Tian if (err != CUDA_SUCCESS) { 32932ed2927SShilei Tian DP("Error when setting CUDA context\n"); 33032ed2927SShilei Tian CUDA_ERR_STRING(err); 33132ed2927SShilei Tian return OFFLOAD_FAIL; 33232ed2927SShilei Tian } 33332ed2927SShilei Tian 33432ed2927SShilei Tian CUstream Stream = selectStream(DeviceId, AsyncInfoPtr); 33532ed2927SShilei Tian 33632ed2927SShilei Tian err = cuMemcpyDtoHAsync(HstPtr, (CUdeviceptr)TgtPtr, Size, Stream); 33732ed2927SShilei Tian if (err != CUDA_SUCCESS) { 33832ed2927SShilei Tian DP("Error when copying data from device to host. Pointers: host = " DPxMOD 33932ed2927SShilei Tian ", device = " DPxMOD ", size = %" PRId64 "\n", 34032ed2927SShilei Tian DPxPTR(HstPtr), DPxPTR(TgtPtr), Size); 34132ed2927SShilei Tian CUDA_ERR_STRING(err); 34232ed2927SShilei Tian return OFFLOAD_FAIL; 34332ed2927SShilei Tian } 34432ed2927SShilei Tian 34532ed2927SShilei Tian return OFFLOAD_SUCCESS; 34632ed2927SShilei Tian } 34732ed2927SShilei Tian 34832ed2927SShilei Tian int32_t dataSubmit(int32_t DeviceId, void *TgtPtr, void *HstPtr, int64_t Size, 34932ed2927SShilei Tian __tgt_async_info *AsyncInfoPtr) { 35032ed2927SShilei Tian assert(AsyncInfoPtr && "AsyncInfoPtr is nullptr"); 35132ed2927SShilei Tian // Set the context we are using. 35232ed2927SShilei Tian CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[DeviceId]); 35332ed2927SShilei Tian if (err != CUDA_SUCCESS) { 35432ed2927SShilei Tian DP("Error when setting CUDA context\n"); 35532ed2927SShilei Tian CUDA_ERR_STRING(err); 35632ed2927SShilei Tian return OFFLOAD_FAIL; 35732ed2927SShilei Tian } 35832ed2927SShilei Tian 35932ed2927SShilei Tian CUstream Stream = selectStream(DeviceId, AsyncInfoPtr); 36032ed2927SShilei Tian 36132ed2927SShilei Tian err = cuMemcpyHtoDAsync((CUdeviceptr)TgtPtr, HstPtr, Size, Stream); 36232ed2927SShilei Tian if (err != CUDA_SUCCESS) { 36332ed2927SShilei Tian DP("Error when copying data from host to device. Pointers: host = " DPxMOD 36432ed2927SShilei Tian ", device = " DPxMOD ", size = %" PRId64 "\n", 36532ed2927SShilei Tian DPxPTR(HstPtr), DPxPTR(TgtPtr), Size); 36632ed2927SShilei Tian CUDA_ERR_STRING(err); 36732ed2927SShilei Tian return OFFLOAD_FAIL; 36832ed2927SShilei Tian } 36932ed2927SShilei Tian 37032ed2927SShilei Tian return OFFLOAD_SUCCESS; 37132ed2927SShilei Tian } 37232ed2927SShilei Tian } // namespace 37332ed2927SShilei Tian 3743de4cd12SGeorge Rokos #ifdef __cplusplus 3753de4cd12SGeorge Rokos extern "C" { 3763de4cd12SGeorge Rokos #endif 3773de4cd12SGeorge Rokos 3783de4cd12SGeorge Rokos int32_t __tgt_rtl_is_valid_binary(__tgt_device_image *image) { 3793de4cd12SGeorge Rokos return elf_check_machine(image, 190); // EM_CUDA = 190. 3803de4cd12SGeorge Rokos } 3813de4cd12SGeorge Rokos 3823de4cd12SGeorge Rokos int32_t __tgt_rtl_number_of_devices() { return DeviceInfo.NumberOfDevices; } 3833de4cd12SGeorge Rokos 384c5fe030cSGheorghe-Teodor Bercea int64_t __tgt_rtl_init_requires(int64_t RequiresFlags) { 385c5fe030cSGheorghe-Teodor Bercea DP("Init requires flags to %ld\n", RequiresFlags); 386c5fe030cSGheorghe-Teodor Bercea DeviceInfo.RequiresFlags = RequiresFlags; 387c5fe030cSGheorghe-Teodor Bercea return RequiresFlags; 388c5fe030cSGheorghe-Teodor Bercea } 389c5fe030cSGheorghe-Teodor Bercea 3903de4cd12SGeorge Rokos int32_t __tgt_rtl_init_device(int32_t device_id) { 3913de4cd12SGeorge Rokos 3923de4cd12SGeorge Rokos CUdevice cuDevice; 3933de4cd12SGeorge Rokos DP("Getting device %d\n", device_id); 3943de4cd12SGeorge Rokos CUresult err = cuDeviceGet(&cuDevice, device_id); 3953de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 3963de4cd12SGeorge Rokos DP("Error when getting CUDA device with id = %d\n", device_id); 3973de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 3983de4cd12SGeorge Rokos return OFFLOAD_FAIL; 3993de4cd12SGeorge Rokos } 4003de4cd12SGeorge Rokos 4013de4cd12SGeorge Rokos // Create the context and save it to use whenever this device is selected. 4023de4cd12SGeorge Rokos err = cuCtxCreate(&DeviceInfo.Contexts[device_id], CU_CTX_SCHED_BLOCKING_SYNC, 4033de4cd12SGeorge Rokos cuDevice); 4043de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 4053de4cd12SGeorge Rokos DP("Error when creating a CUDA context\n"); 4063de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 4073de4cd12SGeorge Rokos return OFFLOAD_FAIL; 4083de4cd12SGeorge Rokos } 4093de4cd12SGeorge Rokos 410a5153dbcSJohannes Doerfert err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]); 411a5153dbcSJohannes Doerfert if (err != CUDA_SUCCESS) { 412a5153dbcSJohannes Doerfert DP("Error when setting current CUDA context\n"); 413a5153dbcSJohannes Doerfert CUDA_ERR_STRING(err); 414a5153dbcSJohannes Doerfert } 415a5153dbcSJohannes Doerfert 416a5153dbcSJohannes Doerfert for (CUstream &Stream : DeviceInfo.Streams[device_id]) { 417a5153dbcSJohannes Doerfert err = cuStreamCreate(&Stream, CU_STREAM_NON_BLOCKING); 418a5153dbcSJohannes Doerfert if (err != CUDA_SUCCESS) { 419a5153dbcSJohannes Doerfert DP("Error when creating CUDA stream\n"); 420a5153dbcSJohannes Doerfert CUDA_ERR_STRING(err); 421a5153dbcSJohannes Doerfert } 422a5153dbcSJohannes Doerfert } 423a5153dbcSJohannes Doerfert 424bb51d398SJonas Hahnfeld // Query attributes to determine number of threads/block and blocks/grid. 425bb51d398SJonas Hahnfeld int maxGridDimX; 426bb51d398SJonas Hahnfeld err = cuDeviceGetAttribute(&maxGridDimX, CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_X, 427bb51d398SJonas Hahnfeld cuDevice); 428c1895235SJonas Hahnfeld if (err != CUDA_SUCCESS) { 429bb51d398SJonas Hahnfeld DP("Error getting max grid dimension, use default\n"); 4303de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id] = RTLDeviceInfoTy::DefaultNumTeams; 431bb51d398SJonas Hahnfeld } else if (maxGridDimX <= RTLDeviceInfoTy::HardTeamLimit) { 432bb51d398SJonas Hahnfeld DeviceInfo.BlocksPerGrid[device_id] = maxGridDimX; 433bb51d398SJonas Hahnfeld DP("Using %d CUDA blocks per grid\n", maxGridDimX); 4343de4cd12SGeorge Rokos } else { 4353de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id] = RTLDeviceInfoTy::HardTeamLimit; 4363de4cd12SGeorge Rokos DP("Max CUDA blocks per grid %d exceeds the hard team limit %d, capping " 437bb51d398SJonas Hahnfeld "at the hard limit\n", 438bb51d398SJonas Hahnfeld maxGridDimX, RTLDeviceInfoTy::HardTeamLimit); 4393de4cd12SGeorge Rokos } 4403de4cd12SGeorge Rokos 441bb51d398SJonas Hahnfeld // We are only exploiting threads along the x axis. 442bb51d398SJonas Hahnfeld int maxBlockDimX; 443bb51d398SJonas Hahnfeld err = cuDeviceGetAttribute(&maxBlockDimX, CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_X, 444bb51d398SJonas Hahnfeld cuDevice); 445bb51d398SJonas Hahnfeld if (err != CUDA_SUCCESS) { 446bb51d398SJonas Hahnfeld DP("Error getting max block dimension, use default\n"); 447bb51d398SJonas Hahnfeld DeviceInfo.ThreadsPerBlock[device_id] = RTLDeviceInfoTy::DefaultNumThreads; 448bb51d398SJonas Hahnfeld } else if (maxBlockDimX <= RTLDeviceInfoTy::HardThreadLimit) { 449bb51d398SJonas Hahnfeld DeviceInfo.ThreadsPerBlock[device_id] = maxBlockDimX; 450bb51d398SJonas Hahnfeld DP("Using %d CUDA threads per block\n", maxBlockDimX); 4513de4cd12SGeorge Rokos } else { 4523de4cd12SGeorge Rokos DeviceInfo.ThreadsPerBlock[device_id] = RTLDeviceInfoTy::HardThreadLimit; 453bb51d398SJonas Hahnfeld DP("Max CUDA threads per block %d exceeds the hard thread limit %d, capping" 454bb51d398SJonas Hahnfeld "at the hard limit\n", 455bb51d398SJonas Hahnfeld maxBlockDimX, RTLDeviceInfoTy::HardThreadLimit); 4563de4cd12SGeorge Rokos } 4573de4cd12SGeorge Rokos 458bb51d398SJonas Hahnfeld int warpSize; 459bb51d398SJonas Hahnfeld err = 460bb51d398SJonas Hahnfeld cuDeviceGetAttribute(&warpSize, CU_DEVICE_ATTRIBUTE_WARP_SIZE, cuDevice); 461bb51d398SJonas Hahnfeld if (err != CUDA_SUCCESS) { 462bb51d398SJonas Hahnfeld DP("Error getting warp size, assume default\n"); 463bb51d398SJonas Hahnfeld DeviceInfo.WarpSize[device_id] = 32; 464bb51d398SJonas Hahnfeld } else { 465bb51d398SJonas Hahnfeld DeviceInfo.WarpSize[device_id] = warpSize; 4663de4cd12SGeorge Rokos } 4673de4cd12SGeorge Rokos 4683de4cd12SGeorge Rokos // Adjust teams to the env variables 4693de4cd12SGeorge Rokos if (DeviceInfo.EnvTeamLimit > 0 && 4703de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id] > DeviceInfo.EnvTeamLimit) { 4713de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id] = DeviceInfo.EnvTeamLimit; 4723de4cd12SGeorge Rokos DP("Capping max CUDA blocks per grid to OMP_TEAM_LIMIT=%d\n", 4733de4cd12SGeorge Rokos DeviceInfo.EnvTeamLimit); 4743de4cd12SGeorge Rokos } 4753de4cd12SGeorge Rokos 4763de4cd12SGeorge Rokos DP("Max number of CUDA blocks %d, threads %d & warp size %d\n", 4773de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id], DeviceInfo.ThreadsPerBlock[device_id], 4783de4cd12SGeorge Rokos DeviceInfo.WarpSize[device_id]); 4793de4cd12SGeorge Rokos 4803de4cd12SGeorge Rokos // Set default number of teams 4813de4cd12SGeorge Rokos if (DeviceInfo.EnvNumTeams > 0) { 4823de4cd12SGeorge Rokos DeviceInfo.NumTeams[device_id] = DeviceInfo.EnvNumTeams; 4833de4cd12SGeorge Rokos DP("Default number of teams set according to environment %d\n", 4843de4cd12SGeorge Rokos DeviceInfo.EnvNumTeams); 4853de4cd12SGeorge Rokos } else { 4863de4cd12SGeorge Rokos DeviceInfo.NumTeams[device_id] = RTLDeviceInfoTy::DefaultNumTeams; 4873de4cd12SGeorge Rokos DP("Default number of teams set according to library's default %d\n", 4883de4cd12SGeorge Rokos RTLDeviceInfoTy::DefaultNumTeams); 4893de4cd12SGeorge Rokos } 4903de4cd12SGeorge Rokos if (DeviceInfo.NumTeams[device_id] > DeviceInfo.BlocksPerGrid[device_id]) { 4913de4cd12SGeorge Rokos DeviceInfo.NumTeams[device_id] = DeviceInfo.BlocksPerGrid[device_id]; 4923de4cd12SGeorge Rokos DP("Default number of teams exceeds device limit, capping at %d\n", 4933de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id]); 4943de4cd12SGeorge Rokos } 4953de4cd12SGeorge Rokos 4963de4cd12SGeorge Rokos // Set default number of threads 4973de4cd12SGeorge Rokos DeviceInfo.NumThreads[device_id] = RTLDeviceInfoTy::DefaultNumThreads; 4983de4cd12SGeorge Rokos DP("Default number of threads set according to library's default %d\n", 4993de4cd12SGeorge Rokos RTLDeviceInfoTy::DefaultNumThreads); 5003de4cd12SGeorge Rokos if (DeviceInfo.NumThreads[device_id] > 5013de4cd12SGeorge Rokos DeviceInfo.ThreadsPerBlock[device_id]) { 5023de4cd12SGeorge Rokos DeviceInfo.NumTeams[device_id] = DeviceInfo.ThreadsPerBlock[device_id]; 5033de4cd12SGeorge Rokos DP("Default number of threads exceeds device limit, capping at %d\n", 5043de4cd12SGeorge Rokos DeviceInfo.ThreadsPerBlock[device_id]); 5053de4cd12SGeorge Rokos } 5063de4cd12SGeorge Rokos 5073de4cd12SGeorge Rokos return OFFLOAD_SUCCESS; 5083de4cd12SGeorge Rokos } 5093de4cd12SGeorge Rokos 5103de4cd12SGeorge Rokos __tgt_target_table *__tgt_rtl_load_binary(int32_t device_id, 5113de4cd12SGeorge Rokos __tgt_device_image *image) { 5123de4cd12SGeorge Rokos 5133de4cd12SGeorge Rokos // Set the context we are using. 5143de4cd12SGeorge Rokos CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]); 5153de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 5163de4cd12SGeorge Rokos DP("Error when setting a CUDA context for device %d\n", device_id); 5173de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 5183de4cd12SGeorge Rokos return NULL; 5193de4cd12SGeorge Rokos } 5203de4cd12SGeorge Rokos 5213de4cd12SGeorge Rokos // Clear the offload table as we are going to create a new one. 5223de4cd12SGeorge Rokos DeviceInfo.clearOffloadEntriesTable(device_id); 5233de4cd12SGeorge Rokos 5243de4cd12SGeorge Rokos // Create the module and extract the function pointers. 5253de4cd12SGeorge Rokos 5263de4cd12SGeorge Rokos CUmodule cumod; 5273de4cd12SGeorge Rokos DP("Load data from image " DPxMOD "\n", DPxPTR(image->ImageStart)); 5283de4cd12SGeorge Rokos err = cuModuleLoadDataEx(&cumod, image->ImageStart, 0, NULL, NULL); 5293de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 5303de4cd12SGeorge Rokos DP("Error when loading CUDA module\n"); 5313de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 5323de4cd12SGeorge Rokos return NULL; 5333de4cd12SGeorge Rokos } 5343de4cd12SGeorge Rokos 5353de4cd12SGeorge Rokos DP("CUDA module successfully loaded!\n"); 5363de4cd12SGeorge Rokos DeviceInfo.Modules.push_back(cumod); 5373de4cd12SGeorge Rokos 5383de4cd12SGeorge Rokos // Find the symbols in the module by name. 5393de4cd12SGeorge Rokos __tgt_offload_entry *HostBegin = image->EntriesBegin; 5403de4cd12SGeorge Rokos __tgt_offload_entry *HostEnd = image->EntriesEnd; 5413de4cd12SGeorge Rokos 5423de4cd12SGeorge Rokos for (__tgt_offload_entry *e = HostBegin; e != HostEnd; ++e) { 5433de4cd12SGeorge Rokos 5443de4cd12SGeorge Rokos if (!e->addr) { 5453de4cd12SGeorge Rokos // We return NULL when something like this happens, the host should have 5463de4cd12SGeorge Rokos // always something in the address to uniquely identify the target region. 5473de4cd12SGeorge Rokos DP("Invalid binary: host entry '<null>' (size = %zd)...\n", e->size); 5483de4cd12SGeorge Rokos 5493de4cd12SGeorge Rokos return NULL; 5503de4cd12SGeorge Rokos } 5513de4cd12SGeorge Rokos 5523de4cd12SGeorge Rokos if (e->size) { 5533de4cd12SGeorge Rokos __tgt_offload_entry entry = *e; 5543de4cd12SGeorge Rokos 5553de4cd12SGeorge Rokos CUdeviceptr cuptr; 5563de4cd12SGeorge Rokos size_t cusize; 5573de4cd12SGeorge Rokos err = cuModuleGetGlobal(&cuptr, &cusize, cumod, e->name); 5583de4cd12SGeorge Rokos 5593de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 5603de4cd12SGeorge Rokos DP("Loading global '%s' (Failed)\n", e->name); 5613de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 5623de4cd12SGeorge Rokos return NULL; 5633de4cd12SGeorge Rokos } 5643de4cd12SGeorge Rokos 5653de4cd12SGeorge Rokos if (cusize != e->size) { 5663de4cd12SGeorge Rokos DP("Loading global '%s' - size mismatch (%zd != %zd)\n", e->name, 5673de4cd12SGeorge Rokos cusize, e->size); 5683de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 5693de4cd12SGeorge Rokos return NULL; 5703de4cd12SGeorge Rokos } 5713de4cd12SGeorge Rokos 5723de4cd12SGeorge Rokos DP("Entry point " DPxMOD " maps to global %s (" DPxMOD ")\n", 5733de4cd12SGeorge Rokos DPxPTR(e - HostBegin), e->name, DPxPTR(cuptr)); 5743de4cd12SGeorge Rokos entry.addr = (void *)cuptr; 5753de4cd12SGeorge Rokos 576aace6d28SGheorghe-Teodor Bercea // Note: In the current implementation declare target variables 577aace6d28SGheorghe-Teodor Bercea // can either be link or to. This means that once unified 578aace6d28SGheorghe-Teodor Bercea // memory is activated via the requires directive, the variable 579aace6d28SGheorghe-Teodor Bercea // can be used directly from the host in both cases. 580aace6d28SGheorghe-Teodor Bercea // TODO: when variables types other than to or link are added, 5814c6a098aSKazuaki Ishizaki // the below condition should be changed to explicitly 582aace6d28SGheorghe-Teodor Bercea // check for to and link variables types: 583aace6d28SGheorghe-Teodor Bercea // (DeviceInfo.RequiresFlags & OMP_REQ_UNIFIED_SHARED_MEMORY && 584aace6d28SGheorghe-Teodor Bercea // (e->flags & OMP_DECLARE_TARGET_LINK || 585aace6d28SGheorghe-Teodor Bercea // e->flags == OMP_DECLARE_TARGET_TO)) 586aace6d28SGheorghe-Teodor Bercea if (DeviceInfo.RequiresFlags & OMP_REQ_UNIFIED_SHARED_MEMORY) { 587aace6d28SGheorghe-Teodor Bercea // If unified memory is present any target link or to variables 588c5fe030cSGheorghe-Teodor Bercea // can access host addresses directly. There is no longer a 589c5fe030cSGheorghe-Teodor Bercea // need for device copies. 590c5fe030cSGheorghe-Teodor Bercea cuMemcpyHtoD(cuptr, e->addr, sizeof(void *)); 591c5fe030cSGheorghe-Teodor Bercea DP("Copy linked variable host address (" DPxMOD ")" 592c5fe030cSGheorghe-Teodor Bercea "to device address (" DPxMOD ")\n", 593c5fe030cSGheorghe-Teodor Bercea DPxPTR(*((void**)e->addr)), DPxPTR(cuptr)); 594c5fe030cSGheorghe-Teodor Bercea } 595c5fe030cSGheorghe-Teodor Bercea 5963de4cd12SGeorge Rokos DeviceInfo.addOffloadEntry(device_id, entry); 5973de4cd12SGeorge Rokos 5983de4cd12SGeorge Rokos continue; 5993de4cd12SGeorge Rokos } 6003de4cd12SGeorge Rokos 6013de4cd12SGeorge Rokos CUfunction fun; 6023de4cd12SGeorge Rokos err = cuModuleGetFunction(&fun, cumod, e->name); 6033de4cd12SGeorge Rokos 6043de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 6053de4cd12SGeorge Rokos DP("Loading '%s' (Failed)\n", e->name); 6063de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 6073de4cd12SGeorge Rokos return NULL; 6083de4cd12SGeorge Rokos } 6093de4cd12SGeorge Rokos 6103de4cd12SGeorge Rokos DP("Entry point " DPxMOD " maps to %s (" DPxMOD ")\n", 6113de4cd12SGeorge Rokos DPxPTR(e - HostBegin), e->name, DPxPTR(fun)); 6123de4cd12SGeorge Rokos 6133de4cd12SGeorge Rokos // default value GENERIC (in case symbol is missing from cubin file) 6143de4cd12SGeorge Rokos int8_t ExecModeVal = ExecutionModeType::GENERIC; 6153de4cd12SGeorge Rokos std::string ExecModeNameStr (e->name); 6163de4cd12SGeorge Rokos ExecModeNameStr += "_exec_mode"; 6173de4cd12SGeorge Rokos const char *ExecModeName = ExecModeNameStr.c_str(); 6183de4cd12SGeorge Rokos 6193de4cd12SGeorge Rokos CUdeviceptr ExecModePtr; 6203de4cd12SGeorge Rokos size_t cusize; 6213de4cd12SGeorge Rokos err = cuModuleGetGlobal(&ExecModePtr, &cusize, cumod, ExecModeName); 6223de4cd12SGeorge Rokos if (err == CUDA_SUCCESS) { 6233de4cd12SGeorge Rokos if ((size_t)cusize != sizeof(int8_t)) { 6243de4cd12SGeorge Rokos DP("Loading global exec_mode '%s' - size mismatch (%zd != %zd)\n", 6253de4cd12SGeorge Rokos ExecModeName, cusize, sizeof(int8_t)); 6263de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 6273de4cd12SGeorge Rokos return NULL; 6283de4cd12SGeorge Rokos } 6293de4cd12SGeorge Rokos 6303de4cd12SGeorge Rokos err = cuMemcpyDtoH(&ExecModeVal, ExecModePtr, cusize); 6313de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 6323de4cd12SGeorge Rokos DP("Error when copying data from device to host. Pointers: " 6333de4cd12SGeorge Rokos "host = " DPxMOD ", device = " DPxMOD ", size = %zd\n", 6343de4cd12SGeorge Rokos DPxPTR(&ExecModeVal), DPxPTR(ExecModePtr), cusize); 6353de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 6363de4cd12SGeorge Rokos return NULL; 6373de4cd12SGeorge Rokos } 6383de4cd12SGeorge Rokos 6393de4cd12SGeorge Rokos if (ExecModeVal < 0 || ExecModeVal > 1) { 6403de4cd12SGeorge Rokos DP("Error wrong exec_mode value specified in cubin file: %d\n", 6413de4cd12SGeorge Rokos ExecModeVal); 6423de4cd12SGeorge Rokos return NULL; 6433de4cd12SGeorge Rokos } 6443de4cd12SGeorge Rokos } else { 6453de4cd12SGeorge Rokos DP("Loading global exec_mode '%s' - symbol missing, using default value " 6463de4cd12SGeorge Rokos "GENERIC (1)\n", ExecModeName); 6473de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 6483de4cd12SGeorge Rokos } 6493de4cd12SGeorge Rokos 6503de4cd12SGeorge Rokos KernelsList.push_back(KernelTy(fun, ExecModeVal)); 6513de4cd12SGeorge Rokos 6523de4cd12SGeorge Rokos __tgt_offload_entry entry = *e; 6533de4cd12SGeorge Rokos entry.addr = (void *)&KernelsList.back(); 6543de4cd12SGeorge Rokos DeviceInfo.addOffloadEntry(device_id, entry); 6553de4cd12SGeorge Rokos } 6563de4cd12SGeorge Rokos 657e1c7a46dSGuansong Zhang // send device environment data to the device 658e1c7a46dSGuansong Zhang { 659e1c7a46dSGuansong Zhang omptarget_device_environmentTy device_env; 660e1c7a46dSGuansong Zhang 661e1c7a46dSGuansong Zhang device_env.debug_level = 0; 662e1c7a46dSGuansong Zhang 663e1c7a46dSGuansong Zhang #ifdef OMPTARGET_DEBUG 664e1c7a46dSGuansong Zhang if (char *envStr = getenv("LIBOMPTARGET_DEVICE_RTL_DEBUG")) { 665e1c7a46dSGuansong Zhang device_env.debug_level = std::stoi(envStr); 666e1c7a46dSGuansong Zhang } 667e1c7a46dSGuansong Zhang #endif 668e1c7a46dSGuansong Zhang 669e1c7a46dSGuansong Zhang const char * device_env_Name="omptarget_device_environment"; 670e1c7a46dSGuansong Zhang CUdeviceptr device_env_Ptr; 671e1c7a46dSGuansong Zhang size_t cusize; 672e1c7a46dSGuansong Zhang 673e1c7a46dSGuansong Zhang err = cuModuleGetGlobal(&device_env_Ptr, &cusize, cumod, device_env_Name); 674e1c7a46dSGuansong Zhang 675e1c7a46dSGuansong Zhang if (err == CUDA_SUCCESS) { 676e1c7a46dSGuansong Zhang if ((size_t)cusize != sizeof(device_env)) { 677e1c7a46dSGuansong Zhang DP("Global device_environment '%s' - size mismatch (%zu != %zu)\n", 678e1c7a46dSGuansong Zhang device_env_Name, cusize, sizeof(int32_t)); 679e1c7a46dSGuansong Zhang CUDA_ERR_STRING(err); 680e1c7a46dSGuansong Zhang return NULL; 681e1c7a46dSGuansong Zhang } 682e1c7a46dSGuansong Zhang 683e1c7a46dSGuansong Zhang err = cuMemcpyHtoD(device_env_Ptr, &device_env, cusize); 684e1c7a46dSGuansong Zhang if (err != CUDA_SUCCESS) { 685e1c7a46dSGuansong Zhang DP("Error when copying data from host to device. Pointers: " 686e1c7a46dSGuansong Zhang "host = " DPxMOD ", device = " DPxMOD ", size = %zu\n", 687e1c7a46dSGuansong Zhang DPxPTR(&device_env), DPxPTR(device_env_Ptr), cusize); 688e1c7a46dSGuansong Zhang CUDA_ERR_STRING(err); 689e1c7a46dSGuansong Zhang return NULL; 690e1c7a46dSGuansong Zhang } 691e1c7a46dSGuansong Zhang 692e1c7a46dSGuansong Zhang DP("Sending global device environment data %zu bytes\n", (size_t)cusize); 693e1c7a46dSGuansong Zhang } else { 694e1c7a46dSGuansong Zhang DP("Finding global device environment '%s' - symbol missing.\n", device_env_Name); 6954c6a098aSKazuaki Ishizaki DP("Continue, considering this is a device RTL which does not accept environment setting.\n"); 696e1c7a46dSGuansong Zhang } 697e1c7a46dSGuansong Zhang } 698e1c7a46dSGuansong Zhang 6993de4cd12SGeorge Rokos return DeviceInfo.getOffloadEntriesTable(device_id); 7003de4cd12SGeorge Rokos } 7013de4cd12SGeorge Rokos 7021546d319SGeorge Rokos void *__tgt_rtl_data_alloc(int32_t device_id, int64_t size, void *hst_ptr) { 7033de4cd12SGeorge Rokos if (size == 0) { 7043de4cd12SGeorge Rokos return NULL; 7053de4cd12SGeorge Rokos } 7063de4cd12SGeorge Rokos 7073de4cd12SGeorge Rokos // Set the context we are using. 7083de4cd12SGeorge Rokos CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]); 7093de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 7103de4cd12SGeorge Rokos DP("Error while trying to set CUDA current context\n"); 7113de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 7123de4cd12SGeorge Rokos return NULL; 7133de4cd12SGeorge Rokos } 7143de4cd12SGeorge Rokos 7153de4cd12SGeorge Rokos CUdeviceptr ptr; 7163de4cd12SGeorge Rokos err = cuMemAlloc(&ptr, size); 7173de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 7183de4cd12SGeorge Rokos DP("Error while trying to allocate %d\n", err); 7193de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 7203de4cd12SGeorge Rokos return NULL; 7213de4cd12SGeorge Rokos } 7223de4cd12SGeorge Rokos 7233de4cd12SGeorge Rokos void *vptr = (void *)ptr; 7243de4cd12SGeorge Rokos return vptr; 7253de4cd12SGeorge Rokos } 7263de4cd12SGeorge Rokos 7273de4cd12SGeorge Rokos int32_t __tgt_rtl_data_submit(int32_t device_id, void *tgt_ptr, void *hst_ptr, 728*03ff643dSShilei Tian int64_t size) { 72932ed2927SShilei Tian __tgt_async_info async_info; 730*03ff643dSShilei Tian int32_t rc = __tgt_rtl_data_submit_async(device_id, tgt_ptr, hst_ptr, size, 731*03ff643dSShilei Tian &async_info); 73232ed2927SShilei Tian if (rc != OFFLOAD_SUCCESS) 7333de4cd12SGeorge Rokos return OFFLOAD_FAIL; 7343de4cd12SGeorge Rokos 73532ed2927SShilei Tian return __tgt_rtl_synchronize(device_id, &async_info); 7363de4cd12SGeorge Rokos } 7373de4cd12SGeorge Rokos 738*03ff643dSShilei Tian int32_t __tgt_rtl_data_submit_async(int32_t device_id, void *tgt_ptr, 739*03ff643dSShilei Tian void *hst_ptr, int64_t size, 74032ed2927SShilei Tian __tgt_async_info *async_info_ptr) { 741*03ff643dSShilei Tian assert(async_info_ptr && "async_info_ptr is nullptr"); 742*03ff643dSShilei Tian return dataSubmit(device_id, tgt_ptr, hst_ptr, size, async_info_ptr); 743*03ff643dSShilei Tian } 74432ed2927SShilei Tian 745*03ff643dSShilei Tian int32_t __tgt_rtl_data_retrieve(int32_t device_id, void *hst_ptr, void *tgt_ptr, 746*03ff643dSShilei Tian int64_t size) { 74732ed2927SShilei Tian __tgt_async_info async_info; 748*03ff643dSShilei Tian int32_t rc = __tgt_rtl_data_retrieve_async(device_id, hst_ptr, tgt_ptr, size, 749*03ff643dSShilei Tian &async_info); 75032ed2927SShilei Tian if (rc != OFFLOAD_SUCCESS) 7513de4cd12SGeorge Rokos return OFFLOAD_FAIL; 7523de4cd12SGeorge Rokos 75332ed2927SShilei Tian return __tgt_rtl_synchronize(device_id, &async_info); 7543de4cd12SGeorge Rokos } 7553de4cd12SGeorge Rokos 756*03ff643dSShilei Tian int32_t __tgt_rtl_data_retrieve_async(int32_t device_id, void *hst_ptr, 757*03ff643dSShilei Tian void *tgt_ptr, int64_t size, 758*03ff643dSShilei Tian __tgt_async_info *async_info_ptr) { 759*03ff643dSShilei Tian assert(async_info_ptr && "async_info_ptr is nullptr"); 760*03ff643dSShilei Tian return dataRetrieve(device_id, hst_ptr, tgt_ptr, size, async_info_ptr); 761*03ff643dSShilei Tian } 762*03ff643dSShilei Tian 7633de4cd12SGeorge Rokos int32_t __tgt_rtl_data_delete(int32_t device_id, void *tgt_ptr) { 7643de4cd12SGeorge Rokos // Set the context we are using. 7653de4cd12SGeorge Rokos CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]); 7663de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 7673de4cd12SGeorge Rokos DP("Error when setting CUDA context\n"); 7683de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 7693de4cd12SGeorge Rokos return OFFLOAD_FAIL; 7703de4cd12SGeorge Rokos } 7713de4cd12SGeorge Rokos 7723de4cd12SGeorge Rokos err = cuMemFree((CUdeviceptr)tgt_ptr); 7733de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 7743de4cd12SGeorge Rokos DP("Error when freeing CUDA memory\n"); 7753de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 7763de4cd12SGeorge Rokos return OFFLOAD_FAIL; 7773de4cd12SGeorge Rokos } 7783de4cd12SGeorge Rokos return OFFLOAD_SUCCESS; 7793de4cd12SGeorge Rokos } 7803de4cd12SGeorge Rokos 7813de4cd12SGeorge Rokos int32_t __tgt_rtl_run_target_team_region(int32_t device_id, void *tgt_entry_ptr, 78232ed2927SShilei Tian void **tgt_args, 78332ed2927SShilei Tian ptrdiff_t *tgt_offsets, 78432ed2927SShilei Tian int32_t arg_num, int32_t team_num, 78532ed2927SShilei Tian int32_t thread_limit, 786*03ff643dSShilei Tian uint64_t loop_tripcount) { 787*03ff643dSShilei Tian __tgt_async_info async_info; 788*03ff643dSShilei Tian int32_t rc = __tgt_rtl_run_target_team_region_async( 789*03ff643dSShilei Tian device_id, tgt_entry_ptr, tgt_args, tgt_offsets, arg_num, team_num, 790*03ff643dSShilei Tian thread_limit, loop_tripcount, &async_info); 791*03ff643dSShilei Tian if (rc != OFFLOAD_SUCCESS) 792*03ff643dSShilei Tian return OFFLOAD_FAIL; 793*03ff643dSShilei Tian 794*03ff643dSShilei Tian return __tgt_rtl_synchronize(device_id, &async_info); 795*03ff643dSShilei Tian } 796*03ff643dSShilei Tian 797*03ff643dSShilei Tian int32_t __tgt_rtl_run_target_team_region_async( 798*03ff643dSShilei Tian int32_t device_id, void *tgt_entry_ptr, void **tgt_args, 799*03ff643dSShilei Tian ptrdiff_t *tgt_offsets, int32_t arg_num, int32_t team_num, 800*03ff643dSShilei Tian int32_t thread_limit, uint64_t loop_tripcount, 80132ed2927SShilei Tian __tgt_async_info *async_info) { 8023de4cd12SGeorge Rokos // Set the context we are using. 8033de4cd12SGeorge Rokos CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]); 8043de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 8053de4cd12SGeorge Rokos DP("Error when setting CUDA context\n"); 8063de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 8073de4cd12SGeorge Rokos return OFFLOAD_FAIL; 8083de4cd12SGeorge Rokos } 8093de4cd12SGeorge Rokos 8103de4cd12SGeorge Rokos // All args are references. 8113de4cd12SGeorge Rokos std::vector<void *> args(arg_num); 8121546d319SGeorge Rokos std::vector<void *> ptrs(arg_num); 8133de4cd12SGeorge Rokos 8141546d319SGeorge Rokos for (int32_t i = 0; i < arg_num; ++i) { 8151546d319SGeorge Rokos ptrs[i] = (void *)((intptr_t)tgt_args[i] + tgt_offsets[i]); 8161546d319SGeorge Rokos args[i] = &ptrs[i]; 8171546d319SGeorge Rokos } 8183de4cd12SGeorge Rokos 8193de4cd12SGeorge Rokos KernelTy *KernelInfo = (KernelTy *)tgt_entry_ptr; 8203de4cd12SGeorge Rokos 8213de4cd12SGeorge Rokos int cudaThreadsPerBlock; 8223de4cd12SGeorge Rokos 8233de4cd12SGeorge Rokos if (thread_limit > 0) { 8243de4cd12SGeorge Rokos cudaThreadsPerBlock = thread_limit; 8253de4cd12SGeorge Rokos DP("Setting CUDA threads per block to requested %d\n", thread_limit); 8263de4cd12SGeorge Rokos // Add master warp if necessary 8273de4cd12SGeorge Rokos if (KernelInfo->ExecutionMode == GENERIC) { 8283de4cd12SGeorge Rokos cudaThreadsPerBlock += DeviceInfo.WarpSize[device_id]; 8293de4cd12SGeorge Rokos DP("Adding master warp: +%d threads\n", DeviceInfo.WarpSize[device_id]); 8303de4cd12SGeorge Rokos } 831c13df8e5SGeorge Rokos } else { 832c13df8e5SGeorge Rokos cudaThreadsPerBlock = DeviceInfo.NumThreads[device_id]; 833c13df8e5SGeorge Rokos DP("Setting CUDA threads per block to default %d\n", 834c13df8e5SGeorge Rokos DeviceInfo.NumThreads[device_id]); 835c13df8e5SGeorge Rokos } 8363de4cd12SGeorge Rokos 8373de4cd12SGeorge Rokos if (cudaThreadsPerBlock > DeviceInfo.ThreadsPerBlock[device_id]) { 8383de4cd12SGeorge Rokos cudaThreadsPerBlock = DeviceInfo.ThreadsPerBlock[device_id]; 8393de4cd12SGeorge Rokos DP("Threads per block capped at device limit %d\n", 8403de4cd12SGeorge Rokos DeviceInfo.ThreadsPerBlock[device_id]); 8413de4cd12SGeorge Rokos } 8423de4cd12SGeorge Rokos 8433de4cd12SGeorge Rokos int kernel_limit; 8443de4cd12SGeorge Rokos err = cuFuncGetAttribute(&kernel_limit, 8453de4cd12SGeorge Rokos CU_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK, KernelInfo->Func); 8463de4cd12SGeorge Rokos if (err == CUDA_SUCCESS) { 8473de4cd12SGeorge Rokos if (kernel_limit < cudaThreadsPerBlock) { 8483de4cd12SGeorge Rokos cudaThreadsPerBlock = kernel_limit; 8493de4cd12SGeorge Rokos DP("Threads per block capped at kernel limit %d\n", kernel_limit); 8503de4cd12SGeorge Rokos } 8513de4cd12SGeorge Rokos } 8523de4cd12SGeorge Rokos 8533de4cd12SGeorge Rokos int cudaBlocksPerGrid; 8543de4cd12SGeorge Rokos if (team_num <= 0) { 8553de4cd12SGeorge Rokos if (loop_tripcount > 0 && DeviceInfo.EnvNumTeams < 0) { 856c13df8e5SGeorge Rokos if (KernelInfo->ExecutionMode == SPMD) { 857c13df8e5SGeorge Rokos // We have a combined construct, i.e. `target teams distribute parallel 858c13df8e5SGeorge Rokos // for [simd]`. We launch so many teams so that each thread will 859c13df8e5SGeorge Rokos // execute one iteration of the loop. 8603de4cd12SGeorge Rokos // round up to the nearest integer 8613de4cd12SGeorge Rokos cudaBlocksPerGrid = ((loop_tripcount - 1) / cudaThreadsPerBlock) + 1; 862c13df8e5SGeorge Rokos } else { 863c13df8e5SGeorge Rokos // If we reach this point, then we have a non-combined construct, i.e. 864c13df8e5SGeorge Rokos // `teams distribute` with a nested `parallel for` and each team is 865c13df8e5SGeorge Rokos // assigned one iteration of the `distribute` loop. E.g.: 866c13df8e5SGeorge Rokos // 867c13df8e5SGeorge Rokos // #pragma omp target teams distribute 868c13df8e5SGeorge Rokos // for(...loop_tripcount...) { 869c13df8e5SGeorge Rokos // #pragma omp parallel for 870c13df8e5SGeorge Rokos // for(...) {} 871c13df8e5SGeorge Rokos // } 872c13df8e5SGeorge Rokos // 873c13df8e5SGeorge Rokos // Threads within a team will execute the iterations of the `parallel` 874c13df8e5SGeorge Rokos // loop. 875c13df8e5SGeorge Rokos cudaBlocksPerGrid = loop_tripcount; 876c13df8e5SGeorge Rokos } 8773de4cd12SGeorge Rokos DP("Using %d teams due to loop trip count %" PRIu64 " and number of " 8783de4cd12SGeorge Rokos "threads per block %d\n", cudaBlocksPerGrid, loop_tripcount, 8793de4cd12SGeorge Rokos cudaThreadsPerBlock); 8803de4cd12SGeorge Rokos } else { 8813de4cd12SGeorge Rokos cudaBlocksPerGrid = DeviceInfo.NumTeams[device_id]; 8823de4cd12SGeorge Rokos DP("Using default number of teams %d\n", DeviceInfo.NumTeams[device_id]); 8833de4cd12SGeorge Rokos } 8843de4cd12SGeorge Rokos } else if (team_num > DeviceInfo.BlocksPerGrid[device_id]) { 8853de4cd12SGeorge Rokos cudaBlocksPerGrid = DeviceInfo.BlocksPerGrid[device_id]; 8863de4cd12SGeorge Rokos DP("Capping number of teams to team limit %d\n", 8873de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id]); 8883de4cd12SGeorge Rokos } else { 8893de4cd12SGeorge Rokos cudaBlocksPerGrid = team_num; 8903de4cd12SGeorge Rokos DP("Using requested number of teams %d\n", team_num); 8913de4cd12SGeorge Rokos } 8923de4cd12SGeorge Rokos 8933de4cd12SGeorge Rokos // Run on the device. 8943de4cd12SGeorge Rokos DP("Launch kernel with %d blocks and %d threads\n", cudaBlocksPerGrid, 8953de4cd12SGeorge Rokos cudaThreadsPerBlock); 8963de4cd12SGeorge Rokos 89732ed2927SShilei Tian CUstream Stream = selectStream(device_id, async_info); 8983de4cd12SGeorge Rokos err = cuLaunchKernel(KernelInfo->Func, cudaBlocksPerGrid, 1, 1, 899a5153dbcSJohannes Doerfert cudaThreadsPerBlock, 1, 1, 0 /*bytes of shared memory*/, 900a5153dbcSJohannes Doerfert Stream, &args[0], 0); 9013de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 9023de4cd12SGeorge Rokos DP("Device kernel launch failed!\n"); 9033de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 9043de4cd12SGeorge Rokos return OFFLOAD_FAIL; 9053de4cd12SGeorge Rokos } 9063de4cd12SGeorge Rokos 9073de4cd12SGeorge Rokos DP("Launch of entry point at " DPxMOD " successful!\n", 9083de4cd12SGeorge Rokos DPxPTR(tgt_entry_ptr)); 9093de4cd12SGeorge Rokos 9103de4cd12SGeorge Rokos return OFFLOAD_SUCCESS; 9113de4cd12SGeorge Rokos } 9123de4cd12SGeorge Rokos 9133de4cd12SGeorge Rokos int32_t __tgt_rtl_run_target_region(int32_t device_id, void *tgt_entry_ptr, 91432ed2927SShilei Tian void **tgt_args, ptrdiff_t *tgt_offsets, 915*03ff643dSShilei Tian int32_t arg_num) { 916*03ff643dSShilei Tian __tgt_async_info async_info; 917*03ff643dSShilei Tian int32_t rc = __tgt_rtl_run_target_region_async( 918*03ff643dSShilei Tian device_id, tgt_entry_ptr, tgt_args, tgt_offsets, arg_num, &async_info); 919*03ff643dSShilei Tian if (rc != OFFLOAD_SUCCESS) 920*03ff643dSShilei Tian return OFFLOAD_FAIL; 921*03ff643dSShilei Tian 922*03ff643dSShilei Tian return __tgt_rtl_synchronize(device_id, &async_info); 923*03ff643dSShilei Tian } 924*03ff643dSShilei Tian 925*03ff643dSShilei Tian int32_t __tgt_rtl_run_target_region_async(int32_t device_id, 926*03ff643dSShilei Tian void *tgt_entry_ptr, void **tgt_args, 927*03ff643dSShilei Tian ptrdiff_t *tgt_offsets, 92832ed2927SShilei Tian int32_t arg_num, 92932ed2927SShilei Tian __tgt_async_info *async_info) { 9303de4cd12SGeorge Rokos // use one team and the default number of threads. 9313de4cd12SGeorge Rokos const int32_t team_num = 1; 9323de4cd12SGeorge Rokos const int32_t thread_limit = 0; 933*03ff643dSShilei Tian return __tgt_rtl_run_target_team_region_async( 934*03ff643dSShilei Tian device_id, tgt_entry_ptr, tgt_args, tgt_offsets, arg_num, team_num, 93532ed2927SShilei Tian thread_limit, 0, async_info); 93632ed2927SShilei Tian } 93732ed2927SShilei Tian 93832ed2927SShilei Tian int32_t __tgt_rtl_synchronize(int32_t device_id, __tgt_async_info *async_info) { 93932ed2927SShilei Tian assert(async_info && "async_info is nullptr"); 94032ed2927SShilei Tian assert(async_info->Queue && "async_info->Queue is nullptr"); 94132ed2927SShilei Tian 94232ed2927SShilei Tian CUstream Stream = reinterpret_cast<CUstream>(async_info->Queue); 94332ed2927SShilei Tian CUresult Err = cuStreamSynchronize(Stream); 94432ed2927SShilei Tian if (Err != CUDA_SUCCESS) { 94532ed2927SShilei Tian DP("Error when synchronizing stream. stream = " DPxMOD 94632ed2927SShilei Tian ", async info ptr = " DPxMOD "\n", 94732ed2927SShilei Tian DPxPTR(Stream), DPxPTR(async_info)); 94832ed2927SShilei Tian CUDA_ERR_STRING(Err); 94932ed2927SShilei Tian return OFFLOAD_FAIL; 95032ed2927SShilei Tian } 95132ed2927SShilei Tian return OFFLOAD_SUCCESS; 9523de4cd12SGeorge Rokos } 9533de4cd12SGeorge Rokos 9543de4cd12SGeorge Rokos #ifdef __cplusplus 9553de4cd12SGeorge Rokos } 9563de4cd12SGeorge Rokos #endif 957