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 DLWRAP(cuGetErrorString, 2); 32 DLWRAP(cuLaunchKernel, 11); 33 34 DLWRAP(cuMemAlloc, 2); 35 DLWRAP(cuMemcpyDtoDAsync, 4); 36 37 DLWRAP(cuMemcpyDtoH, 3); 38 DLWRAP(cuMemcpyDtoHAsync, 4); 39 DLWRAP(cuMemcpyHtoD, 3); 40 DLWRAP(cuMemcpyHtoDAsync, 4); 41 42 DLWRAP(cuMemFree, 1); 43 DLWRAP(cuModuleGetFunction, 3); 44 DLWRAP(cuModuleGetGlobal, 4); 45 46 DLWRAP(cuModuleUnload, 1); 47 DLWRAP(cuStreamCreate, 2); 48 DLWRAP(cuStreamDestroy, 1); 49 DLWRAP(cuStreamSynchronize, 1); 50 DLWRAP(cuCtxSetCurrent, 1); 51 DLWRAP(cuDevicePrimaryCtxRelease, 1); 52 DLWRAP(cuDevicePrimaryCtxGetState, 3); 53 DLWRAP(cuDevicePrimaryCtxSetFlags, 2); 54 DLWRAP(cuDevicePrimaryCtxRetain, 2); 55 DLWRAP(cuModuleLoadDataEx, 5); 56 57 DLWRAP(cuDeviceCanAccessPeer, 3); 58 DLWRAP(cuCtxEnablePeerAccess, 2); 59 DLWRAP(cuMemcpyPeerAsync, 6); 60 61 DLWRAP_FINALIZE(); 62 63 #ifndef DYNAMIC_CUDA_PATH 64 #define DYNAMIC_CUDA_PATH "libcuda.so" 65 #endif 66 67 #define TARGET_NAME CUDA 68 #define DEBUG_PREFIX "Target " GETNAME(TARGET_NAME) " RTL" 69 70 static bool checkForCUDA() { 71 // return true if dlopen succeeded and all functions found 72 73 // Prefer _v2 versions of functions if found in the library 74 std::unordered_map<std::string, const char *> TryFirst = { 75 {"cuMemAlloc", "cuMemAlloc_v2"}, 76 {"cuMemFree", "cuMemFree_v2"}, 77 {"cuMemcpyDtoH", "cuMemcpyDtoH_v2"}, 78 {"cuMemcpyHtoD", "cuMemcpyHtoD_v2"}, 79 {"cuStreamDestroy", "cuStreamDestroy_v2"}, 80 {"cuModuleGetGlobal", "cuModuleGetGlobal_v2"}, 81 {"cuMemcpyDtoHAsync", "cuMemcpyDtoHAsync_v2"}, 82 {"cuMemcpyDtoDAsync", "cuMemcpyDtoDAsync_v2"}, 83 {"cuMemcpyHtoDAsync", "cuMemcpyHtoDAsync_v2"}, 84 {"cuDevicePrimaryCtxRelease", "cuDevicePrimaryCtxRelease_v2"}, 85 {"cuDevicePrimaryCtxSetFlags", "cuDevicePrimaryCtxSetFlags_v2"}, 86 }; 87 88 const char *CudaLib = DYNAMIC_CUDA_PATH; 89 void *DynlibHandle = dlopen(CudaLib, RTLD_NOW); 90 if (!DynlibHandle) { 91 DP("Unable to load library '%s': %s!\n", CudaLib, dlerror()); 92 return false; 93 } 94 95 for (size_t I = 0; I < dlwrap::size(); I++) { 96 const char *Sym = dlwrap::symbol(I); 97 98 auto It = TryFirst.find(Sym); 99 if (It != TryFirst.end()) { 100 const char *First = It->second; 101 void *P = dlsym(DynlibHandle, First); 102 if (P) { 103 DP("Implementing %s with dlsym(%s) -> %p\n", Sym, First, P); 104 *dlwrap::pointer(I) = P; 105 continue; 106 } 107 } 108 109 void *P = dlsym(DynlibHandle, Sym); 110 if (P == nullptr) { 111 DP("Unable to find '%s' in '%s'!\n", Sym, CudaLib); 112 return false; 113 } 114 DP("Implementing %s with dlsym(%s) -> %p\n", Sym, Sym, P); 115 116 *dlwrap::pointer(I) = P; 117 } 118 119 return true; 120 } 121 122 CUresult cuInit(unsigned X) { 123 // Note: Called exactly once from cuda rtl.cpp in a global constructor so 124 // does not need to handle being called repeatedly or concurrently 125 if (!checkForCUDA()) { 126 return CUDA_ERROR_INVALID_HANDLE; 127 } 128 return dlwrap_cuInit(X); 129 } 130