31 occa::device occaDevice;
50 "ceed-cuda",
"occa-cuda",
"raja-cuda",
"cuda",
52 "occa-omp",
"raja-omp",
"omp",
53 "ceed-cpu",
"occa-cpu",
"raja-cpu",
"cpu"
60 Device Device::device_singleton;
61 bool Device::device_env =
false;
62 bool Device::mem_host_env =
false;
63 bool Device::mem_device_env =
false;
74 if (getenv(
"MFEM_MEMORY") && !mem_host_env && !mem_device_env)
76 std::string mem_backend(getenv(
"MFEM_MEMORY"));
77 if (mem_backend ==
"host")
83 else if (mem_backend ==
"host32")
89 else if (mem_backend ==
"host64")
95 else if (mem_backend ==
"umpire")
104 else if (mem_backend ==
"debug")
115 || mem_backend ==
"cuda"
118 || mem_backend ==
"hip"
124 mem_device_env =
true;
127 else if (mem_backend ==
"uvm")
130 mem_device_env =
true;
136 MFEM_ABORT(
"Unknown memory backend!");
141 if (getenv(
"MFEM_DEVICE"))
143 std::string device(getenv(
"MFEM_DEVICE"));
152 if ( device_env && !destroy_mm) {
return; }
153 if (!device_env && destroy_mm && !mem_host_env)
157 CeedDestroy(&internal::ceed);
162 Get().mode = SEQUENTIAL;
176 std::memcpy(
this, &Get(),
sizeof(
Device));
177 Get().destroy_mm =
false;
181 std::map<std::string, Backend::Id> bmap;
184 bmap[internal::backend_name[i]] = internal::backend_list[i];
186 std::string::size_type beg = 0, end, option;
189 end = device.find(
',', beg);
190 end = (end != std::string::npos) ? end : device.size();
191 const std::string bname = device.substr(beg, end - beg);
192 option = bname.find(
':');
193 if (option==std::string::npos)
195 const std::string backend = bname;
196 std::map<std::string, Backend::Id>::iterator it = bmap.find(backend);
197 MFEM_VERIFY(it != bmap.end(),
"invalid backend name: '" << backend <<
'\'');
198 Get().MarkBackend(it->second);
202 const std::string backend = bname.substr(0, option);
203 const std::string boption = bname.substr(option+1);
204 Get().device_option = strdup(boption.c_str());
205 std::map<std::string, Backend::Id>::iterator it = bmap.find(backend);
206 MFEM_VERIFY(it != bmap.end(),
"invalid backend name: '" << backend <<
'\'');
207 Get().MarkBackend(it->second);
209 if (end == device.size()) {
break; }
230 if (
this != &Get()) { std::memcpy(
this, &Get(),
sizeof(
Device)); }
238 out <<
"Device configuration: ";
239 bool add_comma =
false;
242 if (backends & internal::backend_list[i])
244 if (add_comma) { out <<
','; }
246 out << internal::backend_name[i];
253 const char *ceed_backend;
254 CeedGetResource(internal::ceed, &ceed_backend);
255 out <<
"libCEED backend: " << ceed_backend <<
'\n';
258 out <<
"Memory configuration: "
262 out << ',' << MemoryTypeName[static_cast<int>(device_mem_type)];
267 void Device::UpdateMemoryTypeAndClass()
273 #ifdef MFEM_USE_UMPIRE
285 switch (host_mem_type)
299 #ifndef MFEM_USE_UMPIRE
310 if (device && device_option && !strcmp(device_option,
"uvm"))
327 void Device::Enable()
329 const bool accelerated = Get().backends & ~(
Backend::CPU);
330 if (accelerated) { Get().mode = Device::ACCELERATED;}
331 Get().UpdateMemoryTypeAndClass();
335 static void DeviceSetup(
const int dev,
int &ngpu)
338 MFEM_VERIFY(ngpu > 0,
"No CUDA device found!");
339 MFEM_GPU_CHECK(cudaSetDevice(dev));
343 static void CudaDeviceSetup(
const int dev,
int &ngpu)
346 DeviceSetup(dev, ngpu);
348 MFEM_CONTRACT_VAR(dev);
349 MFEM_CONTRACT_VAR(ngpu);
353 static void HipDeviceSetup(
const int dev,
int &ngpu)
357 MFEM_GPU_CHECK(hipGetDevice(&deviceId));
358 hipDeviceProp_t props;
359 MFEM_GPU_CHECK(hipGetDeviceProperties(&props, deviceId));
360 MFEM_VERIFY(dev==deviceId,
"");
363 MFEM_CONTRACT_VAR(dev);
364 MFEM_CONTRACT_VAR(ngpu);
368 static void RajaDeviceSetup(
const int dev,
int &ngpu)
371 if (ngpu <= 0) { DeviceSetup(dev, ngpu); }
373 MFEM_CONTRACT_VAR(dev);
374 MFEM_CONTRACT_VAR(ngpu);
378 static void OccaDeviceSetup(
const int dev)
384 if (cpu + omp + cuda > 1)
386 MFEM_ABORT(
"Only one OCCA backend can be configured at a time!");
390 #if OCCA_CUDA_ENABLED
391 std::string mode(
"mode: 'CUDA', device_id : ");
392 internal::occaDevice.setup(mode.append(1,
'0'+dev));
394 MFEM_ABORT(
"the OCCA CUDA backend requires OCCA built with CUDA!");
399 #if OCCA_OPENMP_ENABLED
400 internal::occaDevice.setup(
"mode: 'OpenMP'");
402 MFEM_ABORT(
"the OCCA OpenMP backend requires OCCA built with OpenMP!");
407 internal::occaDevice.setup(
"mode: 'Serial'");
411 if (occa::io::exists(MFEM_INSTALL_DIR
"/include/mfem/"))
413 mfemDir = MFEM_INSTALL_DIR
"/include/mfem/";
415 else if (occa::io::exists(MFEM_SOURCE_DIR))
417 mfemDir = MFEM_SOURCE_DIR;
421 MFEM_ABORT(
"Cannot find OCCA kernels in MFEM_INSTALL_DIR or MFEM_SOURCE_DIR");
424 occa::io::addLibraryPath(
"mfem", mfemDir);
425 occa::loadKernels(
"mfem");
427 MFEM_CONTRACT_VAR(dev);
428 MFEM_ABORT(
"the OCCA backends require MFEM built with MFEM_USE_OCCA=YES");
432 static void CeedDeviceSetup(
const char* ceed_spec)
435 CeedInit(ceed_spec, &internal::ceed);
436 const char *ceed_backend;
437 CeedGetResource(internal::ceed, &ceed_backend);
438 if (strcmp(ceed_spec, ceed_backend) && strcmp(ceed_spec,
"/cpu/self"))
441 "libCEED is not using the requested backend!!!\n"
442 "WARNING!!!\n" << std::endl;
445 MFEM_CONTRACT_VAR(ceed_spec);
449 void Device::Setup(
const int device)
451 MFEM_VERIFY(ngpu == -1,
"the mfem::Device is already configured!");
455 #ifndef MFEM_USE_CUDA
457 "the CUDA backends require MFEM built with MFEM_USE_CUDA=YES");
461 "the HIP backends require MFEM built with MFEM_USE_HIP=YES");
463 #ifndef MFEM_USE_RAJA
465 "the RAJA backends require MFEM built with MFEM_USE_RAJA=YES");
467 #ifndef MFEM_USE_OPENMP
469 "the OpenMP and RAJA OpenMP backends require MFEM built with"
470 " MFEM_USE_OPENMP=YES");
472 #ifndef MFEM_USE_CEED
474 "the CEED backends require MFEM built with MFEM_USE_CEED=YES");
477 "Only one CEED backend can be enabled at a time!");
488 CeedDeviceSetup(
"/cpu/self");
492 CeedDeviceSetup(device_option);
500 CeedDeviceSetup(
"/gpu/cuda/gen");
504 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...
[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.
[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[].
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.