1*3de4cd12SGeorge Rokos //===----RTLs/cuda/src/rtl.cpp - Target RTLs Implementation ------- C++ -*-===// 2*3de4cd12SGeorge Rokos // 3*3de4cd12SGeorge Rokos // The LLVM Compiler Infrastructure 4*3de4cd12SGeorge Rokos // 5*3de4cd12SGeorge Rokos // This file is dual licensed under the MIT and the University of Illinois Open 6*3de4cd12SGeorge Rokos // Source Licenses. See LICENSE.txt for details. 7*3de4cd12SGeorge Rokos // 8*3de4cd12SGeorge Rokos //===----------------------------------------------------------------------===// 9*3de4cd12SGeorge Rokos // 10*3de4cd12SGeorge Rokos // RTL for CUDA machine 11*3de4cd12SGeorge Rokos // 12*3de4cd12SGeorge Rokos //===----------------------------------------------------------------------===// 13*3de4cd12SGeorge Rokos 14*3de4cd12SGeorge Rokos #include <cassert> 15*3de4cd12SGeorge Rokos #include <cstddef> 16*3de4cd12SGeorge Rokos #include <cuda.h> 17*3de4cd12SGeorge Rokos #include <cuda_runtime_api.h> 18*3de4cd12SGeorge Rokos #include <list> 19*3de4cd12SGeorge Rokos #include <string> 20*3de4cd12SGeorge Rokos #include <vector> 21*3de4cd12SGeorge Rokos 22*3de4cd12SGeorge Rokos #include "omptarget.h" 23*3de4cd12SGeorge Rokos 24*3de4cd12SGeorge Rokos #ifndef TARGET_NAME 25*3de4cd12SGeorge Rokos #define TARGET_NAME CUDA 26*3de4cd12SGeorge Rokos #endif 27*3de4cd12SGeorge Rokos 28*3de4cd12SGeorge Rokos #define GETNAME2(name) #name 29*3de4cd12SGeorge Rokos #define GETNAME(name) GETNAME2(name) 30*3de4cd12SGeorge Rokos #define DP(...) DEBUGP("Target " GETNAME(TARGET_NAME) " RTL", __VA_ARGS__) 31*3de4cd12SGeorge Rokos 32*3de4cd12SGeorge Rokos #include "../../common/elf_common.c" 33*3de4cd12SGeorge Rokos 34*3de4cd12SGeorge Rokos // Utility for retrieving and printing CUDA error string. 35*3de4cd12SGeorge Rokos #ifdef CUDA_ERROR_REPORT 36*3de4cd12SGeorge Rokos #define CUDA_ERR_STRING(err) \ 37*3de4cd12SGeorge Rokos do { \ 38*3de4cd12SGeorge Rokos const char *errStr; \ 39*3de4cd12SGeorge Rokos cuGetErrorString(err, &errStr); \ 40*3de4cd12SGeorge Rokos DP("CUDA error is: %s\n", errStr); \ 41*3de4cd12SGeorge Rokos } while (0) 42*3de4cd12SGeorge Rokos #else 43*3de4cd12SGeorge Rokos #define CUDA_ERR_STRING(err) \ 44*3de4cd12SGeorge Rokos {} 45*3de4cd12SGeorge Rokos #endif 46*3de4cd12SGeorge Rokos 47*3de4cd12SGeorge Rokos /// Keep entries table per device. 48*3de4cd12SGeorge Rokos struct FuncOrGblEntryTy { 49*3de4cd12SGeorge Rokos __tgt_target_table Table; 50*3de4cd12SGeorge Rokos std::vector<__tgt_offload_entry> Entries; 51*3de4cd12SGeorge Rokos }; 52*3de4cd12SGeorge Rokos 53*3de4cd12SGeorge Rokos enum ExecutionModeType { 54*3de4cd12SGeorge Rokos SPMD, 55*3de4cd12SGeorge Rokos GENERIC, 56*3de4cd12SGeorge Rokos NONE 57*3de4cd12SGeorge Rokos }; 58*3de4cd12SGeorge Rokos 59*3de4cd12SGeorge Rokos /// Use a single entity to encode a kernel and a set of flags 60*3de4cd12SGeorge Rokos struct KernelTy { 61*3de4cd12SGeorge Rokos CUfunction Func; 62*3de4cd12SGeorge Rokos 63*3de4cd12SGeorge Rokos // execution mode of kernel 64*3de4cd12SGeorge Rokos // 0 - SPMD mode (without master warp) 65*3de4cd12SGeorge Rokos // 1 - Generic mode (with master warp) 66*3de4cd12SGeorge Rokos int8_t ExecutionMode; 67*3de4cd12SGeorge Rokos 68*3de4cd12SGeorge Rokos KernelTy(CUfunction _Func, int8_t _ExecutionMode) 69*3de4cd12SGeorge Rokos : Func(_Func), ExecutionMode(_ExecutionMode) {} 70*3de4cd12SGeorge Rokos }; 71*3de4cd12SGeorge Rokos 72*3de4cd12SGeorge Rokos /// List that contains all the kernels. 73*3de4cd12SGeorge Rokos /// FIXME: we may need this to be per device and per library. 74*3de4cd12SGeorge Rokos std::list<KernelTy> KernelsList; 75*3de4cd12SGeorge Rokos 76*3de4cd12SGeorge Rokos /// Class containing all the device information. 77*3de4cd12SGeorge Rokos class RTLDeviceInfoTy { 78*3de4cd12SGeorge Rokos std::vector<FuncOrGblEntryTy> FuncGblEntries; 79*3de4cd12SGeorge Rokos 80*3de4cd12SGeorge Rokos public: 81*3de4cd12SGeorge Rokos int NumberOfDevices; 82*3de4cd12SGeorge Rokos std::vector<CUmodule> Modules; 83*3de4cd12SGeorge Rokos std::vector<CUcontext> Contexts; 84*3de4cd12SGeorge Rokos 85*3de4cd12SGeorge Rokos // Device properties 86*3de4cd12SGeorge Rokos std::vector<int> ThreadsPerBlock; 87*3de4cd12SGeorge Rokos std::vector<int> BlocksPerGrid; 88*3de4cd12SGeorge Rokos std::vector<int> WarpSize; 89*3de4cd12SGeorge Rokos 90*3de4cd12SGeorge Rokos // OpenMP properties 91*3de4cd12SGeorge Rokos std::vector<int> NumTeams; 92*3de4cd12SGeorge Rokos std::vector<int> NumThreads; 93*3de4cd12SGeorge Rokos 94*3de4cd12SGeorge Rokos // OpenMP Environment properties 95*3de4cd12SGeorge Rokos int EnvNumTeams; 96*3de4cd12SGeorge Rokos int EnvTeamLimit; 97*3de4cd12SGeorge Rokos 98*3de4cd12SGeorge Rokos //static int EnvNumThreads; 99*3de4cd12SGeorge Rokos static const int HardTeamLimit = 1<<16; // 64k 100*3de4cd12SGeorge Rokos static const int HardThreadLimit = 1024; 101*3de4cd12SGeorge Rokos static const int DefaultNumTeams = 128; 102*3de4cd12SGeorge Rokos static const int DefaultNumThreads = 1024; 103*3de4cd12SGeorge Rokos 104*3de4cd12SGeorge Rokos // Record entry point associated with device 105*3de4cd12SGeorge Rokos void addOffloadEntry(int32_t device_id, __tgt_offload_entry entry) { 106*3de4cd12SGeorge Rokos assert(device_id < (int32_t)FuncGblEntries.size() && 107*3de4cd12SGeorge Rokos "Unexpected device id!"); 108*3de4cd12SGeorge Rokos FuncOrGblEntryTy &E = FuncGblEntries[device_id]; 109*3de4cd12SGeorge Rokos 110*3de4cd12SGeorge Rokos E.Entries.push_back(entry); 111*3de4cd12SGeorge Rokos } 112*3de4cd12SGeorge Rokos 113*3de4cd12SGeorge Rokos // Return true if the entry is associated with device 114*3de4cd12SGeorge Rokos bool findOffloadEntry(int32_t device_id, void *addr) { 115*3de4cd12SGeorge Rokos assert(device_id < (int32_t)FuncGblEntries.size() && 116*3de4cd12SGeorge Rokos "Unexpected device id!"); 117*3de4cd12SGeorge Rokos FuncOrGblEntryTy &E = FuncGblEntries[device_id]; 118*3de4cd12SGeorge Rokos 119*3de4cd12SGeorge Rokos for (auto &it : E.Entries) { 120*3de4cd12SGeorge Rokos if (it.addr == addr) 121*3de4cd12SGeorge Rokos return true; 122*3de4cd12SGeorge Rokos } 123*3de4cd12SGeorge Rokos 124*3de4cd12SGeorge Rokos return false; 125*3de4cd12SGeorge Rokos } 126*3de4cd12SGeorge Rokos 127*3de4cd12SGeorge Rokos // Return the pointer to the target entries table 128*3de4cd12SGeorge Rokos __tgt_target_table *getOffloadEntriesTable(int32_t device_id) { 129*3de4cd12SGeorge Rokos assert(device_id < (int32_t)FuncGblEntries.size() && 130*3de4cd12SGeorge Rokos "Unexpected device id!"); 131*3de4cd12SGeorge Rokos FuncOrGblEntryTy &E = FuncGblEntries[device_id]; 132*3de4cd12SGeorge Rokos 133*3de4cd12SGeorge Rokos int32_t size = E.Entries.size(); 134*3de4cd12SGeorge Rokos 135*3de4cd12SGeorge Rokos // Table is empty 136*3de4cd12SGeorge Rokos if (!size) 137*3de4cd12SGeorge Rokos return 0; 138*3de4cd12SGeorge Rokos 139*3de4cd12SGeorge Rokos __tgt_offload_entry *begin = &E.Entries[0]; 140*3de4cd12SGeorge Rokos __tgt_offload_entry *end = &E.Entries[size - 1]; 141*3de4cd12SGeorge Rokos 142*3de4cd12SGeorge Rokos // Update table info according to the entries and return the pointer 143*3de4cd12SGeorge Rokos E.Table.EntriesBegin = begin; 144*3de4cd12SGeorge Rokos E.Table.EntriesEnd = ++end; 145*3de4cd12SGeorge Rokos 146*3de4cd12SGeorge Rokos return &E.Table; 147*3de4cd12SGeorge Rokos } 148*3de4cd12SGeorge Rokos 149*3de4cd12SGeorge Rokos // Clear entries table for a device 150*3de4cd12SGeorge Rokos void clearOffloadEntriesTable(int32_t device_id) { 151*3de4cd12SGeorge Rokos assert(device_id < (int32_t)FuncGblEntries.size() && 152*3de4cd12SGeorge Rokos "Unexpected device id!"); 153*3de4cd12SGeorge Rokos FuncOrGblEntryTy &E = FuncGblEntries[device_id]; 154*3de4cd12SGeorge Rokos E.Entries.clear(); 155*3de4cd12SGeorge Rokos E.Table.EntriesBegin = E.Table.EntriesEnd = 0; 156*3de4cd12SGeorge Rokos } 157*3de4cd12SGeorge Rokos 158*3de4cd12SGeorge Rokos RTLDeviceInfoTy() { 159*3de4cd12SGeorge Rokos DP("Start initializing CUDA\n"); 160*3de4cd12SGeorge Rokos 161*3de4cd12SGeorge Rokos CUresult err = cuInit(0); 162*3de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 163*3de4cd12SGeorge Rokos DP("Error when initializing CUDA\n"); 164*3de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 165*3de4cd12SGeorge Rokos return; 166*3de4cd12SGeorge Rokos } 167*3de4cd12SGeorge Rokos 168*3de4cd12SGeorge Rokos NumberOfDevices = 0; 169*3de4cd12SGeorge Rokos 170*3de4cd12SGeorge Rokos err = cuDeviceGetCount(&NumberOfDevices); 171*3de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 172*3de4cd12SGeorge Rokos DP("Error when getting CUDA device count\n"); 173*3de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 174*3de4cd12SGeorge Rokos return; 175*3de4cd12SGeorge Rokos } 176*3de4cd12SGeorge Rokos 177*3de4cd12SGeorge Rokos if (NumberOfDevices == 0) { 178*3de4cd12SGeorge Rokos DP("There are no devices supporting CUDA.\n"); 179*3de4cd12SGeorge Rokos return; 180*3de4cd12SGeorge Rokos } 181*3de4cd12SGeorge Rokos 182*3de4cd12SGeorge Rokos FuncGblEntries.resize(NumberOfDevices); 183*3de4cd12SGeorge Rokos Contexts.resize(NumberOfDevices); 184*3de4cd12SGeorge Rokos ThreadsPerBlock.resize(NumberOfDevices); 185*3de4cd12SGeorge Rokos BlocksPerGrid.resize(NumberOfDevices); 186*3de4cd12SGeorge Rokos WarpSize.resize(NumberOfDevices); 187*3de4cd12SGeorge Rokos NumTeams.resize(NumberOfDevices); 188*3de4cd12SGeorge Rokos NumThreads.resize(NumberOfDevices); 189*3de4cd12SGeorge Rokos 190*3de4cd12SGeorge Rokos // Get environment variables regarding teams 191*3de4cd12SGeorge Rokos char *envStr = getenv("OMP_TEAM_LIMIT"); 192*3de4cd12SGeorge Rokos if (envStr) { 193*3de4cd12SGeorge Rokos // OMP_TEAM_LIMIT has been set 194*3de4cd12SGeorge Rokos EnvTeamLimit = std::stoi(envStr); 195*3de4cd12SGeorge Rokos DP("Parsed OMP_TEAM_LIMIT=%d\n", EnvTeamLimit); 196*3de4cd12SGeorge Rokos } else { 197*3de4cd12SGeorge Rokos EnvTeamLimit = -1; 198*3de4cd12SGeorge Rokos } 199*3de4cd12SGeorge Rokos envStr = getenv("OMP_NUM_TEAMS"); 200*3de4cd12SGeorge Rokos if (envStr) { 201*3de4cd12SGeorge Rokos // OMP_NUM_TEAMS has been set 202*3de4cd12SGeorge Rokos EnvNumTeams = std::stoi(envStr); 203*3de4cd12SGeorge Rokos DP("Parsed OMP_NUM_TEAMS=%d\n", EnvNumTeams); 204*3de4cd12SGeorge Rokos } else { 205*3de4cd12SGeorge Rokos EnvNumTeams = -1; 206*3de4cd12SGeorge Rokos } 207*3de4cd12SGeorge Rokos } 208*3de4cd12SGeorge Rokos 209*3de4cd12SGeorge Rokos ~RTLDeviceInfoTy() { 210*3de4cd12SGeorge Rokos // Close modules 211*3de4cd12SGeorge Rokos for (auto &module : Modules) 212*3de4cd12SGeorge Rokos if (module) { 213*3de4cd12SGeorge Rokos CUresult err = cuModuleUnload(module); 214*3de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 215*3de4cd12SGeorge Rokos DP("Error when unloading CUDA module\n"); 216*3de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 217*3de4cd12SGeorge Rokos } 218*3de4cd12SGeorge Rokos } 219*3de4cd12SGeorge Rokos 220*3de4cd12SGeorge Rokos // Destroy contexts 221*3de4cd12SGeorge Rokos for (auto &ctx : Contexts) 222*3de4cd12SGeorge Rokos if (ctx) { 223*3de4cd12SGeorge Rokos CUresult err = cuCtxDestroy(ctx); 224*3de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 225*3de4cd12SGeorge Rokos DP("Error when destroying CUDA context\n"); 226*3de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 227*3de4cd12SGeorge Rokos } 228*3de4cd12SGeorge Rokos } 229*3de4cd12SGeorge Rokos } 230*3de4cd12SGeorge Rokos }; 231*3de4cd12SGeorge Rokos 232*3de4cd12SGeorge Rokos static RTLDeviceInfoTy DeviceInfo; 233*3de4cd12SGeorge Rokos 234*3de4cd12SGeorge Rokos #ifdef __cplusplus 235*3de4cd12SGeorge Rokos extern "C" { 236*3de4cd12SGeorge Rokos #endif 237*3de4cd12SGeorge Rokos 238*3de4cd12SGeorge Rokos int32_t __tgt_rtl_is_valid_binary(__tgt_device_image *image) { 239*3de4cd12SGeorge Rokos return elf_check_machine(image, 190); // EM_CUDA = 190. 240*3de4cd12SGeorge Rokos } 241*3de4cd12SGeorge Rokos 242*3de4cd12SGeorge Rokos int32_t __tgt_rtl_number_of_devices() { return DeviceInfo.NumberOfDevices; } 243*3de4cd12SGeorge Rokos 244*3de4cd12SGeorge Rokos int32_t __tgt_rtl_init_device(int32_t device_id) { 245*3de4cd12SGeorge Rokos 246*3de4cd12SGeorge Rokos CUdevice cuDevice; 247*3de4cd12SGeorge Rokos DP("Getting device %d\n", device_id); 248*3de4cd12SGeorge Rokos CUresult err = cuDeviceGet(&cuDevice, device_id); 249*3de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 250*3de4cd12SGeorge Rokos DP("Error when getting CUDA device with id = %d\n", device_id); 251*3de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 252*3de4cd12SGeorge Rokos return OFFLOAD_FAIL; 253*3de4cd12SGeorge Rokos } 254*3de4cd12SGeorge Rokos 255*3de4cd12SGeorge Rokos // Create the context and save it to use whenever this device is selected. 256*3de4cd12SGeorge Rokos err = cuCtxCreate(&DeviceInfo.Contexts[device_id], CU_CTX_SCHED_BLOCKING_SYNC, 257*3de4cd12SGeorge Rokos cuDevice); 258*3de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 259*3de4cd12SGeorge Rokos DP("Error when creating a CUDA context\n"); 260*3de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 261*3de4cd12SGeorge Rokos return OFFLOAD_FAIL; 262*3de4cd12SGeorge Rokos } 263*3de4cd12SGeorge Rokos 264*3de4cd12SGeorge Rokos // scan properties to determine number of threads/block and blocks/grid. 265*3de4cd12SGeorge Rokos struct cudaDeviceProp Properties; 266*3de4cd12SGeorge Rokos cudaError_t error = cudaGetDeviceProperties(&Properties, device_id); 267*3de4cd12SGeorge Rokos if (error != cudaSuccess) { 268*3de4cd12SGeorge Rokos DP("Error getting device Properties, use defaults\n"); 269*3de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id] = RTLDeviceInfoTy::DefaultNumTeams; 270*3de4cd12SGeorge Rokos DeviceInfo.ThreadsPerBlock[device_id] = RTLDeviceInfoTy::DefaultNumThreads; 271*3de4cd12SGeorge Rokos DeviceInfo.WarpSize[device_id] = 32; 272*3de4cd12SGeorge Rokos } else { 273*3de4cd12SGeorge Rokos // Get blocks per grid 274*3de4cd12SGeorge Rokos if (Properties.maxGridSize[0] <= RTLDeviceInfoTy::HardTeamLimit) { 275*3de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id] = Properties.maxGridSize[0]; 276*3de4cd12SGeorge Rokos DP("Using %d CUDA blocks per grid\n", Properties.maxGridSize[0]); 277*3de4cd12SGeorge Rokos } else { 278*3de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id] = RTLDeviceInfoTy::HardTeamLimit; 279*3de4cd12SGeorge Rokos DP("Max CUDA blocks per grid %d exceeds the hard team limit %d, capping " 280*3de4cd12SGeorge Rokos "at the hard limit\n", Properties.maxGridSize[0], 281*3de4cd12SGeorge Rokos RTLDeviceInfoTy::HardTeamLimit); 282*3de4cd12SGeorge Rokos } 283*3de4cd12SGeorge Rokos 284*3de4cd12SGeorge Rokos // Get threads per block, exploit threads only along x axis 285*3de4cd12SGeorge Rokos if (Properties.maxThreadsDim[0] <= RTLDeviceInfoTy::HardThreadLimit) { 286*3de4cd12SGeorge Rokos DeviceInfo.ThreadsPerBlock[device_id] = Properties.maxThreadsDim[0]; 287*3de4cd12SGeorge Rokos DP("Using %d CUDA threads per block\n", Properties.maxThreadsDim[0]); 288*3de4cd12SGeorge Rokos if (Properties.maxThreadsDim[0] < Properties.maxThreadsPerBlock) { 289*3de4cd12SGeorge Rokos DP("(fewer than max per block along all xyz dims %d)\n", 290*3de4cd12SGeorge Rokos Properties.maxThreadsPerBlock); 291*3de4cd12SGeorge Rokos } 292*3de4cd12SGeorge Rokos } else { 293*3de4cd12SGeorge Rokos DeviceInfo.ThreadsPerBlock[device_id] = RTLDeviceInfoTy::HardThreadLimit; 294*3de4cd12SGeorge Rokos DP("Max CUDA threads per block %d exceeds the hard thread limit %d, " 295*3de4cd12SGeorge Rokos "capping at the hard limit\n", Properties.maxThreadsDim[0], 296*3de4cd12SGeorge Rokos RTLDeviceInfoTy::HardThreadLimit); 297*3de4cd12SGeorge Rokos } 298*3de4cd12SGeorge Rokos 299*3de4cd12SGeorge Rokos // Get warp size 300*3de4cd12SGeorge Rokos DeviceInfo.WarpSize[device_id] = Properties.warpSize; 301*3de4cd12SGeorge Rokos } 302*3de4cd12SGeorge Rokos 303*3de4cd12SGeorge Rokos // Adjust teams to the env variables 304*3de4cd12SGeorge Rokos if (DeviceInfo.EnvTeamLimit > 0 && 305*3de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id] > DeviceInfo.EnvTeamLimit) { 306*3de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id] = DeviceInfo.EnvTeamLimit; 307*3de4cd12SGeorge Rokos DP("Capping max CUDA blocks per grid to OMP_TEAM_LIMIT=%d\n", 308*3de4cd12SGeorge Rokos DeviceInfo.EnvTeamLimit); 309*3de4cd12SGeorge Rokos } 310*3de4cd12SGeorge Rokos 311*3de4cd12SGeorge Rokos DP("Max number of CUDA blocks %d, threads %d & warp size %d\n", 312*3de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id], DeviceInfo.ThreadsPerBlock[device_id], 313*3de4cd12SGeorge Rokos DeviceInfo.WarpSize[device_id]); 314*3de4cd12SGeorge Rokos 315*3de4cd12SGeorge Rokos // Set default number of teams 316*3de4cd12SGeorge Rokos if (DeviceInfo.EnvNumTeams > 0) { 317*3de4cd12SGeorge Rokos DeviceInfo.NumTeams[device_id] = DeviceInfo.EnvNumTeams; 318*3de4cd12SGeorge Rokos DP("Default number of teams set according to environment %d\n", 319*3de4cd12SGeorge Rokos DeviceInfo.EnvNumTeams); 320*3de4cd12SGeorge Rokos } else { 321*3de4cd12SGeorge Rokos DeviceInfo.NumTeams[device_id] = RTLDeviceInfoTy::DefaultNumTeams; 322*3de4cd12SGeorge Rokos DP("Default number of teams set according to library's default %d\n", 323*3de4cd12SGeorge Rokos RTLDeviceInfoTy::DefaultNumTeams); 324*3de4cd12SGeorge Rokos } 325*3de4cd12SGeorge Rokos if (DeviceInfo.NumTeams[device_id] > DeviceInfo.BlocksPerGrid[device_id]) { 326*3de4cd12SGeorge Rokos DeviceInfo.NumTeams[device_id] = DeviceInfo.BlocksPerGrid[device_id]; 327*3de4cd12SGeorge Rokos DP("Default number of teams exceeds device limit, capping at %d\n", 328*3de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id]); 329*3de4cd12SGeorge Rokos } 330*3de4cd12SGeorge Rokos 331*3de4cd12SGeorge Rokos // Set default number of threads 332*3de4cd12SGeorge Rokos DeviceInfo.NumThreads[device_id] = RTLDeviceInfoTy::DefaultNumThreads; 333*3de4cd12SGeorge Rokos DP("Default number of threads set according to library's default %d\n", 334*3de4cd12SGeorge Rokos RTLDeviceInfoTy::DefaultNumThreads); 335*3de4cd12SGeorge Rokos if (DeviceInfo.NumThreads[device_id] > 336*3de4cd12SGeorge Rokos DeviceInfo.ThreadsPerBlock[device_id]) { 337*3de4cd12SGeorge Rokos DeviceInfo.NumTeams[device_id] = DeviceInfo.ThreadsPerBlock[device_id]; 338*3de4cd12SGeorge Rokos DP("Default number of threads exceeds device limit, capping at %d\n", 339*3de4cd12SGeorge Rokos DeviceInfo.ThreadsPerBlock[device_id]); 340*3de4cd12SGeorge Rokos } 341*3de4cd12SGeorge Rokos 342*3de4cd12SGeorge Rokos return OFFLOAD_SUCCESS; 343*3de4cd12SGeorge Rokos } 344*3de4cd12SGeorge Rokos 345*3de4cd12SGeorge Rokos __tgt_target_table *__tgt_rtl_load_binary(int32_t device_id, 346*3de4cd12SGeorge Rokos __tgt_device_image *image) { 347*3de4cd12SGeorge Rokos 348*3de4cd12SGeorge Rokos // Set the context we are using. 349*3de4cd12SGeorge Rokos CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]); 350*3de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 351*3de4cd12SGeorge Rokos DP("Error when setting a CUDA context for device %d\n", device_id); 352*3de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 353*3de4cd12SGeorge Rokos return NULL; 354*3de4cd12SGeorge Rokos } 355*3de4cd12SGeorge Rokos 356*3de4cd12SGeorge Rokos // Clear the offload table as we are going to create a new one. 357*3de4cd12SGeorge Rokos DeviceInfo.clearOffloadEntriesTable(device_id); 358*3de4cd12SGeorge Rokos 359*3de4cd12SGeorge Rokos // Create the module and extract the function pointers. 360*3de4cd12SGeorge Rokos 361*3de4cd12SGeorge Rokos CUmodule cumod; 362*3de4cd12SGeorge Rokos DP("Load data from image " DPxMOD "\n", DPxPTR(image->ImageStart)); 363*3de4cd12SGeorge Rokos err = cuModuleLoadDataEx(&cumod, image->ImageStart, 0, NULL, NULL); 364*3de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 365*3de4cd12SGeorge Rokos DP("Error when loading CUDA module\n"); 366*3de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 367*3de4cd12SGeorge Rokos return NULL; 368*3de4cd12SGeorge Rokos } 369*3de4cd12SGeorge Rokos 370*3de4cd12SGeorge Rokos DP("CUDA module successfully loaded!\n"); 371*3de4cd12SGeorge Rokos DeviceInfo.Modules.push_back(cumod); 372*3de4cd12SGeorge Rokos 373*3de4cd12SGeorge Rokos // Find the symbols in the module by name. 374*3de4cd12SGeorge Rokos __tgt_offload_entry *HostBegin = image->EntriesBegin; 375*3de4cd12SGeorge Rokos __tgt_offload_entry *HostEnd = image->EntriesEnd; 376*3de4cd12SGeorge Rokos 377*3de4cd12SGeorge Rokos for (__tgt_offload_entry *e = HostBegin; e != HostEnd; ++e) { 378*3de4cd12SGeorge Rokos 379*3de4cd12SGeorge Rokos if (!e->addr) { 380*3de4cd12SGeorge Rokos // We return NULL when something like this happens, the host should have 381*3de4cd12SGeorge Rokos // always something in the address to uniquely identify the target region. 382*3de4cd12SGeorge Rokos DP("Invalid binary: host entry '<null>' (size = %zd)...\n", e->size); 383*3de4cd12SGeorge Rokos 384*3de4cd12SGeorge Rokos return NULL; 385*3de4cd12SGeorge Rokos } 386*3de4cd12SGeorge Rokos 387*3de4cd12SGeorge Rokos if (e->size) { 388*3de4cd12SGeorge Rokos __tgt_offload_entry entry = *e; 389*3de4cd12SGeorge Rokos 390*3de4cd12SGeorge Rokos CUdeviceptr cuptr; 391*3de4cd12SGeorge Rokos size_t cusize; 392*3de4cd12SGeorge Rokos err = cuModuleGetGlobal(&cuptr, &cusize, cumod, e->name); 393*3de4cd12SGeorge Rokos 394*3de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 395*3de4cd12SGeorge Rokos DP("Loading global '%s' (Failed)\n", e->name); 396*3de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 397*3de4cd12SGeorge Rokos return NULL; 398*3de4cd12SGeorge Rokos } 399*3de4cd12SGeorge Rokos 400*3de4cd12SGeorge Rokos if (cusize != e->size) { 401*3de4cd12SGeorge Rokos DP("Loading global '%s' - size mismatch (%zd != %zd)\n", e->name, 402*3de4cd12SGeorge Rokos cusize, e->size); 403*3de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 404*3de4cd12SGeorge Rokos return NULL; 405*3de4cd12SGeorge Rokos } 406*3de4cd12SGeorge Rokos 407*3de4cd12SGeorge Rokos DP("Entry point " DPxMOD " maps to global %s (" DPxMOD ")\n", 408*3de4cd12SGeorge Rokos DPxPTR(e - HostBegin), e->name, DPxPTR(cuptr)); 409*3de4cd12SGeorge Rokos entry.addr = (void *)cuptr; 410*3de4cd12SGeorge Rokos 411*3de4cd12SGeorge Rokos DeviceInfo.addOffloadEntry(device_id, entry); 412*3de4cd12SGeorge Rokos 413*3de4cd12SGeorge Rokos continue; 414*3de4cd12SGeorge Rokos } 415*3de4cd12SGeorge Rokos 416*3de4cd12SGeorge Rokos CUfunction fun; 417*3de4cd12SGeorge Rokos err = cuModuleGetFunction(&fun, cumod, e->name); 418*3de4cd12SGeorge Rokos 419*3de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 420*3de4cd12SGeorge Rokos DP("Loading '%s' (Failed)\n", e->name); 421*3de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 422*3de4cd12SGeorge Rokos return NULL; 423*3de4cd12SGeorge Rokos } 424*3de4cd12SGeorge Rokos 425*3de4cd12SGeorge Rokos DP("Entry point " DPxMOD " maps to %s (" DPxMOD ")\n", 426*3de4cd12SGeorge Rokos DPxPTR(e - HostBegin), e->name, DPxPTR(fun)); 427*3de4cd12SGeorge Rokos 428*3de4cd12SGeorge Rokos // default value GENERIC (in case symbol is missing from cubin file) 429*3de4cd12SGeorge Rokos int8_t ExecModeVal = ExecutionModeType::GENERIC; 430*3de4cd12SGeorge Rokos std::string ExecModeNameStr (e->name); 431*3de4cd12SGeorge Rokos ExecModeNameStr += "_exec_mode"; 432*3de4cd12SGeorge Rokos const char *ExecModeName = ExecModeNameStr.c_str(); 433*3de4cd12SGeorge Rokos 434*3de4cd12SGeorge Rokos CUdeviceptr ExecModePtr; 435*3de4cd12SGeorge Rokos size_t cusize; 436*3de4cd12SGeorge Rokos err = cuModuleGetGlobal(&ExecModePtr, &cusize, cumod, ExecModeName); 437*3de4cd12SGeorge Rokos if (err == CUDA_SUCCESS) { 438*3de4cd12SGeorge Rokos if ((size_t)cusize != sizeof(int8_t)) { 439*3de4cd12SGeorge Rokos DP("Loading global exec_mode '%s' - size mismatch (%zd != %zd)\n", 440*3de4cd12SGeorge Rokos ExecModeName, cusize, sizeof(int8_t)); 441*3de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 442*3de4cd12SGeorge Rokos return NULL; 443*3de4cd12SGeorge Rokos } 444*3de4cd12SGeorge Rokos 445*3de4cd12SGeorge Rokos err = cuMemcpyDtoH(&ExecModeVal, ExecModePtr, cusize); 446*3de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 447*3de4cd12SGeorge Rokos DP("Error when copying data from device to host. Pointers: " 448*3de4cd12SGeorge Rokos "host = " DPxMOD ", device = " DPxMOD ", size = %zd\n", 449*3de4cd12SGeorge Rokos DPxPTR(&ExecModeVal), DPxPTR(ExecModePtr), cusize); 450*3de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 451*3de4cd12SGeorge Rokos return NULL; 452*3de4cd12SGeorge Rokos } 453*3de4cd12SGeorge Rokos 454*3de4cd12SGeorge Rokos if (ExecModeVal < 0 || ExecModeVal > 1) { 455*3de4cd12SGeorge Rokos DP("Error wrong exec_mode value specified in cubin file: %d\n", 456*3de4cd12SGeorge Rokos ExecModeVal); 457*3de4cd12SGeorge Rokos return NULL; 458*3de4cd12SGeorge Rokos } 459*3de4cd12SGeorge Rokos } else { 460*3de4cd12SGeorge Rokos DP("Loading global exec_mode '%s' - symbol missing, using default value " 461*3de4cd12SGeorge Rokos "GENERIC (1)\n", ExecModeName); 462*3de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 463*3de4cd12SGeorge Rokos } 464*3de4cd12SGeorge Rokos 465*3de4cd12SGeorge Rokos KernelsList.push_back(KernelTy(fun, ExecModeVal)); 466*3de4cd12SGeorge Rokos 467*3de4cd12SGeorge Rokos __tgt_offload_entry entry = *e; 468*3de4cd12SGeorge Rokos entry.addr = (void *)&KernelsList.back(); 469*3de4cd12SGeorge Rokos DeviceInfo.addOffloadEntry(device_id, entry); 470*3de4cd12SGeorge Rokos } 471*3de4cd12SGeorge Rokos 472*3de4cd12SGeorge Rokos return DeviceInfo.getOffloadEntriesTable(device_id); 473*3de4cd12SGeorge Rokos } 474*3de4cd12SGeorge Rokos 475*3de4cd12SGeorge Rokos void *__tgt_rtl_data_alloc(int32_t device_id, int64_t size) { 476*3de4cd12SGeorge Rokos if (size == 0) { 477*3de4cd12SGeorge Rokos return NULL; 478*3de4cd12SGeorge Rokos } 479*3de4cd12SGeorge Rokos 480*3de4cd12SGeorge Rokos // Set the context we are using. 481*3de4cd12SGeorge Rokos CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]); 482*3de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 483*3de4cd12SGeorge Rokos DP("Error while trying to set CUDA current context\n"); 484*3de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 485*3de4cd12SGeorge Rokos return NULL; 486*3de4cd12SGeorge Rokos } 487*3de4cd12SGeorge Rokos 488*3de4cd12SGeorge Rokos CUdeviceptr ptr; 489*3de4cd12SGeorge Rokos err = cuMemAlloc(&ptr, size); 490*3de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 491*3de4cd12SGeorge Rokos DP("Error while trying to allocate %d\n", err); 492*3de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 493*3de4cd12SGeorge Rokos return NULL; 494*3de4cd12SGeorge Rokos } 495*3de4cd12SGeorge Rokos 496*3de4cd12SGeorge Rokos void *vptr = (void *)ptr; 497*3de4cd12SGeorge Rokos return vptr; 498*3de4cd12SGeorge Rokos } 499*3de4cd12SGeorge Rokos 500*3de4cd12SGeorge Rokos int32_t __tgt_rtl_data_submit(int32_t device_id, void *tgt_ptr, void *hst_ptr, 501*3de4cd12SGeorge Rokos int64_t size) { 502*3de4cd12SGeorge Rokos // Set the context we are using. 503*3de4cd12SGeorge Rokos CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]); 504*3de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 505*3de4cd12SGeorge Rokos DP("Error when setting CUDA context\n"); 506*3de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 507*3de4cd12SGeorge Rokos return OFFLOAD_FAIL; 508*3de4cd12SGeorge Rokos } 509*3de4cd12SGeorge Rokos 510*3de4cd12SGeorge Rokos err = cuMemcpyHtoD((CUdeviceptr)tgt_ptr, hst_ptr, size); 511*3de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 512*3de4cd12SGeorge Rokos DP("Error when copying data from host to device. Pointers: host = " DPxMOD 513*3de4cd12SGeorge Rokos ", device = " DPxMOD ", size = %" PRId64 "\n", DPxPTR(hst_ptr), 514*3de4cd12SGeorge Rokos DPxPTR(tgt_ptr), size); 515*3de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 516*3de4cd12SGeorge Rokos return OFFLOAD_FAIL; 517*3de4cd12SGeorge Rokos } 518*3de4cd12SGeorge Rokos return OFFLOAD_SUCCESS; 519*3de4cd12SGeorge Rokos } 520*3de4cd12SGeorge Rokos 521*3de4cd12SGeorge Rokos int32_t __tgt_rtl_data_retrieve(int32_t device_id, void *hst_ptr, void *tgt_ptr, 522*3de4cd12SGeorge Rokos int64_t size) { 523*3de4cd12SGeorge Rokos // Set the context we are using. 524*3de4cd12SGeorge Rokos CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]); 525*3de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 526*3de4cd12SGeorge Rokos DP("Error when setting CUDA context\n"); 527*3de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 528*3de4cd12SGeorge Rokos return OFFLOAD_FAIL; 529*3de4cd12SGeorge Rokos } 530*3de4cd12SGeorge Rokos 531*3de4cd12SGeorge Rokos err = cuMemcpyDtoH(hst_ptr, (CUdeviceptr)tgt_ptr, size); 532*3de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 533*3de4cd12SGeorge Rokos DP("Error when copying data from device to host. Pointers: host = " DPxMOD 534*3de4cd12SGeorge Rokos ", device = " DPxMOD ", size = %" PRId64 "\n", DPxPTR(hst_ptr), 535*3de4cd12SGeorge Rokos DPxPTR(tgt_ptr), size); 536*3de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 537*3de4cd12SGeorge Rokos return OFFLOAD_FAIL; 538*3de4cd12SGeorge Rokos } 539*3de4cd12SGeorge Rokos return OFFLOAD_SUCCESS; 540*3de4cd12SGeorge Rokos } 541*3de4cd12SGeorge Rokos 542*3de4cd12SGeorge Rokos int32_t __tgt_rtl_data_delete(int32_t device_id, void *tgt_ptr) { 543*3de4cd12SGeorge Rokos // Set the context we are using. 544*3de4cd12SGeorge Rokos CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]); 545*3de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 546*3de4cd12SGeorge Rokos DP("Error when setting CUDA context\n"); 547*3de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 548*3de4cd12SGeorge Rokos return OFFLOAD_FAIL; 549*3de4cd12SGeorge Rokos } 550*3de4cd12SGeorge Rokos 551*3de4cd12SGeorge Rokos err = cuMemFree((CUdeviceptr)tgt_ptr); 552*3de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 553*3de4cd12SGeorge Rokos DP("Error when freeing CUDA memory\n"); 554*3de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 555*3de4cd12SGeorge Rokos return OFFLOAD_FAIL; 556*3de4cd12SGeorge Rokos } 557*3de4cd12SGeorge Rokos return OFFLOAD_SUCCESS; 558*3de4cd12SGeorge Rokos } 559*3de4cd12SGeorge Rokos 560*3de4cd12SGeorge Rokos int32_t __tgt_rtl_run_target_team_region(int32_t device_id, void *tgt_entry_ptr, 561*3de4cd12SGeorge Rokos void **tgt_args, int32_t arg_num, int32_t team_num, int32_t thread_limit, 562*3de4cd12SGeorge Rokos uint64_t loop_tripcount) { 563*3de4cd12SGeorge Rokos // Set the context we are using. 564*3de4cd12SGeorge Rokos CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]); 565*3de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 566*3de4cd12SGeorge Rokos DP("Error when setting CUDA context\n"); 567*3de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 568*3de4cd12SGeorge Rokos return OFFLOAD_FAIL; 569*3de4cd12SGeorge Rokos } 570*3de4cd12SGeorge Rokos 571*3de4cd12SGeorge Rokos // All args are references. 572*3de4cd12SGeorge Rokos std::vector<void *> args(arg_num); 573*3de4cd12SGeorge Rokos 574*3de4cd12SGeorge Rokos for (int32_t i = 0; i < arg_num; ++i) 575*3de4cd12SGeorge Rokos args[i] = &tgt_args[i]; 576*3de4cd12SGeorge Rokos 577*3de4cd12SGeorge Rokos KernelTy *KernelInfo = (KernelTy *)tgt_entry_ptr; 578*3de4cd12SGeorge Rokos 579*3de4cd12SGeorge Rokos int cudaThreadsPerBlock; 580*3de4cd12SGeorge Rokos 581*3de4cd12SGeorge Rokos if (thread_limit > 0) { 582*3de4cd12SGeorge Rokos cudaThreadsPerBlock = thread_limit; 583*3de4cd12SGeorge Rokos DP("Setting CUDA threads per block to requested %d\n", thread_limit); 584*3de4cd12SGeorge Rokos } else { 585*3de4cd12SGeorge Rokos cudaThreadsPerBlock = DeviceInfo.NumThreads[device_id]; 586*3de4cd12SGeorge Rokos DP("Setting CUDA threads per block to default %d\n", 587*3de4cd12SGeorge Rokos DeviceInfo.NumThreads[device_id]); 588*3de4cd12SGeorge Rokos } 589*3de4cd12SGeorge Rokos 590*3de4cd12SGeorge Rokos // Add master warp if necessary 591*3de4cd12SGeorge Rokos if (KernelInfo->ExecutionMode == GENERIC) { 592*3de4cd12SGeorge Rokos cudaThreadsPerBlock += DeviceInfo.WarpSize[device_id]; 593*3de4cd12SGeorge Rokos DP("Adding master warp: +%d threads\n", DeviceInfo.WarpSize[device_id]); 594*3de4cd12SGeorge Rokos } 595*3de4cd12SGeorge Rokos 596*3de4cd12SGeorge Rokos if (cudaThreadsPerBlock > DeviceInfo.ThreadsPerBlock[device_id]) { 597*3de4cd12SGeorge Rokos cudaThreadsPerBlock = DeviceInfo.ThreadsPerBlock[device_id]; 598*3de4cd12SGeorge Rokos DP("Threads per block capped at device limit %d\n", 599*3de4cd12SGeorge Rokos DeviceInfo.ThreadsPerBlock[device_id]); 600*3de4cd12SGeorge Rokos } 601*3de4cd12SGeorge Rokos 602*3de4cd12SGeorge Rokos int kernel_limit; 603*3de4cd12SGeorge Rokos err = cuFuncGetAttribute(&kernel_limit, 604*3de4cd12SGeorge Rokos CU_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK, KernelInfo->Func); 605*3de4cd12SGeorge Rokos if (err == CUDA_SUCCESS) { 606*3de4cd12SGeorge Rokos if (kernel_limit < cudaThreadsPerBlock) { 607*3de4cd12SGeorge Rokos cudaThreadsPerBlock = kernel_limit; 608*3de4cd12SGeorge Rokos DP("Threads per block capped at kernel limit %d\n", kernel_limit); 609*3de4cd12SGeorge Rokos } 610*3de4cd12SGeorge Rokos } 611*3de4cd12SGeorge Rokos 612*3de4cd12SGeorge Rokos int cudaBlocksPerGrid; 613*3de4cd12SGeorge Rokos if (team_num <= 0) { 614*3de4cd12SGeorge Rokos if (loop_tripcount > 0 && DeviceInfo.EnvNumTeams < 0) { 615*3de4cd12SGeorge Rokos // round up to the nearest integer 616*3de4cd12SGeorge Rokos cudaBlocksPerGrid = ((loop_tripcount - 1) / cudaThreadsPerBlock) + 1; 617*3de4cd12SGeorge Rokos DP("Using %d teams due to loop trip count %" PRIu64 " and number of " 618*3de4cd12SGeorge Rokos "threads per block %d\n", cudaBlocksPerGrid, loop_tripcount, 619*3de4cd12SGeorge Rokos cudaThreadsPerBlock); 620*3de4cd12SGeorge Rokos } else { 621*3de4cd12SGeorge Rokos cudaBlocksPerGrid = DeviceInfo.NumTeams[device_id]; 622*3de4cd12SGeorge Rokos DP("Using default number of teams %d\n", DeviceInfo.NumTeams[device_id]); 623*3de4cd12SGeorge Rokos } 624*3de4cd12SGeorge Rokos } else if (team_num > DeviceInfo.BlocksPerGrid[device_id]) { 625*3de4cd12SGeorge Rokos cudaBlocksPerGrid = DeviceInfo.BlocksPerGrid[device_id]; 626*3de4cd12SGeorge Rokos DP("Capping number of teams to team limit %d\n", 627*3de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id]); 628*3de4cd12SGeorge Rokos } else { 629*3de4cd12SGeorge Rokos cudaBlocksPerGrid = team_num; 630*3de4cd12SGeorge Rokos DP("Using requested number of teams %d\n", team_num); 631*3de4cd12SGeorge Rokos } 632*3de4cd12SGeorge Rokos 633*3de4cd12SGeorge Rokos // Run on the device. 634*3de4cd12SGeorge Rokos DP("Launch kernel with %d blocks and %d threads\n", cudaBlocksPerGrid, 635*3de4cd12SGeorge Rokos cudaThreadsPerBlock); 636*3de4cd12SGeorge Rokos 637*3de4cd12SGeorge Rokos err = cuLaunchKernel(KernelInfo->Func, cudaBlocksPerGrid, 1, 1, 638*3de4cd12SGeorge Rokos cudaThreadsPerBlock, 1, 1, 0 /*bytes of shared memory*/, 0, &args[0], 0); 639*3de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 640*3de4cd12SGeorge Rokos DP("Device kernel launch failed!\n"); 641*3de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 642*3de4cd12SGeorge Rokos assert(err == CUDA_SUCCESS && "Unable to launch target execution!"); 643*3de4cd12SGeorge Rokos return OFFLOAD_FAIL; 644*3de4cd12SGeorge Rokos } 645*3de4cd12SGeorge Rokos 646*3de4cd12SGeorge Rokos DP("Launch of entry point at " DPxMOD " successful!\n", 647*3de4cd12SGeorge Rokos DPxPTR(tgt_entry_ptr)); 648*3de4cd12SGeorge Rokos 649*3de4cd12SGeorge Rokos if (cudaDeviceSynchronize() != cudaSuccess) { 650*3de4cd12SGeorge Rokos DP("Kernel execution error at " DPxMOD ".\n", DPxPTR(tgt_entry_ptr)); 651*3de4cd12SGeorge Rokos return OFFLOAD_FAIL; 652*3de4cd12SGeorge Rokos } else { 653*3de4cd12SGeorge Rokos DP("Kernel execution at " DPxMOD " successful!\n", DPxPTR(tgt_entry_ptr)); 654*3de4cd12SGeorge Rokos } 655*3de4cd12SGeorge Rokos 656*3de4cd12SGeorge Rokos return OFFLOAD_SUCCESS; 657*3de4cd12SGeorge Rokos } 658*3de4cd12SGeorge Rokos 659*3de4cd12SGeorge Rokos int32_t __tgt_rtl_run_target_region(int32_t device_id, void *tgt_entry_ptr, 660*3de4cd12SGeorge Rokos void **tgt_args, int32_t arg_num) { 661*3de4cd12SGeorge Rokos // use one team and the default number of threads. 662*3de4cd12SGeorge Rokos const int32_t team_num = 1; 663*3de4cd12SGeorge Rokos const int32_t thread_limit = 0; 664*3de4cd12SGeorge Rokos return __tgt_rtl_run_target_team_region(device_id, tgt_entry_ptr, tgt_args, 665*3de4cd12SGeorge Rokos arg_num, team_num, thread_limit, 0); 666*3de4cd12SGeorge Rokos } 667*3de4cd12SGeorge Rokos 668*3de4cd12SGeorge Rokos #ifdef __cplusplus 669*3de4cd12SGeorge Rokos } 670*3de4cd12SGeorge Rokos #endif 671