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