Compare commits

...
Author SHA1 Message Date
Will Pazner d0611d256b Use static data member instead of static local variable in constructor 2024-11-14 07:47:35 -08:00
Will Pazner e561db6d0a MFEM_EXPORT for static kernel dispatch members
For compatibility with Windows/MSVC
2024-11-13 22:41:29 -08:00
Will Pazner 40dbb933e7 Attempt workaround for MSVC segfault
Potential compiler bug with delegated constructors in MSVC
2024-11-13 19:55:17 -08:00
Will Pazner 293b5f78e8 Change kernel specialization instantiation to use local static variable in constructor
This is in order to avoid issues with the static member variable being optimized
away by the compiler.
2024-11-12 12:55:08 -08:00
Will Pazner 2ebe3efde8 Add unit test for kernel specializations
Adds const reference accessor for the kernel dispatch table
2024-11-12 12:06:14 -08:00
Will Pazner 8007b5073f MFEM_EXPORT static member variables
Move QuadratureInterpolator::Kernels to static local variable
2024-11-09 07:31:08 -08:00
Will Pazner 780eaeda5a Don't inline Kernels::EnsureInitialized()
Prevent the compiler from optimizing out the calls
2024-11-08 14:15:48 -08:00
Will Pazner 8a4bb61a2a Ensure kernel dispatch tables are initialized
The kernel dispatch tables are initialized in the constructor of a static member
variable.

