15 #include "../fem/libceed/ceed.hpp"
18 #include <unordered_map>
32 occa::device occaDevice;
38 CeedBasisMap ceed_basis_map;
39 CeedRestrMap ceed_restr_map;
54 "ceed-cuda",
"occa-cuda",
"raja-cuda",
"cuda",
55 "ceed-hip",
"hip",
"debug",
56 "occa-omp",
"raja-omp",
"omp",
57 "ceed-cpu",
"occa-cpu",
"raja-cpu",
"cpu"
64 Device Device::device_singleton;
65 bool Device::device_env =
false;
66 bool Device::mem_host_env =
false;
67 bool Device::mem_device_env =
false;
78 if (getenv(
"MFEM_MEMORY") && !mem_host_env && !mem_device_env)
80 std::string mem_backend(getenv(
"MFEM_MEMORY"));
81 if (mem_backend ==
"host")
87 else if (mem_backend ==
"host32")
93 else if (mem_backend ==
"host64")
99 else if (mem_backend ==
"umpire")
108 else if (mem_backend ==
"debug")
119 || mem_backend ==
"cuda"
122 || mem_backend ==
"hip"
128 mem_device_env =
true;
131 else if (mem_backend ==
"uvm")
134 mem_device_env =
true;
140 MFEM_ABORT(
"Unknown memory backend!");
145 if (getenv(
"MFEM_DEVICE"))
147 std::string device(getenv(
"MFEM_DEVICE"));
156 if ( device_env && !destroy_mm) {
return; }
157 if (!device_env && destroy_mm && !mem_host_env)
162 for (
auto entry : internal::ceed_basis_map)
164 CeedBasisDestroy(&entry.second);
166 internal::ceed_basis_map.clear();
167 for (
auto entry : internal::ceed_restr_map)
169 CeedElemRestrictionDestroy(&entry.second);
171 internal::ceed_restr_map.clear();
173 CeedDestroy(&internal::ceed);
178 Get().mode = SEQUENTIAL;
192 std::memcpy(
this, &Get(),
sizeof(
Device));
193 Get().destroy_mm =
false;
197 std::map<std::string, Backend::Id> bmap;
200 bmap[internal::backend_name[i]] = internal::backend_list[i];
202 std::string::size_type beg = 0, end, option;
205 end = device.find(
',', beg);
206 end = (end != std::string::npos) ? end : device.size();
207 const std::string bname = device.substr(beg, end - beg);
208 option = bname.find(
':');
209 if (option==std::string::npos)
211 const std::string backend = bname;
212 std::map<std::string, Backend::Id>::iterator it = bmap.find(backend);
213 MFEM_VERIFY(it != bmap.end(),
"invalid backend name: '" << backend <<
'\'');
214 Get().MarkBackend(it->second);
218 const std::string backend = bname.substr(0, option);
219 const std::string boption = bname.substr(option+1);
220 Get().device_option = strdup(boption.c_str());
221 std::map<std::string, Backend::Id>::iterator it = bmap.find(backend);
222 MFEM_VERIFY(it != bmap.end(),
"invalid backend name: '" << backend <<
'\'');
223 Get().MarkBackend(it->second);
225 if (end == device.size()) {
break; }
241 #ifdef MFEM_USE_OPENMP
255 if (
this != &Get()) { std::memcpy(
this, &Get(),
sizeof(
Device)); }
263 out <<
"Device configuration: ";
264 bool add_comma =
false;
267 if (backends & internal::backend_list[i])
269 if (add_comma) { out <<
','; }
271 out << internal::backend_name[i];
278 const char *ceed_backend;
279 CeedGetResource(internal::ceed, &ceed_backend);
280 out <<
"libCEED backend: " << ceed_backend <<
'\n';
283 out <<
"Memory configuration: "
287 out << ',' << MemoryTypeName[static_cast<int>(device_mem_type)];
292 void Device::UpdateMemoryTypeAndClass()
298 #ifdef MFEM_USE_UMPIRE
310 switch (host_mem_type)
324 #ifndef MFEM_USE_UMPIRE
335 if (device && device_option && !strcmp(device_option,
"uvm"))
352 void Device::Enable()
354 const bool accelerated = Get().backends & ~(
Backend::CPU);
355 if (accelerated) { Get().mode = Device::ACCELERATED;}
356 Get().UpdateMemoryTypeAndClass();
360 static void DeviceSetup(
const int dev,
int &ngpu)
363 MFEM_VERIFY(ngpu > 0,
"No CUDA device found!");
364 MFEM_GPU_CHECK(cudaSetDevice(dev));
368 static void CudaDeviceSetup(
const int dev,
int &ngpu)
371 DeviceSetup(dev, ngpu);
373 MFEM_CONTRACT_VAR(dev);
374 MFEM_CONTRACT_VAR(ngpu);
378 static void HipDeviceSetup(
const int dev,
int &ngpu)
382 MFEM_GPU_CHECK(hipGetDevice(&deviceId));
383 hipDeviceProp_t props;
384 MFEM_GPU_CHECK(hipGetDeviceProperties(&props, deviceId));
385 MFEM_VERIFY(dev==deviceId,
"");
388 MFEM_CONTRACT_VAR(dev);
389 MFEM_CONTRACT_VAR(ngpu);
393 static void RajaDeviceSetup(
const int dev,
int &ngpu)
396 if (ngpu <= 0) { DeviceSetup(dev, ngpu); }
398 MFEM_CONTRACT_VAR(dev);
399 MFEM_CONTRACT_VAR(ngpu);
403 static void OccaDeviceSetup(
const int dev)
409 if (cpu + omp + cuda > 1)
411 MFEM_ABORT(
"Only one OCCA backend can be configured at a time!");
415 #if OCCA_CUDA_ENABLED
416 std::string mode(
"mode: 'CUDA', device_id : ");
417 internal::occaDevice.setup(mode.append(1,
'0'+dev));
419 MFEM_ABORT(
"the OCCA CUDA backend requires OCCA built with CUDA!");
424 #if OCCA_OPENMP_ENABLED
425 internal::occaDevice.setup(
"mode: 'OpenMP'");
427 MFEM_ABORT(
"the OCCA OpenMP backend requires OCCA built with OpenMP!");
432 internal::occaDevice.setup(
"mode: 'Serial'");
436 if (occa::io::exists(MFEM_INSTALL_DIR
"/include/mfem/"))
438 mfemDir = MFEM_INSTALL_DIR
"/include/mfem/";
440 else if (occa::io::exists(MFEM_SOURCE_DIR))
442 mfemDir = MFEM_SOURCE_DIR;
446 MFEM_ABORT(
"Cannot find OCCA kernels in MFEM_INSTALL_DIR or MFEM_SOURCE_DIR");
449 occa::io::addLibraryPath(
"mfem", mfemDir);
450 occa::loadKernels(
"mfem");
452 MFEM_CONTRACT_VAR(dev);
453 MFEM_ABORT(
"the OCCA backends require MFEM built with MFEM_USE_OCCA=YES");
457 static void CeedDeviceSetup(
const char* ceed_spec)
460 CeedInit(ceed_spec, &internal::ceed);
461 const char *ceed_backend;
462 CeedGetResource(internal::ceed, &ceed_backend);
463 if (strcmp(ceed_spec, ceed_backend) && strcmp(ceed_spec,
"/cpu/self") &&
464 strcmp(ceed_spec,
"/gpu/hip"))
467 "libCEED is not using the requested backend!!!\n"
468 "WARNING!!!\n" << std::endl;
471 MFEM_CONTRACT_VAR(ceed_spec);
475 void Device::Setup(
const int device)
477 MFEM_VERIFY(ngpu == -1,
"the mfem::Device is already configured!");
481 #ifndef MFEM_USE_CUDA
483 "the CUDA backends require MFEM built with MFEM_USE_CUDA=YES");
487 "the HIP backends require MFEM built with MFEM_USE_HIP=YES");
489 #ifndef MFEM_USE_RAJA
491 "the RAJA backends require MFEM built with MFEM_USE_RAJA=YES");
493 #ifndef MFEM_USE_OPENMP
495 "the OpenMP and RAJA OpenMP backends require MFEM built with"
496 " MFEM_USE_OPENMP=YES");
498 #ifndef MFEM_USE_CEED
500 "the CEED backends require MFEM built with MFEM_USE_CEED=YES");
505 MFEM_VERIFY(ceed_cpu + ceed_cuda + ceed_hip <= 1,
506 "Only one CEED backend can be enabled at a time!");
517 CeedDeviceSetup(
"/cpu/self");
521 CeedDeviceSetup(device_option);
529 CeedDeviceSetup(
"/gpu/cuda/gen");
533 CeedDeviceSetup(device_option);
540 CeedDeviceSetup(
"/gpu/hip");
544 CeedDeviceSetup(device_option);
[device] OCCA CUDA backend. Enabled when MFEM_USE_OCCA = YES and MFEM_USE_CUDA = YES.
Host memory; aligned at 64 bytes.
[host] OCCA OpenMP backend. Enabled when MFEM_USE_OCCA = YES.
Device memory; using CUDA or HIP *Malloc and *Free.
Device memory; using Umpire.
const char * MemoryTypeName[MemoryTypeSize]
Memory type names, used during Device:: configuration.
[device] CEED CUDA backend working together with the CUDA backend. Enabled when MFEM_USE_CEED = YES a...
[host] RAJA OpenMP backend. Enabled when MFEM_USE_RAJA = YES and MFEM_USE_OPENMP = YES...
Biwise-OR of all HIP backends.
Host memory; allocated from a "host-debug" pool.
void Configure(const MemoryType h_mt, const MemoryType d_mt)
void Print(std::ostream &out=mfem::out)
Print the configuration of the MFEM virtual device object.
[device] RAJA CUDA backend. Enabled when MFEM_USE_RAJA = YES and MFEM_USE_CUDA = YES.
int CuGetDeviceCount()
Get the number of CUDA devices.
void Configure(const std::string &device, const int dev=0)
Configure the Device backends.
Host memory; aligned at 32 bytes.
Device()
Default constructor. Unless Configure() is called later, the default Backend::CPU will be used...
Id
In the documentation below, we use square brackets to indicate the type of the backend: host or devic...
[host] OCCA CPU backend: sequential execution on each MPI rank. Enabled when MFEM_USE_OCCA = YES...
Number of backends: from (1 << 0) to (1 << (NUM_BACKENDS-1)).
void Destroy()
Free all the device memories.
[host] RAJA CPU backend: sequential execution on each MPI rank. Enabled when MFEM_USE_RAJA = YES...
[host] Default CPU backend: sequential execution on each MPI rank.
Biwise-OR of all CUDA backends.
MemoryType
Memory types supported by MFEM.
[host] CEED CPU backend. GPU backends can still be used, but with expensive memory transfers...
[host] OpenMP backend. Enabled when MFEM_USE_OPENMP = YES.
static bool Allows(unsigned long b_mask)
Return true if any of the backends in the backend mask, b_mask, are allowed.
MemoryManager mm
The (single) global memory manager object.
Host memory; using new[] and delete[].
[device] CEED HIP backend working together with the HIP backend. Enabled when MFEM_USE_CEED = YES and...
Biwise-OR of all OCCA backends.
Biwise-OR of all RAJA backends.
Host memory; using Umpire.
Biwise-OR of all device backends.
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
The MFEM Device class abstracts hardware devices such as GPUs, as well as programming models such as ...
Bitwise-OR of all CEED backends.
[device] HIP backend. Enabled when MFEM_USE_HIP = YES.
[device] CUDA backend. Enabled when MFEM_USE_CUDA = YES.
MemoryClass
Memory classes identify sets of memory types.
[device] Debug backend: host memory is READ/WRITE protected while a device is in use. It allows to test the "device" code-path (using separate host/device memory pools and host <-> device transfers) without any GPU hardware. As 'DEBUG' is sometimes used as a macro, _DEVICE has been added to avoid conflicts.