9.2
general documentation
cs_base_cuda.h
Go to the documentation of this file.
1#ifndef CS_BASE_CUDA_H
2#define CS_BASE_CUDA_H
3
4/*============================================================================
5 * Definitions, global variables, and base functions for CUDA
6 *============================================================================*/
7
8/*
9 This file is part of code_saturne, a general-purpose CFD tool.
10
11 Copyright (C) 1998-2026 EDF S.A.
12
13 This program is free software; you can redistribute it and/or modify it under
14 the terms of the GNU General Public License as published by the Free Software
15 Foundation; either version 2 of the License, or (at your option) any later
16 version.
17
18 This program is distributed in the hope that it will be useful, but WITHOUT
19 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
21 details.
22
23 You should have received a copy of the GNU General Public License along with
24 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
25 Street, Fifth Floor, Boston, MA 02110-1301, USA.
26*/
27
28/*----------------------------------------------------------------------------*/
29
30#include "base/cs_defs.h"
31
32#if defined(HAVE_CUDA)
33
34/*----------------------------------------------------------------------------
35 * Standard C library headers
36 *----------------------------------------------------------------------------*/
37
38#if defined(HAVE_NCCL)
39#include <nccl.h>
40#endif
41
42/*----------------------------------------------------------------------------
43 * Local headers
44 *----------------------------------------------------------------------------*/
45
46#include "base/cs_base_accel.h"
47#include "base/cs_log.h"
48
49/*=============================================================================
50 * Macro definitions
51 *============================================================================*/
52
53#define CS_CUDA_CHECK(a) { \
54 cudaError_t _l_ret_code = a; \
55 if (cudaSuccess != _l_ret_code) { \
56 bft_error(__FILE__, __LINE__, 0, "[CUDA error] %d: %s\n running: %s", \
57 _l_ret_code, ::cudaGetErrorString(_l_ret_code), #a); \
58 } \
59 }
60
61#define CS_CUDA_CHECK_CALL(a, file_name, line_num) { \
62 cudaError_t _l_ret_code = a; \
63 if (cudaSuccess != _l_ret_code) { \
64 bft_error(file_name, line_num, 0, "[CUDA error] %d: %s\n running: %s", \
65 _l_ret_code, ::cudaGetErrorString(_l_ret_code), #a); \
66 } \
67 }
68
69/* For all current compute capabilities, the warp size is 32; If it ever
70 changes, it can be obtained through cudaDeviceProp, so we could then
71 replace this macro with a global variable */
72
73#define CS_CUDA_WARP_SIZE 32
74
75/*============================================================================
76 * Type definitions
77 *============================================================================*/
78
79/*=============================================================================
80 * Global variable definitions
81 *============================================================================*/
82
83extern int cs_glob_cuda_device_id;
84
85/* Other device parameters */
86
87extern int cs_glob_cuda_shared_mem_per_block;
88extern int cs_glob_cuda_max_threads_per_block;
89extern int cs_glob_cuda_max_block_size;
90extern int cs_glob_cuda_max_blocks;
91extern int cs_glob_cuda_n_mp; /* Number of multiprocessors */
92
93#if defined(HAVE_NCCL)
94
95extern ncclComm_t cs_glob_nccl_comm;
96
97/* NCCL Datatypes associated with code_saturne datatypes */
98extern ncclDataType_t cs_datatype_to_nccl[];
99
100#endif
101
102/* Allow graphs for kernel launches ? May interfere with profiling (nsys),
103 so can be deactivated. */
104
105extern bool cs_glob_cuda_allow_graph;
106
107/*============================================================================
108 * Semi-private function prototypes
109 *
110 * The following functions are intended to be used by the common
111 * host-device memory management functions from cs_base_accel.c, and
112 * not directly by the user.
113 *============================================================================*/
114
115/*----------------------------------------------------------------------------*/
116/*
117 * \brief Copy data from host to device.
118 *
119 * This is simply a wrapper over cudaMemcpy.
120 *
121 * A safety check is added.
122 *
123 * \param [out] dst pointer to destination data
124 * \param [in] src pointer to source data
125 * \param [in] size size of data to copy
126 */
127/*----------------------------------------------------------------------------*/
128
129void
130cs_cuda_copy_h2d(void *dst,
131 const void *src,
132 size_t size);
133
134/*----------------------------------------------------------------------------*/
135/*
136 * \brief Copy data from host to device, possibly returning on the host
137 * before the copy is finished.
138 *
139 * This is simply a wrapper over cudaMemcpyAsync.
140 *
141 * A safety check is added.
142 *
143 * \param [out] dst pointer to destination data
144 * \param [in] src pointer to source data
145 * \param [in] size size of data to copy
146 *
147 * \returns pointer to allocated memory.
148 */
149/*----------------------------------------------------------------------------*/
150
151void
152cs_cuda_copy_h2d_async(void *dst,
153 const void *src,
154 size_t size);
155
156/*----------------------------------------------------------------------------*/
157/*
158 * \brief Copy data from device to host.
159 *
160 * This is simply a wrapper over cudaMemcpy.
161 *
162 * A safety check is added.
163 *
164 * \param [out] dst pointer to destination data
165 * \param [in] src pointer to source data
166 * \param [in] size size of data to copy
167 *
168 * \returns pointer to allocated memory.
169 */
170/*----------------------------------------------------------------------------*/
171
172void
173cs_cuda_copy_d2h(void *dst,
174 const void *src,
175 size_t size);
176
177/*----------------------------------------------------------------------------*/
178/*
179 * \brief Copy data from host to device.
180 *
181 * This is simply a wrapper over cudaMemcpy.
182 *
183 * A safety check is added.
184 *
185 * \param [out] dst pointer to destination data
186 * \param [in] src pointer to source data
187 * \param [in] size size of data to copy
188 *
189 * \returns pointer to allocated memory.
190 */
191/*----------------------------------------------------------------------------*/
192
193void
194cs_cuda_copy_d2h_async(void *dst,
195 const void *src,
196 size_t size);
197
198/*----------------------------------------------------------------------------*/
199/*
200 * \brief Copy data from device to device.
201 *
202 * This is simply a wrapper over cudaMemcpy.
203 *
204 * A safety check is added.
205 *
206 * \param [out] dst pointer to destination data
207 * \param [in] src pointer to source data
208 * \param [in] size size of data to copy
209 */
210/*----------------------------------------------------------------------------*/
211
212void
213cs_cuda_copy_d2d(void *dst,
214 const void *src,
215 size_t size);
216
217/*----------------------------------------------------------------------------*/
218/*
219 * \brief Get host pointer for a managed or device pointer.
220 *
221 * This function can be called with a pointer inside an allocated block of
222 * memory, so is not restricted to values returned by CS_MALLOC_HD.
223 *
224 * This makes it possible to check whether a pointer to an array inside
225 * a larger array is shared or accessible from the device only
226 * (for example when grouping allocations).
227 *
228 * \param [in] ptr pointer to device data
229 *
230 * \return pointer to host data if shared or mapped at the CUDA level,
231 * NULL otherwise.
232 */
233/*----------------------------------------------------------------------------*/
234
235void *
236cs_cuda_get_host_ptr(const void *ptr);
237
238/*=============================================================================
239 * Inline function prototypes
240 *============================================================================*/
241
242/*----------------------------------------------------------------------------*/
255/*----------------------------------------------------------------------------*/
256
257static inline unsigned int
258cs_cuda_grid_size(cs_lnum_t n,
259 unsigned int block_size)
260{
261 return (n % block_size) ? n/block_size + 1 : n/block_size;
262}
263
264#if defined(__NVCC__)
265
266/*----------------------------------------------------------------------------
267 * Synchronize of copy a cs_real_t type array from the host to a device.
268 *
269 * parameters:
270 * val_h <-- pointer to host data
271 * n_vals <-- number of data values
272 * device_id <-- associated device id
273 * stream <-- associated stream (for async prefetch only)
274 * val_d --> matching pointer on device
275 * buf_d --> matching allocation pointer on device (should be freed
276 * after use if non-null)
277 *----------------------------------------------------------------------------*/
278
279template <typename T>
280void
281cs_sync_or_copy_h2d(const T *val_h,
282 cs_lnum_t n_vals,
283 int device_id,
284 cudaStream_t stream,
285 const T **val_d,
286 void **buf_d)
287{
288 const T *_val_d = NULL;
289 void *_buf_d = NULL;
290
291 if (val_h != NULL) {
292
293 cs_alloc_mode_t alloc_mode = cs_check_device_ptr(val_h);
294 size_t size = n_vals * sizeof(T);
295
296 if (alloc_mode == CS_ALLOC_HOST) {
297 CS_CUDA_CHECK(cudaMalloc(&_buf_d, size));
298 cs_cuda_copy_h2d(_buf_d, val_h, size);
299 _val_d = (const T *)_buf_d;
300 }
301 else {
302 _val_d = (const T *)cs_get_device_ptr_const((const void *)val_h);
303
304 if (alloc_mode < CS_ALLOC_HOST_DEVICE_SHARED)
305 cs_sync_h2d(val_h);
306 }
307
308 }
309
310 *val_d = _val_d;
311 *buf_d = _buf_d;
312}
313
314/*=============================================================================
315 * Public function prototypes
316 *============================================================================*/
317
318/*----------------------------------------------------------------------------*/
319/*
320 * \brief Return stream handle from stream pool.
321 *
322 * If the requested stream id is higher than the current number of streams,
323 * one or more new streams will be created, so that size of the stream pool
324 * matches at least stream_id+1.
325 *
326 * By default, the first stream (with id 0) will be used for most operations,
327 * while stream id 1 will be used for operations which can be done
328 * concurrently, such as memory prefetching.
329 *
330 * Additional streams can be used for independent tasks, though opportunities
331 * for this are limited in the current code (this would probably also require
332 * associating different MPI communicators with each task).
333 *
334 * \param [in] stream_id id or requested stream
335 *
336 * \returns handle to requested stream
337 */
338/*----------------------------------------------------------------------------*/
339
340cudaStream_t
341cs_cuda_get_stream(int stream_id);
342
343/*----------------------------------------------------------------------------*/
344/*
345 * \brief Return stream handle used for prefetching.
346 *
347 * By default, a single stream is created specifically for prefetching.
348 *
349 * \returns handle to prefetching stream
350 */
351/*----------------------------------------------------------------------------*/
352
353cudaStream_t
354cs_cuda_get_stream_prefetch(void);
355
356/*----------------------------------------------------------------------------*/
366/*----------------------------------------------------------------------------*/
367
368int
369cs_cuda_get_stream_id(cudaStream_t stream);
370
371/*----------------------------------------------------------------------------*/
386/*----------------------------------------------------------------------------*/
387
388void
389cs_cuda_get_2_stage_reduce_buffers(int stream_id,
390 cs_lnum_t n_elts,
391 size_t elt_size,
392 unsigned int grid_size,
393 void* &r_grid,
394 void* &r_reduce,
395 void* &r_host);
396
397#endif /* defined(__NVCC__) */
398
399/*----------------------------------------------------------------------------*/
400/*
401 * \brief Log information on available CUDA devices.
402 *
403 * \param[in] log_id id of log file in which to print information
404 */
405/*----------------------------------------------------------------------------*/
406
407extern "C" void
408cs_base_cuda_device_info(cs_log_t log_id);
409
410/*----------------------------------------------------------------------------*/
411/*
412 * \brief Log information on available CUDA version.
413 *
414 * \param[in] log_id id of log file in which to print information
415 */
416/*----------------------------------------------------------------------------*/
417
418extern "C" void
419cs_base_cuda_version_info(cs_log_t log_id);
420
421/*----------------------------------------------------------------------------*/
422/*
423 * \brief Log information on CUDA compiler.
424 *
425 * \param[in] log_id id of log file in which to print information
426 */
427/*----------------------------------------------------------------------------*/
428
429extern "C" void
430cs_base_cuda_compiler_info(cs_log_t log_id);
431
432/*----------------------------------------------------------------------------*/
438/*----------------------------------------------------------------------------*/
439
440extern "C" void
441cs_base_cuda_nccl_info(cs_log_t log_id);
442
443/*----------------------------------------------------------------------------*/
444/*
445 * \brief Set CUDA device based on MPI rank and number of devices.
446 *
447 * \param[in] comm associated MPI communicator
448 * \param[in] ranks_per_node number of ranks per node (min and max)
449 *
450 * \return selected device id, or -1 if no usable device is available
451 */
452/*----------------------------------------------------------------------------*/
453
454extern "C" int
455cs_base_cuda_select_default_device(void);
456
457/*----------------------------------------------------------------------------*/
458/*
459 * \brief Return currently selected CUDA devices.
460 *
461 * \return selected device id, or -1 if no usable device is available
462 */
463/*----------------------------------------------------------------------------*/
464
465extern "C" int
466cs_base_cuda_get_device(void);
467
468#endif /* CS_HAVE_CUDA */
469
470/*----------------------------------------------------------------------------*/
471
472#endif /* CS_BASE_CUDA_H */
int cs_lnum_t
local mesh entity id
Definition: cs_defs.h:325
cs_log_t
Definition: cs_log.h:44
void cs_sync_h2d(const void *ptr)
Synchronize data from host to device.
Definition: cs_mem.h:935
cs_alloc_mode_t cs_check_device_ptr(const void *ptr)
Check if a pointer is associated with a device.
Definition: cs_mem.h:727
const void * cs_get_device_ptr_const(const void *ptr)
Return matching device pointer for a given constant pointer.
Definition: cs_mem.h:687
cs_alloc_mode_t
Definition: cs_mem.h:46
@ CS_ALLOC_HOST
Definition: cs_mem.h:48
@ CS_ALLOC_HOST_DEVICE_SHARED
Definition: cs_mem.h:53