https://mooseframework.inl.gov
KokkosDispatcher.h
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
10 #pragma once
11 
12 #include "KokkosHeader.h"
13 #include "KokkosThread.h"
14 
15 #include <typeindex>
16 
17 namespace Moose::Kokkos
18 {
19 
20 using Policy = ::Kokkos::RangePolicy<ExecSpace, ::Kokkos::IndexType<ThreadID>>;
21 
28 {
29 public:
30  virtual ~DispatcherBase() {}
35  virtual void parallelFor(const Policy & /* policy */)
36  {
37  mooseError("parallelFor() called for an instance that is not a dispatcher.");
38  }
45  virtual void parallelReduce(const Policy & /* policy */,
46  ::Kokkos::View<Real *, ::Kokkos::HostSpace> & /* result */)
47  {
48  mooseError("parallelReduce() called for an instance that is not a reducer.");
49  }
50 };
51 
58 template <typename Operation, typename Object>
59 class Dispatcher : public DispatcherBase
60 {
61 public:
68  Dispatcher(const void * object)
69  : _functor_host(*static_cast<const Object *>(object)), _functor_device(_functor_host)
70  {
71  }
75  Dispatcher(const Dispatcher & functor)
77  {
78  }
79 
80  void parallelFor(const Policy & policy) override final
81  {
82  ::Kokkos::parallel_for(policy, *this);
83  ::Kokkos::fence();
84  }
85 
89  KOKKOS_FUNCTION void operator()(const ThreadID tid) const
90  {
91  _functor_device(Operation{}, tid, _functor_device);
92  }
93 
94 private:
98  const Object & _functor_host;
102  const Object _functor_device;
103 };
104 
111 template <typename Operation, typename Object>
112 class Reducer : public DispatcherBase
113 {
114 public:
121  Reducer(const void * object)
122  : _functor_host(*static_cast<const Object *>(object)), _functor_device(_functor_host)
123  {
124  }
128  Reducer(const Reducer & functor)
129  : value_count(functor.value_count),
130  _functor_host(functor._functor_host),
132  {
133  }
134 
135  void parallelReduce(const Policy & policy,
136  ::Kokkos::View<Real *, ::Kokkos::HostSpace> & result) override final
137  {
138  value_count = result.size();
139 
140  ::Kokkos::parallel_reduce(policy, *this, result);
141  ::Kokkos::fence();
142  }
143 
144  using value_type = Real[];
145  using size_type = ::Kokkos::View<Real *>::size_type;
146 
148 
152  KOKKOS_FUNCTION void operator()(const ThreadID tid, value_type result) const
153  {
154  _functor_device(Operation{}, tid, _functor_device, result);
155  }
156 
160  KOKKOS_FUNCTION void join(value_type result, const value_type source) const
162  {
163  _functor_device.template join<Object>(result, source);
164  }
165  KOKKOS_FUNCTION void init(value_type result) const
166  {
167  _functor_device.template init<Object>(result);
168  }
170 
171 private:
175  const Object & _functor_host;
179  const Object _functor_device;
180 };
181 
188 {
189 public:
191 
196  virtual std::unique_ptr<DispatcherBase> build(const void * object) const = 0;
197 
202  void hasUserMethod(bool flag) { _has_user_method = flag; }
207  bool hasUserMethod() const { return _has_user_method; }
208 
209 private:
213  bool _has_user_method = false;
214 };
215 
225 template <typename Operation, typename Object>
228 {
229 public:
230  std::unique_ptr<DispatcherBase> build(const void * object) const override final
231  {
232  return std::make_unique<Dispatcher<Operation, Object>>(object);
233  }
234 };
235 
236 template <typename Operation, typename Object>
238 {
239 public:
240  std::unique_ptr<DispatcherBase> build(const void * object) const override final
241  {
242  return std::make_unique<Reducer<Operation, Object>>(object);
243  }
244 };
246 
251 {
252 public:
253  DispatcherRegistry() = default;
254 
255  DispatcherRegistry(DispatcherRegistry const &) = delete;
256  DispatcherRegistry & operator=(DispatcherRegistry const &) = delete;
257 
260 
267  template <typename Operation, typename Object>
268  static void addDispatcher(const std::string & name)
269  {
270  auto operation = std::type_index(typeid(Operation));
271 
272  getRegistry()._dispatchers[std::make_pair(operation, name)] =
273  std::make_unique<DispatcherRegistryEntry<Operation, Object>>();
274  }
275 
282  template <typename Operation, typename Object>
283  static void addReducer(const std::string & name)
284  {
285  auto operation = std::type_index(typeid(Operation));
286 
287  getRegistry()._dispatchers[std::make_pair(operation, name)] =
288  std::make_unique<ReducerRegistryEntry<Operation, Object>>();
289  }
290 
297  template <typename Operation>
298  static void hasUserMethod(const std::string & name, const bool flag)
299  {
300  getDispatcher<Operation>(name)->hasUserMethod(flag);
301  }
302 
309  template <typename Operation>
310  static bool hasUserMethod(const std::string & name)
311  {
312  return getDispatcher<Operation>(name)->hasUserMethod();
313  }
314 
322  template <typename Operation>
323  static std::unique_ptr<DispatcherBase> build(const void * object, const std::string & name)
324  {
325  return getDispatcher<Operation>(name)->build(object);
326  }
327 
328 private:
333  static DispatcherRegistry & getRegistry();
334 
341  template <typename Operation>
342  static auto & getDispatcher(const std::string & name)
343  {
344  auto operation = std::type_index(typeid(Operation));
345 
346  auto it = getRegistry()._dispatchers.find(std::make_pair(operation, name));
347  if (it == getRegistry()._dispatchers.end())
348  mooseError("Kokkos functor dispatcher not registered for object type '",
349  name,
350  "'. Double check that you used Kokkos-specific registration macro.");
351 
352  return it->second;
353  }
354 
359  std::map<std::pair<std::type_index, std::string>, std::unique_ptr<DispatcherRegistryEntryBase>>
361 };
362 
363 } // namespace Moose::Kokkos
364 
365 // Kernel, NodalKernel, BC
366 
367 #define callRegisterKokkosResidualObjectFunction(classname, objectname) \
368  static char registerKokkosResidualObject##classname() \
369  { \
370  using namespace Moose::Kokkos; \
371  \
372  DispatcherRegistry::addDispatcher<classname::ResidualLoop, classname>(objectname); \
373  DispatcherRegistry::addDispatcher<classname::JacobianLoop, classname>(objectname); \
374  DispatcherRegistry::addDispatcher<classname::OffDiagJacobianLoop, classname>(objectname); \
375  DispatcherRegistry::hasUserMethod<classname::JacobianLoop>( \
376  objectname, \
377  &classname::computeQpJacobian<classname> != classname::defaultJacobian<classname>()); \
378  DispatcherRegistry::hasUserMethod<classname::OffDiagJacobianLoop>( \
379  objectname, \
380  &classname::computeQpOffDiagJacobian<classname> != \
381  classname::defaultOffDiagJacobian<classname>()); \
382  \
383  return 0; \
384  } \
385  \
386  static char combineNames(kokkos_dispatcher_residual_object_##classname, __COUNTER__) = \
387  registerKokkosResidualObject##classname()
388 
389 #define registerKokkosResidualObject(app, classname) \
390  registerMooseObject(app, classname); \
391  callRegisterKokkosResidualObjectFunction(classname, #classname)
392 
393 #define registerKokkosResidualObjectAliased(app, classname, alias) \
394  registerMooseObjectAliased(app, classname, alias); \
395  callRegisterKokkosResidualObjectFunction(classname, alias)
396 
397 // AD Kernel, NodalKernel, BC
398 
399 #define callRegisterKokkosADResidualObjectFunction(classname, objectname) \
400  static char registerKokkosADResidualObject##classname() \
401  { \
402  using namespace Moose::Kokkos; \
403  \
404  DispatcherRegistry::addDispatcher<classname::ResidualLoop, classname>(objectname); \
405  \
406  return 0; \
407  } \
408  \
409  static char combineNames(kokkos_dispatcher_ad_residual_object_##classname, __COUNTER__) = \
410  registerKokkosADResidualObject##classname()
411 
412 #define registerKokkosADResidualObject(app, classname) \
413  registerMooseObject(app, classname); \
414  callRegisterKokkosADResidualObjectFunction(classname, #classname)
415 
416 #define registerKokkosADResidualObjectAliased(app, classname, alias) \
417  registerMooseObjectAliased(app, classname, alias); \
418  callRegisterKokkosADResidualObjectFunction(classname, alias)
419 
420 // Material
421 
422 #define callRegisterKokkosMaterialFunction(classname, objectname) \
423  static char registerKokkosMaterial##classname() \
424  { \
425  using namespace Moose::Kokkos; \
426  \
427  DispatcherRegistry::addDispatcher<classname::ElementInit, classname>(objectname); \
428  DispatcherRegistry::addDispatcher<classname::SideInit, classname>(objectname); \
429  DispatcherRegistry::addDispatcher<classname::NeighborInit, classname>(objectname); \
430  DispatcherRegistry::addDispatcher<classname::ElementCompute, classname>(objectname); \
431  DispatcherRegistry::addDispatcher<classname::SideCompute, classname>(objectname); \
432  DispatcherRegistry::addDispatcher<classname::NeighborCompute, classname>(objectname); \
433  DispatcherRegistry::hasUserMethod<classname::ElementInit>( \
434  objectname, \
435  &classname::initQpStatefulProperties<classname> != \
436  classname::defaultInitStateful<classname>()); \
437  DispatcherRegistry::hasUserMethod<classname::SideInit>( \
438  objectname, \
439  &classname::initQpStatefulProperties<classname> != \
440  classname::defaultInitStateful<classname>()); \
441  DispatcherRegistry::hasUserMethod<classname::NeighborInit>( \
442  objectname, \
443  &classname::initQpStatefulProperties<classname> != \
444  classname::defaultInitStateful<classname>()); \
445  \
446  return 0; \
447  } \
448  \
449  static char combineNames(kokkos_dispatcher_material_##classname, __COUNTER__) = \
450  registerKokkosMaterial##classname()
451 
452 #define registerKokkosMaterial(app, classname) \
453  registerMooseObject(app, classname); \
454  callRegisterKokkosMaterialFunction(classname, #classname)
455 
456 #define registerKokkosMaterialAliased(app, classname, alias) \
457  registerMooseObjectAliased(app, classname, alias); \
458  callRegisterKokkosMaterialFunction(classname, alias)
459 
460 // AuxKernel
461 
462 #define callRegisterKokkosAuxKernelFunction(classname, objectname) \
463  static char registerKokkosAuxKernel##classname() \
464  { \
465  using namespace Moose::Kokkos; \
466  \
467  DispatcherRegistry::addDispatcher<classname::ElementLoop, classname>(objectname); \
468  DispatcherRegistry::addDispatcher<classname::NodeLoop, classname>(objectname); \
469  \
470  return 0; \
471  } \
472  \
473  static char combineNames(kokkos_dispatcher_auxkernel_##classname, __COUNTER__) = \
474  registerKokkosAuxKernel##classname()
475 
476 #define registerKokkosAuxKernel(app, classname) \
477  registerMooseObject(app, classname); \
478  callRegisterKokkosAuxKernelFunction(classname, #classname)
479 
480 #define registerKokkosAuxKernelAliased(app, classname, alias) \
481  registerMooseObjectAliased(app, classname, alias); \
482  callRegisterKokkosAuxKernelFunction(classname, alias)
483 
484 // UserObject
485 
486 #define callRegisterKokkosUserObjectFunction(classname, objectname) \
487  static char registerKokkosUserObject##classname() \
488  { \
489  using namespace Moose::Kokkos; \
490  \
491  DispatcherRegistry::addDispatcher<classname::DefaultLoop, classname>(objectname); \
492  DispatcherRegistry::addReducer<classname::ReducerLoop, classname>(objectname); \
493  DispatcherRegistry::hasUserMethod<classname::DefaultLoop>( \
494  objectname, &classname::execute<classname> != classname::defaultExecute<classname>()); \
495  DispatcherRegistry::hasUserMethod<classname::ReducerLoop>( \
496  objectname, &classname::reduce<classname> != classname::defaultReduce<classname>()); \
497  \
498  return 0; \
499  } \
500  \
501  static char combineNames(kokkos_dispatcher_userobject_##classname, __COUNTER__) = \
502  registerKokkosUserObject##classname()
503 
504 #define registerKokkosUserObject(app, classname) \
505  registerMooseObject(app, classname); \
506  callRegisterKokkosUserObjectFunction(classname, #classname)
507 
508 #define registerKokkosUserObjectAliased(app, classname, alias) \
509  registerMooseObjectAliased(app, classname, alias); \
510  callRegisterKokkosUserObjectFunction(classname, alias)
511 
512 // User-defined parallel operation registry
513 
514 #define registerKokkosAdditionalOperation(classname, operation) \
515  static char registerKokkos##classname##operation() \
516  { \
517  using namespace Moose::Kokkos; \
518  \
519  DispatcherRegistry::addDispatcher<classname::operation, classname>(#classname); \
520  \
521  return 0; \
522  } \
523  \
524  static char combineNames(kokkos_##classname##_##operation, __COUNTER__) = \
525  registerKokkos##classname##operation()
std::string name(const ElemQuality q)
KOKKOS_FUNCTION void join(value_type result, const value_type source) const
Functions required by the reducer concept of Kokkos.
std::unique_ptr< DispatcherBase > build(const void *object) const override final
Build a dispatcher for this operation and functor.
Class that dispatches a parallel loop operation of a Kokkos functor.
static bool hasUserMethod(const std::string &name)
Get whether the user has overriden the hook method associated with an operation of a functor...
Reducer(const void *object)
Constructor.
static void addDispatcher(const std::string &name)
Register a dispatcher of an operation of a functor.
std::unique_ptr< DispatcherBase > build(const void *object) const override final
Build a dispatcher for this operation and functor.
DispatcherRegistry & operator=(DispatcherRegistry const &)=delete
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:311
::Kokkos::View< Real * >::size_type size_type
void parallelReduce(const Policy &policy, ::Kokkos::View< Real *, ::Kokkos::HostSpace > &result) override final
Dispatch this functor with Kokkos parallel_reduce() given a Kokkos execution policy and result buffer...
KOKKOS_FUNCTION void operator()(const ThreadID tid) const
The parallel computation entry function called by Kokkos::parallel_for.
const Object _functor_device
Copy of the functor on device.
static auto & getDispatcher(const std::string &name)
Get the dispatcher shell of an operation of a functor.
virtual void parallelFor(const Policy &)
Dispatch this functor with Kokkos parallel_for() given a Kokkos execution policy. ...
Class that stores the information of a dispatcher and builds it.
::Kokkos::RangePolicy< ExecSpace, ::Kokkos::IndexType< ThreadID > > Policy
Base class for dispatcher registry entry.
MOOSE_KOKKOS_INDEX_TYPE ThreadID
Definition: KokkosThread.h:22
virtual void parallelReduce(const Policy &, ::Kokkos::View< Real *, ::Kokkos::HostSpace > &)
Dispatch this functor with Kokkos parallel_reduce() given a Kokkos execution policy and result buffer...
static void addReducer(const std::string &name)
Register a reducer of an operation of a functor.
KOKKOS_FUNCTION void init(value_type result) const
static std::unique_ptr< DispatcherBase > build(const void *object, const std::string &name)
Build and get a dispatcher of an operation of a functor.
bool _has_user_method
Flag whether the user has overriden the hook method associated with this operation.
bool hasUserMethod() const
Get whether the user has overriden the hook method associated with this operation.
void hasUserMethod(bool flag)
Set whether the user has overriden the hook method associated with this operation.
Base class for Kokkos functor dispatcher.
const Object & _functor_host
Reference of the functor on host.
Dispatcher(const void *object)
Constructor.
const Object _functor_device
Copy of the functor on device.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void parallelFor(const Policy &policy) override final
Dispatch this functor with Kokkos parallel_for() given a Kokkos execution policy. ...
std::map< std::pair< std::type_index, std::string >, std::unique_ptr< DispatcherRegistryEntryBase > > _dispatchers
Map containing the dispatcher shells with the key being the pair of function tag type index and regis...
KOKKOS_FUNCTION void operator()(const ThreadID tid, value_type result) const
The parallel computation entry function called by Kokkos::parallel_reduce.
static void hasUserMethod(const std::string &name, const bool flag)
Set whether the user has overriden the hook method associated with an operation of a functor...
Class that registers dispatchers of all Kokkos functors.
Class that dispatches a parallel reduction operation of a Kokkos functor.
static DispatcherRegistry & getRegistry()
Get the registry singleton.
virtual std::unique_ptr< DispatcherBase > build(const void *object) const =0
Build a dispatcher for this operation and functor.
const Object & _functor_host
Reference of the functor on host.
Reducer(const Reducer &functor)
Copy constructor for parallel dispatch.
Dispatcher(const Dispatcher &functor)
Copy constructor for parallel dispatch.