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 133de4cd12SGeorge Rokos #include <cassert> 143de4cd12SGeorge Rokos #include <cstddef> 153de4cd12SGeorge Rokos #include <cuda.h> 163de4cd12SGeorge Rokos #include <list> 173de4cd12SGeorge Rokos #include <string> 183de4cd12SGeorge Rokos #include <vector> 193de4cd12SGeorge Rokos 201546d319SGeorge Rokos #include "omptargetplugin.h" 213de4cd12SGeorge Rokos 223de4cd12SGeorge Rokos #ifndef TARGET_NAME 233de4cd12SGeorge Rokos #define TARGET_NAME CUDA 243de4cd12SGeorge Rokos #endif 253de4cd12SGeorge Rokos 26b305d26bSSergey Dmitriev #ifdef OMPTARGET_DEBUG 27b305d26bSSergey Dmitriev static int DebugLevel = 0; 28b305d26bSSergey Dmitriev 293de4cd12SGeorge Rokos #define GETNAME2(name) #name 303de4cd12SGeorge Rokos #define GETNAME(name) GETNAME2(name) 31b305d26bSSergey Dmitriev #define DP(...) \ 32b305d26bSSergey Dmitriev do { \ 33b305d26bSSergey Dmitriev if (DebugLevel > 0) { \ 34b305d26bSSergey Dmitriev DEBUGP("Target " GETNAME(TARGET_NAME) " RTL", __VA_ARGS__); \ 35b305d26bSSergey Dmitriev } \ 36b305d26bSSergey Dmitriev } while (false) 37*78769ec4SMichael Kruse 38*78769ec4SMichael Kruse // Utility for retrieving and printing CUDA error string. 39*78769ec4SMichael Kruse #define CUDA_ERR_STRING(err) \ 40*78769ec4SMichael Kruse do { \ 41*78769ec4SMichael Kruse if (DebugLevel > 0) { \ 42*78769ec4SMichael Kruse const char *errStr; \ 43*78769ec4SMichael Kruse cuGetErrorString(err, &errStr); \ 44*78769ec4SMichael Kruse DEBUGP("Target " GETNAME(TARGET_NAME) " RTL", "CUDA error is: %s\n", errStr); \ 45*78769ec4SMichael Kruse } \ 46*78769ec4SMichael Kruse } while (false) 47b305d26bSSergey Dmitriev #else // OMPTARGET_DEBUG 48b305d26bSSergey Dmitriev #define DP(...) {} 49*78769ec4SMichael Kruse #define CUDA_ERR_STRING(err) {} 50b305d26bSSergey Dmitriev #endif // OMPTARGET_DEBUG 513de4cd12SGeorge Rokos 523de4cd12SGeorge Rokos #include "../../common/elf_common.c" 533de4cd12SGeorge Rokos 543de4cd12SGeorge Rokos /// Keep entries table per device. 553de4cd12SGeorge Rokos struct FuncOrGblEntryTy { 563de4cd12SGeorge Rokos __tgt_target_table Table; 573de4cd12SGeorge Rokos std::vector<__tgt_offload_entry> Entries; 583de4cd12SGeorge Rokos }; 593de4cd12SGeorge Rokos 603de4cd12SGeorge Rokos enum ExecutionModeType { 61c13df8e5SGeorge Rokos SPMD, // constructors, destructors, 62c13df8e5SGeorge Rokos // combined constructs (`teams distribute parallel for [simd]`) 63c13df8e5SGeorge Rokos GENERIC, // everything else 643de4cd12SGeorge Rokos NONE 653de4cd12SGeorge Rokos }; 663de4cd12SGeorge Rokos 673de4cd12SGeorge Rokos /// Use a single entity to encode a kernel and a set of flags 683de4cd12SGeorge Rokos struct KernelTy { 693de4cd12SGeorge Rokos CUfunction Func; 703de4cd12SGeorge Rokos 713de4cd12SGeorge Rokos // execution mode of kernel 723de4cd12SGeorge Rokos // 0 - SPMD mode (without master warp) 733de4cd12SGeorge Rokos // 1 - Generic mode (with master warp) 743de4cd12SGeorge Rokos int8_t ExecutionMode; 753de4cd12SGeorge Rokos 763de4cd12SGeorge Rokos KernelTy(CUfunction _Func, int8_t _ExecutionMode) 773de4cd12SGeorge Rokos : Func(_Func), ExecutionMode(_ExecutionMode) {} 783de4cd12SGeorge Rokos }; 793de4cd12SGeorge Rokos 80e1c7a46dSGuansong Zhang /// Device envrionment data 81e1c7a46dSGuansong Zhang /// Manually sync with the deviceRTL side for now, move to a dedicated header file later. 82e1c7a46dSGuansong Zhang struct omptarget_device_environmentTy { 83e1c7a46dSGuansong Zhang int32_t debug_level; 84e1c7a46dSGuansong Zhang }; 85e1c7a46dSGuansong Zhang 863de4cd12SGeorge Rokos /// List that contains all the kernels. 873de4cd12SGeorge Rokos /// FIXME: we may need this to be per device and per library. 883de4cd12SGeorge Rokos std::list<KernelTy> KernelsList; 893de4cd12SGeorge Rokos 903de4cd12SGeorge Rokos /// Class containing all the device information. 913de4cd12SGeorge Rokos class RTLDeviceInfoTy { 922622e9e5SAlexey Bataev std::vector<std::list<FuncOrGblEntryTy>> FuncGblEntries; 933de4cd12SGeorge Rokos 943de4cd12SGeorge Rokos public: 953de4cd12SGeorge Rokos int NumberOfDevices; 963de4cd12SGeorge Rokos std::vector<CUmodule> Modules; 973de4cd12SGeorge Rokos std::vector<CUcontext> Contexts; 983de4cd12SGeorge Rokos 993de4cd12SGeorge Rokos // Device properties 1003de4cd12SGeorge Rokos std::vector<int> ThreadsPerBlock; 1013de4cd12SGeorge Rokos std::vector<int> BlocksPerGrid; 1023de4cd12SGeorge Rokos std::vector<int> WarpSize; 1033de4cd12SGeorge Rokos 1043de4cd12SGeorge Rokos // OpenMP properties 1053de4cd12SGeorge Rokos std::vector<int> NumTeams; 1063de4cd12SGeorge Rokos std::vector<int> NumThreads; 1073de4cd12SGeorge Rokos 1083de4cd12SGeorge Rokos // OpenMP Environment properties 1093de4cd12SGeorge Rokos int EnvNumTeams; 1103de4cd12SGeorge Rokos int EnvTeamLimit; 1113de4cd12SGeorge Rokos 112c5fe030cSGheorghe-Teodor Bercea // OpenMP Requires Flags 113c5fe030cSGheorghe-Teodor Bercea int64_t RequiresFlags; 114c5fe030cSGheorghe-Teodor Bercea 1153de4cd12SGeorge Rokos //static int EnvNumThreads; 1163de4cd12SGeorge Rokos static const int HardTeamLimit = 1<<16; // 64k 1173de4cd12SGeorge Rokos static const int HardThreadLimit = 1024; 1183de4cd12SGeorge Rokos static const int DefaultNumTeams = 128; 119c13df8e5SGeorge Rokos static const int DefaultNumThreads = 128; 1203de4cd12SGeorge Rokos 1213de4cd12SGeorge Rokos // Record entry point associated with device 1223de4cd12SGeorge Rokos void addOffloadEntry(int32_t device_id, __tgt_offload_entry entry) { 1233de4cd12SGeorge Rokos assert(device_id < (int32_t)FuncGblEntries.size() && 1243de4cd12SGeorge Rokos "Unexpected device id!"); 1252622e9e5SAlexey Bataev FuncOrGblEntryTy &E = FuncGblEntries[device_id].back(); 1263de4cd12SGeorge Rokos 1273de4cd12SGeorge Rokos E.Entries.push_back(entry); 1283de4cd12SGeorge Rokos } 1293de4cd12SGeorge Rokos 1303de4cd12SGeorge Rokos // Return true if the entry is associated with device 1313de4cd12SGeorge Rokos bool findOffloadEntry(int32_t device_id, void *addr) { 1323de4cd12SGeorge Rokos assert(device_id < (int32_t)FuncGblEntries.size() && 1333de4cd12SGeorge Rokos "Unexpected device id!"); 1342622e9e5SAlexey Bataev FuncOrGblEntryTy &E = FuncGblEntries[device_id].back(); 1353de4cd12SGeorge Rokos 1363de4cd12SGeorge Rokos for (auto &it : E.Entries) { 1373de4cd12SGeorge Rokos if (it.addr == addr) 1383de4cd12SGeorge Rokos return true; 1393de4cd12SGeorge Rokos } 1403de4cd12SGeorge Rokos 1413de4cd12SGeorge Rokos return false; 1423de4cd12SGeorge Rokos } 1433de4cd12SGeorge Rokos 1443de4cd12SGeorge Rokos // Return the pointer to the target entries table 1453de4cd12SGeorge Rokos __tgt_target_table *getOffloadEntriesTable(int32_t device_id) { 1463de4cd12SGeorge Rokos assert(device_id < (int32_t)FuncGblEntries.size() && 1473de4cd12SGeorge Rokos "Unexpected device id!"); 1482622e9e5SAlexey Bataev FuncOrGblEntryTy &E = FuncGblEntries[device_id].back(); 1493de4cd12SGeorge Rokos 1503de4cd12SGeorge Rokos int32_t size = E.Entries.size(); 1513de4cd12SGeorge Rokos 1523de4cd12SGeorge Rokos // Table is empty 1533de4cd12SGeorge Rokos if (!size) 1543de4cd12SGeorge Rokos return 0; 1553de4cd12SGeorge Rokos 1563de4cd12SGeorge Rokos __tgt_offload_entry *begin = &E.Entries[0]; 1573de4cd12SGeorge Rokos __tgt_offload_entry *end = &E.Entries[size - 1]; 1583de4cd12SGeorge Rokos 1593de4cd12SGeorge Rokos // Update table info according to the entries and return the pointer 1603de4cd12SGeorge Rokos E.Table.EntriesBegin = begin; 1613de4cd12SGeorge Rokos E.Table.EntriesEnd = ++end; 1623de4cd12SGeorge Rokos 1633de4cd12SGeorge Rokos return &E.Table; 1643de4cd12SGeorge Rokos } 1653de4cd12SGeorge Rokos 1663de4cd12SGeorge Rokos // Clear entries table for a device 1673de4cd12SGeorge Rokos void clearOffloadEntriesTable(int32_t device_id) { 1683de4cd12SGeorge Rokos assert(device_id < (int32_t)FuncGblEntries.size() && 1693de4cd12SGeorge Rokos "Unexpected device id!"); 1702622e9e5SAlexey Bataev FuncGblEntries[device_id].emplace_back(); 1712622e9e5SAlexey Bataev FuncOrGblEntryTy &E = FuncGblEntries[device_id].back(); 1723de4cd12SGeorge Rokos E.Entries.clear(); 1733de4cd12SGeorge Rokos E.Table.EntriesBegin = E.Table.EntriesEnd = 0; 1743de4cd12SGeorge Rokos } 1753de4cd12SGeorge Rokos 1763de4cd12SGeorge Rokos RTLDeviceInfoTy() { 177b305d26bSSergey Dmitriev #ifdef OMPTARGET_DEBUG 178b305d26bSSergey Dmitriev if (char *envStr = getenv("LIBOMPTARGET_DEBUG")) { 179b305d26bSSergey Dmitriev DebugLevel = std::stoi(envStr); 180b305d26bSSergey Dmitriev } 181b305d26bSSergey Dmitriev #endif // OMPTARGET_DEBUG 182b305d26bSSergey Dmitriev 1833de4cd12SGeorge Rokos DP("Start initializing CUDA\n"); 1843de4cd12SGeorge Rokos 1853de4cd12SGeorge Rokos CUresult err = cuInit(0); 1863de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 1873de4cd12SGeorge Rokos DP("Error when initializing CUDA\n"); 1883de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 1893de4cd12SGeorge Rokos return; 1903de4cd12SGeorge Rokos } 1913de4cd12SGeorge Rokos 1923de4cd12SGeorge Rokos NumberOfDevices = 0; 1933de4cd12SGeorge Rokos 1943de4cd12SGeorge Rokos err = cuDeviceGetCount(&NumberOfDevices); 1953de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 1963de4cd12SGeorge Rokos DP("Error when getting CUDA device count\n"); 1973de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 1983de4cd12SGeorge Rokos return; 1993de4cd12SGeorge Rokos } 2003de4cd12SGeorge Rokos 2013de4cd12SGeorge Rokos if (NumberOfDevices == 0) { 2023de4cd12SGeorge Rokos DP("There are no devices supporting CUDA.\n"); 2033de4cd12SGeorge Rokos return; 2043de4cd12SGeorge Rokos } 2053de4cd12SGeorge Rokos 2063de4cd12SGeorge Rokos FuncGblEntries.resize(NumberOfDevices); 2073de4cd12SGeorge Rokos Contexts.resize(NumberOfDevices); 2083de4cd12SGeorge Rokos ThreadsPerBlock.resize(NumberOfDevices); 2093de4cd12SGeorge Rokos BlocksPerGrid.resize(NumberOfDevices); 2103de4cd12SGeorge Rokos WarpSize.resize(NumberOfDevices); 2113de4cd12SGeorge Rokos NumTeams.resize(NumberOfDevices); 2123de4cd12SGeorge Rokos NumThreads.resize(NumberOfDevices); 2133de4cd12SGeorge Rokos 2143de4cd12SGeorge Rokos // Get environment variables regarding teams 2153de4cd12SGeorge Rokos char *envStr = getenv("OMP_TEAM_LIMIT"); 2163de4cd12SGeorge Rokos if (envStr) { 2173de4cd12SGeorge Rokos // OMP_TEAM_LIMIT has been set 2183de4cd12SGeorge Rokos EnvTeamLimit = std::stoi(envStr); 2193de4cd12SGeorge Rokos DP("Parsed OMP_TEAM_LIMIT=%d\n", EnvTeamLimit); 2203de4cd12SGeorge Rokos } else { 2213de4cd12SGeorge Rokos EnvTeamLimit = -1; 2223de4cd12SGeorge Rokos } 2233de4cd12SGeorge Rokos envStr = getenv("OMP_NUM_TEAMS"); 2243de4cd12SGeorge Rokos if (envStr) { 2253de4cd12SGeorge Rokos // OMP_NUM_TEAMS has been set 2263de4cd12SGeorge Rokos EnvNumTeams = std::stoi(envStr); 2273de4cd12SGeorge Rokos DP("Parsed OMP_NUM_TEAMS=%d\n", EnvNumTeams); 2283de4cd12SGeorge Rokos } else { 2293de4cd12SGeorge Rokos EnvNumTeams = -1; 2303de4cd12SGeorge Rokos } 231c5fe030cSGheorghe-Teodor Bercea 232c5fe030cSGheorghe-Teodor Bercea // Default state. 233c5fe030cSGheorghe-Teodor Bercea RequiresFlags = OMP_REQ_UNDEFINED; 2343de4cd12SGeorge Rokos } 2353de4cd12SGeorge Rokos 2363de4cd12SGeorge Rokos ~RTLDeviceInfoTy() { 2373de4cd12SGeorge Rokos // Close modules 2383de4cd12SGeorge Rokos for (auto &module : Modules) 2393de4cd12SGeorge Rokos if (module) { 2403de4cd12SGeorge Rokos CUresult err = cuModuleUnload(module); 2413de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 2423de4cd12SGeorge Rokos DP("Error when unloading CUDA module\n"); 2433de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 2443de4cd12SGeorge Rokos } 2453de4cd12SGeorge Rokos } 2463de4cd12SGeorge Rokos 2473de4cd12SGeorge Rokos // Destroy contexts 2483de4cd12SGeorge Rokos for (auto &ctx : Contexts) 2493de4cd12SGeorge Rokos if (ctx) { 2503de4cd12SGeorge Rokos CUresult err = cuCtxDestroy(ctx); 2513de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 2523de4cd12SGeorge Rokos DP("Error when destroying CUDA context\n"); 2533de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 2543de4cd12SGeorge Rokos } 2553de4cd12SGeorge Rokos } 2563de4cd12SGeorge Rokos } 2573de4cd12SGeorge Rokos }; 2583de4cd12SGeorge Rokos 2593de4cd12SGeorge Rokos static RTLDeviceInfoTy DeviceInfo; 2603de4cd12SGeorge Rokos 2613de4cd12SGeorge Rokos #ifdef __cplusplus 2623de4cd12SGeorge Rokos extern "C" { 2633de4cd12SGeorge Rokos #endif 2643de4cd12SGeorge Rokos 2653de4cd12SGeorge Rokos int32_t __tgt_rtl_is_valid_binary(__tgt_device_image *image) { 2663de4cd12SGeorge Rokos return elf_check_machine(image, 190); // EM_CUDA = 190. 2673de4cd12SGeorge Rokos } 2683de4cd12SGeorge Rokos 2693de4cd12SGeorge Rokos int32_t __tgt_rtl_number_of_devices() { return DeviceInfo.NumberOfDevices; } 2703de4cd12SGeorge Rokos 271c5fe030cSGheorghe-Teodor Bercea int64_t __tgt_rtl_init_requires(int64_t RequiresFlags) { 272c5fe030cSGheorghe-Teodor Bercea DP("Init requires flags to %ld\n", RequiresFlags); 273c5fe030cSGheorghe-Teodor Bercea DeviceInfo.RequiresFlags = RequiresFlags; 274c5fe030cSGheorghe-Teodor Bercea return RequiresFlags; 275c5fe030cSGheorghe-Teodor Bercea } 276c5fe030cSGheorghe-Teodor Bercea 2773de4cd12SGeorge Rokos int32_t __tgt_rtl_init_device(int32_t device_id) { 2783de4cd12SGeorge Rokos 2793de4cd12SGeorge Rokos CUdevice cuDevice; 2803de4cd12SGeorge Rokos DP("Getting device %d\n", device_id); 2813de4cd12SGeorge Rokos CUresult err = cuDeviceGet(&cuDevice, device_id); 2823de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 2833de4cd12SGeorge Rokos DP("Error when getting CUDA device with id = %d\n", device_id); 2843de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 2853de4cd12SGeorge Rokos return OFFLOAD_FAIL; 2863de4cd12SGeorge Rokos } 2873de4cd12SGeorge Rokos 2883de4cd12SGeorge Rokos // Create the context and save it to use whenever this device is selected. 2893de4cd12SGeorge Rokos err = cuCtxCreate(&DeviceInfo.Contexts[device_id], CU_CTX_SCHED_BLOCKING_SYNC, 2903de4cd12SGeorge Rokos cuDevice); 2913de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 2923de4cd12SGeorge Rokos DP("Error when creating a CUDA context\n"); 2933de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 2943de4cd12SGeorge Rokos return OFFLOAD_FAIL; 2953de4cd12SGeorge Rokos } 2963de4cd12SGeorge Rokos 297bb51d398SJonas Hahnfeld // Query attributes to determine number of threads/block and blocks/grid. 298bb51d398SJonas Hahnfeld int maxGridDimX; 299bb51d398SJonas Hahnfeld err = cuDeviceGetAttribute(&maxGridDimX, CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_X, 300bb51d398SJonas Hahnfeld cuDevice); 301c1895235SJonas Hahnfeld if (err != CUDA_SUCCESS) { 302bb51d398SJonas Hahnfeld DP("Error getting max grid dimension, use default\n"); 3033de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id] = RTLDeviceInfoTy::DefaultNumTeams; 304bb51d398SJonas Hahnfeld } else if (maxGridDimX <= RTLDeviceInfoTy::HardTeamLimit) { 305bb51d398SJonas Hahnfeld DeviceInfo.BlocksPerGrid[device_id] = maxGridDimX; 306bb51d398SJonas Hahnfeld DP("Using %d CUDA blocks per grid\n", maxGridDimX); 3073de4cd12SGeorge Rokos } else { 3083de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id] = RTLDeviceInfoTy::HardTeamLimit; 3093de4cd12SGeorge Rokos DP("Max CUDA blocks per grid %d exceeds the hard team limit %d, capping " 310bb51d398SJonas Hahnfeld "at the hard limit\n", 311bb51d398SJonas Hahnfeld maxGridDimX, RTLDeviceInfoTy::HardTeamLimit); 3123de4cd12SGeorge Rokos } 3133de4cd12SGeorge Rokos 314bb51d398SJonas Hahnfeld // We are only exploiting threads along the x axis. 315bb51d398SJonas Hahnfeld int maxBlockDimX; 316bb51d398SJonas Hahnfeld err = cuDeviceGetAttribute(&maxBlockDimX, CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_X, 317bb51d398SJonas Hahnfeld cuDevice); 318bb51d398SJonas Hahnfeld if (err != CUDA_SUCCESS) { 319bb51d398SJonas Hahnfeld DP("Error getting max block dimension, use default\n"); 320bb51d398SJonas Hahnfeld DeviceInfo.ThreadsPerBlock[device_id] = RTLDeviceInfoTy::DefaultNumThreads; 321bb51d398SJonas Hahnfeld } else if (maxBlockDimX <= RTLDeviceInfoTy::HardThreadLimit) { 322bb51d398SJonas Hahnfeld DeviceInfo.ThreadsPerBlock[device_id] = maxBlockDimX; 323bb51d398SJonas Hahnfeld DP("Using %d CUDA threads per block\n", maxBlockDimX); 3243de4cd12SGeorge Rokos } else { 3253de4cd12SGeorge Rokos DeviceInfo.ThreadsPerBlock[device_id] = RTLDeviceInfoTy::HardThreadLimit; 326bb51d398SJonas Hahnfeld DP("Max CUDA threads per block %d exceeds the hard thread limit %d, capping" 327bb51d398SJonas Hahnfeld "at the hard limit\n", 328bb51d398SJonas Hahnfeld maxBlockDimX, RTLDeviceInfoTy::HardThreadLimit); 3293de4cd12SGeorge Rokos } 3303de4cd12SGeorge Rokos 331bb51d398SJonas Hahnfeld int warpSize; 332bb51d398SJonas Hahnfeld err = 333bb51d398SJonas Hahnfeld cuDeviceGetAttribute(&warpSize, CU_DEVICE_ATTRIBUTE_WARP_SIZE, cuDevice); 334bb51d398SJonas Hahnfeld if (err != CUDA_SUCCESS) { 335bb51d398SJonas Hahnfeld DP("Error getting warp size, assume default\n"); 336bb51d398SJonas Hahnfeld DeviceInfo.WarpSize[device_id] = 32; 337bb51d398SJonas Hahnfeld } else { 338bb51d398SJonas Hahnfeld DeviceInfo.WarpSize[device_id] = warpSize; 3393de4cd12SGeorge Rokos } 3403de4cd12SGeorge Rokos 3413de4cd12SGeorge Rokos // Adjust teams to the env variables 3423de4cd12SGeorge Rokos if (DeviceInfo.EnvTeamLimit > 0 && 3433de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id] > DeviceInfo.EnvTeamLimit) { 3443de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id] = DeviceInfo.EnvTeamLimit; 3453de4cd12SGeorge Rokos DP("Capping max CUDA blocks per grid to OMP_TEAM_LIMIT=%d\n", 3463de4cd12SGeorge Rokos DeviceInfo.EnvTeamLimit); 3473de4cd12SGeorge Rokos } 3483de4cd12SGeorge Rokos 3493de4cd12SGeorge Rokos DP("Max number of CUDA blocks %d, threads %d & warp size %d\n", 3503de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id], DeviceInfo.ThreadsPerBlock[device_id], 3513de4cd12SGeorge Rokos DeviceInfo.WarpSize[device_id]); 3523de4cd12SGeorge Rokos 3533de4cd12SGeorge Rokos // Set default number of teams 3543de4cd12SGeorge Rokos if (DeviceInfo.EnvNumTeams > 0) { 3553de4cd12SGeorge Rokos DeviceInfo.NumTeams[device_id] = DeviceInfo.EnvNumTeams; 3563de4cd12SGeorge Rokos DP("Default number of teams set according to environment %d\n", 3573de4cd12SGeorge Rokos DeviceInfo.EnvNumTeams); 3583de4cd12SGeorge Rokos } else { 3593de4cd12SGeorge Rokos DeviceInfo.NumTeams[device_id] = RTLDeviceInfoTy::DefaultNumTeams; 3603de4cd12SGeorge Rokos DP("Default number of teams set according to library's default %d\n", 3613de4cd12SGeorge Rokos RTLDeviceInfoTy::DefaultNumTeams); 3623de4cd12SGeorge Rokos } 3633de4cd12SGeorge Rokos if (DeviceInfo.NumTeams[device_id] > DeviceInfo.BlocksPerGrid[device_id]) { 3643de4cd12SGeorge Rokos DeviceInfo.NumTeams[device_id] = DeviceInfo.BlocksPerGrid[device_id]; 3653de4cd12SGeorge Rokos DP("Default number of teams exceeds device limit, capping at %d\n", 3663de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id]); 3673de4cd12SGeorge Rokos } 3683de4cd12SGeorge Rokos 3693de4cd12SGeorge Rokos // Set default number of threads 3703de4cd12SGeorge Rokos DeviceInfo.NumThreads[device_id] = RTLDeviceInfoTy::DefaultNumThreads; 3713de4cd12SGeorge Rokos DP("Default number of threads set according to library's default %d\n", 3723de4cd12SGeorge Rokos RTLDeviceInfoTy::DefaultNumThreads); 3733de4cd12SGeorge Rokos if (DeviceInfo.NumThreads[device_id] > 3743de4cd12SGeorge Rokos DeviceInfo.ThreadsPerBlock[device_id]) { 3753de4cd12SGeorge Rokos DeviceInfo.NumTeams[device_id] = DeviceInfo.ThreadsPerBlock[device_id]; 3763de4cd12SGeorge Rokos DP("Default number of threads exceeds device limit, capping at %d\n", 3773de4cd12SGeorge Rokos DeviceInfo.ThreadsPerBlock[device_id]); 3783de4cd12SGeorge Rokos } 3793de4cd12SGeorge Rokos 3803de4cd12SGeorge Rokos return OFFLOAD_SUCCESS; 3813de4cd12SGeorge Rokos } 3823de4cd12SGeorge Rokos 3833de4cd12SGeorge Rokos __tgt_target_table *__tgt_rtl_load_binary(int32_t device_id, 3843de4cd12SGeorge Rokos __tgt_device_image *image) { 3853de4cd12SGeorge Rokos 3863de4cd12SGeorge Rokos // Set the context we are using. 3873de4cd12SGeorge Rokos CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]); 3883de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 3893de4cd12SGeorge Rokos DP("Error when setting a CUDA context for device %d\n", device_id); 3903de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 3913de4cd12SGeorge Rokos return NULL; 3923de4cd12SGeorge Rokos } 3933de4cd12SGeorge Rokos 3943de4cd12SGeorge Rokos // Clear the offload table as we are going to create a new one. 3953de4cd12SGeorge Rokos DeviceInfo.clearOffloadEntriesTable(device_id); 3963de4cd12SGeorge Rokos 3973de4cd12SGeorge Rokos // Create the module and extract the function pointers. 3983de4cd12SGeorge Rokos 3993de4cd12SGeorge Rokos CUmodule cumod; 4003de4cd12SGeorge Rokos DP("Load data from image " DPxMOD "\n", DPxPTR(image->ImageStart)); 4013de4cd12SGeorge Rokos err = cuModuleLoadDataEx(&cumod, image->ImageStart, 0, NULL, NULL); 4023de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 4033de4cd12SGeorge Rokos DP("Error when loading CUDA module\n"); 4043de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 4053de4cd12SGeorge Rokos return NULL; 4063de4cd12SGeorge Rokos } 4073de4cd12SGeorge Rokos 4083de4cd12SGeorge Rokos DP("CUDA module successfully loaded!\n"); 4093de4cd12SGeorge Rokos DeviceInfo.Modules.push_back(cumod); 4103de4cd12SGeorge Rokos 4113de4cd12SGeorge Rokos // Find the symbols in the module by name. 4123de4cd12SGeorge Rokos __tgt_offload_entry *HostBegin = image->EntriesBegin; 4133de4cd12SGeorge Rokos __tgt_offload_entry *HostEnd = image->EntriesEnd; 4143de4cd12SGeorge Rokos 4153de4cd12SGeorge Rokos for (__tgt_offload_entry *e = HostBegin; e != HostEnd; ++e) { 4163de4cd12SGeorge Rokos 4173de4cd12SGeorge Rokos if (!e->addr) { 4183de4cd12SGeorge Rokos // We return NULL when something like this happens, the host should have 4193de4cd12SGeorge Rokos // always something in the address to uniquely identify the target region. 4203de4cd12SGeorge Rokos DP("Invalid binary: host entry '<null>' (size = %zd)...\n", e->size); 4213de4cd12SGeorge Rokos 4223de4cd12SGeorge Rokos return NULL; 4233de4cd12SGeorge Rokos } 4243de4cd12SGeorge Rokos 4253de4cd12SGeorge Rokos if (e->size) { 4263de4cd12SGeorge Rokos __tgt_offload_entry entry = *e; 4273de4cd12SGeorge Rokos 4283de4cd12SGeorge Rokos CUdeviceptr cuptr; 4293de4cd12SGeorge Rokos size_t cusize; 4303de4cd12SGeorge Rokos err = cuModuleGetGlobal(&cuptr, &cusize, cumod, e->name); 4313de4cd12SGeorge Rokos 4323de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 4333de4cd12SGeorge Rokos DP("Loading global '%s' (Failed)\n", e->name); 4343de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 4353de4cd12SGeorge Rokos return NULL; 4363de4cd12SGeorge Rokos } 4373de4cd12SGeorge Rokos 4383de4cd12SGeorge Rokos if (cusize != e->size) { 4393de4cd12SGeorge Rokos DP("Loading global '%s' - size mismatch (%zd != %zd)\n", e->name, 4403de4cd12SGeorge Rokos cusize, e->size); 4413de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 4423de4cd12SGeorge Rokos return NULL; 4433de4cd12SGeorge Rokos } 4443de4cd12SGeorge Rokos 4453de4cd12SGeorge Rokos DP("Entry point " DPxMOD " maps to global %s (" DPxMOD ")\n", 4463de4cd12SGeorge Rokos DPxPTR(e - HostBegin), e->name, DPxPTR(cuptr)); 4473de4cd12SGeorge Rokos entry.addr = (void *)cuptr; 4483de4cd12SGeorge Rokos 449aace6d28SGheorghe-Teodor Bercea // Note: In the current implementation declare target variables 450aace6d28SGheorghe-Teodor Bercea // can either be link or to. This means that once unified 451aace6d28SGheorghe-Teodor Bercea // memory is activated via the requires directive, the variable 452aace6d28SGheorghe-Teodor Bercea // can be used directly from the host in both cases. 453aace6d28SGheorghe-Teodor Bercea // TODO: when variables types other than to or link are added, 454aace6d28SGheorghe-Teodor Bercea // the below condition should be changed to explicitely 455aace6d28SGheorghe-Teodor Bercea // check for to and link variables types: 456aace6d28SGheorghe-Teodor Bercea // (DeviceInfo.RequiresFlags & OMP_REQ_UNIFIED_SHARED_MEMORY && 457aace6d28SGheorghe-Teodor Bercea // (e->flags & OMP_DECLARE_TARGET_LINK || 458aace6d28SGheorghe-Teodor Bercea // e->flags == OMP_DECLARE_TARGET_TO)) 459aace6d28SGheorghe-Teodor Bercea if (DeviceInfo.RequiresFlags & OMP_REQ_UNIFIED_SHARED_MEMORY) { 460aace6d28SGheorghe-Teodor Bercea // If unified memory is present any target link or to variables 461c5fe030cSGheorghe-Teodor Bercea // can access host addresses directly. There is no longer a 462c5fe030cSGheorghe-Teodor Bercea // need for device copies. 463c5fe030cSGheorghe-Teodor Bercea cuMemcpyHtoD(cuptr, e->addr, sizeof(void *)); 464c5fe030cSGheorghe-Teodor Bercea DP("Copy linked variable host address (" DPxMOD ")" 465c5fe030cSGheorghe-Teodor Bercea "to device address (" DPxMOD ")\n", 466c5fe030cSGheorghe-Teodor Bercea DPxPTR(*((void**)e->addr)), DPxPTR(cuptr)); 467c5fe030cSGheorghe-Teodor Bercea } 468c5fe030cSGheorghe-Teodor Bercea 4693de4cd12SGeorge Rokos DeviceInfo.addOffloadEntry(device_id, entry); 4703de4cd12SGeorge Rokos 4713de4cd12SGeorge Rokos continue; 4723de4cd12SGeorge Rokos } 4733de4cd12SGeorge Rokos 4743de4cd12SGeorge Rokos CUfunction fun; 4753de4cd12SGeorge Rokos err = cuModuleGetFunction(&fun, cumod, e->name); 4763de4cd12SGeorge Rokos 4773de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 4783de4cd12SGeorge Rokos DP("Loading '%s' (Failed)\n", e->name); 4793de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 4803de4cd12SGeorge Rokos return NULL; 4813de4cd12SGeorge Rokos } 4823de4cd12SGeorge Rokos 4833de4cd12SGeorge Rokos DP("Entry point " DPxMOD " maps to %s (" DPxMOD ")\n", 4843de4cd12SGeorge Rokos DPxPTR(e - HostBegin), e->name, DPxPTR(fun)); 4853de4cd12SGeorge Rokos 4863de4cd12SGeorge Rokos // default value GENERIC (in case symbol is missing from cubin file) 4873de4cd12SGeorge Rokos int8_t ExecModeVal = ExecutionModeType::GENERIC; 4883de4cd12SGeorge Rokos std::string ExecModeNameStr (e->name); 4893de4cd12SGeorge Rokos ExecModeNameStr += "_exec_mode"; 4903de4cd12SGeorge Rokos const char *ExecModeName = ExecModeNameStr.c_str(); 4913de4cd12SGeorge Rokos 4923de4cd12SGeorge Rokos CUdeviceptr ExecModePtr; 4933de4cd12SGeorge Rokos size_t cusize; 4943de4cd12SGeorge Rokos err = cuModuleGetGlobal(&ExecModePtr, &cusize, cumod, ExecModeName); 4953de4cd12SGeorge Rokos if (err == CUDA_SUCCESS) { 4963de4cd12SGeorge Rokos if ((size_t)cusize != sizeof(int8_t)) { 4973de4cd12SGeorge Rokos DP("Loading global exec_mode '%s' - size mismatch (%zd != %zd)\n", 4983de4cd12SGeorge Rokos ExecModeName, cusize, sizeof(int8_t)); 4993de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 5003de4cd12SGeorge Rokos return NULL; 5013de4cd12SGeorge Rokos } 5023de4cd12SGeorge Rokos 5033de4cd12SGeorge Rokos err = cuMemcpyDtoH(&ExecModeVal, ExecModePtr, cusize); 5043de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 5053de4cd12SGeorge Rokos DP("Error when copying data from device to host. Pointers: " 5063de4cd12SGeorge Rokos "host = " DPxMOD ", device = " DPxMOD ", size = %zd\n", 5073de4cd12SGeorge Rokos DPxPTR(&ExecModeVal), DPxPTR(ExecModePtr), cusize); 5083de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 5093de4cd12SGeorge Rokos return NULL; 5103de4cd12SGeorge Rokos } 5113de4cd12SGeorge Rokos 5123de4cd12SGeorge Rokos if (ExecModeVal < 0 || ExecModeVal > 1) { 5133de4cd12SGeorge Rokos DP("Error wrong exec_mode value specified in cubin file: %d\n", 5143de4cd12SGeorge Rokos ExecModeVal); 5153de4cd12SGeorge Rokos return NULL; 5163de4cd12SGeorge Rokos } 5173de4cd12SGeorge Rokos } else { 5183de4cd12SGeorge Rokos DP("Loading global exec_mode '%s' - symbol missing, using default value " 5193de4cd12SGeorge Rokos "GENERIC (1)\n", ExecModeName); 5203de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 5213de4cd12SGeorge Rokos } 5223de4cd12SGeorge Rokos 5233de4cd12SGeorge Rokos KernelsList.push_back(KernelTy(fun, ExecModeVal)); 5243de4cd12SGeorge Rokos 5253de4cd12SGeorge Rokos __tgt_offload_entry entry = *e; 5263de4cd12SGeorge Rokos entry.addr = (void *)&KernelsList.back(); 5273de4cd12SGeorge Rokos DeviceInfo.addOffloadEntry(device_id, entry); 5283de4cd12SGeorge Rokos } 5293de4cd12SGeorge Rokos 530e1c7a46dSGuansong Zhang // send device environment data to the device 531e1c7a46dSGuansong Zhang { 532e1c7a46dSGuansong Zhang omptarget_device_environmentTy device_env; 533e1c7a46dSGuansong Zhang 534e1c7a46dSGuansong Zhang device_env.debug_level = 0; 535e1c7a46dSGuansong Zhang 536e1c7a46dSGuansong Zhang #ifdef OMPTARGET_DEBUG 537e1c7a46dSGuansong Zhang if (char *envStr = getenv("LIBOMPTARGET_DEVICE_RTL_DEBUG")) { 538e1c7a46dSGuansong Zhang device_env.debug_level = std::stoi(envStr); 539e1c7a46dSGuansong Zhang } 540e1c7a46dSGuansong Zhang #endif 541e1c7a46dSGuansong Zhang 542e1c7a46dSGuansong Zhang const char * device_env_Name="omptarget_device_environment"; 543e1c7a46dSGuansong Zhang CUdeviceptr device_env_Ptr; 544e1c7a46dSGuansong Zhang size_t cusize; 545e1c7a46dSGuansong Zhang 546e1c7a46dSGuansong Zhang err = cuModuleGetGlobal(&device_env_Ptr, &cusize, cumod, device_env_Name); 547e1c7a46dSGuansong Zhang 548e1c7a46dSGuansong Zhang if (err == CUDA_SUCCESS) { 549e1c7a46dSGuansong Zhang if ((size_t)cusize != sizeof(device_env)) { 550e1c7a46dSGuansong Zhang DP("Global device_environment '%s' - size mismatch (%zu != %zu)\n", 551e1c7a46dSGuansong Zhang device_env_Name, cusize, sizeof(int32_t)); 552e1c7a46dSGuansong Zhang CUDA_ERR_STRING(err); 553e1c7a46dSGuansong Zhang return NULL; 554e1c7a46dSGuansong Zhang } 555e1c7a46dSGuansong Zhang 556e1c7a46dSGuansong Zhang err = cuMemcpyHtoD(device_env_Ptr, &device_env, cusize); 557e1c7a46dSGuansong Zhang if (err != CUDA_SUCCESS) { 558e1c7a46dSGuansong Zhang DP("Error when copying data from host to device. Pointers: " 559e1c7a46dSGuansong Zhang "host = " DPxMOD ", device = " DPxMOD ", size = %zu\n", 560e1c7a46dSGuansong Zhang DPxPTR(&device_env), DPxPTR(device_env_Ptr), cusize); 561e1c7a46dSGuansong Zhang CUDA_ERR_STRING(err); 562e1c7a46dSGuansong Zhang return NULL; 563e1c7a46dSGuansong Zhang } 564e1c7a46dSGuansong Zhang 565e1c7a46dSGuansong Zhang DP("Sending global device environment data %zu bytes\n", (size_t)cusize); 566e1c7a46dSGuansong Zhang } else { 567e1c7a46dSGuansong Zhang DP("Finding global device environment '%s' - symbol missing.\n", device_env_Name); 568e1c7a46dSGuansong Zhang DP("Continue, considering this is a device RTL which does not accept envrionment setting.\n"); 569e1c7a46dSGuansong Zhang } 570e1c7a46dSGuansong Zhang } 571e1c7a46dSGuansong Zhang 5723de4cd12SGeorge Rokos return DeviceInfo.getOffloadEntriesTable(device_id); 5733de4cd12SGeorge Rokos } 5743de4cd12SGeorge Rokos 5751546d319SGeorge Rokos void *__tgt_rtl_data_alloc(int32_t device_id, int64_t size, void *hst_ptr) { 5763de4cd12SGeorge Rokos if (size == 0) { 5773de4cd12SGeorge Rokos return NULL; 5783de4cd12SGeorge Rokos } 5793de4cd12SGeorge Rokos 5803de4cd12SGeorge Rokos // Set the context we are using. 5813de4cd12SGeorge Rokos CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]); 5823de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 5833de4cd12SGeorge Rokos DP("Error while trying to set CUDA current context\n"); 5843de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 5853de4cd12SGeorge Rokos return NULL; 5863de4cd12SGeorge Rokos } 5873de4cd12SGeorge Rokos 5883de4cd12SGeorge Rokos CUdeviceptr ptr; 5893de4cd12SGeorge Rokos err = cuMemAlloc(&ptr, size); 5903de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 5913de4cd12SGeorge Rokos DP("Error while trying to allocate %d\n", err); 5923de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 5933de4cd12SGeorge Rokos return NULL; 5943de4cd12SGeorge Rokos } 5953de4cd12SGeorge Rokos 5963de4cd12SGeorge Rokos void *vptr = (void *)ptr; 5973de4cd12SGeorge Rokos return vptr; 5983de4cd12SGeorge Rokos } 5993de4cd12SGeorge Rokos 6003de4cd12SGeorge Rokos int32_t __tgt_rtl_data_submit(int32_t device_id, void *tgt_ptr, void *hst_ptr, 6013de4cd12SGeorge Rokos int64_t size) { 6023de4cd12SGeorge Rokos // Set the context we are using. 6033de4cd12SGeorge Rokos CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]); 6043de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 6053de4cd12SGeorge Rokos DP("Error when setting CUDA context\n"); 6063de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 6073de4cd12SGeorge Rokos return OFFLOAD_FAIL; 6083de4cd12SGeorge Rokos } 6093de4cd12SGeorge Rokos 6103de4cd12SGeorge Rokos err = cuMemcpyHtoD((CUdeviceptr)tgt_ptr, hst_ptr, size); 6113de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 6123de4cd12SGeorge Rokos DP("Error when copying data from host to device. Pointers: host = " DPxMOD 6133de4cd12SGeorge Rokos ", device = " DPxMOD ", size = %" PRId64 "\n", DPxPTR(hst_ptr), 6143de4cd12SGeorge Rokos DPxPTR(tgt_ptr), size); 6153de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 6163de4cd12SGeorge Rokos return OFFLOAD_FAIL; 6173de4cd12SGeorge Rokos } 6183de4cd12SGeorge Rokos return OFFLOAD_SUCCESS; 6193de4cd12SGeorge Rokos } 6203de4cd12SGeorge Rokos 6213de4cd12SGeorge Rokos int32_t __tgt_rtl_data_retrieve(int32_t device_id, void *hst_ptr, void *tgt_ptr, 6223de4cd12SGeorge Rokos int64_t size) { 6233de4cd12SGeorge Rokos // Set the context we are using. 6243de4cd12SGeorge Rokos CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]); 6253de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 6263de4cd12SGeorge Rokos DP("Error when setting CUDA context\n"); 6273de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 6283de4cd12SGeorge Rokos return OFFLOAD_FAIL; 6293de4cd12SGeorge Rokos } 6303de4cd12SGeorge Rokos 6313de4cd12SGeorge Rokos err = cuMemcpyDtoH(hst_ptr, (CUdeviceptr)tgt_ptr, size); 6323de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 6333de4cd12SGeorge Rokos DP("Error when copying data from device to host. Pointers: host = " DPxMOD 6343de4cd12SGeorge Rokos ", device = " DPxMOD ", size = %" PRId64 "\n", DPxPTR(hst_ptr), 6353de4cd12SGeorge Rokos DPxPTR(tgt_ptr), size); 6363de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 6373de4cd12SGeorge Rokos return OFFLOAD_FAIL; 6383de4cd12SGeorge Rokos } 6393de4cd12SGeorge Rokos return OFFLOAD_SUCCESS; 6403de4cd12SGeorge Rokos } 6413de4cd12SGeorge Rokos 6423de4cd12SGeorge Rokos int32_t __tgt_rtl_data_delete(int32_t device_id, void *tgt_ptr) { 6433de4cd12SGeorge Rokos // Set the context we are using. 6443de4cd12SGeorge Rokos CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]); 6453de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 6463de4cd12SGeorge Rokos DP("Error when setting CUDA context\n"); 6473de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 6483de4cd12SGeorge Rokos return OFFLOAD_FAIL; 6493de4cd12SGeorge Rokos } 6503de4cd12SGeorge Rokos 6513de4cd12SGeorge Rokos err = cuMemFree((CUdeviceptr)tgt_ptr); 6523de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 6533de4cd12SGeorge Rokos DP("Error when freeing CUDA memory\n"); 6543de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 6553de4cd12SGeorge Rokos return OFFLOAD_FAIL; 6563de4cd12SGeorge Rokos } 6573de4cd12SGeorge Rokos return OFFLOAD_SUCCESS; 6583de4cd12SGeorge Rokos } 6593de4cd12SGeorge Rokos 6603de4cd12SGeorge Rokos int32_t __tgt_rtl_run_target_team_region(int32_t device_id, void *tgt_entry_ptr, 6611546d319SGeorge Rokos void **tgt_args, ptrdiff_t *tgt_offsets, int32_t arg_num, int32_t team_num, 6621546d319SGeorge Rokos int32_t thread_limit, uint64_t loop_tripcount) { 6633de4cd12SGeorge Rokos // Set the context we are using. 6643de4cd12SGeorge Rokos CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]); 6653de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 6663de4cd12SGeorge Rokos DP("Error when setting CUDA context\n"); 6673de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 6683de4cd12SGeorge Rokos return OFFLOAD_FAIL; 6693de4cd12SGeorge Rokos } 6703de4cd12SGeorge Rokos 6713de4cd12SGeorge Rokos // All args are references. 6723de4cd12SGeorge Rokos std::vector<void *> args(arg_num); 6731546d319SGeorge Rokos std::vector<void *> ptrs(arg_num); 6743de4cd12SGeorge Rokos 6751546d319SGeorge Rokos for (int32_t i = 0; i < arg_num; ++i) { 6761546d319SGeorge Rokos ptrs[i] = (void *)((intptr_t)tgt_args[i] + tgt_offsets[i]); 6771546d319SGeorge Rokos args[i] = &ptrs[i]; 6781546d319SGeorge Rokos } 6793de4cd12SGeorge Rokos 6803de4cd12SGeorge Rokos KernelTy *KernelInfo = (KernelTy *)tgt_entry_ptr; 6813de4cd12SGeorge Rokos 6823de4cd12SGeorge Rokos int cudaThreadsPerBlock; 6833de4cd12SGeorge Rokos 6843de4cd12SGeorge Rokos if (thread_limit > 0) { 6853de4cd12SGeorge Rokos cudaThreadsPerBlock = thread_limit; 6863de4cd12SGeorge Rokos DP("Setting CUDA threads per block to requested %d\n", thread_limit); 6873de4cd12SGeorge Rokos // Add master warp if necessary 6883de4cd12SGeorge Rokos if (KernelInfo->ExecutionMode == GENERIC) { 6893de4cd12SGeorge Rokos cudaThreadsPerBlock += DeviceInfo.WarpSize[device_id]; 6903de4cd12SGeorge Rokos DP("Adding master warp: +%d threads\n", DeviceInfo.WarpSize[device_id]); 6913de4cd12SGeorge Rokos } 692c13df8e5SGeorge Rokos } else { 693c13df8e5SGeorge Rokos cudaThreadsPerBlock = DeviceInfo.NumThreads[device_id]; 694c13df8e5SGeorge Rokos DP("Setting CUDA threads per block to default %d\n", 695c13df8e5SGeorge Rokos DeviceInfo.NumThreads[device_id]); 696c13df8e5SGeorge Rokos } 6973de4cd12SGeorge Rokos 6983de4cd12SGeorge Rokos if (cudaThreadsPerBlock > DeviceInfo.ThreadsPerBlock[device_id]) { 6993de4cd12SGeorge Rokos cudaThreadsPerBlock = DeviceInfo.ThreadsPerBlock[device_id]; 7003de4cd12SGeorge Rokos DP("Threads per block capped at device limit %d\n", 7013de4cd12SGeorge Rokos DeviceInfo.ThreadsPerBlock[device_id]); 7023de4cd12SGeorge Rokos } 7033de4cd12SGeorge Rokos 7043de4cd12SGeorge Rokos int kernel_limit; 7053de4cd12SGeorge Rokos err = cuFuncGetAttribute(&kernel_limit, 7063de4cd12SGeorge Rokos CU_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK, KernelInfo->Func); 7073de4cd12SGeorge Rokos if (err == CUDA_SUCCESS) { 7083de4cd12SGeorge Rokos if (kernel_limit < cudaThreadsPerBlock) { 7093de4cd12SGeorge Rokos cudaThreadsPerBlock = kernel_limit; 7103de4cd12SGeorge Rokos DP("Threads per block capped at kernel limit %d\n", kernel_limit); 7113de4cd12SGeorge Rokos } 7123de4cd12SGeorge Rokos } 7133de4cd12SGeorge Rokos 7143de4cd12SGeorge Rokos int cudaBlocksPerGrid; 7153de4cd12SGeorge Rokos if (team_num <= 0) { 7163de4cd12SGeorge Rokos if (loop_tripcount > 0 && DeviceInfo.EnvNumTeams < 0) { 717c13df8e5SGeorge Rokos if (KernelInfo->ExecutionMode == SPMD) { 718c13df8e5SGeorge Rokos // We have a combined construct, i.e. `target teams distribute parallel 719c13df8e5SGeorge Rokos // for [simd]`. We launch so many teams so that each thread will 720c13df8e5SGeorge Rokos // execute one iteration of the loop. 7213de4cd12SGeorge Rokos // round up to the nearest integer 7223de4cd12SGeorge Rokos cudaBlocksPerGrid = ((loop_tripcount - 1) / cudaThreadsPerBlock) + 1; 723c13df8e5SGeorge Rokos } else { 724c13df8e5SGeorge Rokos // If we reach this point, then we have a non-combined construct, i.e. 725c13df8e5SGeorge Rokos // `teams distribute` with a nested `parallel for` and each team is 726c13df8e5SGeorge Rokos // assigned one iteration of the `distribute` loop. E.g.: 727c13df8e5SGeorge Rokos // 728c13df8e5SGeorge Rokos // #pragma omp target teams distribute 729c13df8e5SGeorge Rokos // for(...loop_tripcount...) { 730c13df8e5SGeorge Rokos // #pragma omp parallel for 731c13df8e5SGeorge Rokos // for(...) {} 732c13df8e5SGeorge Rokos // } 733c13df8e5SGeorge Rokos // 734c13df8e5SGeorge Rokos // Threads within a team will execute the iterations of the `parallel` 735c13df8e5SGeorge Rokos // loop. 736c13df8e5SGeorge Rokos cudaBlocksPerGrid = loop_tripcount; 737c13df8e5SGeorge Rokos } 7383de4cd12SGeorge Rokos DP("Using %d teams due to loop trip count %" PRIu64 " and number of " 7393de4cd12SGeorge Rokos "threads per block %d\n", cudaBlocksPerGrid, loop_tripcount, 7403de4cd12SGeorge Rokos cudaThreadsPerBlock); 7413de4cd12SGeorge Rokos } else { 7423de4cd12SGeorge Rokos cudaBlocksPerGrid = DeviceInfo.NumTeams[device_id]; 7433de4cd12SGeorge Rokos DP("Using default number of teams %d\n", DeviceInfo.NumTeams[device_id]); 7443de4cd12SGeorge Rokos } 7453de4cd12SGeorge Rokos } else if (team_num > DeviceInfo.BlocksPerGrid[device_id]) { 7463de4cd12SGeorge Rokos cudaBlocksPerGrid = DeviceInfo.BlocksPerGrid[device_id]; 7473de4cd12SGeorge Rokos DP("Capping number of teams to team limit %d\n", 7483de4cd12SGeorge Rokos DeviceInfo.BlocksPerGrid[device_id]); 7493de4cd12SGeorge Rokos } else { 7503de4cd12SGeorge Rokos cudaBlocksPerGrid = team_num; 7513de4cd12SGeorge Rokos DP("Using requested number of teams %d\n", team_num); 7523de4cd12SGeorge Rokos } 7533de4cd12SGeorge Rokos 7543de4cd12SGeorge Rokos // Run on the device. 7553de4cd12SGeorge Rokos DP("Launch kernel with %d blocks and %d threads\n", cudaBlocksPerGrid, 7563de4cd12SGeorge Rokos cudaThreadsPerBlock); 7573de4cd12SGeorge Rokos 7583de4cd12SGeorge Rokos err = cuLaunchKernel(KernelInfo->Func, cudaBlocksPerGrid, 1, 1, 7593de4cd12SGeorge Rokos cudaThreadsPerBlock, 1, 1, 0 /*bytes of shared memory*/, 0, &args[0], 0); 7603de4cd12SGeorge Rokos if (err != CUDA_SUCCESS) { 7613de4cd12SGeorge Rokos DP("Device kernel launch failed!\n"); 7623de4cd12SGeorge Rokos CUDA_ERR_STRING(err); 7633de4cd12SGeorge Rokos return OFFLOAD_FAIL; 7643de4cd12SGeorge Rokos } 7653de4cd12SGeorge Rokos 7663de4cd12SGeorge Rokos DP("Launch of entry point at " DPxMOD " successful!\n", 7673de4cd12SGeorge Rokos DPxPTR(tgt_entry_ptr)); 7683de4cd12SGeorge Rokos 769c1895235SJonas Hahnfeld CUresult sync_err = cuCtxSynchronize(); 770c1895235SJonas Hahnfeld if (sync_err != CUDA_SUCCESS) { 771c1895235SJonas Hahnfeld DP("Kernel execution error at " DPxMOD "!\n", DPxPTR(tgt_entry_ptr)); 772c1895235SJonas Hahnfeld CUDA_ERR_STRING(sync_err); 7733de4cd12SGeorge Rokos return OFFLOAD_FAIL; 7743de4cd12SGeorge Rokos } else { 7753de4cd12SGeorge Rokos DP("Kernel execution at " DPxMOD " successful!\n", DPxPTR(tgt_entry_ptr)); 7763de4cd12SGeorge Rokos } 7773de4cd12SGeorge Rokos 7783de4cd12SGeorge Rokos return OFFLOAD_SUCCESS; 7793de4cd12SGeorge Rokos } 7803de4cd12SGeorge Rokos 7813de4cd12SGeorge Rokos int32_t __tgt_rtl_run_target_region(int32_t device_id, void *tgt_entry_ptr, 7821546d319SGeorge Rokos void **tgt_args, ptrdiff_t *tgt_offsets, int32_t arg_num) { 7833de4cd12SGeorge Rokos // use one team and the default number of threads. 7843de4cd12SGeorge Rokos const int32_t team_num = 1; 7853de4cd12SGeorge Rokos const int32_t thread_limit = 0; 7863de4cd12SGeorge Rokos return __tgt_rtl_run_target_team_region(device_id, tgt_entry_ptr, tgt_args, 7871546d319SGeorge Rokos tgt_offsets, arg_num, team_num, thread_limit, 0); 7883de4cd12SGeorge Rokos } 7893de4cd12SGeorge Rokos 7903de4cd12SGeorge Rokos #ifdef __cplusplus 7913de4cd12SGeorge Rokos } 7923de4cd12SGeorge Rokos #endif 793