skip to content
==> 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}