Skip to content

Commit

Permalink
Merge pull request mfem#4504 from helloworld922/master
Browse files Browse the repository at this point in the history
Fix CUDA-enabled HYPRE finalization order issue
  • Loading branch information
tzanio authored Dec 12, 2024
2 parents c3771b3 + 51a7589 commit 9a9087e
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 17 deletions.
13 changes: 12 additions & 1 deletion general/device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@ Device::Device()

Device::~Device()
{
#ifdef MFEM_USE_MPI
Hypre::Finalize();
#endif
if ( device_env && !destroy_mm) { return; }
if (!device_env && destroy_mm && !mem_host_env)
{
Expand Down Expand Up @@ -255,7 +258,15 @@ void Device::Configure(const std::string &device, const int device_id)
destroy_mm = true;

#ifdef MFEM_USE_MPI
Hypre::InitDevice();
#if defined(HYPRE_USING_GPU) && (MFEM_HYPRE_VERSION >= 23100)
// Skip the call to Hypre::InitDevice() if HYPRE is not initialized, e.g.
// * if running a serial code
// * if running with the environment variable MFEM_DEVICE set.
if (HYPRE_Initialized())
{
Hypre::InitDevice();
}
#endif
#endif
}

Expand Down
26 changes: 17 additions & 9 deletions linalg/hypre.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,23 @@ namespace mfem
{

bool Hypre::configure_runtime_policy_from_mfem = true;
Hypre::State Hypre::state = Hypre::State::UNINITIALIZED;

Hypre::Hypre()
void Hypre::Init()
{
if (state != State::INITIALIZED)
{
#if MFEM_HYPRE_VERSION >= 21900
// Initializing hypre
HYPRE_Init();
HYPRE_Init();
#endif

// Global hypre options that we set by default
SetDefaultOptions();
SetDefaultOptions();
// Apply the setting of 'configure_runtime_policy_from_mfem' according to
// the current configuration of the mfem::Device (HYPRE >= 2.31.0):
InitDevice();
// Create the singleton Hypre object AFTER initializing HYPRE:
Instance();
}
state = State::INITIALIZED;
}

void Hypre::InitDevice()
Expand All @@ -48,6 +55,8 @@ void Hypre::InitDevice()
#if defined(HYPRE_USING_GPU) && (MFEM_HYPRE_VERSION >= 23100)
if (configure_runtime_policy_from_mfem)
{
MFEM_VERIFY(HYPRE_Initialized(), "HYPRE must be initialized before"
" calling Hypre::InitDevice()");
if (Device::Allows(Backend::DEVICE_MASK & ~Backend::DEBUG_DEVICE))
{
HYPRE_SetMemoryLocation(HYPRE_MEMORY_DEVICE);
Expand All @@ -65,14 +74,13 @@ void Hypre::InitDevice()

void Hypre::Finalize()
{
Hypre &hypre = Instance();
if (!hypre.finalized)
if (state != State::UNINITIALIZED)
{
#if MFEM_HYPRE_VERSION >= 21900
HYPRE_Finalize();
#endif
hypre.finalized = true;
}
state = State::UNINITIALIZED;
}

void Hypre::SetDefaultOptions()
Expand Down
27 changes: 20 additions & 7 deletions linalg/hypre.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,11 @@ class Hypre
public:
/// @brief Initialize hypre by calling HYPRE_Init() and set default options.
/// After calling Hypre::Init(), hypre will be finalized automatically at
/// program exit.
/// program exit. May be re-initialized after finalize.
///
/// Calling HYPRE_Finalize() manually is not compatible with this class.
static void Init() { Instance(); }
/// Calling HYPRE_Init() or HYPRE_Finalize() manually is only supported for
/// HYPRE 2.29.0+
static void Init();

/// @brief Configure HYPRE's compute and memory policy.
///
Expand All @@ -94,6 +95,9 @@ class Hypre
///
/// Multiple calls to Hypre::Finalize() have no effect. This function can be
/// called manually to more precisely control when hypre is finalized.
///
/// Calling HYPRE_Init() or HYPRE_Finalize() manually is only supported for
/// HYPRE 2.29.0+
static void Finalize();

/// @brief Use MFEM's device policy to configure HYPRE's device policy, true
Expand All @@ -104,14 +108,20 @@ class Hypre
static bool configure_runtime_policy_from_mfem;

private:
/// Calls HYPRE_Init() when the singleton is constructed.
Hypre();
/// Default constructor. Singleton object; private.
Hypre() = default;

/// Copy constructor. Deleted.
Hypre(Hypre&) = delete;

/// Move constructor. Deleted.
Hypre(Hypre&&) = delete;

/// The singleton destructor (called at program exit) finalizes hypre.
~Hypre() { Finalize(); }

/// Set the default hypre global options (mostly GPU-relevant).
void SetDefaultOptions();
static void SetDefaultOptions();

/// Create and return the Hypre singleton object.
static Hypre &Instance()
Expand All @@ -120,7 +130,10 @@ class Hypre
return hypre;
}

bool finalized = false; ///< Has Hypre::Finalize() been called already?
enum class State { UNINITIALIZED, INITIALIZED };

/// Tracks whether Hypre was initialized or finalized by this class.
static State state;
};


Expand Down

0 comments on commit 9a9087e

Please sign in to comment.