If this variable is not odr-used, then it may be optimized away, and the
initialization code is never called. This commit ensures the initialization occurs
by adding a no-op EnsureInitialized member function to the Kernels class that can
be called from the integrator constructor.
2024-11-08 12:05:33 -08:00
7 changed files with 81 additions and 34 deletions
+14 -8
View File
@@ -2156,7 +2156,7 @@ public:
MFEM_REGISTER_KERNELS(ApplyPAKernels, ApplyKernelType, (int, int, int));
MFEM_REGISTER_KERNELS(DiagonalPAKernels, DiagonalKernelType, (int, int, int));
static struct Kernels { Kernels(); } kernels;
MFEM_EXPORT static struct Kernels { Kernels(); void EnsureInitialized(); } kernels;
protected:
Coefficient *Q;
@@ -2236,24 +2236,28 @@ public:
/// Construct a diffusion integrator with coefficient Q = 1
DiffusionIntegrator(const IntegrationRule *ir = nullptr)
: BilinearFormIntegrator(ir),
Q(NULL), VQ(NULL), MQ(NULL), maps(NULL), geom(NULL) { }
Q(NULL), VQ(NULL), MQ(NULL), maps(NULL), geom(NULL)
{ kernels.EnsureInitialized(); }
/// Construct a diffusion integrator with a scalar coefficient q
DiffusionIntegrator(Coefficient &q, const IntegrationRule *ir = nullptr)
: BilinearFormIntegrator(ir),
Q(&q), VQ(NULL), MQ(NULL), maps(NULL), geom(NULL) { }
Q(&q), VQ(NULL), MQ(NULL), maps(NULL), geom(NULL)
{ kernels.EnsureInitialized(); }
/// Construct a diffusion integrator with a vector coefficient q
DiffusionIntegrator(VectorCoefficient &q,
const IntegrationRule *ir = nullptr)
: BilinearFormIntegrator(ir),
Q(NULL), VQ(&q), MQ(NULL), maps(NULL), geom(NULL) { }
Q(NULL), VQ(&q), MQ(NULL), maps(NULL), geom(NULL)
{ kernels.EnsureInitialized(); }
/// Construct a diffusion integrator with a matrix coefficient q
DiffusionIntegrator(MatrixCoefficient &q,
const IntegrationRule *ir = nullptr)
: BilinearFormIntegrator(ir),
Q(NULL), VQ(NULL), MQ(&q), maps(NULL), geom(NULL) { }
Q(NULL), VQ(NULL), MQ(&q), maps(NULL), geom(NULL)
{ kernels.EnsureInitialized(); }
/** Given a particular Finite Element computes the element stiffness matrix
elmat. */
@@ -2356,15 +2360,17 @@ public:
MFEM_REGISTER_KERNELS(ApplyPAKernels, ApplyKernelType, (int, int, int));
MFEM_REGISTER_KERNELS(DiagonalPAKernels, DiagonalKernelType, (int, int, int));
static struct Kernels { Kernels(); } kernels;
MFEM_EXPORT static struct Kernels { Kernels(); void EnsureInitialized(); } kernels;
public:
MassIntegrator(const IntegrationRule *ir = NULL)
: BilinearFormIntegrator(ir), Q(NULL), maps(NULL), geom(NULL) { }
: BilinearFormIntegrator(ir), Q(NULL), maps(NULL), geom(NULL)
{ kernels.EnsureInitialized(); }
/// Construct a mass integrator with coefficient q
MassIntegrator(Coefficient &q, const IntegrationRule *ir = NULL)
: BilinearFormIntegrator(ir), Q(&q), maps(NULL), geom(NULL) { }
: BilinearFormIntegrator(ir), Q(&q), maps(NULL), geom(NULL)
{ kernels.EnsureInitialized(); }
/** Given a particular Finite Element computes the element mass matrix
elmat. */
@@ -41,6 +41,8 @@ DiffusionIntegrator::Kernels::Kernels()
DiffusionIntegrator::AddSpecialization<3,8,9>();
}
void DiffusionIntegrator::Kernels::EnsureInitialized() { }
namespace internal
{
+2
View File
@@ -39,6 +39,8 @@ MassIntegrator::Kernels::Kernels()
MassIntegrator::AddSpecialization<3,8,9>();
}
void MassIntegrator::Kernels::EnsureInitialized() { }
namespace internal
{
+12 -6
View File
@@ -78,9 +78,9 @@ namespace mfem
const char *kernel_name = MFEM_KERNEL_NAME(KernelName); \
using KernelSignature = KernelType; \
template <MFEM_PARAM_LIST P3> \
static KernelSignature Kernel(); \
static KernelSignature Fallback(MFEM_PARAM_LIST P1); \
static KernelName &Get() \
static MFEM_EXPORT KernelSignature Kernel(); \
static MFEM_EXPORT KernelSignature Fallback(MFEM_PARAM_LIST P1); \
static MFEM_EXPORT KernelName &Get() \
{ static KernelName table; return table;} \
}
@@ -126,9 +126,9 @@ class KernelDispatchTable<Kernels,
internal::KernelTypeList<Params...>,
internal::KernelTypeList<OptParams...>>
{
std::unordered_map<std::tuple<Params...>,
Signature,
KernelDispatchKeyHash<Params...>> table;
using TableType = std::unordered_map<std::tuple<Params...>,
Signature, KernelDispatchKeyHash<Params...>>;
TableType table;
public:
/// @brief Run the kernel with the given dispatch parameters and arguments.
@@ -176,6 +176,12 @@ public:
}
};
};
/// Return the dispatch map table
static const TableType &GetDispatchTable()
{
return Kernels::Get().table;
}
};
}
+21 -18
View File
@@ -30,26 +30,27 @@ void InitEvalKernels();
void InitDetKernels();
template <bool P> void InitGradByNodesKernels();
template <bool P> void InitGradByVDimKernels();
}
}
QuadratureInterpolator::Kernels QuadratureInterpolator::kernels;
QuadratureInterpolator::Kernels::Kernels()
struct Kernels
{
using namespace internal::quadrature_interpolator;
Kernels()
{
using namespace internal::quadrature_interpolator;
InitEvalByNodesKernels();
InitEvalByVDimKernels();
// Non-phys grad kernels
InitGradByNodesKernels<false>();
InitGradByVDimKernels<false>();
// Phys grad kernels
InitGradByNodesKernels<true>();
InitGradByVDimKernels<true>();
// Determinants
InitDetKernels();
// Non-tensor
InitEvalKernels();
InitEvalByNodesKernels();
InitEvalByVDimKernels();
// Non-phys grad kernels
InitGradByNodesKernels<false>();
InitGradByVDimKernels<false>();
// Phys grad kernels
InitGradByNodesKernels<true>();
InitGradByVDimKernels<true>();
// Determinants
InitDetKernels();
// Non-tensor
InitEvalKernels();
}
};
}
}
QuadratureInterpolator::QuadratureInterpolator(const FiniteElementSpace &fes,
@@ -61,6 +62,8 @@ QuadratureInterpolator::QuadratureInterpolator(const FiniteElementSpace &fes,
q_layout(QVectorLayout::byNODES),
use_tensor_products(UsesTensorBasis(fes))
{
static internal::quadrature_interpolator::Kernels kernels;
d_buffer.UseDevice(true);
if (fespace->GetNE() == 0) { return; }
const FiniteElement *fe = fespace->GetFE(0);
-2
View File
@@ -158,8 +158,6 @@ public:
MFEM_REGISTER_KERNELS(EvalKernels, EvalKernelType, (int, int, int, int));
MFEM_REGISTER_KERNELS(CollocatedGradKernels, CollocatedGradKernelType,
(int, QVectorLayout, bool, int, int), (int));
static struct Kernels { Kernels(); } kernels;
};
}
+30
View File
@@ -830,3 +830,33 @@ TEST_CASE("Parallel PA DG Diffusion", "[PartialAssembly][Parallel][CUDA]")
#endif
} // namespace pa_kernels
TEST_CASE("Dispatch Map Specializations")
{
// The kernel specializations are registered the first time the associated
// object is created (in the constructor of a static local variable in the
// object's constructor). We create a dummy objects here to ensure that the
// kernels are registered before testing.
MassIntegrator{};
REQUIRE_FALSE(MassIntegrator::ApplyPAKernels::GetDispatchTable().empty());
REQUIRE_FALSE(MassIntegrator::DiagonalPAKernels::GetDispatchTable().empty());
DiffusionIntegrator{};
REQUIRE_FALSE(
DiffusionIntegrator::ApplyPAKernels::GetDispatchTable().empty());
REQUIRE_FALSE(
DiffusionIntegrator::DiagonalPAKernels::GetDispatchTable().empty());
Mesh mesh = Mesh::MakeCartesian2D(2, 2, Element::QUADRILATERAL);
H1_FECollection fec(1, mesh.Dimension());
FiniteElementSpace fes(&mesh, &fec);
fes.GetQuadratureInterpolator(IntRules.Get(mesh.GetElementGeometry(0), 1));
using QI = QuadratureInterpolator;
REQUIRE_FALSE(QI::TensorEvalKernels::GetDispatchTable().empty());
REQUIRE_FALSE(QI::GradKernels::GetDispatchTable().empty());
REQUIRE_FALSE(QI::DetKernels::GetDispatchTable().empty());
REQUIRE_FALSE(QI::EvalKernels::GetDispatchTable().empty());
REQUIRE_FALSE(QI::CollocatedGradKernels::GetDispatchTable().empty());
}