MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
device.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2026, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
12#include "device.hpp"
13#include "forall.hpp"
14#include "occa.hpp"
15#ifdef MFEM_USE_CEED
17#endif
18#ifdef MFEM_USE_MPI
19#include "communication.hpp"
20#include "../linalg/hypre.hpp"
21#endif
22
23#include <unordered_map>
24#include <map>
25#include <sstream>
26#include <iomanip>
27
28namespace mfem
29{
30
31// Place the following variables in the mfem::internal namespace, so that they
32// will not be included in the doxygen documentation.
33namespace internal
34{
35
36#ifdef MFEM_USE_OCCA
37// Default occa::device used by MFEM.
38occa::device occaDevice;
39#endif
40
41#ifdef MFEM_USE_CEED
42Ceed ceed = NULL;
43
44ceed::BasisMap ceed_basis_map;
45ceed::RestrMap ceed_restr_map;
46#endif
47
48// Backends listed by priority, high to low:
49static const Backend::Id backend_list[Backend::NUM_BACKENDS] =
50{
55};
56
57// Backend names listed by priority, high to low:
58static const char *backend_name[Backend::NUM_BACKENDS] =
59{
60 "ceed-cuda", "occa-cuda", "raja-cuda", "cuda",
61 "ceed-hip", "raja-hip", "hip", "debug",
62 "occa-omp", "raja-omp", "omp",
63 "ceed-cpu", "occa-cpu", "raja-cpu", "cpu"
64};
65
66} // namespace mfem::internal
67
68
69// Initialize the unique global Device variable.
70Device Device::device_singleton;
71bool Device::device_env = false;
72bool Device::mem_host_env = false;
73bool Device::mem_device_env = false;
74bool Device::mem_types_set = false;
75
77{
78 if (GetEnv("MFEM_MEMORY") && !mem_host_env && !mem_device_env)
79 {
80 std::string mem_backend(GetEnv("MFEM_MEMORY"));
81 if (mem_backend == "host")
82 {
83 mem_host_env = true;
84 host_mem_type = MemoryType::HOST;
85 device_mem_type = MemoryType::HOST;
86 }
87 else if (mem_backend == "host32")
88 {
89 mem_host_env = true;
90 host_mem_type = MemoryType::HOST_32;
91 device_mem_type = MemoryType::HOST_32;
92 }
93 else if (mem_backend == "host64")
94 {
95 mem_host_env = true;
96 host_mem_type = MemoryType::HOST_64;
97 device_mem_type = MemoryType::HOST_64;
98 }
99 else if (mem_backend == "umpire")
100 {
101 mem_host_env = true;
102 host_mem_type = MemoryType::HOST_UMPIRE;
103 // Note: device_mem_type will be set to MemoryType::DEVICE_UMPIRE only
104 // when an actual device is configured -- this is done later in
105 // Device::UpdateMemoryTypeAndClass().
106 device_mem_type = MemoryType::HOST_UMPIRE;
107 }
108 else if (mem_backend == "debug")
109 {
110 mem_host_env = true;
111 host_mem_type = MemoryType::HOST_DEBUG;
112 // Note: device_mem_type will be set to MemoryType::DEVICE_DEBUG only
113 // when an actual device is configured -- this is done later in
114 // Device::UpdateMemoryTypeAndClass().
115 device_mem_type = MemoryType::HOST_DEBUG;
116 }
117 else if (false
118#ifdef MFEM_USE_CUDA
119 || mem_backend == "cuda"
120#endif
121#ifdef MFEM_USE_HIP
122 || mem_backend == "hip"
123#endif
124 )
125 {
126 mem_host_env = true;
127 host_mem_type = MemoryType::HOST;
128 mem_device_env = true;
129 device_mem_type = MemoryType::DEVICE;
130 }
131 else if (mem_backend == "uvm")
132 {
133 mem_host_env = true;
134 mem_device_env = true;
135 host_mem_type = MemoryType::MANAGED;
136 device_mem_type = MemoryType::MANAGED;
137 }
138 else
139 {
140 MFEM_ABORT("Unknown memory backend!");
141 }
142 mm.Configure(host_mem_type, device_mem_type);
143 }
144
145 if (GetEnv("MFEM_DEVICE"))
146 {
147 std::string device(GetEnv("MFEM_DEVICE"));
148 Configure(device);
149 device_env = true;
150 }
151
152 if (GetEnv("MFEM_GPU_AWARE_MPI"))
153 {
154 SetGPUAwareMPI(true);
155 }
156}
157
159{
160#ifdef MFEM_USE_MPI
162#endif
163 if ( device_env && !destroy_mm) { return; }
164 if (!device_env && destroy_mm && !mem_host_env)
165 {
166#ifdef MFEM_USE_CEED
167 // Destroy FES -> CeedBasis, CeedElemRestriction hash table contents
168 for (auto entry : internal::ceed_basis_map)
169 {
170 CeedBasisDestroy(&entry.second);
171 }
172 internal::ceed_basis_map.clear();
173 for (auto entry : internal::ceed_restr_map)
174 {
175 CeedElemRestrictionDestroy(&entry.second);
176 }
177 internal::ceed_restr_map.clear();
178 // Destroy Ceed context
179 CeedDestroy(&internal::ceed);
180#endif
181 mm.Destroy();
182 }
183 Get().ngpu = -1;
184 Get().backends = Backend::CPU;
185 Get().host_mem_type = MemoryType::HOST;
186 Get().host_mem_class = MemoryClass::HOST;
187 Get().device_mem_type = MemoryType::HOST;
188 Get().device_mem_class = MemoryClass::HOST;
189}
190
191void Device::Configure(const std::string &device, const int device_id)
192{
193 // If a device was configured via the environment, skip the configuration,
194 // and avoid the 'singleton_device' to destroy the mm.
195 if (device_env)
196 {
197 std::memcpy((void*)this, &Get(), sizeof(Device));
198 Get().destroy_mm = false;
199 return;
200 }
201
202 std::map<std::string, Backend::Id> bmap;
203 for (int i = 0; i < Backend::NUM_BACKENDS; i++)
204 {
205 bmap[internal::backend_name[i]] = internal::backend_list[i];
206 }
207 // auto-detect GPU configurations
208 // assumes only one of HIP or CUDA are available
209#ifdef MFEM_USE_HIP
210 bmap["gpu"] = Backend::HIP;
211#ifdef MFEM_USE_RAJA
212 bmap["raja-gpu"] = Backend::RAJA_HIP;
213#endif
214#ifdef MFEM_USE_CEED
215 bmap["ceed-gpu"] = Backend::CEED_HIP;
216#endif
217 // no OCCA+HIP?
218#elif defined(MFEM_USE_CUDA)
219 bmap["gpu"] = Backend::CUDA;
220#ifdef MFEM_USE_RAJA
221 bmap["raja-gpu"] = Backend::RAJA_CUDA;
222#endif
223#ifdef MFEM_USE_CEED
224 bmap["ceed-gpu"] = Backend::CEED_CUDA;
225#endif
226#ifdef MFEM_USE_OCCA
227 bmap["occa-gpu"] = Backend::OCCA_CUDA;
228#endif
229#endif
230 std::string device_option;
231 std::string::size_type beg = 0, end;
232 while (1)
233 {
234 end = device.find(',', beg);
235 end = (end != std::string::npos) ? end : device.size();
236 const std::string bname = device.substr(beg, end - beg);
237 const auto option = bname.find(':');
238 const std::string backend = (option != std::string::npos) ?
239 bname.substr(0, option) : bname;
240 const auto it = bmap.find(backend);
241 MFEM_VERIFY(it != bmap.end(), "Invalid backend name: '" << backend << '\'');
242 Get().MarkBackend(it->second);
243 if (option != std::string::npos)
244 {
245 device_option += bname.substr(option);
246 }
247 if (end == device.size()) { break; }
248 beg = end + 1;
249 }
250
251 // OCCA_CUDA and CEED_CUDA need CUDA or RAJA_CUDA:
254 {
255 Get().MarkBackend(Backend::CUDA);
256 }
257 // CEED_HIP needs HIP:
259 {
260 Get().MarkBackend(Backend::HIP);
261 }
262 // OCCA_OMP will use OMP or RAJA_OMP unless MFEM_USE_OPENMP=NO:
263#ifdef MFEM_USE_OPENMP
265 {
266 Get().MarkBackend(Backend::OMP);
267 }
268#endif
269
270 // Perform setup.
271 Get().Setup(device_option, device_id);
272
273 // Configure the host/device MemoryType/MemoryClass.
274 Get().UpdateMemoryTypeAndClass(device_option);
275
276 // Copy all data members from the global 'singleton_device' into '*this'.
277 if (this != &Get()) { std::memcpy((void*)this, &Get(), sizeof(Device)); }
278
279 // Only '*this' will call the MemoryManager::Destroy() method.
280 destroy_mm = true;
281
282#ifdef MFEM_USE_MPI
283#if defined(HYPRE_USING_GPU) && (MFEM_HYPRE_VERSION >= 23100)
284 // Skip the call to Hypre::InitDevice() if HYPRE is not initialized, e.g.
285 // * if running a serial code
286 // * if running with the environment variable MFEM_DEVICE set.
287 if (HYPRE_Initialized())
288 {
290 }
291#endif
292#endif
293}
294
295// static method
297{
298 // If the device and/or the MemoryTypes are configured through the
299 // environment (variables 'MFEM_DEVICE', 'MFEM_MEMORY'), ignore calls to this
300 // method.
301 if (mem_host_env || mem_device_env || device_env) { return; }
302
303 MFEM_VERIFY(!IsConfigured(), "the default MemoryTypes can only be set before"
304 " Device construction and configuration");
305 MFEM_VERIFY(IsHostMemory(h_mt),
306 "invalid host MemoryType, h_mt = " << (int)h_mt);
307 MFEM_VERIFY(IsDeviceMemory(d_mt) || d_mt == h_mt,
308 "invalid device MemoryType, d_mt = " << (int)d_mt
309 << " (h_mt = " << (int)h_mt << ')');
310
311 Get().host_mem_type = h_mt;
312 Get().device_mem_type = d_mt;
313 mem_types_set = true;
314
315 // h_mt and d_mt will be set as dual to each other during configuration by
316 // the call mm.Configure(...) in UpdateMemoryTypeAndClass()
317}
318
319void Device::Print(std::ostream &os)
320{
321 os << "Device configuration: ";
322 bool add_comma = false;
323 for (int i = 0; i < Backend::NUM_BACKENDS; i++)
324 {
325 if (backends & internal::backend_list[i])
326 {
327 if (add_comma) { os << ','; }
328 add_comma = true;
329 os << internal::backend_name[i];
330 }
331 }
332 os << '\n';
333#ifdef MFEM_USE_CEED
335 {
336 const char *ceed_backend;
337 CeedGetResource(internal::ceed, &ceed_backend);
338 os << "libCEED backend: " << ceed_backend << '\n';
339 }
340#endif
341 os << "Memory configuration: "
342 << MemoryTypeName[static_cast<int>(host_mem_type)];
344 {
345 os << ',' << MemoryTypeName[static_cast<int>(device_mem_type)];
346 }
347#ifdef MFEM_USE_MPI
350 {
351 os << "\nUse GPU-aware MPI: " << (GetGPUAwareMPI() ? "yes" : "no");
352 }
353#endif
354 os << std::endl;
355}
356
357void Device::UpdateMemoryTypeAndClass(const std::string &device_option)
358{
359 const bool debug = Device::Allows(Backend::DEBUG_DEVICE);
360 const bool device = Device::Allows(Backend::DEVICE_MASK);
361
362#ifdef MFEM_USE_UMPIRE
363 // If MFEM has been compiled with Umpire support, use it as the default
364 if (!mem_host_env && !mem_types_set)
365 {
366 host_mem_type = MemoryType::HOST_UMPIRE;
367 if (!mem_device_env)
368 {
369 device_mem_type = MemoryType::HOST_UMPIRE;
370 }
371 }
372#endif
373
374 // Enable the device memory type
375 if (device)
376 {
377 if (!mem_device_env)
378 {
379 if (mem_host_env)
380 {
381 switch (host_mem_type)
382 {
384 device_mem_type = MemoryType::DEVICE_UMPIRE;
385 break;
387 device_mem_type = MemoryType::DEVICE_DEBUG;
388 break;
389 default:
390 device_mem_type = MemoryType::DEVICE;
391 }
392 }
393 else if (!mem_types_set)
394 {
395#ifndef MFEM_USE_UMPIRE
396 device_mem_type = MemoryType::DEVICE;
397#else
398 device_mem_type = MemoryType::DEVICE_UMPIRE;
399#endif
400 }
401 }
402 device_mem_class = MemoryClass::DEVICE;
403 }
404
405 // Enable the UVM shortcut when requested
406 if (device && device_option.find(":uvm") != std::string::npos)
407 {
408 host_mem_type = MemoryType::MANAGED;
409 device_mem_type = MemoryType::MANAGED;
410 }
411
412 // Enable the DEBUG mode when requested
413 if (debug)
414 {
415 host_mem_type = MemoryType::HOST_DEBUG;
416 device_mem_type = MemoryType::DEVICE_DEBUG;
417 }
418
419 MFEM_VERIFY(!device || IsDeviceMemory(device_mem_type),
420 "invalid device memory configuration!");
421
422 // Update the memory manager with the new settings
423 mm.Configure(host_mem_type, device_mem_type);
424}
425
426// static method
428{
429 if (Get().ngpu >= 0) { return Get().ngpu; }
430#if defined(MFEM_USE_CUDA)
431 return CuGetDeviceCount();
432#elif defined(MFEM_USE_HIP)
433 int ngpu;
434 MFEM_GPU_CHECK(hipGetDeviceCount(&ngpu));
435 return ngpu;
436#else
437 MFEM_ABORT("Unable to query number of available devices without"
438 " MFEM_USE_CUDA or MFEM_USE_HIP!");
439 return -1;
440#endif
441}
442
443static void CudaDeviceSetup(const int dev, int &ngpu)
444{
445#ifdef MFEM_USE_CUDA
446 ngpu = CuGetDeviceCount();
447 MFEM_VERIFY(ngpu > 0, "No CUDA device found!");
448 MFEM_GPU_CHECK(cudaSetDevice(dev));
449#else
450 MFEM_CONTRACT_VAR(dev);
451 MFEM_CONTRACT_VAR(ngpu);
452#endif
453}
454
455static void HipDeviceSetup(const int dev, int &ngpu)
456{
457#ifdef MFEM_USE_HIP
458 MFEM_GPU_CHECK(hipGetDeviceCount(&ngpu));
459 MFEM_VERIFY(ngpu > 0, "No HIP device found!");
460 MFEM_GPU_CHECK(hipSetDevice(dev));
461#else
462 MFEM_CONTRACT_VAR(dev);
463 MFEM_CONTRACT_VAR(ngpu);
464#endif
465}
466
467static void RajaDeviceSetup(const int dev, int &ngpu)
468{
469#ifdef MFEM_USE_CUDA
470 CudaDeviceSetup(dev, ngpu);
471#elif defined(MFEM_USE_HIP)
472 HipDeviceSetup(dev, ngpu);
473#else
474 MFEM_CONTRACT_VAR(dev);
475 MFEM_CONTRACT_VAR(ngpu);
476#endif
477}
478
479static void OccaDeviceSetup(const int dev)
480{
481#ifdef MFEM_USE_OCCA
482 const int cpu = Device::Allows(Backend::OCCA_CPU);
483 const int omp = Device::Allows(Backend::OCCA_OMP);
484 const int cuda = Device::Allows(Backend::OCCA_CUDA);
485 if (cpu + omp + cuda > 1)
486 {
487 MFEM_ABORT("Only one OCCA backend can be configured at a time!");
488 }
489 if (cuda)
490 {
491#if OCCA_CUDA_ENABLED
492 std::string mode("mode: 'CUDA', device_id : ");
493 internal::occaDevice.setup(mode.append(1,'0'+dev));
494#else
495 MFEM_ABORT("the OCCA CUDA backend requires OCCA built with CUDA!");
496#endif
497 }
498 else if (omp)
499 {
500#if OCCA_OPENMP_ENABLED
501 internal::occaDevice.setup("mode: 'OpenMP'");
502#else
503 MFEM_ABORT("the OCCA OpenMP backend requires OCCA built with OpenMP!");
504#endif
505 }
506 else
507 {
508 internal::occaDevice.setup("mode: 'Serial'");
509 }
510
511 std::string mfemDir;
512 if (occa::io::exists(MFEM_INSTALL_DIR "/include/mfem/"))
513 {
514 mfemDir = MFEM_INSTALL_DIR "/include/mfem/";
515 }
516 else if (occa::io::exists(MFEM_SOURCE_DIR))
517 {
518 mfemDir = MFEM_SOURCE_DIR;
519 }
520 else
521 {
522 MFEM_ABORT("Cannot find OCCA kernels in MFEM_INSTALL_DIR or MFEM_SOURCE_DIR");
523 }
524
525 occa::io::addLibraryPath("mfem", mfemDir);
526 occa::loadKernels("mfem");
527#else
528 MFEM_CONTRACT_VAR(dev);
529 MFEM_ABORT("the OCCA backends require MFEM built with MFEM_USE_OCCA=YES");
530#endif
531}
532
533static void CeedDeviceSetup(const char* ceed_spec)
534{
535#ifdef MFEM_USE_CEED
536 CeedInit(ceed_spec, &internal::ceed);
537 const char *ceed_backend;
538 CeedGetResource(internal::ceed, &ceed_backend);
539 if (strcmp(ceed_spec, ceed_backend) && strcmp(ceed_spec, "/cpu/self") &&
540 strcmp(ceed_spec, "/gpu/hip"))
541 {
542 mfem::out << std::endl << "WARNING!!!\n"
543 "libCEED is not using the requested backend!!!\n"
544 "WARNING!!!\n" << std::endl;
545 }
546#ifdef MFEM_DEBUG
547 CeedSetErrorHandler(internal::ceed, CeedErrorStore);
548#endif
549#else
550 MFEM_CONTRACT_VAR(ceed_spec);
551#endif
552}
553
554void Device::Setup(const std::string &device_option, const int device_id)
555{
556 MFEM_VERIFY(ngpu == -1, "the mfem::Device is already configured!");
557
558 ngpu = 0;
559 dev = device_id;
560#ifndef MFEM_USE_CUDA
561 MFEM_VERIFY(!Allows(Backend::CUDA_MASK),
562 "the CUDA backends require MFEM built with MFEM_USE_CUDA=YES");
563#endif
564#ifndef MFEM_USE_HIP
565 MFEM_VERIFY(!Allows(Backend::HIP_MASK),
566 "the HIP backends require MFEM built with MFEM_USE_HIP=YES");
567#endif
568#ifndef MFEM_USE_RAJA
569 MFEM_VERIFY(!Allows(Backend::RAJA_MASK),
570 "the RAJA backends require MFEM built with MFEM_USE_RAJA=YES");
571#endif
572#ifndef MFEM_USE_OPENMP
574 "the OpenMP and RAJA OpenMP backends require MFEM built with"
575 " MFEM_USE_OPENMP=YES");
576#endif
577#ifndef MFEM_USE_CEED
578 MFEM_VERIFY(!Allows(Backend::CEED_MASK),
579 "the CEED backends require MFEM built with MFEM_USE_CEED=YES");
580#endif
581 if (Allows(Backend::CUDA)) { CudaDeviceSetup(dev, ngpu); }
582 if (Allows(Backend::HIP)) { HipDeviceSetup(dev, ngpu); }
584 {
585 RajaDeviceSetup(dev, ngpu);
586 }
587 // The check for MFEM_USE_OCCA is in the function OccaDeviceSetup().
588 if (Allows(Backend::OCCA_MASK)) { OccaDeviceSetup(dev); }
590 {
591 int ceed_cpu = Allows(Backend::CEED_CPU);
592 int ceed_cuda = Allows(Backend::CEED_CUDA);
593 int ceed_hip = Allows(Backend::CEED_HIP);
594 MFEM_VERIFY(ceed_cpu + ceed_cuda + ceed_hip == 1,
595 "Only one CEED backend can be enabled at a time!");
596
597 // NOTE: libCEED's /gpu/cuda/gen and /gpu/hip/gen backends are non-
598 // deterministic!
599 const char *ceed_spec_search =
600 Allows(Backend::CEED_CPU) ? ":/cpu/self" :
601 (Allows(Backend::CEED_CUDA) ? ":/gpu/cuda" :
602 (Allows(Backend::CEED_HIP) ? ":/gpu/hip" : ""));
603 const char *ceed_spec_default =
604 Allows(Backend::CEED_CPU) ? "/cpu/self" :
605 (Allows(Backend::CEED_CUDA) ? "/gpu/cuda/gen" :
606 (Allows(Backend::CEED_HIP) ? "/gpu/hip/gen" : ""));
607 std::string::size_type beg = device_option.find(ceed_spec_search), end;
608 if (beg == std::string::npos)
609 {
610 CeedDeviceSetup(ceed_spec_default);
611 }
612 else
613 {
614 end = device_option.find(':', beg + 1);
615 end = (end != std::string::npos) ? end : device_option.size();
616 CeedDeviceSetup(device_option.substr(beg + 1, end - beg - 1).c_str());
617 }
618 }
619 if (Allows(Backend::DEBUG_DEVICE)) { ngpu = 1; }
620}
621
623{
624 // from HYPRE's hypre_GetPointerLocation
626#if defined(MFEM_USE_CUDA)
627 struct cudaPointerAttributes attr;
628
629#if (CUDART_VERSION >= 11000)
630 MFEM_GPU_CHECK(cudaPointerGetAttributes(&attr, ptr));
631#else
632 cudaPointerGetAttributes(&attr, ptr);
633 if (err != cudaSuccess)
634 {
635 /* clear the error */
636 cudaGetLastError();
637 }
638#endif
639 switch (attr.type)
640 {
641 case cudaMemoryTypeUnregistered:
642 // host
643 break;
644 case cudaMemoryTypeHost:
646 break;
647 case cudaMemoryTypeDevice:
648 res = MemoryType::DEVICE;
649 break;
650 case cudaMemoryTypeManaged:
652 break;
653 }
654
655#elif defined(MFEM_USE_HIP)
656 struct hipPointerAttribute_t attr;
657
658 hipError_t error = hipPointerGetAttributes(&attr, ptr);
659 if (error != hipSuccess)
660 {
661 if (error == hipErrorInvalidValue)
662 {
663 // host memory
664 /* clear the error */
665 (void)hipGetLastError();
666 }
667 else
668 {
669 MFEM_GPU_CHECK(error);
670 }
671 }
672 else if (attr.isManaged)
673 {
675 }
676#if (HIP_VERSION_MAJOR >= 6)
677 else if (attr.type == hipMemoryTypeDevice)
678#else // (HIP_VERSION_MAJOR < 6)
679 else if (attr.memoryType == hipMemoryTypeDevice)
680#endif // (HIP_VERSION_MAJOR >= 6)
681 {
682 res = MemoryType::DEVICE;
683 }
684#if (HIP_VERSION_MAJOR >= 6)
685 else if (attr.type == hipMemoryTypeHost)
686#else // (HIP_VERSION_MAJOR < 6)
687 else if (attr.memoryType == hipMemoryTypeHost)
688#endif // (HIP_VERSION_MAJOR >= 6)
689 {
691 }
692#if (HIP_VERSION_MAJOR >= 6)
693 else if (attr.type == hipMemoryTypeUnregistered)
694 {
695 // host memory
696 }
697#endif
698#else
699 MFEM_CONTRACT_VAR(ptr);
700#endif
701 return res;
702}
703
704void Device::DeviceMem(size_t *free, size_t *total)
705{
706#if defined(MFEM_USE_CUDA)
707 cudaMemGetInfo(free, total);
708#elif defined(MFEM_USE_HIP)
709 MFEM_GPU_CHECK(hipMemGetInfo(free, total));
710#else
711 // not compiled with GPU support
712 if (free)
713 {
714 *free = 0;
715 }
716 if (*total)
717 {
718 *total = 0;
719 }
720#endif
721}
722
723std::string Device::GetUUID(const int device_id)
724{
725 std::stringstream res;
726#if defined(MFEM_USE_CUDA)
727 cudaDeviceProp prop;
728 MFEM_GPU_CHECK(cudaGetDeviceProperties(&prop, device_id));
729 for (int i = 0; i < 16; ++i)
730 {
731 const unsigned b = static_cast<unsigned char>(prop.uuid.bytes[i]);
732 res << std::setfill('0') << std::setw(2) << std::hex << b;
733 }
734#elif defined(MFEM_USE_HIP)
735 hipUUID uuid;
736 MFEM_GPU_CHECK(hipDeviceGetUuid(&uuid, device_id));
737 for (int i = 0; i < 16; ++i)
738 {
739 const unsigned b = static_cast<unsigned char>(uuid.bytes[i]);
740 res << std::setfill('0') << std::setw(2) << std::hex << b;
741 }
742#endif
743 return res.str();
744}
745
747{
748#if defined(MFEM_USE_CUDA)
749 int res;
750 cudaDeviceGetAttribute(&res, cudaDevAttrMultiProcessorCount, dev);
751 return res;
752#elif defined(MFEM_USE_HIP)
753 int res;
754 MFEM_GPU_CHECK(
755 hipDeviceGetAttribute(&res, hipDeviceAttributeMultiprocessorCount, dev));
756 return res;
757#else
758 // not compiled with GPU support
759 MFEM_CONTRACT_VAR(dev);
760 return 0;
761#endif
762}
763
765{
766 int dev = 0;
767#if defined(MFEM_USE_CUDA)
768 cudaGetDevice(&dev);
769#elif defined(MFEM_USE_HIP)
770 MFEM_GPU_CHECK(hipGetDevice(&dev));
771#endif
772 return NumMultiprocessors(dev);
773}
774
776{
777#if defined(MFEM_USE_CUDA)
778 int res;
779 cudaDeviceGetAttribute(&res, cudaDevAttrWarpSize, dev);
780 return res;
781#elif defined(MFEM_USE_HIP)
782 int res;
783 MFEM_GPU_CHECK(hipDeviceGetAttribute(&res, hipDeviceAttributeWarpSize, dev));
784 return res;
785#else
786 // not compiled with GPU support
787 MFEM_CONTRACT_VAR(dev);
788 return 0;
789#endif
790}
791
793{
794 int dev = 0;
795#if defined(MFEM_USE_CUDA)
796 cudaGetDevice(&dev);
797#elif defined(MFEM_USE_HIP)
798 MFEM_GPU_CHECK(hipGetDevice(&dev));
799#endif
800 return WarpSize(dev);
801}
802
803} // namespace mfem
The MFEM Device class abstracts hardware devices such as GPUs, as well as programming models such as ...
Definition device.hpp:129
~Device()
Destructor.
Definition device.cpp:158
static void DeviceMem(size_t *free, size_t *total)
Gets the free and total memory on the device.
Definition device.cpp:704
void Configure(const std::string &device, const int device_id=0)
Configure the Device backends.
Definition device.cpp:191
static void SetGPUAwareMPI(const bool force=true)
Manually set the status of GPU-aware MPI flag for use in MPI communication routines which have optimi...
Definition device.hpp:315
static int NumMultiprocessors()
Same as NumMultiprocessors(int), for the currently active device.
Definition device.cpp:764
static bool IsConfigured()
Return true if Configure() has been called previously.
Definition device.hpp:246
static MemoryType QueryMemoryType(const void *ptr)
Definition device.cpp:622
static std::string GetUUID(const int device_id=0)
Definition device.cpp:723
void Print(std::ostream &os=mfem::out)
Print the configuration of the MFEM virtual device object.
Definition device.cpp:319
static bool Allows(unsigned long b_mask)
Return true if any of the backends in the backend mask, b_mask, are allowed.
Definition device.hpp:271
static void SetMemoryTypes(MemoryType h_mt, MemoryType d_mt)
Set the default host and device MemoryTypes, h_mt and d_mt.
Definition device.cpp:296
static bool GetGPUAwareMPI()
Get the status of GPU-aware MPI flag.
Definition device.hpp:319
static int WarpSize()
Same as WarpSize(int), for the currently active device.
Definition device.cpp:792
static int GetDeviceCount()
Get the number of available devices (may be called before configuration).
Definition device.cpp:427
Device()
Default constructor. Unless Configure() is called later, the default Backend::CPU will be used.
Definition device.cpp:76
static void InitDevice()
Configure HYPRE's compute and memory policy.
Definition hypre.cpp:50
static void Finalize()
Finalize hypre (called automatically at program exit if Hypre::Init() has been called).
Definition hypre.cpp:75
void Configure(const MemoryType h_mt, const MemoryType d_mt)
Configure the Memory manager with given default host and device types. This method will be called whe...
void Destroy()
Free all the device memories.
static bool IsFinalized()
Return true if MPI has been finalized.
static bool IsInitialized()
Return true if MPI has been initialized.
real_t b
Definition lissajous.cpp:42
std::unordered_map< const BasisKey, CeedBasis, BasisHash > BasisMap
Definition util.hpp:144
std::unordered_map< const RestrKey, CeedElemRestriction, RestrHash > RestrMap
Definition util.hpp:165
MFEM_HOST_DEVICE tensor< T, n, n > dev(const tensor< T, n, n > &A)
Calculates the deviator of a matrix (rank-2 tensor)
Definition tensor.hpp:1354
bool IsDeviceMemory(MemoryType mt)
Return true if the given memory type is in MemoryClass::DEVICE.
const char * GetEnv(const char *name)
Wrapper for std::getenv.
Definition globals.cpp:79
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition globals.hpp:66
MemoryManager mm
The (single) global memory manager object.
int CuGetDeviceCount()
Get the number of CUDA devices.
Definition cuda.cpp:185
bool IsHostMemory(MemoryType mt)
Return true if the given memory type is in MemoryClass::HOST.
const char * MemoryTypeName[MemoryTypeSize]
Memory type names, used during Device:: configuration.
OutStream err(std::cerr)
Global stream used by the library for standard error output. Initially it uses the same std::streambu...
Definition globals.hpp:71
MemoryType
Memory types supported by MFEM.
@ HOST_32
Host memory; aligned at 32 bytes.
@ HOST_64
Host memory; aligned at 64 bytes.
@ HOST
Host memory; using new[] and delete[].
@ HOST_PINNED
Host memory: pinned (page-locked)
@ HOST_DEBUG
Host memory; allocated from a "host-debug" pool.
@ DEVICE
Device memory; using CUDA or HIP *Malloc and *Free.
Id
In the documentation below, we use square brackets to indicate the type of the backend: host or devic...
Definition device.hpp:39
@ RAJA_OMP
[host] RAJA OpenMP backend. Enabled when MFEM_USE_RAJA = YES and MFEM_USE_OPENMP = YES.
Definition device.hpp:53
@ RAJA_CUDA
[device] RAJA CUDA backend. Enabled when MFEM_USE_RAJA = YES and MFEM_USE_CUDA = YES.
Definition device.hpp:56
@ DEBUG_DEVICE
[device] Debug backend: host memory is READ/WRITE protected while a device is in use....
Definition device.hpp:83
@ RAJA_CPU
[host] RAJA CPU backend: sequential execution on each MPI rank. Enabled when MFEM_USE_RAJA = YES.
Definition device.hpp:50
@ OMP
[host] OpenMP backend. Enabled when MFEM_USE_OPENMP = YES.
Definition device.hpp:43
@ HIP
[device] HIP backend. Enabled when MFEM_USE_HIP = YES.
Definition device.hpp:47
@ OCCA_OMP
[host] OCCA OpenMP backend. Enabled when MFEM_USE_OCCA = YES.
Definition device.hpp:64
@ RAJA_HIP
[device] RAJA HIP backend. Enabled when MFEM_USE_RAJA = YES and MFEM_USE_HIP = YES.
Definition device.hpp:59
@ OCCA_CUDA
[device] OCCA CUDA backend. Enabled when MFEM_USE_OCCA = YES and MFEM_USE_CUDA = YES.
Definition device.hpp:67
@ CEED_CPU
[host] CEED CPU backend. GPU backends can still be used, but with expensive memory transfers....
Definition device.hpp:70
@ OCCA_CPU
[host] OCCA CPU backend: sequential execution on each MPI rank. Enabled when MFEM_USE_OCCA = YES.
Definition device.hpp:62
@ CEED_CUDA
[device] CEED CUDA backend working together with the CUDA backend. Enabled when MFEM_USE_CEED = YES a...
Definition device.hpp:74
@ CPU
[host] Default CPU backend: sequential execution on each MPI rank.
Definition device.hpp:41
@ CUDA
[device] CUDA backend. Enabled when MFEM_USE_CUDA = YES.
Definition device.hpp:45
@ CEED_HIP
[device] CEED HIP backend working together with the HIP backend. Enabled when MFEM_USE_CEED = YES and...
Definition device.hpp:77
@ RAJA_MASK
Biwise-OR of all RAJA backends.
Definition device.hpp:106
@ DEVICE_MASK
Biwise-OR of all device backends.
Definition device.hpp:104
@ CEED_MASK
Bitwise-OR of all CEED backends.
Definition device.hpp:102
@ OCCA_MASK
Biwise-OR of all OCCA backends.
Definition device.hpp:108
@ HIP_MASK
Biwise-OR of all HIP backends.
Definition device.hpp:98
@ NUM_BACKENDS
Number of backends: from (1 << 0) to (1 << (NUM_BACKENDS-1)).
Definition device.hpp:91
@ CUDA_MASK
Biwise-OR of all CUDA backends.
Definition device.hpp:96