1 //===--- cuda/dynamic_cuda/cuda.pp ------------------------------- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Implement subset of cuda api by calling into cuda library via dlopen 10 // Does the dlopen/dlsym calls as part of the call to cuInit 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "cuda.h" 15 #include "Debug.h" 16 #include "dlwrap.h" 17 18 #include <string> 19 #include <unordered_map> 20 21 #include <dlfcn.h> 22 23 DLWRAP_INTERNAL(cuInit, 1); 24 25 DLWRAP(cuCtxGetDevice, 1); 26 DLWRAP(cuDeviceGet, 2); 27 DLWRAP(cuDeviceGetAttribute, 3); 28 DLWRAP(cuDeviceGetCount, 1); 29 DLWRAP(cuFuncGetAttribute, 3); 30 31 // Device info 32 DLWRAP(cuDeviceGetName, 3); 33 DLWRAP(cuDeviceTotalMem, 2); 34 DLWRAP(cuDriverGetVersion, 1); 35 36 DLWRAP(cuGetErrorString, 2); 37 DLWRAP(cuLaunchKernel, 11); 38 39 DLWRAP(cuMemAlloc, 2); 40 DLWRAP(cuMemAllocHost, 2); 41 DLWRAP(cuMemAllocManaged, 3); 42 43 DLWRAP(cuMemcpyDtoDAsync, 4); 44 DLWRAP(cuMemcpyDtoH, 3); 45 DLWRAP(cuMemcpyDtoHAsync, 4); 46 DLWRAP(cuMemcpyHtoD, 3); 47 DLWRAP(cuMemcpyHtoDAsync, 4); 48 49 DLWRAP(cuMemFree, 1); 50 DLWRAP(cuMemFreeHost, 1); 51 DLWRAP(cuModuleGetFunction, 3); 52 DLWRAP(cuModuleGetGlobal, 4); 53 54 DLWRAP(cuModuleUnload, 1); 55 DLWRAP(cuStreamCreate, 2); 56 DLWRAP(cuStreamDestroy, 1); 57 DLWRAP(cuStreamSynchronize, 1); 58 DLWRAP(cuCtxSetCurrent, 1); 59 DLWRAP(cuDevicePrimaryCtxRelease, 1); 60 DLWRAP(cuDevicePrimaryCtxGetState, 3); 61 DLWRAP(cuDevicePrimaryCtxSetFlags, 2); 62 DLWRAP(cuDevicePrimaryCtxRetain, 2); 63 DLWRAP(cuModuleLoadDataEx, 5); 64 65 DLWRAP(cuDeviceCanAccessPeer, 3); 66 DLWRAP(cuCtxEnablePeerAccess, 2); 67 DLWRAP(cuMemcpyPeerAsync, 6); 68 69 DLWRAP(cuCtxGetLimit, 2); 70 DLWRAP(cuCtxSetLimit, 2); 71 72 DLWRAP(cuEventCreate, 2); 73 DLWRAP(cuEventRecord, 2); 74 DLWRAP(cuStreamWaitEvent, 3); 75 DLWRAP(cuEventSynchronize, 1); 76 DLWRAP(cuEventDestroy, 1); 77 78 DLWRAP_FINALIZE(); 79 80 #ifndef DYNAMIC_CUDA_PATH 81 #define DYNAMIC_CUDA_PATH "libcuda.so" 82 #endif 83 84 #define TARGET_NAME CUDA 85 #define DEBUG_PREFIX "Target " GETNAME(TARGET_NAME) " RTL" 86 87 static bool checkForCUDA() { 88 // return true if dlopen succeeded and all functions found 89 90 // Prefer _v2 versions of functions if found in the library 91 std::unordered_map<std::string, const char *> TryFirst = { 92 {"cuMemAlloc", "cuMemAlloc_v2"}, 93 {"cuMemFree", "cuMemFree_v2"}, 94 {"cuMemcpyDtoH", "cuMemcpyDtoH_v2"}, 95 {"cuMemcpyHtoD", "cuMemcpyHtoD_v2"}, 96 {"cuStreamDestroy", "cuStreamDestroy_v2"}, 97 {"cuModuleGetGlobal", "cuModuleGetGlobal_v2"}, 98 {"cuMemcpyDtoHAsync", "cuMemcpyDtoHAsync_v2"}, 99 {"cuMemcpyDtoDAsync", "cuMemcpyDtoDAsync_v2"}, 100 {"cuMemcpyHtoDAsync", "cuMemcpyHtoDAsync_v2"}, 101 {"cuDevicePrimaryCtxRelease", "cuDevicePrimaryCtxRelease_v2"}, 102 {"cuDevicePrimaryCtxSetFlags", "cuDevicePrimaryCtxSetFlags_v2"}, 103 }; 104 105 const char *CudaLib = DYNAMIC_CUDA_PATH; 106 void *DynlibHandle = dlopen(CudaLib, RTLD_NOW); 107 if (!DynlibHandle) { 108 DP("Unable to load library '%s': %s!\n", CudaLib, dlerror()); 109 return false; 110 } 111 112 for (size_t I = 0; I < dlwrap::size(); I++) { 113 const char *Sym = dlwrap::symbol(I); 114 115 auto It = TryFirst.find(Sym); 116 if (It != TryFirst.end()) { 117 const char *First = It->second; 118 void *P = dlsym(DynlibHandle, First); 119 if (P) { 120 DP("Implementing %s with dlsym(%s) -> %p\n", Sym, First, P); 121 *dlwrap::pointer(I) = P; 122 continue; 123 } 124 } 125 126 void *P = dlsym(DynlibHandle, Sym); 127 if (P == nullptr) { 128 DP("Unable to find '%s' in '%s'!\n", Sym, CudaLib); 129 return false; 130 } 131 DP("Implementing %s with dlsym(%s) -> %p\n", Sym, Sym, P); 132 133 *dlwrap::pointer(I) = P; 134 } 135 136 return true; 137 } 138 139 CUresult cuInit(unsigned X) { 140 // Note: Called exactly once from cuda rtl.cpp in a global constructor so 141 // does not need to handle being called repeatedly or concurrently 142 if (!checkForCUDA()) { 143 return CUDA_ERROR_INVALID_HANDLE; 144 } 145 return dlwrap_cuInit(X); 146 } 147