MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
kernel_dispatch.hpp
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#ifndef MFEM_KERNEL_DISPATCH_HPP
13#define MFEM_KERNEL_DISPATCH_HPP
14
15#include "../config/config.hpp"
16#include "kernel_reporter.hpp"
18#include <unordered_map>
19#include <tuple>
20#include <type_traits>
21#include <cstddef>
22
23namespace mfem
24{
25
26// The MFEM_REGISTER_KERNELS macro registers kernels for runtime dispatch using
27// a dispatch map.
28//
29// This creates a dispatch table (a static member variable) named @a KernelName
30// containing function points of type @a KernelType. These are followed by one
31// or two sets of parenthesized argument types.
32//
33// The first set of argument types contains the types that are used to dispatch
34// to either specialized or fallback kernels. The second set of argument types
35// can be used to further specialize the kernel without participating in
36// dispatch (a canonical example is NBZ, determining the size of the thread
37// blocks; this is required to specialize kernels for optimal performance, but
38// is not relevant for dispatch).
39//
40// After calling this macro, the user must implement the Kernel and Fallback
41// static member functions, which return pointers to the appropriate kernel
42// functions depending on the parameters.
43//
44// Specialized functions can be registered using the static AddSpecialization
45// member function.
46
47#define MFEM_EXPAND(X) X // Workaround needed for MSVC compiler
48
49#define MFEM_REGISTER_KERNELS(KernelName, KernelType, ...) \
50 MFEM_EXPAND(MFEM_EXPAND(MFEM_REGISTER_KERNELS_N(__VA_ARGS__,2,1,)) \
51 (KernelName,KernelType,__VA_ARGS__))
52
53#define MFEM_REGISTER_KERNELS_N(_1, _2, N, ...) MFEM_REGISTER_KERNELS_##N
54
55// Expands a variable length macro parameter so that multiple variable length
56// parameters can be passed to the same macro.
57#define MFEM_PARAM_LIST(...) __VA_ARGS__
58
59// Version of MFEM_REGISTER_KERNELS without any "optional" (non-dispatch)
60// parameters.
61#define MFEM_REGISTER_KERNELS_1(KernelName, KernelType, Params) \
62 MFEM_REGISTER_KERNELS_(KernelName, KernelType, Params, (), Params)
63
64// Version of MFEM_REGISTER_KERNELS with optional (non-dispatch)
65// parameters (e.g. NBZ).
66#define MFEM_REGISTER_KERNELS_2(KernelName, KernelType, Params, OptParams) \
67 MFEM_REGISTER_KERNELS_(KernelName, KernelType, Params, OptParams, \
68 (MFEM_PARAM_LIST Params, MFEM_PARAM_LIST OptParams))
69
70// P1 are the parameters, P2 are the optional (non-dispatch parameters), and P3
71// is the concatenation of P1 and P2. We need to pass it as a separate argument
72// to avoid a trailing comma in the case that P2 is empty.
73#define MFEM_REGISTER_KERNELS_(KernelName, KernelType, P1, P2, P3) \
74 class KernelName \
75 : public ::mfem::KernelDispatchTable< \
76 KernelName, KernelType, \
77 ::mfem::internal::KernelTypeList<MFEM_PARAM_LIST P1>, \
78 ::mfem::internal::KernelTypeList<MFEM_PARAM_LIST P2>> { \
79 public: \
80 const char *kernel_name = MFEM_KERNEL_NAME(KernelName); \
81 using KernelSignature = KernelType; \
82 template <MFEM_PARAM_LIST P3> static KernelSignature Kernel(); \
83 static MFEM_EXPORT KernelSignature Fallback(MFEM_PARAM_LIST P1); \
84 static MFEM_EXPORT KernelName &Get() { \
85 static KernelName table; \
86 return table; \
87 } \
88 }
89
90namespace internal { template<typename... Types> struct KernelTypeList { }; }
91
92template<typename... T> class KernelDispatchTable { };
93
94template <typename Kernels,
95 typename Signature,
96 typename... Params,
97 typename... OptParams>
99 Signature,
100 internal::KernelTypeList<Params...>,
101 internal::KernelTypeList<OptParams...>>
102{
103 using TableType =
104 std::unordered_map<std::tuple<Params...>, Signature, TupleHasher>;
105 TableType table;
106
107 /// @brief Call function @a f with arguments @a args (perfect forwarding).
108 ///
109 /// Only valid when the function @a f is not a member function.
110 template <typename F, typename... Args,
111 typename std::enable_if<std::is_pointer<F>::value,bool>::type=true>
112 static void Invoke(F f, Args&&... args)
113 {
114 f(std::forward<Args>(args)...);
115 }
116
117 /// @brief Calls member function @a f on object @a t with arguments @a args
118 /// (perfect forwarding).
119 ///
120 /// Only valid when @a f is a member function of class @a T.
121 template <typename F, typename T, typename... Args,
122 typename std::enable_if<
123 std::is_member_function_pointer<F>::value,bool>::type=true>
124 static void Invoke(F f, T&& t, Args&&... args)
125 {
126 (t.*f)(std::forward<Args>(args)...);
127 }
128
129public:
130 /// @brief Run the kernel with the given dispatch parameters and arguments.
131 ///
132 /// If a compile-time specialized version of the kernel with the given
133 /// parameters has been registered, it will be called. Otherwise, the
134 /// fallback kernel will be called.
135 ///
136 /// If the kernel is a member function, then the first argument after @a
137 /// params should be the object on which it is called.
138 template<typename... Args>
139 static void Run(Params... params, Args&&... args)
140 {
141 const auto &table = Kernels::Get().table;
142 const std::tuple<Params...> key = std::make_tuple(params...);
143 const auto it = table.find(key);
144 if (it != table.end())
145 {
146 Invoke(it->second, std::forward<Args>(args)...);
147 }
148 else
149 {
150 KernelReporter::ReportFallback(Kernels::Get().kernel_name, params...);
151 Invoke(Kernels::Fallback(params...), std::forward<Args>(args)...);
152 }
153 }
154
155 /// Register a specialized kernel for dispatch.
156 template <Params... PARAMS>
158 {
159 // Version without optional parameters
160 static void Add()
161 {
162 std::tuple<Params...> param_tuple(PARAMS...);
163 Kernels::Get().table[param_tuple] =
164 Kernels:: template Kernel<PARAMS..., OptParams{}...>();
165 };
166 // Version with optional parameters
167 template <OptParams... OPT_PARAMS>
168 struct Opt
169 {
170 static void Add()
171 {
172 std::tuple<Params...> param_tuple(PARAMS...);
173 Kernels::Get().table[param_tuple] =
174 Kernels:: template Kernel<PARAMS..., OPT_PARAMS...>();
175 }
176 };
177 };
178
179 /// Return the dispatch map table
180 static const TableType &GetDispatchTable()
181 {
182 return Kernels::Get().table;
183 }
184};
185
186}
187
188#endif
static void Run(Params... params, Args &&... args)
Run the kernel with the given dispatch parameters and arguments.
static void ReportFallback(const std::string &kernel_name, Params &&... params)
Report the fallback kernel with given parameters.
SchrodingerBaseKernels< ParMesh, ParFiniteElementSpace, ParComplexGridFunction, ParGridFunction, ParBilinearForm, ParMixedBilinearForm, ParLinearForm > Kernels
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30
Base class for Schrodinger solver kernels.
Helper class for hashing std::tuple of hashable types.