==> src/driver.c <==1/* The table, dlopen'd once, or injected. */
2#include "mesh/cuda_driver.h"
3#include "mesh/text.h"
4
5#include <dlfcn.h>
6#include <pthread.h>
7#include <stdlib.h>
8#include <string.h>
9
10extern const mesh_cu_name mesh_cu_result_names[];
11extern const size_t mesh_cu_result_names_len;
12
13static mesh_cuda_fns loaded;
14static const mesh_cuda_fns *current;
15static pthread_mutex_t mu = PTHREAD_MUTEX_INITIALIZER;
16static bool tried, ok;
17static char *load_err;
18
19const mesh_cuda_fns *mesh_cuda(void) { return current; }
20void mesh_cuda_set(const mesh_cuda_fns *fns) { current = fns; }
21bool mesh_cuda_injected(void) { return current != NULL && current != &loaded; }
22
23#define SYM(name) \
24 do { \
25 void *p = dlsym(lib, #name); \
26 if (!p) { \
27 load_err = mesh_fmt("cuda: libcuda.so.1 has no %s", #name); \
28 return false; \
29 } \
30 memcpy(&loaded.name, &p, sizeof p); \
31 } while (0)
32
33static bool load_all(void) {
34 void *lib = dlopen("libcuda.so.1", RTLD_NOW | RTLD_LOCAL);
35 if (!lib) {
36 const char *e = dlerror();
37 load_err = mesh_fmt("cuda: cannot open libcuda.so.1: %s", e ? e : "");
38 return false;
39 }
40 SYM(cuInit);
41 SYM(cuGetErrorName);
42 SYM(cuModuleGetLoadingMode);
43 SYM(cuDeviceGet);
44 SYM(cuDeviceGetName);
45 SYM(cuDeviceGetAttribute);
46 SYM(cuDevicePrimaryCtxRetain);
47 SYM(cuCtxSetCurrent);
48 SYM(cuCtxGetLimit);
49 SYM(cuCtxSetLimit);
50 SYM(cuDeviceGetDevResource);
51 SYM(cuDevSmResourceSplitByCount);
52 SYM(cuDevResourceGenerateDesc);
53 SYM(cuGreenCtxCreate);
54 SYM(cuCtxFromGreenCtx);
55 SYM(cuGreenCtxStreamCreate);
56 SYM(cuStreamCreate);
57 SYM(cuStreamDestroy_v2);
58 SYM(cuStreamQuery);
59 SYM(cuStreamSynchronize);
60 SYM(cuMemHostRegister_v2);
61 SYM(cuMemHostGetDevicePointer_v2);
62 SYM(cuModuleLoadData);
63 SYM(cuModuleGetFunction);
64 SYM(cuModuleUnload);
65 SYM(cuModuleGetGlobal_v2);
66 SYM(cuFuncGetAttribute);
67 SYM(cuFuncSetAttribute);
68 SYM(cuOccupancyMaxActiveBlocksPerMultiprocessor);
69 SYM(cuMemAlloc_v2);
70 SYM(cuMemFree_v2);
71 SYM(cuMemsetD8Async);
72 SYM(cuMemcpyDtoH_v2);
73 SYM(cuLaunchKernel);
74 return true;
75}
76
77bool mesh_cuda_load(char **err) {
78 pthread_mutex_lock(&mu);
79 if (!tried) {
80 tried = true;
81 ok = load_all();
82 if (ok && !current) current = &loaded;
83 }
84 bool r = ok;
85 if (!r) mesh_errf(err, "%s", load_err ? load_err : "cuda: not loaded");
86 pthread_mutex_unlock(&mu);
87 return r;
88}
89
90const char *mesh_cu_result_name(CUresult r) {
91 for (size_t i = 0; i < mesh_cu_result_names_len; i++)
92 if (mesh_cu_result_names[i].code == r) return mesh_cu_result_names[i].name;
93 return NULL;
94}
95
96char *mesh_cu_result_debug(CUresult r) {
97 const char *n = mesh_cu_result_name(r);
98 return n ? mesh_strdup(n) : mesh_fmt("cudaError_enum(%d)", r);
99}
100
101bool mesh_cu_ck(CUresult r, const char *what, char **err) {
102 if (r == CUDA_SUCCESS) return true;
103 const char *s = NULL;
104 if (current && current->cuGetErrorName) current->cuGetErrorName(r, &s);
105 if (s) return mesh_errf(err, "%s: %s", what, s);
106 char *d = mesh_cu_result_debug(r);
107 mesh_errf(err, "%s: %s", what, d);
108 free(d);
109 return false;
110}
111
112bool mesh_cu_ck_debug(CUresult r, const char *what, char **err) {
113 if (r == CUDA_SUCCESS) return true;
114 char *d = mesh_cu_result_debug(r);
115 mesh_errf(err, "%s: %s", what, d);
116 free(d);
117 return false;
118}