Yet Another eXchange Tool 0.11.3
Loading...
Searching...
No Matches
xt_cuda.c
Go to the documentation of this file.
1
12/*
13 * Keywords:
14 * Maintainer: Jörg Behrens <behrens@dkrz.de>
15 * Moritz Hanke <hanke@dkrz.de>
16 * Thomas Jahns <jahns@dkrz.de>
17 * URL: https://dkrz-sw.gitlab-pages.dkrz.de/yaxt/
18 *
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions are
21 * met:
22 *
23 * Redistributions of source code must retain the above copyright notice,
24 * this list of conditions and the following disclaimer.
25 *
26 * Redistributions in binary form must reproduce the above copyright
27 * notice, this list of conditions and the following disclaimer in the
28 * documentation and/or other materials provided with the distribution.
29 *
30 * Neither the name of the DKRZ GmbH nor the names of its contributors
31 * may be used to endorse or promote products derived from this software
32 * without specific prior written permission.
33 *
34 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
35 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
36 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
37 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
38 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
39 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
40 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
41 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
42 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
43 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
44 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45 */
46#ifdef HAVE_CONFIG_H
47#include "config.h"
48#endif
49
50#include "xt_cuda.h"
51
52#include <cuda.h>
53#include <dlfcn.h>
54#include <stdbool.h>
55#include <stdio.h>
56#include <string.h>
57
58#include "core/core.h"
59#include "core/ppm_xfuncs.h"
60#include "xt_gpu.h"
61
62#ifdef XT_CUDA_NVTX_ENABLE
63#include <nvToolsExt.h>
64#endif
65
66static const char filename[] = "xt_cuda.c";
67
68#define MAX(a,b) ((a) >= (b) ? (a) : (b))
69
70#define STRINGIFY2(x) #x
71#define STRINGIFY(x) STRINGIFY2(x)
72
73#define DLSYM(name) \
74do { \
75 void * ptr = dlsym(libcuda_handle, STRINGIFY(name)); \
76 if (ptr != NULL) { \
77 *(void **)(&(func_ ## name)) = ptr; \
78 } else { \
79 load_successful = false; \
80 fprintf( \
81 stderr, "ERROR:failed to load routine \"%s\" " \
82 "from %s\n", STRINGIFY(name), lib); \
83 } \
84} while(0)
85
86#define CU_ERROR_CHECK(ret) \
87do{ \
88 CUresult err = ret; \
89 if(err != CUDA_SUCCESS) \
90 { \
91 char const * err_string; \
92 if (CUDA_SUCCESS != \
93 func_cuGetErrorString(err, &err_string)) \
94 err_string = "undefined error"; \
95 fprintf(stderr, "Cuda driver error %d %s:: %s\n", \
96 __LINE__, __func__, err_string); \
97 exit(EXIT_FAILURE); \
98 } \
99} while(0)
100
101static CUresult (*func_cuGetErrorString)(CUresult error, const char** pStr);
103 (void* data, CUpointer_attribute attribute, CUdeviceptr ptr);
104static CUresult (*func_cuMemAlloc)(CUdeviceptr* dptr, size_t bytesize);
105static CUresult (*func_cuMemFree)(CUdeviceptr dptr);
106static CUresult (*func_cuMemcpyDtoD)(
107 CUdeviceptr dstDevice, CUdeviceptr srcDevice, size_t ByteCount);
108static CUresult (*func_cuMemcpyHtoD)(
109 CUdeviceptr dstDevice, const void* srcHost, size_t ByteCount);
110static CUresult (*func_cuMemcpyDtoH)(
111 void* dstHost, CUdeviceptr srcDevice, size_t ByteCount);
112
113static void * xt_cuda_malloc(
114 size_t alloc_size, enum xt_memtype memtype) {
115
116 switch (memtype) {
117 default:
118 Xt_abort(
119 Xt_default_comm,
120 "ERROR(xt_cuda_malloc): unsupported memory type",
121 filename, __LINE__);
122 return NULL;
123 case (XT_MEMTYPE_HOST):
124 return xmalloc(alloc_size);
125 case (XT_MEMTYPE_DEVICE): {
126 CUdeviceptr dptr;
127 // cuMemAlloc fails for (alloc_size == 0)
128 CU_ERROR_CHECK(func_cuMemAlloc(&dptr, MAX(alloc_size,1)));
129 return (void*)dptr;
130 }
131 }
132}
133
134static void xt_cuda_free(void * ptr, enum xt_memtype memtype) {
135
136 switch (memtype) {
137 default:
138 Xt_abort(
139 Xt_default_comm,
140 "ERROR(xt_cuda_free): unsupported memory type",
141 filename, __LINE__);
142 break;
143 case (XT_MEMTYPE_HOST):
144 free(ptr);
145 break;
146 case (XT_MEMTYPE_DEVICE):
147 CU_ERROR_CHECK(func_cuMemFree((CUdeviceptr)ptr));
148 break;
149 }
150}
151
152static void xt_cuda_memcpy(
153 void * dst, void const * src, size_t buffer_size,
154 enum xt_memtype dst_memtype, enum xt_memtype src_memtype) {
155
156 if (src_memtype == dst_memtype) {
157 switch (src_memtype) {
158 default:
159 Xt_abort(
160 Xt_default_comm,
161 "ERROR(xt_cuda_memcpy): unsupported memory type",
162 filename, __LINE__);
163 break;
164 case (XT_MEMTYPE_HOST):
165 memcpy(dst, src, buffer_size);
166 break;
167 case (XT_MEMTYPE_DEVICE):
170 (CUdeviceptr)dst, (CUdeviceptr)src, buffer_size));
171 break;
172 }
173 } else {
174 switch (src_memtype) {
175 default:
176 Xt_abort(
177 Xt_default_comm,
178 "ERROR(xt_cuda_memcpy): unsupported source memory type",
179 filename, __LINE__);
180 break;
181 case (XT_MEMTYPE_HOST):
182 if (dst_memtype != XT_MEMTYPE_DEVICE)
183 Xt_abort(
184 Xt_default_comm,
185 "ERROR(xt_cuda_memcpy): unsupported destination memory type",
186 filename, __LINE__);
188 func_cuMemcpyHtoD((CUdeviceptr)dst, src, buffer_size));
189 break;
190 case (XT_MEMTYPE_DEVICE):
191 if (dst_memtype != XT_MEMTYPE_HOST)
192 Xt_abort(
193 Xt_default_comm,
194 "ERROR(xt_cuda_memcpy): unsupported destination memory type",
195 filename, __LINE__);
197 func_cuMemcpyDtoH(dst, (CUdeviceptr)src, buffer_size));
198 break;
199 }
200 }
201}
202
203static enum xt_memtype xt_cuda_get_memtype(const void *ptr) {
204
206
207 CUmemorytype memorytype;
208 CUresult ret =
210 &memorytype, CU_POINTER_ATTRIBUTE_MEMORY_TYPE, (CUdeviceptr)ptr);
211
213
214 // in case the call to cuPointerGetAttribute failed, we just assume that
215 // the pointer is a host pointer
216 return
217 ((ret == CUDA_SUCCESS) &&
218 (memorytype == CU_MEMORYTYPE_DEVICE))?
220}
221
222#ifndef XT_CUDA_NVTX_ENABLE
223static int dummy_instr_push(char const * XT_UNUSED(name)) {return 0;}
224static int dummy_instr_pop() {return 0;}
225#endif
226
227static int load_cuda_library(void) {
228
229 static int first_call = 1;
230 static bool load_successful = false;
231
232 if (!first_call) return load_successful;
233 first_call = 0;
234
235 static const char lib[] =
236#ifdef __linux__
237 "libcuda.so.1"
238#elif defined __APPLE__ && defined __MACH__
239 "libcuda.dylib"
240#else
241#warning "unsupported system, but trying libcuda.so.1"
242 "libcuda.so.1"
243#endif
244 ;
245 void *libcuda_handle = dlopen(lib, RTLD_NOW);
246
247 load_successful = libcuda_handle != NULL;
248
249 if (load_successful) {
250
251 // load required CUDA library functions
252 DLSYM(cuGetErrorString);
253 DLSYM(cuPointerGetAttribute);
254 DLSYM(cuMemAlloc);
255 DLSYM(cuMemFree);
256 DLSYM(cuMemcpyDtoD);
257 DLSYM(cuMemcpyHtoD);
258 DLSYM(cuMemcpyDtoH);
259
260 dlclose(libcuda_handle);
261
262 } else {
263
264 int print_warning = 1;
265
266 // check whether we are supposed to write a warning or not
267 char const * cuda_warning_env =
268 getenv("XT_CUDA_WARN_ON_MISSING_LIBCUDA");
269
270 if (cuda_warning_env) {
271 if (!strcmp(cuda_warning_env, "0")) print_warning = 0;
272 else if (!strcmp(cuda_warning_env, "1")) print_warning = 1;
273 else {
274 Xt_abort(
275 Xt_default_comm,
276 "invalid value of XT_CUDA_WARN_ON_MISSING_LIBCUDA "
277 "environment variable (has to be \"0\" or \"1\")",
278 filename, __LINE__);
279 }
280 }
281
282 if (print_warning) {
283 // warn user about failed loading of CUDA library
284 fputs(
285 "-----------------------------------------------------------------------\n"
286 "WARNING: yaxt was compiled with CUDA-support, but the library could not\n"
287 " be loaded. CUDA-support will be deactivated. Try setting\n"
288 " LD_LIBRARY_PATH to the location of libcuda.so.1 or set RPATH\n"
289 " accordingly.\n"
290 " To suppress this message set the\n"
291 " XT_CUDA_WARN_ON_MISSING_LIBCUDA environment variable to \"0\"\n"
292 "-----------------------------------------------------------------------\n",
293 stderr);
294 }
295 }
296
297 return load_successful;
298}
299
300static struct xt_gpu_vtable const cuda_vtable = {
302 .Free = xt_cuda_free,
303 .Memcpy = xt_cuda_memcpy,
304 .Get_memtype = xt_cuda_get_memtype,
305#ifdef XT_CUDA_NVTX_ENABLE
306 .Instr_push = nvtxRangePush,
307 .Instr_pop = nvtxRangePop,
308#else
309 .Instr_push = dummy_instr_push,
310 .Instr_pop = dummy_instr_pop,
311#endif
312};
313
314const struct xt_gpu_vtable *xt_cuda_init(void) {
315
316 return load_cuda_library() ? &cuda_vtable : (struct xt_gpu_vtable *)NULL;
317}
318
319/*
320 * Local Variables:
321 * c-basic-offset: 2
322 * coding: utf-8
323 * indent-tabs-mode: nil
324 * show-trailing-whitespace: t
325 * require-trailing-newline: t
326 * End:
327 */
#define XT_UNUSED(x)
Definition core.h:84
add versions of standard API functions not returning on error
#define xmalloc(size)
Definition ppm_xfuncs.h:70
void *(* Malloc)(size_t alloc_size, enum xt_memtype memtype)
Definition xt_gpu.h:75
char name[32]
Definition xt_config.c:93
static int dummy_instr_pop()
Definition xt_cuda.c:224
static const char filename[]
Definition xt_cuda.c:66
static int load_cuda_library(void)
Definition xt_cuda.c:227
#define DLSYM(name)
Definition xt_cuda.c:73
static CUresult(* func_cuMemcpyDtoH)(void *dstHost, CUdeviceptr srcDevice, size_t ByteCount)
Definition xt_cuda.c:110
static CUresult(* func_cuMemAlloc)(CUdeviceptr *dptr, size_t bytesize)
Definition xt_cuda.c:104
static void xt_cuda_free(void *ptr, enum xt_memtype memtype)
Definition xt_cuda.c:134
static CUresult(* func_cuPointerGetAttribute)(void *data, CUpointer_attribute attribute, CUdeviceptr ptr)
Definition xt_cuda.c:103
static CUresult(* func_cuGetErrorString)(CUresult error, const char **pStr)
Definition xt_cuda.c:101
static CUresult(* func_cuMemcpyDtoD)(CUdeviceptr dstDevice, CUdeviceptr srcDevice, size_t ByteCount)
Definition xt_cuda.c:106
static CUresult(* func_cuMemcpyHtoD)(CUdeviceptr dstDevice, const void *srcHost, size_t ByteCount)
Definition xt_cuda.c:108
#define CU_ERROR_CHECK(ret)
Definition xt_cuda.c:86
static int dummy_instr_push(char const *XT_UNUSED(name))
Definition xt_cuda.c:223
const struct xt_gpu_vtable * xt_cuda_init(void)
Definition xt_cuda.c:314
static void * xt_cuda_malloc(size_t alloc_size, enum xt_memtype memtype)
Definition xt_cuda.c:113
static struct xt_gpu_vtable const cuda_vtable
Definition xt_cuda.c:300
static void xt_cuda_memcpy(void *dst, void const *src, size_t buffer_size, enum xt_memtype dst_memtype, enum xt_memtype src_memtype)
Definition xt_cuda.c:152
static enum xt_memtype xt_cuda_get_memtype(const void *ptr)
Definition xt_cuda.c:203
static CUresult(* func_cuMemFree)(CUdeviceptr dptr)
Definition xt_cuda.c:105
#define MAX(a, b)
Definition xt_cuda.c:68
routines for using CUDA in yaxt
routines for using GPU devices
#define XT_GPU_INSTR_POP
Definition xt_gpu.h:60
xt_memtype
Definition xt_gpu.h:68
@ XT_MEMTYPE_HOST
Definition xt_gpu.h:69
@ XT_MEMTYPE_DEVICE
Definition xt_gpu.h:70
#define XT_GPU_INSTR_PUSH(arg)
Definition xt_gpu.h:59